# Actualizar un Tercero [BETA]

<p class="callout warning">**Funcionalidad en desarrollo y pruebas:** este servicio está disponible en el ambiente de pruebas y todavía no debe usarse en producción. El funcionamiento, los campos y los mensajes de error pueden cambiar antes del despliegue definitivo.</p>

Este servicio hace un **upsert por documento**: si el tercero existe, actualiza solo los campos que envías; si no existe, lo crea. Está pensado para que tu aplicación pueda propagar cambios sin conocer el `tercero_id` de nuby.

La regla más importante: **lo que no envías se conserva**. Esto aplica a los tipos de tercero, a los datos del cónyuge y a cualquier otro campo o JSON. No se borra nada por omisión.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para **mantener el tercero de nuby alineado con el de tu plataforma** sin guardar ni mapear identificadores internos. Los casos de uso más frecuentes son:</p>

<div class="page-content" dir="auto" id="bkmrk-propagar-un-cambio-d"><div dir="auto">- **Propagar un cambio de datos** del tercero —nombre, dirección, teléfono o correo— desde tu sistema hacia nuby.
- **Actualizar un solo campo** (por ejemplo el `email`) sin reenviar el resto: lo que no envías se conserva.
- **Crear el tercero si el documento todavía no existe**, con el mismo servicio y los obligatorios del alta.
- **Corregir datos sin tocar los tipos ni el cónyuge** que ya estaban registrados.
- **Propagar cambios desde un sistema que solo conoce el documento** del cliente, no el `tercero_id`.

---

</div></div>#### **1. El Endpoint (La dirección web)**

##### **Método y dirección**

<div class="page-content" dir="auto" id="bkmrk-dato-valor-m%C3%A9todo-pu"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 23%;"></col><col style="width: 77%;"></col></colgroup><thead><tr><th>Dato</th><th>Valor</th></tr></thead><tbody><tr><td>Método</td><td>`PUT`</td></tr><tr><td>Ruta</td><td>`/third-parties`</td></tr><tr><td>Scope requerido</td><td>`third-parties:update`</td></tr><tr><td>Autenticación</td><td>`Authorization: Bearer <jwt>`</td></tr><tr><td>Cuerpo de la petición</td><td>Objeto JSON con los datos del tercero</td></tr></tbody></table>

</div></div>```http
PUT https://{{instancia}}/service/v2/public/third-parties
```

##### **¿Qué debo colocar en `{{instancia}}`?**

Es la **dirección web principal** con la que ingresas a tu plataforma, incluyendo la terminación `.nuby.app` o `.arrendasoft.co`. Si entras a nuby escribiendo `inmobiliaria.nuby.app` en el navegador, esa es tu instancia.

<p class="callout warning">**Importante:** no incluyas `https://` ni barras diagonales (`/`) al final. La dirección se compone así: `https://` + tu instancia + `/service/v2/public/third-parties`.</p>

##### **Encabezados requeridos**

<div class="page-content" dir="auto" id="bkmrk-encabezado-%C2%BFobligato"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 14%;"></col><col style="width: 64%;"></col></colgroup><thead><tr><th>Encabezado</th><th>¿Obligatorio?</th><th>Valor</th></tr></thead><tbody><tr><td>`Authorization`</td><td>Sí</td><td>`Bearer <token>`, con el token obtenido en el servicio **Login**.</td></tr><tr><td>`Content-Type`</td><td>Sí</td><td>`application/json`: la petición lleva cuerpo JSON.</td></tr></tbody></table>

</div></div>##### **Permiso requerido (scope): `third-parties:update`**

El cliente OAuth con el que se genera el token debe tener habilitado el permiso `third-parties:update`. Si el token es válido pero al cliente le falta ese permiso, la respuesta es `403` con el código `RECURSO_NO_AUTORIZADO`.

<p class="callout info">Si aún no tienes un token, consulta la página [*<span class="tw-font-bold tw-text-arrBlue hover:tw-text-nubyBlue tw-cursor-pointer">Login</span>*](https://docs.nuby.ai/books/api-nuby-v2/page/login) del libro **API nuby V2**. Allí se explica cómo identificarte y cómo se construye el encabezado `Authorization`.</p>

##### **Requisitos previos de esta operación**

<div class="page-content" dir="auto" id="bkmrk-documento-es-obligat"><div dir="auto">- `documento` es obligatorio siempre: es la llave con la que nuby identifica el tercero.
- El `documento` solo admite **letras y números**: sin puntos, guiones ni espacios (`900.123.456` se rechaza).
- Si el tercero **no existe**, el payload debe traer los obligatorios del alta; si falta uno, la respuesta es `422`.
- El cliente OAuth del token debe tener el permiso `third-parties:update`.

</div></div><p class="callout warning">**El documento es la clave.** No se modifica por este endpoint: un documento distinto identifica otro tercero.</p>

#### **2. La Petición (¿Qué debes enviarnos?)**

El cuerpo debe ser un **objeto JSON**. En la raíz viaja la referencia de idempotencia y, al mismo nivel, los datos del tercero.

##### **Obligatorios en el alta**

`referencia_externa`, `documento`, `tipo_doc_id`, `nombre1`, `direccion1`, `municipio_id` y al menos un tipo (`tipo_tercero_id` o `tipos[]`).

##### **Obligatorios en la edición**

`referencia_externa` y `documento`. El resto es opcional: solo se actualiza lo que envías.

##### **Campos del cuerpo**

<div class="page-content" dir="auto" id="bkmrk-campo-tipo-requerido"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 27%;"></col><col style="width: 8%;"></col><col style="width: 9%;"></col><col style="width: 56%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>`referencia_externa`</td><td>texto</td><td>Sí</td><td>Identificador único de **tu** operación: es la llave de idempotencia. No puede venir vacía.</td></tr><tr><td>`documento`</td><td>texto</td><td>Sí</td><td>Documento o NIT del tercero. Es la llave de identidad y **no se modifica** por este endpoint. Solo letras y números.</td></tr><tr><td>`tipo_doc_id`</td><td>entero</td><td>Solo en el alta</td><td>Identificador del tipo de documento en la maestra de nuby. Debe ser mayor que cero y existir en el sistema.</td></tr><tr><td>`nombre1`</td><td>texto</td><td>Solo en el alta</td><td>Primer nombre, o la razón social si es una empresa. nuby lo guarda en mayúsculas.</td></tr><tr><td>`direccion1`</td><td>texto</td><td>Solo en el alta</td><td>Dirección principal del tercero.</td></tr><tr><td>`municipio_id`</td><td>entero</td><td>Solo en el alta</td><td>Identificador del municipio. Debe ser mayor que cero y existir en la maestra de municipios.</td></tr><tr><td>`tipo_tercero_id` *o* `tipos[]`</td><td>entero / arreglo o cadena</td><td>Solo en el alta (al menos uno)</td><td>Rol o roles del tercero. Se fusionan, se eliminan duplicados y se descartan valores no numéricos o `<= 0`. Si no se envían en la edición, se conservan los tipos actuales y, si no queda ninguno, la respuesta es `422`.</td></tr><tr><td>`persona`</td><td>entero</td><td>No</td><td>`1` persona natural (no admite NIT/NOP); `2` persona jurídica (exige NIT/NOP). Si se omite, la coherencia documento↔persona no se valida.</td></tr><tr><td>`nombre2`</td><td>texto</td><td>No</td><td>Segundo nombre. Se almacena en mayúsculas. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`apellido1`</td><td>texto</td><td>No</td><td>Primer apellido. Se almacena en mayúsculas. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`apellido2`</td><td>texto</td><td>No</td><td>Segundo apellido. Se almacena en mayúsculas. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`sexo`</td><td>texto</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`fecha_nacimiento`</td><td>fecha</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`dv`</td><td>texto</td><td>No</td><td>Dígito de verificación del documento. Se acepta si viene y se conserva si no.</td></tr><tr><td>`tratamiento_id`</td><td>entero</td><td>No</td><td>Identificador de la maestra de tratamiento. Se valida contra el catálogo.</td></tr><tr><td>`direccion2`</td><td>texto</td><td>No</td><td>Dirección secundaria. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`telefono1`, `telefono2`</td><td>texto</td><td>No</td><td>Teléfonos del tercero. Si no se envían, se conservan.</td></tr><tr><td>`fax`</td><td>texto</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`email`</td><td>texto</td><td>No</td><td>Correo principal. El servicio no valida su formato.</td></tr><tr><td>`email_cumpleanos`</td><td>texto</td><td>No</td><td>Correo alterno. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`codigo_postal`</td><td>texto</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`tipo_persona_id`</td><td>entero</td><td>No</td><td>Identificador de la maestra de tipo de persona. Se valida contra el catálogo.</td></tr><tr><td>`regimen_id`</td><td>entero</td><td>No</td><td>Régimen tributario. Se valida contra el catálogo.</td></tr><tr><td>`resp_fiscal_id`</td><td>entero</td><td>No</td><td>Responsabilidad fiscal. Se valida contra el catálogo.</td></tr><tr><td>`autoretenedor`</td><td>indicador</td><td>No</td><td>Marca de autorretenedor. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`autore_res`</td><td>indicador</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`gran_contribuyente`</td><td>indicador</td><td>No</td><td>Marca de gran contribuyente. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`gran_contr_res`</td><td>indicador</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`aplica_documento_soporte`</td><td>indicador</td><td>No</td><td>Marca de documento soporte. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`banco_id`</td><td>entero</td><td>No</td><td>Banco del tercero. Se valida contra el catálogo.</td></tr><tr><td>`intTipoCuentaB`</td><td>entero</td><td>No</td><td>Tipo de cuenta bancaria. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`no_cuenta`</td><td>texto</td><td>No</td><td>Número de cuenta bancaria. Si no se envía, se conserva el valor actual.</td></tr><tr><td>`representante`</td><td>texto</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`representante_legal`</td><td>texto</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`certificado`</td><td>texto / indicador</td><td>No</td><td>Si no se envía, se conserva el valor actual.</td></tr><tr><td>`CY_*` (campos del cónyuge)</td><td>según el campo</td><td>No</td><td>Sin ningún `CY_*` se conserva `data_conyuge`; si envías algunos, solo esos cambian.</td></tr><tr><td>`data_conyuge`</td><td>objeto JSON</td><td>No</td><td>Datos del cónyuge. Si no llega ningún `CY_*`, se conserva completo.</td></tr><tr><td>`data_propiedades`</td><td>objeto JSON</td><td>No</td><td>Si no se envía, se conserva el JSON anterior.</td></tr><tr><td>`por_retencion`</td><td>objeto JSON</td><td>No</td><td>Si no se envía, se conserva el JSON anterior.</td></tr><tr><td>`nombre_aux`</td><td>texto</td><td>No</td><td>Se calcula en el alta si falta y se conserva en la edición.</td></tr></tbody></table>

</div></div><p class="callout warning">**Campos que se ignoran:** los campos fuera de esta lista (por ejemplo `tercero_id`, `creadopor` o `password_hash`) nunca se escriben y no generan error.</p>

##### **Preservación**

<div class="page-content" dir="auto" id="bkmrk-sin-tipo_tercero_id%2F"><div dir="auto">- Sin `tipo_tercero_id`/`tipos[]`: se conservan los tipos existentes.
- Sin `CY_*`: se conserva el cónyuge; si envías algunos, solo esos cambian.
- Sin un campo o JSON: se conserva el valor anterior.
- `nombre_aux` se calcula en el alta si falta y se conserva en la edición.

</div></div>##### **Ejemplos de cuerpo**

**Actualizar solo el email** de un tercero que ya existe:

```json
{
  "referencia_externa": "TP-2026-0001-EDIT-1",
  "documento": "900123456",
  "email": "nuevo@acme.co"
}
```

**Crear si no existe**, con los obligatorios del alta:

```json
{
  "referencia_externa": "TP-2026-0002",
  "documento": "900654321",
  "tipo_doc_id": 1,
  "nombre1": "ACME SAS",
  "tipo_tercero_id": 1,
  "direccion1": "CL 1 #2-3",
  "municipio_id": 1
}
```

#### **3. La Respuesta (¿Qué te entregaremos?)**

Si el tercero existe y el payload es válido, la respuesta es `200` con el identificador del tercero y los indicadores de la operación:

```json
{
  "success": true,
  "status": 200,
  "message": "Tercero actualizado.",
  "body": {
    "tercero_id": 123,
    "documento": "900123456",
    "created": false,
    "updated": true,
    "idempotent_replay": false
  }
}
```

##### **Estructura principal de la respuesta**

<div class="page-content" dir="auto" id="bkmrk-campo-tipo-descripci"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 8%;"></col><col style="width: 70%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`success`</td><td>booleano</td><td>`true` cuando la operación se completó.</td></tr><tr><td>`status`</td><td>entero</td><td>Replica el código HTTP de la respuesta: `200` si actualizó, `201` si creó.</td></tr><tr><td>`message`</td><td>texto</td><td>Mensaje legible del resultado.</td></tr><tr><td>`body`</td><td>objeto</td><td>Identificador del tercero e indicadores de la operación. En un error, este campo no existe.</td></tr></tbody></table>

</div></div><p class="callout info">Las respuestas de escritura **no** traen `pagination` ni `filters_applied`: esos campos pertenecen a las consultas de lectura.</p>

##### **Campos del cuerpo (`body`)**

<div class="page-content" dir="auto" id="bkmrk-campo-tipo-descripci-1"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 8%;"></col><col style="width: 70%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`tercero_id`</td><td>entero</td><td>Identificador interno del tercero en nuby.</td></tr><tr><td>`documento`</td><td>texto</td><td>Documento con el que se resolvió el tercero: el mismo que enviaste.</td></tr><tr><td>`created`</td><td>booleano</td><td>`true` si el tercero se creó en esta llamada.</td></tr><tr><td>`updated`</td><td>booleano</td><td>`true` si el tercero existía y se aplicaron los campos enviados.</td></tr><tr><td>`idempotent_replay`</td><td>booleano</td><td>`true` cuando la respuesta viene de un reintento con la misma `referencia_externa`.</td></tr></tbody></table>

</div></div>##### **Escenarios alternativos**

Si el documento no existía y el payload trae los obligatorios, responde `201` con `created: true, updated: false`. El `body` queda así:

```json
{
  "tercero_id": 124,
  "documento": "900654321",
  "created": true,
  "updated": false,
  "idempotent_replay": false
}
```

`idempotent_replay: true` indica que la respuesta viene de un reintento con la misma `referencia_externa`:

```json
{
  "tercero_id": 123,
  "documento": "900123456",
  "created": false,
  "updated": true,
  "idempotent_replay": true
}
```

#### **4. Idempotencia y reintentos**

Toda escritura exige `referencia_externa`. La clave lógica es la combinación de tu origen, el recurso `tercero` y la referencia; el hash del payload es SHA-256 sobre una forma canónica del JSON, así que el **orden de las llaves no altera la comparación**.

<div class="page-content" dir="auto" id="bkmrk-situaci%C3%B3n-qu%C3%A9-respon"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 34%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Situación</th><th>Qué responde nuby</th></tr></thead><tbody><tr><td>Reintento con el mismo payload</td><td>La respuesta original con `idempotent_replay: true`.</td></tr><tr><td>Otra solicitud con la misma referencia en curso</td><td>`409 IDEMPOTENCY_IN_PROGRESS`.</td></tr><tr><td>La misma referencia con un payload distinto</td><td>`409 IDEMPOTENCY_PAYLOAD_MISMATCH`.</td></tr><tr><td>La solicitud anterior terminó en `422`</td><td>La referencia se **libera**: puedes reintentar con el mismo valor y el payload corregido.</td></tr><tr><td>La solicitud anterior terminó en `500`</td><td>Se permite reintentar, incluso con datos corregidos.</td></tr><tr><td>No se pudo registrar la solicitud de idempotencia</td><td>`500 IDEMPOTENCY_STORAGE_ERROR`.</td></tr></tbody></table>

</div></div><p class="callout info">**Una referencia por cambio.** Una referencia distinta habilita un cambio nuevo sobre el mismo documento; reutilizar la anterior devuelve la respuesta vieja y tu cambio no se aplica.</p>

#### **5. Seguridad y Posibles Errores**

##### **Tu pase tiene fecha de caducidad**

Por medidas de seguridad, el token que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el sistema te bloquea el acceso con un error `401` y tu sistema debe volver a consumir el servicio de **Login** para pedir un pase nuevo.

Esta respuesta la produce el **middleware de autenticación** y no el contrato de la operación, así que usa el envelope heredado (`statusCode` y `error.description`), no `success` ni `error_code`:

<div class="page-content" dir="auto" id="bkmrk-situaci%C3%B3n-http-detal"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 34%;"></col><col style="width: 14%;"></col><col style="width: 52%;"></col></colgroup><thead><tr><th>Situación</th><th>HTTP</th><th>Detalle</th></tr></thead><tbody><tr><td>No se envió el encabezado `Authorization`</td><td>`401`</td><td>`JWT Token required.`</td></tr><tr><td>El encabezado no tiene el formato `Bearer {token}`</td><td>`400`</td><td>`JWT Token not send.`</td></tr><tr><td>El token no fue encontrado en el sistema</td><td>`401`</td><td>`JWT Token not found.`</td></tr><tr><td>El token expiró</td><td>`401`</td><td>`JWT Token expired.`</td></tr></tbody></table>

</div></div>##### **Errores del contrato de la operación**

Los errores de la operación traen `success: false`, el código HTTP, un `message` legible y un `error_code` estable:

<div class="page-content" dir="auto" id="bkmrk-http-error_code-cu%C3%A1n"><div dir="auto"><table style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 14%;"></col><col style="width: 64%;"></col></colgroup><thead><tr><th>HTTP</th><th>`error_code`</th><th>Cuándo</th></tr></thead><tbody><tr><td>`400`</td><td>`VALIDATION_ERROR`</td><td>El cuerpo no es un objeto JSON.</td></tr><tr><td>`403`</td><td>`CONSUMIDOR_NO_AUTENTICADO`</td><td>El token es válido, pero no corresponde a un cliente OAuth habilitado para consumir la API.</td></tr><tr><td>`403`</td><td>`RECURSO_NO_AUTORIZADO`</td><td>El consumidor no tiene `third-parties:update`.</td></tr><tr><td>`409`</td><td>`TERCERO_IDENTIDAD_CONFLICTIVA`</td><td>El documento existe con otro `tipo_doc_id`.</td></tr><tr><td>`409`</td><td>`IDEMPOTENCY_PAYLOAD_MISMATCH`</td><td>La misma referencia se usó con otro payload.</td></tr><tr><td>`409`</td><td>`IDEMPOTENCY_IN_PROGRESS`</td><td>Otra solicitud con la misma referencia está en proceso.</td></tr><tr><td>`422`</td><td>`VALIDATION_ERROR`</td><td>Falta un obligatorio o un valor no cumple las reglas del modelo.</td></tr><tr><td>`500`</td><td>`INTERNAL_ERROR`</td><td>Fallo técnico; el detalle queda en el log `API_INTEGRACION`.</td></tr></tbody></table>

</div></div>##### **Mensajes de validación frecuentes**

<div class="page-content" dir="auto" id="bkmrk-el-campo-%22%7Betiqueta%7D"><div dir="auto">- `El campo "{Etiqueta}" es obligatorio.`
- `El campo "{Etiqueta}" debe ser un identificador numérico mayor que cero.` (para `tipo_doc_id` y `municipio_id`)
- `Debe enviar al menos un tipo de tercero en "Tipo de Tercero" o en tipos[].`
- `El valor ingresado en el campo "{Etiqueta}" no es válido para el sistema.` (maestras)
- `Una Persona Natural no puede registrarse con un tipo de documento de tipo NIT.`
- `Una Persona Jurídica debe registrarse de forma obligatoria con un documento de tipo NIT.`

</div></div><p class="callout warning">**Trata el `409 TERCERO_IDENTIDAD_CONFLICTIVA` como un caso de negocio**, no como una falla técnica: ese documento existe en nuby con otro tipo de documento, y este endpoint no lo cambia. No lo reintentes con el mismo payload.</p>

<div class="page-content" dir="auto" id="bkmrk-"><div dir="auto">---

</div></div>#### **6. Ejemplos de integración**

Aquí tienes ejemplos listos para adaptar a tu plataforma. Todos usan `{{instancia}}`, `Authorization: Bearer`, actualizan solo el `email` de un tercero y tratan el éxito (`200`/`201`) junto con los rechazos de negocio más frecuentes (`409` y `422`).

<div class="page-content" dir="auto" id="bkmrk-curl-token%3D%22tu_token"><div dir="auto"><details><summary>cURL</summary>

```bash
TOKEN="TU_TOKEN_AQUI"
INSTANCIA="mi-inmobiliaria.nuby.app"

curl -X PUT "https://${INSTANCIA}/service/v2/public/third-parties" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  -d '{
    "referencia_externa": "TP-2026-0001-EDIT-1",
    "documento": "900123456",
    "email": "nuevo@acme.co"
  }'
```

</details><details><summary>PHP</summary>

```php
<?php
$instancia = 'mi-inmobiliaria.nuby.app'; // Tu dirección web completa
$token     = 'TU_TOKEN_AQUI';            // Token obtenido del servicio Login

$payload = [
    'referencia_externa' => 'TP-2026-0001-EDIT-1',
    'documento'          => '900123456',
    'email'              => 'nuevo@acme.co',
];

$ch = curl_init("https://{$instancia}/service/v2/public/third-parties");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

$respuesta = curl_exec($ch);
$httpCode  = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$info = json_decode($respuesta, true);

if ($httpCode === 200 || $httpCode === 201) {
    echo "Tercero {$info['body']['tercero_id']}: {$httpCode}\n";
    echo "Creado: " . var_export($info['body']['created'], true) . "\n";
    echo "Actualizado: " . var_export($info['body']['updated'], true) . "\n";
} elseif ($httpCode === 409 || $httpCode === 422) {
    echo "Rechazo de negocio {$info['error_code']}: {$info['message']}\n";
} else {
    echo "Error HTTP {$httpCode}: {$info['message']}\n";
}
```

</details><details><summary>Python</summary>

```python
import requests

# 1. Configura tus datos de acceso
instancia = "mi-inmobiliaria.nuby.app"  # Reemplaza con tu dirección web completa
token = "TU_TOKEN_AQUI"                 # Token obtenido del servicio Login

# 2. Prepara el cuerpo y envía la petición
url = f"https://{instancia}/service/v2/public/third-parties"
headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}",
}
payload = {
    "referencia_externa": "TP-2026-0001-EDIT-1",
    "documento": "900123456",
    "email": "nuevo@acme.co",
}

respuesta = requests.put(url, json=payload, headers=headers, timeout=30)

# 3. Procesa la respuesta
if respuesta.status_code in (200, 201):
    body = respuesta.json()["body"]
    print(f"Tercero {body['tercero_id']} - creado: {body['created']} - actualizado: {body['updated']}")
elif respuesta.status_code in (409, 422):
    error = respuesta.json()
    print(f"Rechazo de negocio {error['error_code']}: {error['message']}")
else:
    print(f"Error HTTP {respuesta.status_code}: {respuesta.text}")
```

</details><details><summary>JavaScript (Fetch API)</summary>

```javascript
// 1. Configura tus datos de acceso
const instancia = 'mi-inmobiliaria.nuby.app'; // Reemplaza con tu dirección web completa
const token = 'TU_TOKEN_AQUI';                // Token obtenido del servicio Login

// 2. Función que actualiza (o crea) el tercero
async function actualizarTercero(payload) {
  const url = `https://${instancia}/service/v2/public/third-parties`;

  const response = await fetch(url, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify(payload),
  });

  const info = await response.json().catch(() => ({}));

  if (!response.ok) {
    console.error(`Error HTTP ${response.status} ${info.error_code ?? ''}: ${info.message ?? ''}`);
    return null;
  }

  return info.body;
}

// 3. Cambia solo el email y revisa el resultado
actualizarTercero({
  referencia_externa: 'TP-2026-0001-EDIT-1',
  documento: '900123456',
  email: 'nuevo@acme.co',
}).then((body) => {
  if (!body) {
    return;
  }

  console.log(`Tercero ${body.tercero_id} creado: ${body.created} actualizado: ${body.updated}`);
});
```

</details></div></div>#### **7. Buenas prácticas y límites conocidos**

##### **Recomendaciones**

<div class="page-content" dir="auto" id="bkmrk-manda-una-referencia"><div dir="auto">- **Manda una referencia nueva por cambio.** No reutilices la referencia de un cambio anterior: el replay devuelve la respuesta vieja.
- **No envíes campos vacíos para “borrar”.** Un campo ausente se conserva; para limpiar un valor hay que definir una regla explícita (no cubierta por este endpoint).
- **Manda el tipo de tercero en el alta.** Puede ser cualquiera válido; no hay un mapeo fijo.
- **Verifica el 201/200.** El primero crea, el segundo actualiza; ambos son éxito.
- **No cambies el documento por este endpoint.** Si el documento cambió, es otro tercero.

</div></div>##### **Límites de este servicio**

<div class="page-content" dir="auto" id="bkmrk-no-devuelve-el-detal"><div dir="auto">- **No devuelve el detalle del tercero.** Solo el `tercero_id`, el `documento` y los indicadores de la operación.
- **No borra datos.** Un campo que no envías se conserva; no existe una operación de borrado por este servicio.
- **No completa datos por su cuenta.** Si el tercero no existe y falta un obligatorio, responde `422`.
- **No cambia el tipo de documento.** Si el documento existe con otro `tipo_doc_id`, responde `409 TERCERO_IDENTIDAD_CONFLICTIVA`.
- **No impone un tipo de tercero.** Acepta cualquier `tipo_tercero_id` o `tipos[]` válido.

</div></div>