# API nuby V2

Aquí encontrarás el catálogo detallado de todos los servicios que nuestra plataforma tiene disponibles para ti.

<span>Para que quede súper claro, piensa en esta sección como si fuera el menú de un restaurante o un directorio muy bien organizado. Aquí te vamos a mostrar </span>**qué opciones tienes disponibles y cómo pedirnos la información**.

<span>En el mundo de la tecnología, a estas opciones las llamamos </span>**endpoints**<span> (puntos de conexión a los que te diriges para pedir algo específico). A lo largo de este documento te explicaremos:</span>

- <span>Qué hace cada uno de estos </span>**endpoints**<span> o servicios.</span>
- <span>Qué datos exactos debes enviarnos para que te entendamos (a esto le llamamos </span>**parámetros**<span> o datos de petición).</span>
- Qué información exacta te va a devolver nuestro sistema como respuesta.

Con este directorio a la mano, tú o tu equipo técnico sabrán exactamente cómo comunicarse con el sistema, permitiendo que tus plataformas externas se integren a la perfección con el ecosistema (al que llamamos "instancia") de tu inmobiliaria en nuby.

¡Explora nuestro directorio y descubre toda la información que puedes consultar y gestionar!

# Autenticación

<span>Bienvenido al </span>**filtro de seguridad**<span> de nuestra API. Antes de consultar o enviar información, necesitamos validar que tu conexión tenga los permisos necesarios para proteger tus datos en todo momento.</span>

**¿Cómo funciona el acceso?**<span> Piensa en esta sección como la recepción de un edificio privado. Aquí te explicamos cómo tu aplicación debe "identificarse" para obtener un </span>**token**<span> (tu llave de acceso temporal).</span>

**Reglas clave de tu token de acceso:**

- **Pase obligatorio:**<span> Absolutamente todos los servicios de nuestro sistema te exigirán esta llave antes de procesar tus peticiones.</span>
- **Vigencia limitada (1 hora):**<span> Por tu seguridad, el token tiene un ciclo de vida corto para evitar accesos no autorizados prolongados.</span>
- **Renovación continua:**<span> Cuando el tiempo se agote, tu sistema simplemente debe solicitar uno nuevo a través de esta sección para seguir trabajando sin interrupciones.</span>

¡Explora cómo generar tu primera llave para comenzar a integrarte de forma segura!

# Login

Antes de que tus sistemas puedan comunicarse con nuestra API, necesitan identificarse. Este servicio es como la recepción de nuestro edificio digital: aquí entregas tus credenciales y, a cambio, recibes un "pase de invitado" temporal (llamado **Token**). Necesitarás presentar este pase para que el sistema te permita acceder a cualquier otra sección (como contratos, facturas o propiedades).

<p class="callout warning">**¿Aún no tienes tus credenciales de acceso?**  
Para usar este servicio, primero necesitas un usuario y contraseña especiales para tu aplicación. Descubre [cómo crear un nuevo cliente OAuth2 en nuby para consumo de la API paso a paso aquí](https://docs.nuby.ai/books/herramientas/page/como-crear-un-nuevo-cliente-oauth2-en-nuby-para-consumo-de-la-api).</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
POST https://{{instancia}}/service/v2/public/auth/login
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Tu sistema debe enviarnos un paquete de datos en formato JSON indicando que el contenido es `application/json`. El cuerpo de tu petición debe verse así:

```json
{
    "username": "TU_CLIENT_ID",
    "password": "TU_SECRET_KEY"
}
```

<table border="1" id="bkmrk-username-es-el-id-de" style="border-collapse: collapse; width: 100%;"><colgroup> <col style="width: 20%;"></col> <col style="width: 80%;"></col> </colgroup><tbody><tr><td>**username**</td><td>Es el **ID del Cliente** (OAuth2) que generaste previamente en el sistema.</td></tr><tr><td>**password**</td><td>Es la **Clave Secreta** (Secret Key / OAuth2) vinculada a tu usuario.</td></tr></tbody></table>

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

Si tus credenciales son correctas, el sistema te dará la bienvenida entregándote tu pase de acceso (Token). La respuesta se verá similar a esta:

```json
{
  "message": null,
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "expiration": 1690540790
}
```

<table border="1" id="bkmrk-token-tu-llave-de-ac" style="border-collapse: collapse; width: 100%;"><colgroup> <col style="width: 20%;"></col> <col style="width: 80%;"></col> </colgroup><tbody><tr><td>**token**</td><td>**Tu llave de acceso.** A partir de ahora, en todas tus siguientes consultas a nuestra plataforma, deberás incluir este código en los encabezados (Headers) de tu petición usando el formato: `Authorization: Bearer TU_TOKEN_AQUI`</td></tr><tr><td>**expiration**</td><td>La fecha y hora exacta (en formato *timestamp*) en la que este pase dejará de funcionar.</td></tr><tr><td>**message**</td><td>Mensaje de confirmación o texto explicativo (en caso de presentarse alguna novedad).</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401 Unauthorized`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir este servicio de Login para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-ejemplo-usando-curl-"><summary>cURL</summary>

```bash
curl -X POST "https://{{instancia}}/service/v2/public/auth/login" \
-H "Content-Type: application/json" \
-d '{
  "username": "TU_CLIENT_ID", 
  "password": "TU_SECRET_KEY"
}'
```

</details><details id="bkmrk-ejemplo-usando-php-%3C"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$username = 'TU_CLIENT_ID'; // Reemplaza con el ID de cliente proporcionado
$password = 'TU_SECRET_KEY'; // Reemplaza con la clave secreta proporcionada

$url = "https://{$instance}/service/v2/public/auth/login";

$data = json_encode([
    'username' => $username,
    'password' => $password
]);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data)
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";
    $responseData = json_decode($response, true);
    
    if (isset($responseData['token'])) {
        echo "¡Éxito! Tu Token de Autenticación es: " . $responseData['token'] . "\n";
    } else {
        echo "Autenticación fallida.\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><summary>Python</summary>

```python
import requests

# 1. Configura tus datos de acceso
instancia = 'mi-inmobiliaria.nuby.app' # Reemplaza con tu dirección web completa
username = 'TU_CLIENT_ID' # Reemplaza con el ID de cliente proporcionado
password = 'TU_SECRET_KEY' # Reemplaza con la clave secreta proporcionada

# 2. Prepara la dirección y los datos a enviar
url = f"https://{instancia}/service/v2/public/auth/login"

headers = {
    "Content-Type": "application/json"
}

payload = {
    "username": username,
    "password": password
}

# 3. Envía la petición a la plataforma y procesa la respuesta
try:
    # Enviamos la petición POST (la librería convierte automáticamente el payload a JSON)
    response = requests.post(url, json=payload, headers=headers)
    
    print(f"Código de estado HTTP: {response.status_code}")
    
    # Si la petición es exitosa (código 200 OK)
    if response.status_code == 200:
        data = response.json()
        token = data.get("token")
        print(f"¡Éxito! Tu Token de Autenticación es: {token}")
    else:
        print("Autenticación fallida.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</summary>

```javascript
// 1. Configura tus datos de acceso
const instancia = 'mi-inmobiliaria.nuby.app'; // Reemplaza con tu dirección web completa
const username = 'TU_CLIENT_ID'; // Reemplaza con el ID de cliente proporcionado
const password = 'TU_SECRET_KEY'; // Reemplaza con la clave secreta proporcionada

// 2. Prepara la dirección y los datos a enviar
const url = `https://${instancia}/service/v2/public/auth/login`;

const data = {
    username: username,
    password: password
};

// 3. Función para enviar la petición a la plataforma
async function realizarLogin() {
    try {
        // Configuramos y enviamos la petición POST
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data) // Convertimos los datos a formato JSON
        });
        
        console.log(`Código de estado HTTP: ${response.status}`);
        
        // Si la petición es exitosa (códigos 200-299)
        if (response.ok) {
            const responseData = await response.json();
            console.log(`¡Éxito! Tu Token de Autenticación es: ${responseData.token}`);
        } else {
            console.log("Autenticación fallida.");
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
realizarLogin();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 1. Configura tus datos de acceso
    instancia = "mi-inmobiliaria.nuby.app", // Reemplaza con tu dirección web completa
    username = "TU_CLIENT_ID", // Reemplaza con el ID de cliente proporcionado
    password = "TU_SECRET_KEY", // Reemplaza con la clave secreta proporcionada

    // 2. Prepara la dirección y el cuerpo de la petición (en formato JSON)
    url = "https://" & instancia & "/service/v2/public/auth/login",
    
    body = Json.FromValue([
        username = username,
        password = password
    ]),

    // 3. Envía la petición POST a la plataforma
    response = Web.Contents(url, [
        Headers = [#"Content-Type"="application/json"],
        Content = body
    ]),

    // 4. Decodifica la respuesta JSON y extrae el token
    jsonResponse = Json.Document(response),
    token = jsonResponse[token]
in
    token
```

</details>

# Maestras

<span>Bienvenido a la </span>**base estructural**<span> de tus integraciones. En esta sección detallamos los servicios disponibles para consultar las "entidades maestras" en la API REST de nuby.</span>

**¿Qué son exactamente las entidades maestras?**<span> Para evitar términos técnicos complejos, piensa en ellas como los </span>**diccionarios predefinidos**, los catálogos base o las listas desplegables de tu sistema.

**¿Por qué son tan importantes para tu conexión?**

- **Estandarización total:**<span> Son listas fijas que organizan la información para que todo se mantenga ordenado y sin ambigüedades (garantizando, por ejemplo, que el sistema identifique correctamente una "Casa" frente a un "Apartamento").</span>
- **Sincronización de lenguaje:**<span> Permiten que tus plataformas externas lean, entiendan y clasifiquen los datos usando exactamente los mismos parámetros y reglas que utiliza tu inmobiliaria.</span>

¡Explora las opciones a continuación para sincronizar tus catálogos y asegurar que todos tus sistemas hablen el mismo idioma!

# Propiedades / Listar Estados

Permite obtener la lista completa de estados posibles que puede tener una propiedad en el sistema. Cada elemento de la respuesta contiene el identificador numérico del estado y su descripción en texto. Este servicio es útil para poblar selectores o filtros de estado en tus integraciones.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para conocer los valores válidos del campo `estado` al momento de filtrar, crear o actualizar propiedades a través de la API. Así te aseguras de enviar siempre un valor reconocido por el sistema.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/masters/properties/states
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas enviar los encabezados correctos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido, el sistema te devolverá una lista con todos los estados posibles de una propiedad. La respuesta se verá así:

```json
[
    {
        "id": 1,
        "estado": "Activa"
    },
    {
        "id": 0,
        "estado": "Arrendada"
    },
    {
        "id": 2,
        "estado": "Inactiva"
    },
    {
        "id": 3,
        "estado": "Vendida"
    }
]
```

Tabla con la descripción de cada campo del JSON:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Clave</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador numérico del estado. Utiliza este valor cuando necesites filtrar propiedades por estado o actualizar el estado de una propiedad a través de la API.</td></tr><tr><td>**estado**</td><td>Nombre descriptivo del estado en texto legible (por ejemplo: "Activa", "Arrendada").</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-curl--x-get-%22ht"><summary>cURL</summary>

```bash
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/states" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio de Login

$url = "https://{$instance}/service/v2/public/masters/properties/states";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $estados = json_decode($response, true);
        echo "Estados de propiedades:\n";
        foreach ($estados as $estado) {
            echo "  ID: {$estado['id']} - {$estado['estado']}\n";
        }
    } else {
        echo "Error al consultar los estados.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 de Login

# 2. Prepara la dirección y los encabezados
url = f"https://{instancia}/service/v2/public/masters/properties/states"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        estados = response.json()
        print("Estados de propiedades:")
        for estado in estados:
            print(f"  ID: {estado['id']} - {estado['estado']}")
    else:
        print("Error al consultar los estados.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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 de Login

// 2. Prepara la dirección
const url = `https://${instancia}/service/v2/public/masters/properties/states`;

// 3. Función para consultar los estados de propiedades
async function consultarEstados() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const estados = await response.json();
            console.log('Estados de propiedades:');
            estados.forEach(estado => {
                console.log(`  ID: ${estado.id} - ${estado.estado}`);
            });
        } else {
            console.log('Error al consultar los estados.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarEstados();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 de Login

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/masters/properties/states",

    // 3. Envía la petición GET con el token de autenticación
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1", {"id", "estado"}, {"ID", "Estado"})
in
    expandido
```

</details>

# Propiedades / Listar Clases de Inmueble

Permite obtener la lista completa de clases de inmueble disponibles en el sistema. Cada elemento de la respuesta contiene el identificador único de la clase y su nombre descriptivo. Este servicio es útil para poblar selectores de tipo de inmueble en tus integraciones.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para conocer los valores válidos del campo `clase` de inmueble al momento de filtrar o registrar propiedades a través de la API. Así te aseguras de enviar siempre un valor reconocido por el sistema. Las clases de inmueble disponibles dependen de la configuración de cada instancia.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/masters/properties/property-classes
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas enviar los encabezados correctos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido, el sistema te devolverá una lista con todas las clases de inmueble configuradas en tu instancia. La respuesta se verá similar a esta:

```json
[
    {
        "id": "1367",
        "clase": "Amoblados"
    },
    {
        "id": "1253",
        "clase": "Apartaestudio"
    },
    {
        "id": "1247",
        "clase": "Apartamento"
    },
    {
        "id": "1248",
        "clase": "Bodega"
    },
    {
        "id": "1249",
        "clase": "Casa"
    }
]
```

<p class="callout info">**Nota:** Los valores de `id` y la cantidad de clases disponibles pueden variar entre instancias, ya que dependen de la configuración particular de cada inmobiliaria. La lista se devuelve ordenada alfabéticamente por el nombre de la clase.</p>

Tabla con la descripción de cada campo del JSON:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Clave</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador único de la clase de inmueble (tipo texto). Utiliza este valor cuando necesites filtrar propiedades por clase de inmueble a través de la API.</td></tr><tr><td>**clase**</td><td>Nombre descriptivo de la clase de inmueble (por ejemplo: "Apartamento", "Casa", "Bodega").</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-curl--x-get-%22ht"><summary>cURL</summary>

```bash
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/property-classes" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio de Login

$url = "https://{$instance}/service/v2/public/masters/properties/property-classes";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $clases = json_decode($response, true);
        echo "Clases de inmueble:\n";
        foreach ($clases as $clase) {
            echo "  ID: {$clase['id']} - {$clase['clase']}\n";
        }
    } else {
        echo "Error al consultar las clases de inmueble.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 de Login

# 2. Prepara la dirección y los encabezados
url = f"https://{instancia}/service/v2/public/masters/properties/property-classes"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        clases = response.json()
        print("Clases de inmueble:")
        for clase in clases:
            print(f"  ID: {clase['id']} - {clase['clase']}")
    else:
        print("Error al consultar las clases de inmueble.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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 de Login

// 2. Prepara la dirección
const url = `https://${instancia}/service/v2/public/masters/properties/property-classes`;

// 3. Función para consultar las clases de inmueble
async function consultarClasesDeInmueble() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const clases = await response.json();
            console.log('Clases de inmueble:');
            clases.forEach(clase => {
                console.log(`  ID: ${clase.id} - ${clase.clase}`);
            });
        } else {
            console.log('Error al consultar las clases de inmueble.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarClasesDeInmueble();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 de Login

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/masters/properties/property-classes",

    // 3. Envía la petición GET con el token de autenticación
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1", {"id", "clase"}, {"ID", "Clase"})
in
    expandido
```

</details>

# Propiedades / Listar Tipos de Servicios

Permite obtener la lista completa de tipos de servicio que puede tener una propiedad en el sistema. Cada elemento de la respuesta contiene el identificador del tipo de servicio y su nombre descriptivo. Este servicio es útil para poblar selectores o filtros de tipo de servicio en tus integraciones.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para conocer los valores válidos del campo de tipo de servicio al momento de filtrar o registrar propiedades a través de la API. Así te aseguras de enviar siempre un valor reconocido por el sistema. Los nombres descriptivos pueden variar ligeramente entre instancias según la configuración de cada inmobiliaria, pero los identificadores (`id`) son siempre los mismos.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/masters/properties/service-types
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas enviar los encabezados correctos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido, el sistema te devolverá una lista con los tres tipos de servicio disponibles para propiedades. La respuesta se verá similar a esta:

```json
[
    {
        "id": "arriendo",
        "servicio": "Arriendo"
    },
    {
        "id": "venta",
        "servicio": "Venta"
    },
    {
        "id": "venta y arriendo",
        "servicio": "Venta y Arriendo"
    }
]
```

<p class="callout info">**Nota:** El campo `id` es de tipo texto (string) y sus valores son fijos: `"arriendo"`, `"venta"` y `"venta y arriendo"`. El campo `servicio` muestra el nombre descriptivo, que puede variar ligeramente entre instancias según la configuración de cada inmobiliaria.</p>

Tabla con la descripción de cada campo del JSON:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Clave</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador del tipo de servicio (tipo texto). Valores posibles: `"arriendo"`, `"venta"`, `"venta y arriendo"`. Utiliza este valor cuando necesites filtrar propiedades por tipo de servicio a través de la API.</td></tr><tr><td>**servicio**</td><td>Nombre descriptivo del tipo de servicio (por ejemplo: "Arriendo", "Venta", "Venta y Arriendo").</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-curl--x-get-%22ht"><summary>cURL</summary>

```bash
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/service-types" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio de Login

$url = "https://{$instance}/service/v2/public/masters/properties/service-types";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $servicios = json_decode($response, true);
        echo "Tipos de servicio:\n";
        foreach ($servicios as $servicio) {
            echo "  ID: {$servicio['id']} - {$servicio['servicio']}\n";
        }
    } else {
        echo "Error al consultar los tipos de servicio.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 de Login

# 2. Prepara la dirección y los encabezados
url = f"https://{instancia}/service/v2/public/masters/properties/service-types"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        servicios = response.json()
        print("Tipos de servicio:")
        for servicio in servicios:
            print(f"  ID: {servicio['id']} - {servicio['servicio']}")
    else:
        print("Error al consultar los tipos de servicio.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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 de Login

// 2. Prepara la dirección
const url = `https://${instancia}/service/v2/public/masters/properties/service-types`;

// 3. Función para consultar los tipos de servicio
async function consultarTiposDeServicio() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const servicios = await response.json();
            console.log('Tipos de servicio:');
            servicios.forEach(servicio => {
                console.log(`  ID: ${servicio.id} - ${servicio.servicio}`);
            });
        } else {
            console.log('Error al consultar los tipos de servicio.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarTiposDeServicio();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 de Login

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/masters/properties/service-types",

    // 3. Envía la petición GET con el token de autenticación
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1", {"id", "servicio"}, {"ID", "Servicio"})
in
    expandido
```

</details>

# Propiedades / Listar Características

Permite obtener la lista completa de características que pueden tener las propiedades en el sistema. Cada elemento de la respuesta contiene la información detallada de una característica, incluyendo su tipo de campo, opciones disponibles y la clase de inmueble a la que pertenece. Este servicio es útil para construir formularios dinámicos de propiedades o para conocer qué datos se pueden registrar en cada tipo de inmueble.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para obtener el catálogo de características configuradas en la plataforma. Cada característica está vinculada a una clase de inmueble específica (Apartamento, Casa, Bodega, etc.) y tiene un tipo de campo que indica cómo debe capturarse la información (numérico, checkbox, lista desplegable, etc.). Si necesitas consultar solo las características de una clase de inmueble en particular, utiliza el endpoint de **Listar Características por Clase de Inmueble**.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/masters/properties/features
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas enviar los encabezados correctos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido, el sistema te devolverá una lista con todas las características configuradas para las propiedades. La respuesta se verá similar a esta:

```json
[
    {
        "id": "1",
        "descripcion": "Nº De Habitaciones",
        "tipo_campo": "numeric",
        "opciones_valores": null,
        "opciones_descripciones": null,
        "orden": "1",
        "grupo": "Características del inmueble",
        "clase_inmueble_id": "1367",
        "clase_inmueble": "Amoblados"
    },
    {
        "id": "2",
        "descripcion": "Nº De Baños",
        "tipo_campo": "numeric",
        "opciones_valores": null,
        "opciones_descripciones": null,
        "orden": "2",
        "grupo": "Características del inmueble",
        "clase_inmueble_id": "1367",
        "clase_inmueble": "Amoblados"
    },
    {
        "id": "54",
        "descripcion": "Oficina",
        "tipo_campo": "checkbox",
        "opciones_valores": "",
        "opciones_descripciones": "",
        "orden": "3",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1248",
        "clase_inmueble": "Bodega"
    },
    {
        "id": "13",
        "descripcion": "Baño Auxiliar",
        "tipo_campo": "checkbox",
        "opciones_valores": null,
        "opciones_descripciones": null,
        "orden": "4",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    },
    {
        "id": "38",
        "descripcion": "Parqueadero",
        "tipo_campo": "select",
        "opciones_valores": "propio,visitantes",
        "opciones_descripciones": "Propio,Visitantes",
        "orden": "12",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    }
]
```

<p class="callout info">**Nota:** Las características disponibles, sus grupos y las clases de inmueble asociadas dependen de la configuración de cada instancia. La lista se devuelve ordenada por grupo, luego por orden dentro del grupo, y finalmente por descripción alfabéticamente.</p>

Tabla con la descripción de cada campo del JSON:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Clave</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador único de la característica (tipo texto).</td></tr><tr><td>**descripcion**</td><td>Nombre descriptivo de la característica (por ejemplo: "Nº De Habitaciones", "Parqueadero").</td></tr><tr><td>**tipo\_campo**</td><td>Tipo de campo que define cómo se captura la información. Valores posibles: `numeric` (campo numérico), `checkbox` (casilla de verificación), `select` (lista desplegable con opciones predefinidas), entre otros.</td></tr><tr><td>**opciones\_valores**</td><td>Valores técnicos de las opciones disponibles, separados por coma. Aplica únicamente cuando `tipo_campo` es `select`. Será `null` o vacío para otros tipos de campo.</td></tr><tr><td>**opciones\_descripciones**</td><td>Descripciones legibles de las opciones disponibles, separadas por coma. Cada descripción corresponde posicionalmente al valor en `opciones_valores`. Por ejemplo, si `opciones_valores` es `"propio,visitantes"`, las descripciones serán `"Propio,Visitantes"`.</td></tr><tr><td>**orden**</td><td>Posición numérica que indica el orden de presentación de la característica dentro de su grupo.</td></tr><tr><td>**grupo**</td><td>Nombre del grupo al que pertenece la característica (por ejemplo: "Características del Inmueble"). Permite agrupar visualmente las características en un formulario.</td></tr><tr><td>**clase\_inmueble\_id**</td><td>Identificador de la clase de inmueble a la que está asociada esta característica. Corresponde al `id` devuelto por el servicio **Listar Clases de Inmueble**.</td></tr><tr><td>**clase\_inmueble**</td><td>Nombre descriptivo de la clase de inmueble (por ejemplo: "Amoblados", "Casa", "Bodega").</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Endpoint relacionado: Filtrar por Clase de Inmueble**

Si necesitas obtener únicamente las características de una clase de inmueble específica, puedes usar el siguiente endpoint en lugar de filtrar la respuesta completa:

```http
GET https://{{instancia}}/service/v2/public/masters/properties/features/property-class/{id}
```

Donde `{id}` es el identificador numérico de la clase de inmueble (obtenido del servicio **Listar Clases de Inmueble**). La respuesta tiene exactamente la misma estructura que este endpoint, pero filtrada a la clase indicada.

Si el parámetro `{id}` está vacío o no es numérico, el sistema devolverá un error `400`:

```json
{
    "error": "El ID de la clase del inmueble no puede estar vacío y debe ser de tipo numérico"
}
```

---

#### **6. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-listar-todas-"><summary>cURL</summary>

```bash
# Listar todas las características
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/features" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Listar características de una clase de inmueble específica (ej. ID 1249 = Casa)
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/features/property-class/1249" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio de Login

// Para todas las características:
$url = "https://{$instance}/service/v2/public/masters/properties/features";

// Para filtrar por clase de inmueble (descomentar y reemplazar el ID):
// $claseInmuebleId = 1249; // Ejemplo: Casa
// $url = "https://{$instance}/service/v2/public/masters/properties/features/property-class/{$claseInmuebleId}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $caracteristicas = json_decode($response, true);
        echo "Características de propiedades:\n";
        foreach ($caracteristicas as $car) {
            echo "  [{$car['clase_inmueble']}] {$car['descripcion']} (tipo: {$car['tipo_campo']})\n";
        }
    } else {
        echo "Error al consultar las características.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 de Login

# 2. Prepara la dirección y los encabezados
# Para todas las características:
url = f"https://{instancia}/service/v2/public/masters/properties/features"

# Para filtrar por clase de inmueble (descomentar y reemplazar el ID):
# clase_inmueble_id = 1249  # Ejemplo: Casa
# url = f"https://{instancia}/service/v2/public/masters/properties/features/property-class/{clase_inmueble_id}"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        caracteristicas = response.json()
        print("Características de propiedades:")
        for car in caracteristicas:
            print(f"  [{car['clase_inmueble']}] {car['descripcion']} (tipo: {car['tipo_campo']})")
    else:
        print("Error al consultar las características.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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 de Login

// 2. Prepara la dirección
// Para todas las características:
const url = `https://${instancia}/service/v2/public/masters/properties/features`;

// Para filtrar por clase de inmueble (descomentar y reemplazar el ID):
// const claseInmuebleId = 1249; // Ejemplo: Casa
// const url = `https://${instancia}/service/v2/public/masters/properties/features/property-class/${claseInmuebleId}`;

// 3. Función para consultar las características
async function consultarCaracteristicas() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const caracteristicas = await response.json();
            console.log('Características de propiedades:');
            caracteristicas.forEach(car => {
                console.log(`  [${car.clase_inmueble}] ${car.descripcion} (tipo: ${car.tipo_campo})`);
            });
        } else {
            console.log('Error al consultar las características.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarCaracteristicas();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 de Login

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/masters/properties/features",

    // 3. Envía la petición GET con el token de autenticación
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"id", "descripcion", "tipo_campo", "opciones_valores", "opciones_descripciones", "orden", "grupo", "clase_inmueble_id", "clase_inmueble"},
        {"ID", "Descripcion", "TipoCampo", "OpcionesValores", "OpcionesDescripciones", "Orden", "Grupo", "ClaseInmuebleID", "ClaseInmueble"})
in
    expandido
```

</details>

# Propiedades / Listar Características por Clase de Inmueble

Permite obtener la lista de características que puede tener una propiedad, filtrada por una clase de inmueble específica. Cada elemento de la respuesta contiene la información detallada de una característica perteneciente a la clase indicada. Este servicio es ideal cuando ya conoces la clase de inmueble y solo necesitas las características aplicables a ese tipo.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo cuando necesites construir un formulario dinámico para un tipo de inmueble en particular (por ejemplo, solo las características de "Casa" o de "Apartamento"). Si prefieres obtener todas las características de todas las clases de una sola vez, utiliza el endpoint de [**Listar Características**](https://docs.nuby.ai/books/api-nuby-v2/page/listar-caracteristicas). Para conocer los identificadores válidos de clases de inmueble, consulta el servicio de [**Listar Clases de Inmueble**](https://docs.nuby.ai/books/api-nuby-v2/page/listar-clases-de-inmueble).</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma, y <span style="color: rgb(241, 196, 15);">**{{id}}**</span> por el identificador numérico de la clase de inmueble que deseas consultar.

```http
GET https://{{instancia}}/service/v2/public/masters/properties/features/property-class/{{id}}
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas enviar los encabezados correctos y el parámetro de ruta:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

**Parámetro de ruta:**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 15%;"></col><col style="width: 15%;"></col><col style="width: 50%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Numérico</td><td>Sí</td><td>Identificador único de la clase de inmueble. Puedes obtener los valores válidos consultando el servicio de [**Listar Clases de Inmueble**](https://docs.nuby.ai/books/api-nuby-v2/page/listar-clases-de-inmueble).</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido y el `id` de la clase de inmueble es correcto, el sistema te devolverá una lista con las características asociadas a esa clase. Por ejemplo, para la clase "Casa" (`id = 1249`), la respuesta se verá similar a esta:

```json
[
    {
        "id": "1",
        "descripcion": "Nº De Habitaciones",
        "tipo_campo": "numeric",
        "opciones_valores": null,
        "opciones_descripciones": null,
        "orden": "1",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    },
    {
        "id": "31",
        "descripcion": "Red de gas",
        "tipo_campo": "select",
        "opciones_valores": "si,no",
        "opciones_descripciones": "Si,No",
        "orden": "5",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    },
    {
        "id": "22",
        "descripcion": "Balcón",
        "tipo_campo": "checkbox",
        "opciones_valores": null,
        "opciones_descripciones": null,
        "orden": "10",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    },
    {
        "id": "38",
        "descripcion": "Parqueadero",
        "tipo_campo": "select",
        "opciones_valores": "propio,visitantes",
        "opciones_descripciones": "Propio,Visitantes",
        "orden": "12",
        "grupo": "Características del Inmueble",
        "clase_inmueble_id": "1249",
        "clase_inmueble": "Casa"
    }
]
```

<p class="callout info">**Nota:** Las características disponibles y sus grupos dependen de la configuración de cada instancia. La lista se devuelve ordenada por grupo, luego por orden dentro del grupo, y finalmente por descripción alfabéticamente. La estructura de la respuesta es idéntica a la del servicio de **Listar Características**, pero filtrada a la clase de inmueble indicada.</p>

Tabla con la descripción de cada campo del JSON:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Clave</th><th>Descripción</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador único de la característica (tipo texto).</td></tr><tr><td>**descripcion**</td><td>Nombre descriptivo de la característica (por ejemplo: "Nº De Habitaciones", "Parqueadero").</td></tr><tr><td>**tipo\_campo**</td><td>Tipo de campo que define cómo se captura la información. Valores posibles: `numeric` (campo numérico), `checkbox` (casilla de verificación), `select` (lista desplegable con opciones predefinidas), entre otros.</td></tr><tr><td>**opciones\_valores**</td><td>Valores técnicos de las opciones disponibles, separados por coma. Aplica únicamente cuando `tipo_campo` es `select`. Será `null` o vacío para otros tipos de campo.</td></tr><tr><td>**opciones\_descripciones**</td><td>Descripciones legibles de las opciones disponibles, separadas por coma. Cada descripción corresponde posicionalmente al valor en `opciones_valores`. Por ejemplo, si `opciones_valores` es `"propio,visitantes"`, las descripciones serán `"Propio,Visitantes"`.</td></tr><tr><td>**orden**</td><td>Posición numérica que indica el orden de presentación de la característica dentro de su grupo.</td></tr><tr><td>**grupo**</td><td>Nombre del grupo al que pertenece la característica (por ejemplo: "Características del Inmueble"). Permite agrupar visualmente las características en un formulario.</td></tr><tr><td>**clase\_inmueble\_id**</td><td>Identificador de la clase de inmueble a la que está asociada esta característica. Coincidirá con el `id` enviado en la URL.</td></tr><tr><td>**clase\_inmueble**</td><td>Nombre descriptivo de la clase de inmueble (por ejemplo: "Casa", "Apartamento", "Bodega").</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Si envías un `id` vacío o no numérico, el sistema te devolverá un error de validación:

```json
{
    "error": "El ID de la clase del inmueble no puede estar vacío y debe ser de tipo numérico"
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado, formato incorrecto, o el parámetro `id` está vacío o no es numérico.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma. En estos ejemplos se consulta la clase "Casa" con `id = 1249`:

<details id="bkmrk-curl-curl--x-get-%22ht"><summary>cURL</summary>

```bash
curl -X GET "https://{{instancia}}/service/v2/public/masters/properties/features/property-class/1249" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio de Login
$claseInmuebleId = 1249; // ID de la clase de inmueble (ej. Casa)

$url = "https://{$instance}/service/v2/public/masters/properties/features/property-class/{$claseInmuebleId}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $caracteristicas = json_decode($response, true);
        echo "Características de la clase de inmueble (ID {$claseInmuebleId}):\n";
        foreach ($caracteristicas as $car) {
            echo "  {$car['descripcion']} (tipo: {$car['tipo_campo']})\n";
        }
    } else {
        echo "Error al consultar las características.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 de Login
clase_inmueble_id = 1249 # ID de la clase de inmueble (ej. Casa)

# 2. Prepara la dirección y los encabezados
url = f"https://{instancia}/service/v2/public/masters/properties/features/property-class/{clase_inmueble_id}"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        caracteristicas = response.json()
        print(f"Características de la clase de inmueble (ID {clase_inmueble_id}):")
        for car in caracteristicas:
            print(f"  {car['descripcion']} (tipo: {car['tipo_campo']})")
    else:
        print("Error al consultar las características.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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 de Login
const claseInmuebleId = 1249; // ID de la clase de inmueble (ej. Casa)

// 2. Prepara la dirección
const url = `https://${instancia}/service/v2/public/masters/properties/features/property-class/${claseInmuebleId}`;

// 3. Función para consultar las características por clase de inmueble
async function consultarCaracteristicasPorClase() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const caracteristicas = await response.json();
            console.log(`Características de la clase de inmueble (ID ${claseInmuebleId}):`);
            caracteristicas.forEach(car => {
                console.log(`  ${car.descripcion} (tipo: ${car.tipo_campo})`);
            });
        } else {
            console.log('Error al consultar las características.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarCaracteristicasPorClase();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 de Login
    claseInmuebleId = "1249", // ID de la clase de inmueble (ej. Casa)

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/masters/properties/features/property-class/" & claseInmuebleId,

    // 3. Envía la petición GET con el token de autenticación
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"id", "descripcion", "tipo_campo", "opciones_valores", "opciones_descripciones", "orden", "grupo", "clase_inmueble_id", "clase_inmueble"},
        {"ID", "Descripcion", "TipoCampo", "OpcionesValores", "OpcionesDescripciones", "Orden", "Grupo", "ClaseInmuebleID", "ClaseInmueble"})
in
    expandido
```

</details>

# Propiedades

<span>Bienvenido al </span>**inventario digital**<span> de tu inmobiliaria. En esta sección te explicamos cómo conectar tus herramientas externas para gestionar, consultar y mantener sincronizada toda la información de tus inmuebles.</span>

**¿Qué puedes hacer en este módulo?**

**1. Exploración y consulta detallada:**<span> Extrae tu catálogo completo utilizando filtros estratégicos (como fechas de creación o actualización) o profundiza en los datos de una propiedad específica. Podrás acceder a sus características precisas, material multimedia (fotografías y videos) y la información de sus propietarios.</span>

**2. Gestión segura de estados:**<span> ¡No solo puedes leer información, también puedes tomar acción! Mantén tu inventario al día actualizando la disponibilidad de tus inmuebles. Para tu tranquilidad, nuestro sistema cuenta con validaciones inteligentes que protegen tu información y previenen errores accidentales (por ejemplo, bloqueando cambios automáticos si la propiedad ya figura como "Arrendada").</span>

¡Explora las opciones a continuación y sácale el máximo provecho a la gestión automatizada de tu portafolio!

# Listar Propiedades

Permite obtener una lista paginada de propiedades registradas en la inmobiliaria, incluyendo información detallada de cada una: datos generales, ubicación, valores económicos, características, propietarios, imágenes, videos y códigos de portales inmobiliarios.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para sincronizar el inventario de propiedades con tu sistema externo, alimentar un sitio web, generar reportes o integrar la información de inmuebles con plataformas de terceros. El endpoint soporta paginación y filtros por rangos de fecha para consultas eficientes.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/properties
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio requiere autenticación mediante un Token JWT. Envía los encabezados requeridos y opcionalmente los parámetros de filtrado en la URL:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio **Login**.</td></tr></tbody></table>

<p class="callout danger">**Autenticación requerida**  
Este servicio requiere un Token de autenticación válido. Debes incluir el encabezado `Authorization: Bearer TU_TOKEN` en cada petición. El token se obtiene consumiendo el servicio de **Login**. Adicionalmente, el cliente OAuth debe contar con el scope `read` para poder consumir este endpoint.</p>

**Parámetros de consulta (query string):**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 12%;"></col><col style="width: 46%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Por defecto</th><th>Descripción</th></tr></thead><tbody><tr><td>**page**</td><td>integer</td><td>No</td><td>1</td><td>Número de página de resultados que se desea recuperar.</td></tr><tr><td>**limit**</td><td>integer</td><td>No</td><td>10</td><td>Número máximo de propiedades por página. Valor máximo permitido: **50**.</td></tr><tr><td>**listing\_start\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de inicio del rango de **consignación** del inmueble.  
Formato: `YYYY-MM-DD` (ejemplo: `2024-03-01`).</td></tr><tr><td>**listing\_end\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de fin del rango de **consignación** del inmueble.  
Formato: `YYYY-MM-DD`.</td></tr><tr><td>**created\_start\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de inicio del rango de **creación** del inmueble en el sistema.  
Formato: `YYYY-MM-DD`.</td></tr><tr><td>**created\_end\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de fin del rango de **creación** del inmueble en el sistema.  
Formato: `YYYY-MM-DD`.</td></tr><tr><td>**last\_modified\_start\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de inicio del rango de **última modificación** del inmueble.  
Formato: `YYYY-MM-DD`.</td></tr><tr><td>**last\_modified\_end\_date**</td><td>string</td><td>No</td><td>—</td><td>Fecha de fin del rango de **última modificación** del inmueble.  
Formato: `YYYY-MM-DD`.</td></tr></tbody></table>

<p class="callout info">**Comportamiento de los filtros de fecha**  
Para los parámetros de tipo fecha que se componen de un rango (por ejemplo `listing_start_date` y `listing_end_date`):  
— Si envías **solo el start\_date**: se retornarán registros con fecha **mayor o igual (&gt;=)** a la indicada.  
— Si envías **solo el end\_date**: se retornarán registros con fecha **menor o igual (&lt;=)** a la indicada.  
— Si envías **ambos**: se retornarán registros dentro de ese rango de fechas (BETWEEN).  
— La fecha de inicio **no puede ser mayor** que la fecha de fin; de lo contrario se devolverá un error de validación.</p>

**Ejemplos de peticiones:**

```http
GET https://{{instancia}}/service/v2/public/properties
```

```http
GET https://{{instancia}}/service/v2/public/properties?page=1&limit=10
```

```http
GET https://{{instancia}}/service/v2/public/properties?page=1&limit=10&listing_start_date=2024-03-26
```

```http
GET https://{{instancia}}/service/v2/public/properties?page=1&limit=10&listing_start_date=2024-03-01&listing_end_date=2024-03-31
```

```http
GET https://{{instancia}}/service/v2/public/properties?page=2&limit=20&created_start_date=2024-01-01&created_end_date=2024-06-30
```

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

El sistema te devolverá una lista con las propiedades que coincidan con los filtros aplicados. Cada propiedad incluye datos generales, ubicación, valores económicos, características, propietarios, imágenes, videos y códigos de portales inmobiliarios. La respuesta se verá similar a esta:

```json
[
    {
        "codigo": "137",
        "titulo": "Apartamento amplio con vista al parque central",
        "clase_id": "1247",
        "clase_inmueble": "Apartamento",
        "tipo_servicio_id": "arriendo",
        "tipo_servicio": "Arriendo",
        "estrato": "1258",
        "estrato_texto": "Cuatro",
        "fecha_consignacion": "2024-04-26",
        "asesor_id": "5",
        "asesor": "María López Ramírez",
        "pais_id": "1",
        "pais": "COLOMBIA",
        "departamento_id": "5",
        "departamento": "Antioquia",
        "municipio_id": "1",
        "municipio": "Medellin",
        "barrio_id": "3",
        "barrio": "Los Rosales",
        "direccion": "CALLE 45 # 32 - 18",
        "coordenadas": "6.24830000000000:-75.56120000000000",
        "valor_arriendo1": "1600000",
        "valor_arriendo2": "0",
        "valor_venta1": "0",
        "valor_venta2": "0",
        "valor_administracion": "0",
        "avaluo_catastral": "0",
        "impuesto_predial": "0.00",
        "area": "75.00",
        "observaciones": null,
        "propiedad_destacada": "No",
        "llaves_en": "oficina",
        "llaves_otro": null,
        "paga_cuota_sost": "propietario",
        "folio_matricula": null,
        "referencia_catastral": null,
        "edificio_unidad": "urbanizacion",
        "estado": "1",
        "estado_texto": "Activa",
        "cantidad_images": "3",
        "cantidad_videos": "1",
        "fecha_creacion": "2024-04-26 10:30:00",
        "ultima_fecha_modificacion": "2024-05-15 14:22:00",
        "caracteristicas": [
            {
                "id": "1",
                "descripcion": "Nº De Habitaciones",
                "tipo_campo": "numeric",
                "orden": "1",
                "grupo": "Características del inmueble",
                "valor": "4"
            },
            {
                "id": "2",
                "descripcion": "Nº De Baños",
                "tipo_campo": "numeric",
                "orden": "2",
                "grupo": "Características del inmueble",
                "valor": "3"
            },
            {
                "id": "31",
                "descripcion": "Red de gas",
                "tipo_campo": "select",
                "orden": "5",
                "grupo": "Características del Inmueble",
                "valor": "si",
                "valor_texto": "Si"
            },
            {
                "id": "14",
                "descripcion": "Cocina Integral",
                "tipo_campo": "checkbox",
                "orden": "5",
                "grupo": "Características Internas",
                "valor": "1"
            }
        ],
        "propietarios": [
            {
                "id": "272",
                "documento": "1020304050",
                "nombres": "ANA MARÍA",
                "apellidos": "PÉREZ RODRÍGUEZ"
            }
        ],
        "imagenes": [
            {
                "posicion": "1",
                "size": "19201080",
                "img": "img/fotos/1920x1080_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.jpeg",
                "imagen": "https://mi-inmobiliaria.nuby.app/img/fotos/1920x1080_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.jpeg"
            },
            {
                "posicion": "2",
                "size": "19201080",
                "img": "img/fotos/1920x1080_f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3.jpeg",
                "imagen": "https://mi-inmobiliaria.nuby.app/img/fotos/1920x1080_f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3.jpeg"
            }
        ],
        "videos": [
            {
                "url": "dQw4w9WgXcQ",
                "tipo": "youtube",
                "descripcion": null,
                "posicion": "1"
            }
        ],
        "codigos_portales": [
            {
                "nombre_portal": "metrocuadrado",
                "id_portal": "MC-12345",
                "tipo_servicio": "arriendo"
            }
        ]
    }
]
```

##### **Campos principales de la propiedad**

Esta tabla enumera las claves presentes en el JSON de cada propiedad y proporciona una descripción de cada una:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-co" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**codigo**</td><td>Código único del inmueble en el sistema.</td></tr><tr><td>**titulo**</td><td>Título del anuncio del inmueble.</td></tr><tr><td>**clase\_id**</td><td>Identificador de la clase de inmueble. Corresponde al `id` del servicio **Listar Clases de Inmueble**.</td></tr><tr><td>**clase\_inmueble**</td><td>Nombre de la clase de inmueble (por ejemplo: "Apartamento", "Casa", "Finca").</td></tr><tr><td>**tipo\_servicio\_id**</td><td>Identificador del tipo de servicio. Valores posibles: `"arriendo"`, `"venta"`, `"venta y arriendo"`.</td></tr><tr><td>**tipo\_servicio**</td><td>Nombre descriptivo del tipo de servicio (por ejemplo: "Arriendo", "Venta").</td></tr><tr><td>**estrato**</td><td>Identificador del estrato socioeconómico del inmueble.</td></tr><tr><td>**estrato\_texto**</td><td>Texto descriptivo del estrato (por ejemplo: "Cuatro", "Tres").</td></tr><tr><td>**fecha\_consignacion**</td><td>Fecha en que el inmueble fue captado/consignado para su gestión. Formato: `YYYY-MM-DD`.</td></tr><tr><td>**asesor\_id**</td><td>Identificador del asesor asignado al inmueble. Vacío si no tiene asesor asignado.</td></tr><tr><td>**asesor**</td><td>Nombre completo del asesor asignado.</td></tr><tr><td>**pais\_id**</td><td>Identificador del país donde se ubica el inmueble.</td></tr><tr><td>**pais**</td><td>Nombre del país.</td></tr><tr><td>**departamento\_id**</td><td>Identificador del departamento/estado/provincia.</td></tr><tr><td>**departamento**</td><td>Nombre del departamento.</td></tr><tr><td>**municipio\_id**</td><td>Identificador del municipio/ciudad.</td></tr><tr><td>**municipio**</td><td>Nombre del municipio.</td></tr><tr><td>**barrio\_id**</td><td>Identificador del barrio. Puede ser `null` si no se ha asignado barrio.</td></tr><tr><td>**barrio**</td><td>Nombre del barrio.</td></tr><tr><td>**direccion**</td><td>Dirección física del inmueble.</td></tr><tr><td>**coordenadas**</td><td>Coordenadas geográficas del inmueble en formato `latitud:longitud`.</td></tr><tr><td>**valor\_arriendo1**</td><td>Valor principal de arriendo (canon mensual).</td></tr><tr><td>**valor\_arriendo2**</td><td>Valor secundario de arriendo. `0` si no aplica.</td></tr><tr><td>**valor\_venta1**</td><td>Valor principal de venta.</td></tr><tr><td>**valor\_venta2**</td><td>Valor secundario de venta. `0` si no aplica.</td></tr><tr><td>**valor\_administracion**</td><td>Valor de la cuota de administración.</td></tr><tr><td>**avaluo\_catastral**</td><td>Avalúo catastral del inmueble.</td></tr><tr><td>**impuesto\_predial**</td><td>Valor del impuesto predial.</td></tr><tr><td>**area**</td><td>Área del inmueble en metros cuadrados.</td></tr><tr><td>**observaciones**</td><td>Observaciones o descripción adicional del inmueble. Puede ser `null`.</td></tr><tr><td>**propiedad\_destacada**</td><td>Indica si la propiedad está marcada como destacada. Valores: `"Si"` o `"No"`.</td></tr><tr><td>**llaves\_en**</td><td>Lugar donde se encuentran las llaves del inmueble (por ejemplo: "oficina").</td></tr><tr><td>**llaves\_otro**</td><td>Ubicación alternativa de las llaves, si aplica. Puede ser `null`.</td></tr><tr><td>**paga\_cuota\_sost**</td><td>Quién paga la cuota de sostenimiento (por ejemplo: "propietario"). Puede ser `null`.</td></tr><tr><td>**folio\_matricula**</td><td>Número de folio de matrícula inmobiliaria. Puede ser `null`.</td></tr><tr><td>**referencia\_catastral**</td><td>Referencia catastral del inmueble. Puede ser `null`.</td></tr><tr><td>**edificio\_unidad**</td><td>Tipo de agrupamiento del inmueble (por ejemplo: "urbanizacion", "edificio", "conjunto").</td></tr><tr><td>**estado**</td><td>Identificador numérico del estado del inmueble. Valores: `0` (Arrendada), `1` (Activa), `2` (Inactiva), `3` (Vendida).</td></tr><tr><td>**estado\_texto**</td><td>Texto descriptivo del estado (por ejemplo: "Activa", "Arrendada").</td></tr><tr><td>**cantidad\_images**</td><td>Cantidad de imágenes asociadas al inmueble.</td></tr><tr><td>**cantidad\_videos**</td><td>Cantidad de videos asociados al inmueble.</td></tr><tr><td>**fecha\_creacion**</td><td>Fecha y hora de creación del registro en el sistema. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td>**ultima\_fecha\_modificacion**</td><td>Fecha y hora de la última modificación del registro. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td>**caracteristicas**</td><td>Lista de características del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**propietarios**</td><td>Lista de propietarios del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**imagenes**</td><td>Lista de imágenes del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**videos**</td><td>Lista de videos del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**codigos\_portales**</td><td>Lista de códigos de publicación en portales inmobiliarios externos (ver tabla detallada abajo).</td></tr></tbody></table>

##### **Características**

Cada elemento dentro de la lista `caracteristicas` contiene la información de una característica del inmueble y su valor asignado:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador de la característica. Corresponde al `id` del servicio **Listar Características**.</td></tr><tr><td>**descripcion**</td><td>Nombre descriptivo de la característica (por ejemplo: "Nº De Habitaciones").</td></tr><tr><td>**tipo\_campo**</td><td>Tipo de campo: `numeric`, `checkbox`, `select`, entre otros.</td></tr><tr><td>**orden**</td><td>Posición de la característica dentro de su grupo.</td></tr><tr><td>**grupo**</td><td>Grupo al que pertenece la característica.</td></tr><tr><td>**valor**</td><td>Valor asignado a la característica para esta propiedad. Para `numeric`: un número. Para `checkbox`: `"1"` (marcado). Para `select`: el valor técnico de la opción seleccionada.</td></tr><tr><td>**valor\_texto**</td><td>Descripción legible del valor seleccionado. Solo presente cuando `tipo_campo` es `select` (por ejemplo: valor `"si"` → valor\_texto `"Si"`).</td></tr></tbody></table>

##### **Propietarios**

Cada elemento dentro de la lista `propietarios` contiene la información de un propietario del inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id-1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador del propietario (tercero) en el sistema.</td></tr><tr><td>**documento**</td><td>Número de documento de identificación del propietario.</td></tr><tr><td>**nombres**</td><td>Nombres del propietario.</td></tr><tr><td>**apellidos**</td><td>Apellidos del propietario.</td></tr></tbody></table>

##### **Imágenes**

Cada elemento dentro de la lista `imagenes` contiene la información de una fotografía del inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-po" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**posicion**</td><td>Posición de ordenamiento de la imagen (1 = principal).</td></tr><tr><td>**size**</td><td>Resolución de la imagen (por ejemplo: "19201080").</td></tr><tr><td>**img**</td><td>Ruta relativa de la imagen en el servidor.</td></tr><tr><td>**imagen**</td><td>URL completa de la imagen, lista para consumir directamente.</td></tr></tbody></table>

##### **Videos**

Cada elemento dentro de la lista `videos` contiene la información de un video asociado al inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-ur" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**url**</td><td>Identificador o URL del video (por ejemplo, el ID de YouTube: `"608AV8w6gL0"`).</td></tr><tr><td>**tipo**</td><td>Plataforma del video (por ejemplo: `"youtube"`).</td></tr><tr><td>**descripcion**</td><td>Descripción del video. Puede ser `null`.</td></tr><tr><td>**posicion**</td><td>Posición de ordenamiento del video.</td></tr></tbody></table>

##### **Códigos de Portales**

Cada elemento dentro de la lista `codigos_portales` contiene la información de publicación del inmueble en un portal inmobiliario externo:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-no" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**nombre\_portal**</td><td>Nombre del portal inmobiliario (por ejemplo: "metrocuadrado", "fincaraiz").</td></tr><tr><td>**id\_portal**</td><td>Identificador de la propiedad en el portal externo.</td></tr><tr><td>**tipo\_servicio**</td><td>Tipo de servicio bajo el cual fue publicada la propiedad en ese portal.</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

El sistema realiza validaciones de autenticación, scopes y parámetros. Si alguna falla, devolverá un error con su respectivo código HTTP:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`  
  
**Parámetros inválidos.** Posibles causas:  
— `page` no es numérico.  
— `limit` no es numérico o es mayor a 50.  
— Las fechas no tienen el formato `YYYY-MM-DD`.  
— La fecha de inicio es mayor que la fecha de fin en un rango.</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**. Mensaje: `"JWT Token expired."`</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-listar-propie"><summary>cURL</summary>

```bash
# Listar propiedades con paginación
curl -X GET "https://{{instancia}}/service/v2/public/properties?page=1&limit=10" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Filtrar por rango de fecha de consignación
curl -X GET "https://{{instancia}}/service/v2/public/properties?page=1&limit=10&listing_start_date=2024-03-01&listing_end_date=2024-03-31" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Filtrar por fecha de creación
curl -X GET "https://{{instancia}}/service/v2/public/properties?page=1&limit=20&created_start_date=2024-01-01" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login

// Parámetros de consulta
$page = 1;
$limit = 10;
$listingStartDate = '2024-03-01';
$listingEndDate = '2024-03-31';

$queryParams = http_build_query([
    'page' => $page,
    'limit' => $limit,
    'listing_start_date' => $listingStartDate,
    'listing_end_date' => $listingEndDate
]);

$url = "https://{$instance}/service/v2/public/properties?{$queryParams}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $propiedades = json_decode($response, true);
        echo "Propiedades encontradas: " . count($propiedades) . "\n";
        foreach ($propiedades as $propiedad) {
            echo "  [{$propiedad['codigo']}] {$propiedad['titulo']} - {$propiedad['estado_texto']}\n";
        }
    } else {
        echo "Error al consultar las propiedades.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 la dirección y los parámetros
url = f"https://{instancia}/service/v2/public/properties"

params = {
    "page": 1,
    "limit": 10,
    "listing_start_date": "2024-03-01",
    "listing_end_date": "2024-03-31"
}

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, params=params, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        propiedades = response.json()
        print(f"Propiedades encontradas: {len(propiedades)}")
        for prop in propiedades:
            print(f"  [{prop['codigo']}] {prop['titulo']} - {prop['estado_texto']}")
    else:
        print("Error al consultar las propiedades.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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. Prepara la dirección con parámetros
const params = new URLSearchParams({
    page: 1,
    limit: 10,
    listing_start_date: '2024-03-01',
    listing_end_date: '2024-03-31'
});

const url = `https://${instancia}/service/v2/public/properties?${params}`;

// 3. Función para consultar las propiedades
async function consultarPropiedades() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const propiedades = await response.json();
            console.log(`Propiedades encontradas: ${propiedades.length}`);
            propiedades.forEach(prop => {
                console.log(`  [${prop.codigo}] ${prop.titulo} - ${prop.estado_texto}`);
            });
        } else {
            console.log('Error al consultar las propiedades.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarPropiedades();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 la dirección de la petición con parámetros
    url = "https://" & instancia & "/service/v2/public/properties?page=1&limit=50",

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"codigo", "titulo", "clase_inmueble", "tipo_servicio", "estado_texto", "direccion", "municipio", "departamento", "area", "valor_arriendo1", "valor_venta1", "fecha_consignacion"},
        {"Codigo", "Titulo", "ClaseInmueble", "TipoServicio", "Estado", "Direccion", "Municipio", "Departamento", "Area", "ValorArriendo", "ValorVenta", "FechaConsignacion"})
in
    expandido
```

</details>

# Buscar Propiedad por Código

Permite obtener la información completa de una propiedad específica a partir de su código único. La respuesta incluye datos generales, ubicación, valores económicos, características, propietarios, imágenes, videos y códigos de portales inmobiliarios.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo cuando ya conoces el código del inmueble y necesitas consultar toda su información detallada. Es ideal para mostrar la ficha completa de una propiedad en tu sitio web, sincronizar datos de un inmueble puntual o verificar la información registrada en el sistema.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma, y <span style="color: rgb(241, 196, 15);">**{{code}}**</span> por el código numérico del inmueble que deseas consultar.

```http
GET https://{{instancia}}/service/v2/public/properties/{{code}}
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio requiere autenticación mediante un Token JWT. Construye la URL con el código de la propiedad como parte de la ruta e incluye los encabezados requeridos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio **Login**.</td></tr></tbody></table>

<p class="callout danger">**Autenticación requerida**  
Este servicio requiere un Token de autenticación válido. Debes incluir el encabezado `Authorization: Bearer TU_TOKEN` en cada petición. El token se obtiene consumiendo el servicio de **Login**. Adicionalmente, el cliente OAuth debe contar con el scope `read` para poder consumir este endpoint.</p>

**Parámetro de ruta:**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 58%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>**code**</td><td>integer</td><td>Sí</td><td>Código numérico único del inmueble que se desea consultar. Debe ser un número entero positivo.</td></tr></tbody></table>

**Ejemplos de peticiones:**

```http
GET https://{{instancia}}/service/v2/public/properties/137
```

```http
GET https://{{instancia}}/service/v2/public/properties/2045
```

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

El sistema te devolverá un **objeto JSON** con toda la información de la propiedad solicitada. Si el código no corresponde a ningún inmueble registrado, se devolverá un arreglo vacío `[]`.

<p class="callout info">**Respuesta como objeto, no como lista**  
A diferencia del servicio **Listar Propiedades** que devuelve un arreglo de objetos `[{...}, {...}]`, este servicio devuelve directamente un único objeto `{...}` con la información del inmueble consultado.</p>

La respuesta exitosa se verá similar a esta:

```json
{
    "codigo": "137",
    "titulo": "Apartamento amplio con vista al parque central",
    "clase_id": "1247",
    "clase_inmueble": "Apartamento",
    "tipo_servicio_id": "arriendo",
    "tipo_servicio": "Arriendo",
    "estrato": "1258",
    "estrato_texto": "Cuatro",
    "fecha_consignacion": "2024-04-26",
    "asesor_id": "5",
    "asesor": "María López Ramírez",
    "pais_id": "1",
    "pais": "COLOMBIA",
    "departamento_id": "5",
    "departamento": "Antioquia",
    "municipio_id": "1",
    "municipio": "Medellin",
    "barrio_id": "3",
    "barrio": "Los Rosales",
    "direccion": "CALLE 45 # 32 - 18",
    "coordenadas": "6.24830000000000:-75.56120000000000",
    "valor_arriendo1": "1600000",
    "valor_arriendo2": "0",
    "valor_venta1": "0",
    "valor_venta2": "0",
    "valor_administracion": "250000",
    "avaluo_catastral": "185000000",
    "impuesto_predial": "1250000.00",
    "area": "75.00",
    "observaciones": "Inmueble ubicado en zona residencial tranquila, cerca de centros comerciales y transporte público.",
    "propiedad_destacada": "No",
    "llaves_en": "oficina",
    "llaves_otro": null,
    "paga_cuota_sost": "propietario",
    "folio_matricula": "001-123456",
    "referencia_catastral": "05001010203040",
    "edificio_unidad": "urbanizacion",
    "estado": "1",
    "estado_texto": "Activa",
    "cantidad_images": "3",
    "cantidad_videos": "1",
    "fecha_creacion": "2024-04-26 10:30:00",
    "ultima_fecha_modificacion": "2024-05-15 14:22:00",
    "caracteristicas": [
        {
            "id": "1",
            "descripcion": "Nº De Habitaciones",
            "tipo_campo": "numeric",
            "orden": "1",
            "grupo": "Características del inmueble",
            "valor": "4"
        },
        {
            "id": "2",
            "descripcion": "Nº De Baños",
            "tipo_campo": "numeric",
            "orden": "2",
            "grupo": "Características del inmueble",
            "valor": "3"
        },
        {
            "id": "5",
            "descripcion": "Nº De Piso",
            "tipo_campo": "numeric",
            "orden": "3",
            "grupo": "Características del inmueble",
            "valor": "1"
        },
        {
            "id": "4",
            "descripcion": "Antigüedad del Inmueble",
            "tipo_campo": "numeric",
            "orden": "5",
            "grupo": "Características del Inmueble",
            "valor": "3"
        },
        {
            "id": "14",
            "descripcion": "Cocina Integral",
            "tipo_campo": "checkbox",
            "orden": "5",
            "grupo": "Características Internas",
            "valor": "1"
        },
        {
            "id": "34",
            "descripcion": "Sala",
            "tipo_campo": "checkbox",
            "orden": "6",
            "grupo": "Características del Inmueble",
            "valor": "1"
        },
        {
            "id": "31",
            "descripcion": "Red de gas",
            "tipo_campo": "select",
            "orden": "5",
            "grupo": "Características del Inmueble",
            "valor": "si",
            "valor_texto": "Si"
        },
        {
            "id": "63",
            "descripcion": "Garaje",
            "tipo_campo": "checkbox",
            "orden": "10",
            "grupo": "Características Internas",
            "valor": "1"
        }
    ],
    "propietarios": [
        {
            "id": "272",
            "documento": "1020304050",
            "nombres": "ANA MARÍA",
            "apellidos": "PÉREZ RODRÍGUEZ"
        }
    ],
    "imagenes": [
        {
            "posicion": "1",
            "size": "19201080",
            "img": "img/fotos/1920x1080_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.jpeg",
            "imagen": "https://mi-inmobiliaria.nuby.app/img/fotos/1920x1080_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.jpeg"
        },
        {
            "posicion": "2",
            "size": "19201080",
            "img": "img/fotos/1920x1080_f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3.jpeg",
            "imagen": "https://mi-inmobiliaria.nuby.app/img/fotos/1920x1080_f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3.jpeg"
        },
        {
            "posicion": "3",
            "size": "19201080",
            "img": "img/fotos/1920x1080_b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8.jpeg",
            "imagen": "https://mi-inmobiliaria.nuby.app/img/fotos/1920x1080_b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8.jpeg"
        }
    ],
    "videos": [
        {
            "url": "dQw4w9WgXcQ",
            "tipo": "youtube",
            "descripcion": null,
            "posicion": "1"
        }
    ],
    "codigos_portales": [
        {
            "nombre_portal": "metrocuadrado",
            "id_portal": "MC-98765",
            "tipo_servicio": "arriendo"
        }
    ]
}
```

Cuando el código no corresponde a ningún inmueble, la respuesta será:

```json
[]
```

##### **Campos principales de la propiedad**

Esta tabla enumera las claves presentes en el JSON de la propiedad y proporciona una descripción de cada una:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-co" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**codigo**</td><td>Código único del inmueble en el sistema.</td></tr><tr><td>**titulo**</td><td>Título del anuncio del inmueble.</td></tr><tr><td>**clase\_id**</td><td>Identificador de la clase de inmueble. Corresponde al `id` del servicio **Listar Clases de Inmueble**.</td></tr><tr><td>**clase\_inmueble**</td><td>Nombre de la clase de inmueble (por ejemplo: "Apartamento", "Casa", "Finca").</td></tr><tr><td>**tipo\_servicio\_id**</td><td>Identificador del tipo de servicio. Valores posibles: `"arriendo"`, `"venta"`, `"venta y arriendo"`.</td></tr><tr><td>**tipo\_servicio**</td><td>Nombre descriptivo del tipo de servicio (por ejemplo: "Arriendo", "Venta").</td></tr><tr><td>**estrato**</td><td>Identificador del estrato socioeconómico del inmueble.</td></tr><tr><td>**estrato\_texto**</td><td>Texto descriptivo del estrato (por ejemplo: "Cuatro", "Tres").</td></tr><tr><td>**fecha\_consignacion**</td><td>Fecha en que el inmueble fue captado/consignado para su gestión. Formato: `YYYY-MM-DD`.</td></tr><tr><td>**asesor\_id**</td><td>Identificador del asesor asignado al inmueble. Cadena vacía si no tiene asesor asignado.</td></tr><tr><td>**asesor**</td><td>Nombre completo del asesor asignado.</td></tr><tr><td>**pais\_id**</td><td>Identificador del país donde se ubica el inmueble.</td></tr><tr><td>**pais**</td><td>Nombre del país.</td></tr><tr><td>**departamento\_id**</td><td>Identificador del departamento/estado/provincia.</td></tr><tr><td>**departamento**</td><td>Nombre del departamento.</td></tr><tr><td>**municipio\_id**</td><td>Identificador del municipio/ciudad.</td></tr><tr><td>**municipio**</td><td>Nombre del municipio.</td></tr><tr><td>**barrio\_id**</td><td>Identificador del barrio. Puede ser `null` si no se ha asignado barrio.</td></tr><tr><td>**barrio**</td><td>Nombre del barrio.</td></tr><tr><td>**direccion**</td><td>Dirección física del inmueble.</td></tr><tr><td>**coordenadas**</td><td>Coordenadas geográficas del inmueble en formato `latitud:longitud`.</td></tr><tr><td>**valor\_arriendo1**</td><td>Valor principal de arriendo (canon mensual).</td></tr><tr><td>**valor\_arriendo2**</td><td>Valor secundario de arriendo. `0` si no aplica.</td></tr><tr><td>**valor\_venta1**</td><td>Valor principal de venta.</td></tr><tr><td>**valor\_venta2**</td><td>Valor secundario de venta. `0` si no aplica.</td></tr><tr><td>**valor\_administracion**</td><td>Valor de la cuota de administración.</td></tr><tr><td>**avaluo\_catastral**</td><td>Avalúo catastral del inmueble.</td></tr><tr><td>**impuesto\_predial**</td><td>Valor del impuesto predial.</td></tr><tr><td>**area**</td><td>Área del inmueble en metros cuadrados.</td></tr><tr><td>**observaciones**</td><td>Observaciones o descripción adicional del inmueble. Puede ser `null`.</td></tr><tr><td>**propiedad\_destacada**</td><td>Indica si la propiedad está marcada como destacada. Valores: `"Si"` o `"No"`.</td></tr><tr><td>**llaves\_en**</td><td>Lugar donde se encuentran las llaves del inmueble (por ejemplo: "oficina").</td></tr><tr><td>**llaves\_otro**</td><td>Ubicación alternativa de las llaves, si aplica. Puede ser `null`.</td></tr><tr><td>**paga\_cuota\_sost**</td><td>Quién paga la cuota de sostenimiento (por ejemplo: "propietario"). Puede ser `null`.</td></tr><tr><td>**folio\_matricula**</td><td>Número de folio de matrícula inmobiliaria. Puede ser `null`.</td></tr><tr><td>**referencia\_catastral**</td><td>Referencia catastral del inmueble. Puede ser `null`.</td></tr><tr><td>**edificio\_unidad**</td><td>Tipo de agrupamiento del inmueble (por ejemplo: "urbanizacion", "edificio", "conjunto").</td></tr><tr><td>**estado**</td><td>Identificador numérico del estado del inmueble. Valores: `0` (Arrendada), `1` (Activa), `2` (Inactiva), `3` (Vendida).</td></tr><tr><td>**estado\_texto**</td><td>Texto descriptivo del estado (por ejemplo: "Activa", "Arrendada").</td></tr><tr><td>**cantidad\_images**</td><td>Cantidad de imágenes asociadas al inmueble.</td></tr><tr><td>**cantidad\_videos**</td><td>Cantidad de videos asociados al inmueble.</td></tr><tr><td>**fecha\_creacion**</td><td>Fecha y hora de creación del registro en el sistema. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td>**ultima\_fecha\_modificacion**</td><td>Fecha y hora de la última modificación del registro. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td>**caracteristicas**</td><td>Lista de características del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**propietarios**</td><td>Lista de propietarios del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**imagenes**</td><td>Lista de imágenes del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**videos**</td><td>Lista de videos del inmueble (ver tabla detallada abajo).</td></tr><tr><td>**codigos\_portales**</td><td>Lista de códigos de publicación en portales inmobiliarios externos (ver tabla detallada abajo).</td></tr></tbody></table>

##### **Características**

Cada elemento dentro de la lista `caracteristicas` contiene la información de una característica del inmueble y su valor asignado:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador de la característica. Corresponde al `id` del servicio **Listar Características**.</td></tr><tr><td>**descripcion**</td><td>Nombre descriptivo de la característica (por ejemplo: "Nº De Habitaciones").</td></tr><tr><td>**tipo\_campo**</td><td>Tipo de campo: `numeric`, `checkbox`, `select`, entre otros.</td></tr><tr><td>**orden**</td><td>Posición de la característica dentro de su grupo.</td></tr><tr><td>**grupo**</td><td>Grupo al que pertenece la característica.</td></tr><tr><td>**valor**</td><td>Valor asignado a la característica para esta propiedad. Para `numeric`: un número. Para `checkbox`: `"1"` (marcado). Para `select`: el valor técnico de la opción seleccionada.</td></tr><tr><td>**valor\_texto**</td><td>Descripción legible del valor seleccionado. Solo presente cuando `tipo_campo` es `select` (por ejemplo: valor `"si"` → valor\_texto `"Si"`).</td></tr></tbody></table>

##### **Propietarios**

Cada elemento dentro de la lista `propietarios` contiene la información de un propietario del inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-id-1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**id**</td><td>Identificador del propietario (tercero) en el sistema.</td></tr><tr><td>**documento**</td><td>Número de documento de identificación del propietario.</td></tr><tr><td>**nombres**</td><td>Nombres del propietario.</td></tr><tr><td>**apellidos**</td><td>Apellidos del propietario.</td></tr></tbody></table>

##### **Imágenes**

Cada elemento dentro de la lista `imagenes` contiene la información de una fotografía del inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-po" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**posicion**</td><td>Posición de ordenamiento de la imagen (1 = principal).</td></tr><tr><td>**size**</td><td>Resolución de la imagen (por ejemplo: "19201080").</td></tr><tr><td>**img**</td><td>Ruta relativa de la imagen en el servidor.</td></tr><tr><td>**imagen**</td><td>URL completa de la imagen, lista para consumir directamente.</td></tr></tbody></table>

##### **Videos**

Cada elemento dentro de la lista `videos` contiene la información de un video asociado al inmueble:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-ur" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**url**</td><td>Identificador o URL del video (por ejemplo, el ID de YouTube: `"dQw4w9WgXcQ"`).</td></tr><tr><td>**tipo**</td><td>Plataforma del video (por ejemplo: `"youtube"`).</td></tr><tr><td>**descripcion**</td><td>Descripción del video. Puede ser `null`.</td></tr><tr><td>**posicion**</td><td>Posición de ordenamiento del video.</td></tr></tbody></table>

##### **Códigos de Portales**

Cada elemento dentro de la lista `codigos_portales` contiene la información de publicación del inmueble en un portal inmobiliario externo:

<table border="1" id="bkmrk-clave-descripci%C3%B3n-no" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**nombre\_portal**</td><td>Nombre del portal inmobiliario (por ejemplo: "metrocuadrado", "fincaraiz").</td></tr><tr><td>**id\_portal**</td><td>Identificador de la propiedad en el portal externo.</td></tr><tr><td>**tipo\_servicio**</td><td>Tipo de servicio bajo el cual fue publicada la propiedad en ese portal.</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

El sistema realiza validaciones de autenticación, scopes y parámetros de ruta:

Cuando el código es numérico pero no corresponde a ningún inmueble registrado, el sistema **no devuelve un error**. En su lugar, responde con un HTTP `200` y un arreglo vacío:

```json
[]
```

<p class="callout warning">**Importante**  
Asegúrate de validar en tu integración si la respuesta es un arreglo vacío `[]` para manejar correctamente el caso en que la propiedad no exista.</p>

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**200**</td><td>Respuesta exitosa. Contiene el objeto JSON de la propiedad, o un arreglo vacío `[]` si no se encontró ningún inmueble con ese código.</td></tr><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**. Mensaje: `"JWT Token expired."`</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr><tr><td>**404**</td><td>La ruta no fue encontrada. Ocurre cuando el valor de `code` no es numérico (por ejemplo: `/properties/abc`).</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-consultar-pro"><summary>cURL</summary>

```bash
# Consultar propiedad por código
curl -X GET "https://{{instancia}}/service/v2/public/properties/137" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login
$code = 137; // Código de la propiedad a consultar

$url = "https://{$instance}/service/v2/public/properties/{$code}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $propiedad = json_decode($response, true);

        if (!empty($propiedad)) {
            echo "Propiedad encontrada:\n";
            echo "  Código: {$propiedad['codigo']}\n";
            echo "  Título: {$propiedad['titulo']}\n";
            echo "  Estado: {$propiedad['estado_texto']}\n";
            echo "  Dirección: {$propiedad['direccion']}\n";
            echo "  Imágenes: {$propiedad['cantidad_images']}\n";
        } else {
            echo "No se encontró ninguna propiedad con el código {$code}.\n";
        }
    } else {
        echo "Error al consultar la propiedad.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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
codigo = 137 # Código de la propiedad a consultar

# 2. Prepara la dirección de la petición
url = f"https://{instancia}/service/v2/public/properties/{codigo}"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        propiedad = response.json()

        if propiedad:
            print(f"Propiedad encontrada:")
            print(f"  Código: {propiedad['codigo']}")
            print(f"  Título: {propiedad['titulo']}")
            print(f"  Estado: {propiedad['estado_texto']}")
            print(f"  Dirección: {propiedad['direccion']}")
            print(f"  Características: {len(propiedad['caracteristicas'])}")
        else:
            print(f"No se encontró ninguna propiedad con el código {codigo}.")
    else:
        print("Error al consultar la propiedad.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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
const codigo = 137; // Código de la propiedad a consultar

// 2. Prepara la dirección de la petición
const url = `https://${instancia}/service/v2/public/properties/${codigo}`;

// 3. Función para consultar la propiedad
async function consultarPropiedad() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const propiedad = await response.json();

            if (propiedad && !Array.isArray(propiedad)) {
                console.log(`Propiedad encontrada:`);
                console.log(`  Código: ${propiedad.codigo}`);
                console.log(`  Título: ${propiedad.titulo}`);
                console.log(`  Estado: ${propiedad.estado_texto}`);
                console.log(`  Dirección: ${propiedad.direccion}`);
                console.log(`  Imágenes: ${propiedad.cantidad_images}`);
            } else {
                console.log(`No se encontró ninguna propiedad con el código ${codigo}.`);
            }
        } else {
            console.log('Error al consultar la propiedad.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarPropiedad();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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
    codigo = "137", // Código de la propiedad a consultar

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/properties/" & codigo,

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en registro
    jsonResponse = Json.Document(response),
    resultado = Record.ToTable(jsonResponse),
    expandido = Table.Pivot(resultado, List.Distinct(resultado[Name]), "Name", "Value")
in
    expandido
```

</details>

# Actualizar Estado de la Propiedad

Permite actualizar el estado de una propiedad específica a partir de su código único. Este servicio es útil para cambiar el estado de un inmueble entre los estados permitidos por el sistema.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo cuando necesites cambiar el estado de un inmueble desde tu sistema externo, por ejemplo: marcar una propiedad como inactiva cuando se retira del mercado, reactivarla cuando vuelve a estar disponible, o registrar que fue vendida.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma, y <span style="color: rgb(241, 196, 15);">**{{code}}**</span> por el código numérico del inmueble cuyo estado deseas actualizar.

```http
PATCH https://{{instancia}}/service/v2/public/properties/{{code}}/status
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Debes enviar una petición **PATCH** con el nuevo estado en el cuerpo de la solicitud en formato JSON:

<table border="1" id="bkmrk-m%C3%A9todo-patch-content" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>PATCH</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio **Login**.</td></tr></tbody></table>

<p class="callout danger">**Autenticación requerida**  
Este servicio requiere un Token de autenticación válido. Debes incluir el encabezado `Authorization: Bearer TU_TOKEN` en cada petición. El token se obtiene consumiendo el servicio de **Login**. Adicionalmente, el cliente OAuth debe contar con el scope `update` para poder consumir este endpoint.</p>

**Parámetro de ruta:**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 58%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>**code**</td><td>integer</td><td>Sí</td><td>Código numérico único del inmueble cuyo estado se desea actualizar.</td></tr></tbody></table>

**Cuerpo de la petición (Body):**

<table border="1" id="bkmrk-campo-tipo-requerido" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 58%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>**status**</td><td>integer</td><td>Sí</td><td>Nuevo estado que se desea asignar a la propiedad. Los valores válidos son:  
`1` = Activa  
`2` = Inactiva  
`3` = Vendida</td></tr></tbody></table>

<p class="callout danger">**Restricción importante sobre el estado "Arrendada" (0)**  
Aunque el estado `0` (Arrendada) existe en el sistema, **no es posible asignar este estado a través de la API**. El estado "Arrendada" se gestiona internamente por el sistema cuando se registra un contrato de arrendamiento asociado al inmueble.</p>

##### **Estados válidos del sistema**

<table border="1" id="bkmrk-id-estado-descripci%C3%B3" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 10%;"></col><col style="width: 20%;"></col><col style="width: 70%;"></col></colgroup><thead><tr><th>ID</th><th>Estado</th><th>Descripción</th></tr></thead><tbody><tr><td>0</td><td>Arrendada</td><td>El inmueble tiene un contrato de arrendamiento vigente. **No se puede asignar vía API.**</td></tr><tr><td>**1**</td><td>Activa</td><td>El inmueble está disponible en el mercado para arriendo o venta.</td></tr><tr><td>**2**</td><td>Inactiva</td><td>El inmueble fue retirado temporalmente del mercado.</td></tr><tr><td>**3**</td><td>Vendida</td><td>El inmueble fue vendido.</td></tr></tbody></table>

##### **Reglas de transición de estado**

El sistema solo permite cambiar el estado de una propiedad cuando su estado actual es **Activa (1)** o **Inactiva (2)**. Las transiciones posibles son:

<table border="1" id="bkmrk-estado-actual-puede-" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 25%;"></col><col style="width: 75%;"></col></colgroup><thead><tr><th>Estado actual</th><th>Puede cambiar a</th></tr></thead><tbody><tr><td>**Activa (1)**</td><td>`2` (Inactiva) o `3` (Vendida)</td></tr><tr><td>**Inactiva (2)**</td><td>`1` (Activa) o `3` (Vendida)</td></tr><tr><td>**Arrendada (0)**</td><td>No se permite cambiar el estado vía API.</td></tr><tr><td>**Vendida (3)**</td><td>No se permite cambiar el estado vía API.</td></tr></tbody></table>

<p class="callout info">**¿Por qué no se puede modificar el estado de una propiedad "Arrendada" o "Vendida"?**  
Estos son estados terminales que representan transacciones completadas. El cambio de estos estados se gestiona internamente a través de los procesos de negocio del sistema (por ejemplo, al finalizar un contrato de arrendamiento o reversar una venta).</p>

**Ejemplo de petición:**

```http
PATCH https://{{instancia}}/service/v2/public/properties/137/status
```

```json
{
    "status": 2
}
```

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

Si la actualización fue exitosa, el sistema responderá con HTTP `200` y un mensaje de confirmación:

```json
{
    "message": "Se actualizo el estado de la propiedad correctamente"
}
```

<table border="1" id="bkmrk-clave-descripci%C3%B3n-me" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 78%;"></col></colgroup><thead><tr><th>**Clave**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>**message**</td><td>Mensaje indicando que el estado de la propiedad fue actualizado correctamente.</td></tr></tbody></table>

#### **4. Seguridad y Posibles Errores**

El sistema realiza validaciones de autenticación, scopes y datos de la petición. Si alguna falla, devolverá un error con su respectivo código HTTP:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 45%;"></col><col style="width: 43%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th><th>Ejemplo de respuesta</th></tr></thead><tbody><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`  
  
**Parámetros inválidos.** El campo `status` no fue enviado o no es numérico.</td><td>```json
{
    "error": "El estado(status) es requerido"
}
```

</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**.</td><td>```json
"JWT Token expired."
```

</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario. Para endpoints PATCH se requiere el scope `update`.</td><td>```json
"Insufficient scope. Required: 'update', granted: '{scope_actual}'."
```

</td></tr><tr><td>**404**</td><td>No se encontró ninguna propiedad con el código indicado.</td><td>```json
{
    "error": "No se encontró la propiedad"
}
```

</td></tr><tr><td>**422**</td><td>El valor de `status` no corresponde a un estado válido del sistema (no es 0, 1, 2 o 3).</td><td>```json
{
    "error": "El estado no es válido"
}
```

</td></tr><tr><td>**422**</td><td>El estado actual de la propiedad no permite la modificación (por ejemplo: la propiedad está en estado "Arrendada" o "Vendida").</td><td>```json
{
    "error": "El estado actual de la propiedad no permite este tipo de modificación."
}
```

</td></tr><tr><td>**500**</td><td>Error interno del servidor. No se pudo ejecutar la actualización en la base de datos.</td><td>```json
{
    "error": "No se pudo actualizar el estado de la propiedad"
}
```

</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-cambiar-estad"><summary>cURL</summary>

```bash
# Cambiar estado de propiedad 137 a Inactiva (2)
curl -X PATCH "https://{{instancia}}/service/v2/public/properties/137/status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI" \
-d '{"status": 2}'

# Cambiar estado de propiedad 2045 a Vendida (3)
curl -X PATCH "https://{{instancia}}/service/v2/public/properties/2045/status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI" \
-d '{"status": 3}'

# Reactivar propiedad 890 (de Inactiva a Activa)
curl -X PATCH "https://{{instancia}}/service/v2/public/properties/890/status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI" \
-d '{"status": 1}'
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login
$code = 137; // Código de la propiedad
$nuevoEstado = 2; // 1 = Activa, 2 = Inactiva, 3 = Vendida

$url = "https://{$instance}/service/v2/public/properties/{$code}/status";

$body = json_encode([
    'status' => $nuevoEstado
]);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    $data = json_decode($response, true);

    if ($http_code === 200) {
        echo "Éxito: " . $data['message'] . "\n";
    } else {
        echo "Error: " . ($data['error'] ?? 'Error desconocido') . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><summary>Python</summary>

```python
import requests
import json

# 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
codigo = 137 # Código de la propiedad
nuevo_estado = 2 # 1 = Activa, 2 = Inactiva, 3 = Vendida

# 2. Prepara la dirección y el cuerpo de la petición
url = f"https://{instancia}/service/v2/public/properties/{codigo}/status"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

body = {
    "status": nuevo_estado
}

# 3. Envía la petición PATCH y procesa la respuesta
try:
    response = requests.patch(url, headers=headers, json=body)

    print(f"Código de estado HTTP: {response.status_code}")

    data = response.json()

    if response.status_code == 200:
        print(f"Éxito: {data['message']}")
    else:
        error_msg = data.get('error', 'Error desconocido')
        print(f"Error: {error_msg}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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
const codigo = 137; // Código de la propiedad
const nuevoEstado = 2; // 1 = Activa, 2 = Inactiva, 3 = Vendida

// 2. Prepara la dirección de la petición
const url = `https://${instancia}/service/v2/public/properties/${codigo}/status`;

// 3. Función para actualizar el estado
async function actualizarEstadoPropiedad() {
    try {
        const response = await fetch(url, {
            method: 'PATCH',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            },
            body: JSON.stringify({
                status: nuevoEstado
            })
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        const data = await response.json();

        if (response.ok) {
            console.log(`Éxito: ${data.message}`);
        } else {
            console.log(`Error: ${data.error || 'Error desconocido'}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
actualizarEstadoPropiedad();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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
    codigo = "137", // Código de la propiedad
    nuevoEstado = 2, // 1 = Activa, 2 = Inactiva, 3 = Vendida

    // 2. Prepara la dirección y el cuerpo de la petición
    url = "https://" & instancia & "/service/v2/public/properties/" & codigo & "/status",
    body = Json.FromValue([status = nuevoEstado]),

    // 3. Envía la petición PATCH
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ],
        Content = body
    ]),

    // 4. Decodifica la respuesta JSON
    jsonResponse = Json.Document(response)
in
    jsonResponse
```

</details>

# Asesores

<span>Bienvenido al </span>**directorio digital de personal**<span> de tu inmobiliaria. En esta sección agrupamos las herramientas necesarias para que tus aplicaciones externas consulten y sincronicen la información de tu equipo de asesores.</span>

**¿Cuál es el objetivo de este módulo?**<span> Garantizar que tu ecosistema de herramientas siempre sepa quiénes conforman tu equipo de trabajo. Ya sea que necesites extraer tu plantilla completa o ubicar a alguien en particular de manera rápida, tus plataformas podrán acceder a estos datos de forma totalmente automática.</span>

**¿Qué datos obtendrás en tus consultas?**<span> Por cada asesor, el sistema devolverá una "tarjeta de presentación" digital completa y lista para usar, que incluye:</span>

- **Identificación:**<span> Nombre completo y número de documento de identidad.</span>
- **Contacto:**<span> Número de teléfono y correo electrónico.</span>
- **Recurso visual:**<span> Enlace directo a su fotografía de perfil.</span>

¡Explora las opciones a continuación para que tus plataformas externas mantengan la información de tu equipo perfectamente actualizada!

# Listar Asesores

Permite obtener la lista completa de asesores registrados en el sistema. Cada elemento de la respuesta contiene los datos básicos de contacto de cada asesor: documento de identidad, nombre completo, teléfono, correo electrónico y fotografía.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo cuando necesites conocer los asesores disponibles en la inmobiliaria, por ejemplo para mostrar un directorio de agentes en tu sitio web, poblar un selector de asesores en un formulario de contacto, o sincronizar la información de los agentes con tu sistema externo.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/agents
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición ni parámetros adicionales. Solo necesitas enviar los encabezados correctos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

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

Si tu Token es válido, el sistema te devolverá una lista con todos los asesores registrados (excluyendo usuarios internos del sistema). Los asesores se devuelven ordenados alfabéticamente por nombre. La respuesta se verá similar a esta:

```json
[
    {
        "id": "3",
        "documento": "52498731",
        "nombre": "ANDREA MILENA CASTRO ROJAS",
        "telefono": "3104567890",
        "email": "andrea.castro@miredinmobiliaria.com",
        "path_photo": "https://mi-inmobiliaria.nuby.app/pic/usuarios/foto_andrea_castro.jpg"
    },
    {
        "id": "7",
        "documento": "80213654",
        "nombre": "CARLOS EDUARDO PINEDA VARGAS",
        "telefono": "3209876543",
        "email": "carlos.pineda@miredinmobiliaria.com",
        "path_photo": "https://mi-inmobiliaria.nuby.app/pic/usuarios/foto_carlos_pineda.jpg"
    },
    {
        "id": "12",
        "documento": "1098745231",
        "nombre": "JULIANA PATRICIA RÍOS MENDOZA",
        "telefono": "3156781234",
        "email": "juliana.rios@miredinmobiliaria.com",
        "path_photo": "https://mi-inmobiliaria.nuby.app/pic/iconos/user_photo.png"
    }
]
```

**Descripción de cada campo:**

<table border="1" id="bkmrk-campo-tipo-descripci" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 12%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`id`</td><td>string</td><td>Identificador único del usuario en el sistema.</td></tr><tr><td>`documento`</td><td>string</td><td>Número de documento de identidad del asesor.</td></tr><tr><td>`nombre`</td><td>string</td><td>Nombre completo del asesor (compuesto por primer nombre, segundo nombre, primer apellido y segundo apellido).</td></tr><tr><td>`telefono`</td><td>string</td><td>Número de teléfono del asesor.</td></tr><tr><td>`email`</td><td>string</td><td>Dirección de correo electrónico del asesor.</td></tr><tr><td>`path_photo`</td><td>string</td><td>URL completa de la fotografía del asesor. Si el asesor no tiene foto registrada, se devuelve la imagen genérica del sistema.</td></tr></tbody></table>

<p class="callout info">**Nota sobre la respuesta**  
El listado excluye automáticamente los usuarios internos del sistema (cuentas de administración y soporte). Solo se devuelven los asesores reales de la inmobiliaria. Si no hay asesores registrados, la respuesta será un arreglo vacío `[]`.</p>

---

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-curl--x-get-%22ht"><summary>cURL</summary>

```bash
curl -X GET "https://{{instancia}}/service/v2/public/agents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login

$url = "https://{$instance}/service/v2/public/agents";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $asesores = json_decode($response, true);
        echo "Asesores encontrados: " . count($asesores) . "\n";
        foreach ($asesores as $asesor) {
            echo "  [{$asesor['id']}] {$asesor['nombre']} - {$asesor['email']}\n";
        }
    } else {
        echo "Error al consultar los asesores.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 la dirección de la petición
url = f"https://{instancia}/service/v2/public/agents"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        asesores = response.json()
        print(f"Asesores encontrados: {len(asesores)}")
        for asesor in asesores:
            print(f"  [{asesor['id']}] {asesor['nombre']} - {asesor['email']}")
    else:
        print("Error al consultar los asesores.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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. Prepara la dirección de la petición
const url = `https://${instancia}/service/v2/public/agents`;

// 3. Función para consultar los asesores
async function consultarAsesores() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const asesores = await response.json();
            console.log(`Asesores encontrados: ${asesores.length}`);
            asesores.forEach(asesor => {
                console.log(`  [${asesor.id}] ${asesor.nombre} - ${asesor.email}`);
            });
        } else {
            console.log('Error al consultar los asesores.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarAsesores();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/agents",

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en tabla
    jsonResponse = Json.Document(response),
    tabla = Table.FromList(jsonResponse, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"id", "documento", "nombre", "telefono", "email", "path_photo"},
        {"ID", "Documento", "Nombre", "Telefono", "Email", "Foto"})
in
    expandido
```

</details>

# Buscar Asesor por Documento

Permite obtener la información de un asesor específico a partir de su número de documento de identidad. La respuesta contiene los datos básicos de contacto del asesor: documento, nombre completo, teléfono, correo electrónico y fotografía.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo cuando ya conoces el número de documento del asesor y necesitas consultar su información detallada. Es ideal para mostrar la ficha de un agente en particular, verificar datos de un asesor asignado a una propiedad o sincronizar la información de un agente puntual con tu sistema externo.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma, y <span style="color: rgb(241, 196, 15);">**{{document}}**</span> por el número de documento de identidad del asesor que deseas consultar.

```http
GET https://{{instancia}}/service/v2/public/agents/{{document}}
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Solo necesitas construir la URL con el número de documento del asesor como parte de la ruta e incluir los encabezados requeridos:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

**Parámetro de ruta:**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 58%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>`document`</td><td>string</td><td>Sí</td><td>Número de documento de identidad del asesor que se desea consultar. Se envía directamente en la URL.</td></tr></tbody></table>

**Ejemplo de petición:**

```http
GET https://mi-inmobiliaria.nuby.app/service/v2/public/agents/52498731
```

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

Si tu Token es válido y el documento corresponde a un asesor registrado, el sistema te devolverá un objeto JSON con la información del asesor. La respuesta se verá similar a esta:

```json
{
    "id": "3",
    "documento": "52498731",
    "nombre": "ANDREA MILENA CASTRO ROJAS",
    "telefono": "3104567890",
    "email": "andrea.castro@miredinmobiliaria.com",
    "path_photo": "https://mi-inmobiliaria.nuby.app/pic/usuarios/foto_andrea_castro.jpg"
}
```

**Descripción de cada campo:**

<table border="1" id="bkmrk-campo-tipo-descripci" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 12%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`id`</td><td>string</td><td>Identificador único del usuario en el sistema.</td></tr><tr><td>`documento`</td><td>string</td><td>Número de documento de identidad del asesor.</td></tr><tr><td>`nombre`</td><td>string</td><td>Nombre completo del asesor (compuesto por primer nombre, segundo nombre, primer apellido y segundo apellido).</td></tr><tr><td>`telefono`</td><td>string</td><td>Número de teléfono del asesor.</td></tr><tr><td>`email`</td><td>string</td><td>Dirección de correo electrónico del asesor.</td></tr><tr><td>`path_photo`</td><td>string</td><td>URL completa de la fotografía del asesor. Si el asesor no tiene foto registrada, se devuelve la imagen genérica del sistema.</td></tr></tbody></table>

<p class="callout warning">**Importante: asesor no encontrado**  
Cuando el documento no corresponde a ningún asesor registrado, el sistema **no devuelve un error**. En su lugar, responde con un HTTP `200` y un arreglo vacío:</p>

```json
[]
```

Asegúrate de validar en tu integración si la respuesta es un arreglo vacío `[]` para manejar correctamente el caso en que el asesor no exista.

---

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Otros posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**200**</td><td>Respuesta exitosa. Contiene el objeto JSON del asesor, o un arreglo vacío `[]` si no se encontró ningún asesor con ese documento.</td></tr><tr><td>**400**</td><td>Token no enviado o con formato incorrecto. Asegúrate de incluir el encabezado `Authorization: Bearer TU_TOKEN`.</td></tr><tr><td>**401**</td><td>Token expirado o inválido. Solicita uno nuevo a través del servicio de Login.</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-consultar-ase"><summary>cURL</summary>

```bash
# Consultar asesor por documento
curl -X GET "https://{{instancia}}/service/v2/public/agents/52498731" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login
$documento = '52498731'; // Documento del asesor a consultar

$url = "https://{$instance}/service/v2/public/agents/{$documento}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    if ($http_code === 200) {
        $asesor = json_decode($response, true);

        if (!empty($asesor)) {
            echo "Asesor encontrado:\n";
            echo "  ID: {$asesor['id']}\n";
            echo "  Nombre: {$asesor['nombre']}\n";
            echo "  Email: {$asesor['email']}\n";
            echo "  Teléfono: {$asesor['telefono']}\n";
        } else {
            echo "No se encontró ningún asesor con el documento {$documento}.\n";
        }
    } else {
        echo "Error al consultar el asesor.\n";
        echo $response . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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
documento = '52498731' # Documento del asesor a consultar

# 2. Prepara la dirección de la petición
url = f"https://{instancia}/service/v2/public/agents/{documento}"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        asesor = response.json()

        if asesor:
            print(f"Asesor encontrado:")
            print(f"  ID: {asesor['id']}")
            print(f"  Nombre: {asesor['nombre']}")
            print(f"  Email: {asesor['email']}")
            print(f"  Teléfono: {asesor['telefono']}")
        else:
            print(f"No se encontró ningún asesor con el documento {documento}.")
    else:
        print("Error al consultar el asesor.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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
const documento = '52498731'; // Documento del asesor a consultar

// 2. Prepara la dirección de la petición
const url = `https://${instancia}/service/v2/public/agents/${documento}`;

// 3. Función para consultar el asesor
async function consultarAsesor() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const asesor = await response.json();

            if (asesor && !Array.isArray(asesor)) {
                console.log(`Asesor encontrado:`);
                console.log(`  ID: ${asesor.id}`);
                console.log(`  Nombre: ${asesor.nombre}`);
                console.log(`  Email: ${asesor.email}`);
                console.log(`  Teléfono: ${asesor.telefono}`);
            } else {
                console.log(`No se encontró ningún asesor con el documento ${documento}.`);
            }
        } else {
            console.log('Error al consultar el asesor.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarAsesor();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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
    documento = "52498731", // Documento del asesor a consultar

    // 2. Prepara la dirección de la petición
    url = "https://" & instancia & "/service/v2/public/agents/" & documento,

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON y conviértela en registro
    jsonResponse = Json.Document(response),
    resultado = Record.ToTable(jsonResponse),
    expandido = Table.Pivot(resultado, List.Distinct(resultado[Name]), "Name", "Value")
in
    expandido
```

</details>

# Facturas

<span>Bienvenido a la </span>**caja registradora virtual**<span> de tu inmobiliaria. En esta sección centralizamos las conexiones para que tus plataformas externas gestionen automáticamente todo el ciclo de facturación y cobros.</span>

**¿Qué puedes lograr en este módulo?**

**1. Consulta sincronizada:**<span> Tus aplicaciones podrán revisar el historial de cuentas, buscar saldos pendientes por cliente y obtener enlaces seguros para descargar documentos en PDF. Además, tendrás acceso a configuraciones clave como tus resoluciones de facturación y medios de pago habilitados.</span>

**2. Acción directa sobre tu cartera:**<span> ¡Esta sección no es de solo lectura! Si recibes un pago en una plataforma externa, tu sistema puede reportarnos el monto y la fecha. Nosotros nos encargamos del trabajo pesado: calculamos el saldo, registramos el abono (ya sea parcial o total), generamos el recibo de ingreso y creamos el documento contable de forma automática.</span>

Explora las opciones a continuación para automatizar tus cobros y mantener las finanzas de tus clientes siempre al día.

# Listar Facturas

Permite obtener la lista paginada de todas las facturas registradas en el sistema. Cada elemento incluye el número de factura, resolución, fechas, valor total, saldo pendiente, tercero facturado, estado, información DIAN y datos de auditoría.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para sincronizar la información de facturación con tu sistema externo, generar reportes de cartera, alimentar dashboards con indicadores de facturación, validar el estado de cobro de los contratos o exportar la información a Excel y Power BI.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/invoices/list
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Envía los encabezados requeridos y opcionalmente los parámetros de paginación en la URL:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

**Parámetros de consulta (query string):**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 16%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 14%;"></col><col style="width: 50%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Por defecto</th><th>Descripción</th></tr></thead><tbody><tr><td>`page`</td><td>integer</td><td>No</td><td>1</td><td>Número de página de resultados que se desea recuperar. Debe ser un número positivo.</td></tr><tr><td>`page_size`</td><td>integer</td><td>No</td><td>10</td><td>Número máximo de facturas por página. Debe ser un número positivo. Valor máximo permitido: **1000**.</td></tr></tbody></table>

**Ejemplos de petición:**

```http
GET https://mi-inmobiliaria.nuby.app/service/v2/public/invoices/list
GET https://mi-inmobiliaria.nuby.app/service/v2/public/invoices/list?page=2
GET https://mi-inmobiliaria.nuby.app/service/v2/public/invoices/list?page_size=50
GET https://mi-inmobiliaria.nuby.app/service/v2/public/invoices/list?page=3&page_size=100
```

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

Si tu Token es válido, el sistema te devolverá un objeto JSON con el estado de la respuesta, el listado de facturas y la información de paginación. Los resultados están ordenados por fecha de factura descendente (más recientes primero). La respuesta se verá similar a esta:

```json
{
    "status": 200,
    "message": null,
    "body": [
        {
            "factura_id": 15230,
            "factura_numero": 8745,
            "resolucion": "FECO - 18764000002851",
            "fecha_factura": "2025-04-01",
            "fecha_vencimiento": "2025-04-06",
            "valor_total": "2850000.00",
            "saldo": "2850000.00",
            "documento_tercero": "80213654",
            "nombre_tercero": "CARLOS EDUARDO PINEDA VARGAS",
            "estado": "Facturada",
            "estado_dian": "Aceptada",
            "estado_cliente_dian": "Recibida",
            "notas": 0,
            "creado_por": "Sandra",
            "fecha_envio_dian": "2025-04-01 08:30:15",
            "fecha_creacion": "2025-04-01 07:45:22"
        },
        {
            "factura_id": 15229,
            "factura_numero": 8744,
            "resolucion": "FECO - 18764000002851",
            "fecha_factura": "2025-04-01",
            "fecha_vencimiento": "2025-04-06",
            "valor_total": "4500000.00",
            "saldo": "0.00",
            "documento_tercero": "1098745231",
            "nombre_tercero": "JULIANA PATRICIA RÍOS MENDOZA",
            "estado": "Pagada",
            "estado_dian": "Aceptada",
            "estado_cliente_dian": "Recibida",
            "notas": 0,
            "creado_por": "Sandra",
            "fecha_envio_dian": "2025-04-01 08:31:02",
            "fecha_creacion": "2025-04-01 07:46:10"
        },
        {
            "factura_id": 15210,
            "factura_numero": 8730,
            "resolucion": "0 - 18764000002851",
            "fecha_factura": "2025-03-01",
            "fecha_vencimiento": "2025-03-06",
            "valor_total": "1200000.00",
            "saldo": "1200000.00",
            "documento_tercero": "43876123",
            "nombre_tercero": "DIANA MARCELA OSPINA VELÁSQUEZ",
            "estado": "Facturada",
            "estado_dian": null,
            "estado_cliente_dian": null,
            "notas": 1,
            "creado_por": "Administrador",
            "fecha_envio_dian": null,
            "fecha_creacion": "2025-03-01 09:12:33"
        },
        {
            "factura_id": 14850,
            "factura_numero": 8520,
            "resolucion": "FECO - 18764000002851",
            "fecha_factura": "2025-02-01",
            "fecha_vencimiento": "2025-02-06",
            "valor_total": "3950000.00",
            "saldo": "3950000.00",
            "documento_tercero": "900456789",
            "nombre_tercero": "INVERSIONES HORIZONTE S.A.S.",
            "estado": "Anulada por NC",
            "estado_dian": "Aceptada",
            "estado_cliente_dian": null,
            "notas": 1,
            "creado_por": "Sandra",
            "fecha_envio_dian": "2025-02-01 10:05:44",
            "fecha_creacion": "2025-02-01 08:20:15"
        }
    ],
    "pagination": {
        "total_records": 15230,
        "total_pages": 305,
        "current_page": 1,
        "page_size": 50,
        "current_page_records": 4,
        "has_next_page": true,
        "has_previous_page": false
    }
}
```

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

<table border="1" id="bkmrk-campo-tipo-descripci" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 16%;"></col><col style="width: 14%;"></col><col style="width: 70%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`status`</td><td>integer</td><td>Código del estado de la respuesta. `200` para exitoso, `400` para error de validación, `500` para error interno.</td></tr><tr><td>`message`</td><td>string | null</td><td>Cuando la respuesta es exitosa vale `null`. Si no se encuentran facturas, contiene el mensaje informativo. Si hay error, describe el problema.</td></tr><tr><td>`body`</td><td>array | null</td><td>Listado de facturas devueltas. Arreglo vacío `[]` si no hay resultados. `null` en caso de error.</td></tr><tr><td>`pagination`</td><td>object | null</td><td>Información de paginación para recorrer los resultados. `null` en caso de error.</td></tr></tbody></table>

##### **Campos de cada factura (body)**

Cada elemento dentro del arreglo `body` contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 14%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`factura_id`</td><td>integer</td><td>Identificador único de la factura en el sistema.</td></tr><tr><td>`factura_numero`</td><td>integer</td><td>Número consecutivo de la factura.</td></tr><tr><td>`resolucion`</td><td>string</td><td>Prefijo y número de la resolución de facturación en formato `PREFIJO - NÚMERO` (ej. `"FECO - 18764000002851"`).</td></tr><tr><td>`fecha_factura`</td><td>string</td><td>Fecha de emisión de la factura en formato `YYYY-MM-DD`.</td></tr><tr><td>`fecha_vencimiento`</td><td>string</td><td>Fecha de vencimiento de la factura en formato `YYYY-MM-DD`.</td></tr><tr><td>`valor_total`</td><td>string</td><td>Valor total de la factura con decimales (ej. `"2850000.00"`).</td></tr><tr><td>`saldo`</td><td>string</td><td>Saldo pendiente de pago de la factura con decimales (ej. `"0.00"` cuando está pagada).</td></tr><tr><td>`documento_tercero`</td><td>string</td><td>Número de documento de identidad del tercero/cliente facturado.</td></tr><tr><td>`nombre_tercero`</td><td>string</td><td>Nombre completo del tercero/cliente facturado.</td></tr><tr><td>`estado`</td><td>string</td><td>Estado textual de la factura. Valores posibles: `Facturada`, `Anulada`, `Pagada`, `Borrador`, `Anulada por NC`, `Contabilizada`.</td></tr><tr><td>`estado_dian`</td><td>string | null</td><td>Estado de la factura en la DIAN cuando es factura electrónica (ej. `"Aceptada"`). `null` si no aplica o no se ha enviado.</td></tr><tr><td>`estado_cliente_dian`</td><td>string | null</td><td>Estado de aceptación/rechazo del cliente ante la DIAN cuando es factura electrónica. `null` si no aplica.</td></tr><tr><td>`notas`</td><td>integer</td><td>Cantidad de notas débito o crédito asociadas a la factura.</td></tr><tr><td>`creado_por`</td><td>string</td><td>Nombre del usuario que creó la factura en el sistema.</td></tr><tr><td>`fecha_envio_dian`</td><td>string | null</td><td>Fecha y hora de envío de la factura a la DIAN en formato `YYYY-MM-DD HH:MM:SS`. `null` si no se ha enviado.</td></tr><tr><td>`fecha_creacion`</td><td>string</td><td>Fecha y hora de creación del registro en formato `YYYY-MM-DD HH:MM:SS`.</td></tr></tbody></table>

##### **Campos de paginación (pagination)**

El objeto `pagination` contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-2" 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>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`total_records`</td><td>integer</td><td>Total de facturas registradas en el sistema.</td></tr><tr><td>`total_pages`</td><td>integer</td><td>Cantidad total de páginas disponibles (total de registros dividido por el tamaño de página).</td></tr><tr><td>`current_page`</td><td>integer</td><td>Número de la página actual consultada.</td></tr><tr><td>`page_size`</td><td>integer</td><td>Tamaño de la página (cantidad de registros solicitados por consulta).</td></tr><tr><td>`current_page_records`</td><td>integer</td><td>Cantidad de registros efectivamente devueltos en la página actual.</td></tr><tr><td>`has_next_page`</td><td>boolean</td><td>`true` si existen páginas posteriores que se pueden consultar.</td></tr><tr><td>`has_previous_page`</td><td>boolean</td><td>`true` si existen páginas anteriores que se pueden consultar.</td></tr></tbody></table>

<p class="callout info">**Nota sobre facturas sin resultados**  
Si no existen facturas registradas en el sistema, la respuesta tendrá HTTP `200` con `body` vacío (`[]`), un `message` informativo: `"No se encontraron facturas en el sistema."` y los valores de paginación en cero.</p>

---

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Si alguno de los parámetros de paginación no cumple con las validaciones, el sistema devolverá un error `400`. Por ejemplo:

```json
{
    "status": 400,
    "message": "El parámetro \"page_size\" debe ser un número positivo.",
    "body": null,
    "pagination": null
}
```

Posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`  
  
**Parámetros inválidos.** Posibles causas:  
— `page` no es numérico o no es positivo. Mensaje: `"El parámetro \"page\" debe ser un número positivo."`  
— `page_size` no es numérico o no es positivo. Mensaje: `"El parámetro \"page_size\" debe ser un número positivo."`</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**. Mensaje: `"JWT Token expired."`</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr><tr><td>**500**</td><td>Error interno del servidor al procesar la consulta de facturas. Mensaje: `"Error interno del servidor al obtener las facturas."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-listar-factur"><summary>cURL</summary>

```bash
# Listar facturas con paginación por defecto
curl -X GET "https://{{instancia}}/service/v2/public/invoices/list" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Listar facturas página 3 con 100 registros por página
curl -X GET "https://{{instancia}}/service/v2/public/invoices/list?page=3&page_size=100" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login

// Parámetros de paginación
$page = 1;
$page_size = 50;

$queryParams = http_build_query([
    'page' => $page,
    'page_size' => $page_size
]);

$url = "https://{$instance}/service/v2/public/invoices/list?{$queryParams}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    $info = json_decode($response, true);
    $body = $info['body'] ?? [];

    if ($http_code === 200 && !empty($body)) {
        $pagination = $info['pagination'];
        echo "Facturas encontradas: {$pagination['total_records']} (página {$pagination['current_page']} de {$pagination['total_pages']})\n";

        foreach ($body as $factura) {
            echo "  Factura #{$factura['factura_numero']} - {$factura['nombre_tercero']} - {$factura['estado']} - Total: \${$factura['valor_total']} - Saldo: \${$factura['saldo']}\n";
        }
    } else {
        echo "Mensaje: " . ($info['message'] ?? 'Sin resultados') . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 la dirección y los parámetros
url = f"https://{instancia}/service/v2/public/invoices/list"

params = {
    "page": 1,
    "page_size": 50
}

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, params=params, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        info = response.json()
        body = info.get('body', [])
        pagination = info.get('pagination', {})

        if body:
            print(f"Facturas: {pagination['total_records']} total (página {pagination['current_page']} de {pagination['total_pages']})")
            for factura in body:
                print(f"  #{factura['factura_numero']} - {factura['nombre_tercero']} - {factura['estado']} - Total: ${factura['valor_total']} - Saldo: ${factura['saldo']}")
        else:
            print(f"Mensaje: {info.get('message', 'Sin resultados')}")
    else:
        print("Error al consultar las facturas.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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. Prepara la dirección con parámetros
const params = new URLSearchParams({
    page: 1,
    page_size: 50
});

const url = `https://${instancia}/service/v2/public/invoices/list?${params}`;

// 3. Función para consultar las facturas
async function consultarFacturas() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const info = await response.json();
            const body = info.body || [];
            const pagination = info.pagination || {};

            if (body.length > 0) {
                console.log(`Facturas: ${pagination.total_records} total (página ${pagination.current_page} de ${pagination.total_pages})`);
                body.forEach(factura => {
                    console.log(`  #${factura.factura_numero} - ${factura.nombre_tercero} - ${factura.estado} - Total: $${factura.valor_total} - Saldo: $${factura.saldo}`);
                });
            } else {
                console.log(`Mensaje: ${info.message || 'Sin resultados'}`);
            }
        } else {
            console.log('Error al consultar las facturas.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarFacturas();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 la dirección de la petición con parámetros
    url = "https://" & instancia & "/service/v2/public/invoices/list?page=1&page_size=1000",

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON
    jsonResponse = Json.Document(response),
    body = jsonResponse[body],

    // 5. Convierte el listado en tabla
    tabla = Table.FromList(body, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"factura_id", "factura_numero", "resolucion", "fecha_factura", "fecha_vencimiento", "valor_total", "saldo", "documento_tercero", "nombre_tercero", "estado", "estado_dian", "notas", "creado_por", "fecha_creacion"},
        {"FacturaID", "Numero", "Resolucion", "FechaFactura", "FechaVencimiento", "ValorTotal", "Saldo", "DocTercero", "NombreTercero", "Estado", "EstadoDian", "Notas", "CreadoPor", "FechaCreacion"})
in
    expandido
```

</details>

# Registrar Pago de Factura [BETA]

<p class="callout info">**Funcionalidad en pruebas**  
Esta funcionalidad forma parte de un proceso de pruebas internas y no se encuentra disponible para usuarios del sistema.</p>

Permite registrar el pago de una factura existente en el sistema. Si no se especifica la forma de pago, el sistema intentará determinarla automáticamente basándose en el cliente OAuth2 autenticado o utilizará la forma de pago por defecto configurada (Consignación bancaria).

**Endpoint:** https://<span style="color: rgb(241, 196, 15);">***{{instancia}}***</span>.arrendasoft.co/service/v2/public/invoices/register-payment

**<span style="color: rgb(241, 196, 15);">{{instancia}}</span>:** Hace referencia a la instancia de cada inmobiliaria.

#### **Petición**

<div class="markdown-body" dir="auto" id="bkmrk-m%C3%A9todo-post-content-"><table border="1" id="bkmrk-m%C3%A9todo-post-content" style="width: 100%; height: 105.844px;"><colgroup><col style="width: 51.4498%;"></col><col style="width: 48.5104%;"></col></colgroup><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">**Método**</td><td style="height: 29.7969px;">POST</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">**Content-Type**</td><td style="height: 29.7969px;">application/json</td></tr><tr style="height: 46.25px;"><td style="height: 46.25px;">**Authorization**</td><td style="height: 46.25px;">**Bearer token,** Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login)</td></tr></tbody></table>

<table border="1" id="bkmrk-par%C3%A1metro-tipo-oblig" style="width: 100%; height: 292.563px;"><colgroup><col style="width: 15.0119%;"></col><col style="width: 7.86338%;"></col><col style="width: 10.7228%;"></col><col style="width: 16.6782%;"></col><col style="width: 49.684%;"></col></colgroup><tbody><tr style="height: 29.7969px;"><td class="align-center" colspan="5" style="height: 29.7969px;">**Parámetros del Body (JSON)**</td></tr><tr style="height: 29.7969px;"><td class="align-center" style="height: 29.7969px;">**Parámetro**</td><td class="align-center" style="height: 29.7969px;">**Tipo**</td><td class="align-center" style="height: 29.7969px;">**Obligatorio**</td><td class="align-center" style="height: 29.7969px;">**Valor por defecto**</td><td class="align-center" style="height: 29.7969px;">**Descripción**</td></tr><tr style="height: 46.5938px;"><td style="height: 46.5938px;">factura\_id</td><td style="height: 46.5938px;">integer</td><td class="align-center" style="height: 46.5938px;">Sí</td><td class="align-center" style="height: 46.5938px;">-</td><td style="height: 46.5938px;">Identificador único de la factura a la cual se registrará el pago. Debe ser un número entero positivo y coincidir con una factura en el sistema.</td></tr><tr style="height: 46.5938px;"><td style="height: 46.5938px;">monto</td><td style="height: 46.5938px;">float</td><td class="align-center" style="height: 46.5938px;">Sí</td><td class="align-center" style="height: 46.5938px;">-</td><td style="height: 46.5938px;">Monto del pago a registrar. Debe ser un número positivo y no puede exceder el saldo pendiente de la factura.</td></tr><tr style="height: 46.5938px;"><td style="height: 46.5938px;">fecha\_pago</td><td style="height: 46.5938px;">string</td><td class="align-center" style="height: 46.5938px;">Sí</td><td class="align-center" style="height: 46.5938px;">-</td><td style="height: 46.5938px;"><div><div>Fecha y hora en que se realizó el pago. Formato: Y-m-d H:i:s (ej: 2026-02-05 14:30:00).</div></div></td></tr><tr style="height: 63.3906px;"><td style="height: 63.3906px;">forma\_pago\_id</td><td style="height: 63.3906px;">integer</td><td class="align-center" style="height: 63.3906px;">No</td><td class="align-center" style="height: 63.3906px;">Auto</td><td style="height: 63.3906px;">ID de la forma de pago. Si no se proporciona, se determina automáticamente según el cliente o la configuración por defecto.</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">n\_comprobante</td><td style="height: 29.7969px;">string</td><td class="align-center" style="height: 29.7969px;">No</td><td class="align-center" style="height: 29.7969px;">-</td><td style="height: 29.7969px;">Número de comprobante o referencia del pago realizado. Máximo 100 caracteres. Solo se permiten letras, números, guiones (-), guiones bajos (\_), puntos (.) y espacios.</td></tr></tbody></table>

</div>**Ejemplo de petición (Body JSON)**

```json
{
    "factura_id": 366,
    "monto": 50000,
    "fecha_pago": "2026-02-05 14:30:00",
    "forma_pago_id": 1,
    "n_comprobante": "REF123456"
}
```

**Ejemplo mínimo (solo campos requeridos):**

```json
{
    "factura_id": 366,
    "monto": 50000,
    "fecha_pago": "2026-02-05 10:00:00"
}
```

#### **Respuestas**

##### Respuesta Exitosa (200)

Cuando el pago se registra correctamente, la respuesta incluye los detalles completos del pago registrado, incluyendo los IDs de los registros generados en el sistema (pago, recibo de ingreso y documento contable) así como el estado actualizado de la factura.

```json
{
    "success": true,
    "status": 200,
    "message": "Pago registrado exitosamente.",
    "body": {
        "factura_id": 366,
        "pago_id": 142,
        "recibo_id": 589,
        "documento_contable_id": 1023,
        "monto_pagado": 50000,
        "fecha_pago": "2026-02-05 14:30:00",
        "forma_pago_id": 1,
        "forma_pago": "Consignación bancaria",
        "n_comprobante": "REF123456",
        "saldo_anterior": 150000,
        "saldo_actual": 100000,
        "estado_factura": "Facturada",
        "gateway": null,
        "client_name": "MiAplicacion"
    }
}
```

##### Claves y Descripciones del JSON de Respuesta

<div class="markdown-body" dir="auto" id="bkmrk-clave-tipo-descripci"><table id="bkmrk-clave-descripci%C3%B3n-co" style="width: 100%; height: 230.458px;"><thead><tr style="height: 29.4583px;"><th style="width: 9.8888%; height: 29.4583px;">**Clave**</th><th style="width: 10.9616%; height: 29.4583px;">**Tipo**</th><th style="width: 79.1099%; height: 29.4583px;">**Descripción**</th></tr></thead><tbody><tr style="height: 51.5833px;"><td style="width: 9.8888%; height: 51.5833px;">`success`

</td><td style="width: 10.9616%; height: 51.5833px;">Booleano</td><td style="width: 79.1099%; height: 51.5833px;">Indica si la operación fue exitosa (true) o fallida (false).</td></tr><tr style="height: 46.25px;"><td style="width: 9.8888%; height: 46.25px;">`status`</td><td style="width: 10.9616%; height: 46.25px;">Entero</td><td style="width: 79.1099%; height: 46.25px;">Código HTTP de la respuesta: 200 (exitoso), 400 (error de validación), 404 (no encontrado), 422 (error de negocio), 500 (error interno).</td></tr><tr style="height: 44.25px;"><td style="width: 9.8888%; height: 44.25px;">`message`</td><td style="width: 10.9616%; height: 44.25px;">Texto</td><td style="width: 79.1099%; height: 44.25px;">Mensaje descriptivo del resultado de la operación.</td></tr><tr style="height: 29.4583px;"><td style="width: 9.8888%; height: 29.4583px;">`body`</td><td style="width: 10.9616%; height: 29.4583px;">Objeto</td><td style="width: 79.1099%; height: 29.4583px;">Contiene los detalles del pago registrado cuando la operación es exitosa. Es nulo cuando hay error.</td></tr><tr style="height: 29.4583px;"><td style="width: 9.8888%; height: 29.4583px;">`errors`</td><td style="width: 10.9616%; height: 29.4583px;">Array</td><td style="width: 79.1099%; height: 29.4583px;">Lista de errores de validación. Solo presente cuando status es 400.</td></tr></tbody></table>

</div>##### Cuerpo de Respuesta Exitosa (body)

Cuando la operación es exitosa, el objeto `body` contiene las siguientes claves:

<div class="markdown-body" dir="auto" id="bkmrk-%2A%2Aclave%2A%2A-%2A%2Atipo%2A%2A-%2A"><table id="bkmrk-clave-descripci%C3%B3n-id" style="width: 89.6429%; height: 450.703px;"><thead><tr style="height: 29.7969px;"><th style="width: 23.1383%; height: 29.7969px;">**Clave**</th><th style="width: 10.6383%; height: 29.7969px;">**Tipo**</th><th style="width: 66.2234%; height: 29.7969px;">**Descripción**</th></tr></thead><tbody><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`factura_id`</td><td style="width: 10.6383%; height: 30.1094px;">Entero</td><td style="width: 66.2234%; height: 30.1094px;">ID de la factura a la que se aplicó el pago.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`pago_id`</td><td style="width: 10.6383%; height: 30.1094px;">Entero</td><td style="width: 66.2234%; height: 30.1094px;">ID del registro de pago creado en el sistema.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`recibo_id`</td><td style="width: 10.6383%; height: 30.1094px;">Entero</td><td style="width: 66.2234%; height: 30.1094px;">ID del recibo de caja generado.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`documento_contable_id`</td><td style="width: 10.6383%; height: 30.1094px;">Entero</td><td style="width: 66.2234%; height: 30.1094px;">ID del documento contable creado.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`monto_pagado`</td><td style="width: 10.6383%; height: 30.1094px;">Numérico</td><td style="width: 66.2234%; height: 30.1094px;">Monto del pago registrado.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`fecha_pago`</td><td style="width: 10.6383%; height: 30.1094px;">Texto</td><td style="width: 66.2234%; height: 30.1094px;">Fecha y hora del pago en formato Y-m-d H:i:s.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`forma_pago_id`</td><td style="width: 10.6383%; height: 30.1094px;">Entero</td><td style="width: 66.2234%; height: 30.1094px;">ID de la forma de pago utilizada.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`forma_pago`</td><td style="width: 10.6383%; height: 30.1094px;">Texto</td><td style="width: 66.2234%; height: 30.1094px;">Nombre de la forma de pago utilizada.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`n_comprobante`</td><td style="width: 10.6383%; height: 30.1094px;">Texto</td><td style="width: 66.2234%; height: 30.1094px;">Número de comprobante o referencia del pago. Máximo 100 caracteres. Nulo si no se proporcionó.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`saldo_anterior`</td><td style="width: 10.6383%; height: 30.1094px;">Numérico</td><td style="width: 66.2234%; height: 30.1094px;">Saldo de la factura antes de aplicar el pago.</td></tr><tr style="height: 29.7969px;"><td style="width: 23.1383%;">`saldo_actual`</td><td style="width: 10.6383%;">Numérico</td><td style="width: 66.2234%;">Saldo de la factura después de aplicar el pago. Si es 0, la factura quedó totalmente pagada.</td></tr><tr><td style="width: 23.1383%;">`estado_factura`</td><td style="width: 10.6383%;">Texto</td><td style="width: 66.2234%;">Estado de la factura después de aplicar el pago (ej: "Facturada", "Pagada").</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`gateway`</td><td style="width: 10.6383%; height: 30.1094px;">Texto</td><td style="width: 66.2234%; height: 30.1094px;">Nombre de la pasarela de pago si aplica. Nulo si no se usó pasarela.</td></tr><tr style="height: 30.1094px;"><td style="width: 23.1383%; height: 30.1094px;">`client_name`</td><td style="width: 10.6383%; height: 30.1094px;">Texto</td><td style="width: 66.2234%; height: 30.1094px;">Nombre del cliente OAuth autenticado que realizó la petición.</td></tr></tbody></table>

</div>#### **Respuestas de Error**

##### Error de Validación (400)

Se retorna cuando los parámetros enviados no cumplen con las validaciones requeridas.

```json
{
    "success": false,
    "status": 400,
    "message": "Errores de validación",
    "body": null,
    "errors": [
        "El parámetro \"factura_id\" es requerido.",
        "El parámetro \"monto\" debe ser un número positivo.",
        "El parámetro \"fecha_pago\" debe tener el formato Y-m-d H:i:s (ej: 2026-02-02 14:30:00).",
        "El parámetro \"n_comprobante\" no puede exceder 100 caracteres.",
        "El parámetro \"n_comprobante\" contiene caracteres no permitidos. Solo se aceptan letras, números, guiones, guiones bajos, puntos y espacios."
    ]
}
```

##### Factura No Encontrada (404)

Se retorna cuando no existe una factura con el ID proporcionado.

```json
{
    "success": false,
    "status": 404,
    "message": "No se encontró la factura con el ID proporcionado.",
    "body": null
}
```

##### Error de Negocio (422)

Se retorna cuando la factura existe pero no puede recibir el pago por razones de negocio.

**Factura no activa:**

```json
{
    "success": false,
    "status": 422,
    "message": "La factura no está en estado activo/pendiente de pago. Estado actual: Pagada",
    "body": null
}
```

**Monto excede saldo:**

```json
{
    "success": false,
    "status": 422,
    "message": "El monto a pagar (100000) excede el saldo de la factura (50000).",
    "body": null
}
```

**Forma de pago no determinada:**

```json
{
    "success": false,
    "status": 422,
    "message": "No se pudo determinar la forma de pago automáticamente. Por favor especifique el parámetro \"forma_pago_id\".",
    "body": null
}
```

**Factura sin detalles:**

```json
{
    "success": false,
    "status": 422,
    "message": "La factura no tiene detalles asociados. No es posible registrar el pago.",
    "body": null
}
```

**Forma de pago sin cuenta contable:**

```json
{
    "success": false,
    "status": 422,
    "message": "La forma de pago seleccionada no tiene una cuenta contable configurada. No es posible registrar el pago.",
    "body": null
}
```

**Periodo contable no activo:**

```json
{
    "success": false,
    "status": 422,
    "message": "No existe un periodo contable activo para la fecha 2026-01-15. Verifique que el periodo esté abierto en el módulo de contabilidad.",
    "body": null
}
```


##### Error Interno (500)

Se retorna cuando ocurre un error inesperado en el servidor o cuando el proceso de registro del pago falla.

**Error general:**

```json
{
    "success": false,
    "status": 500,
    "message": "Error interno del servidor al registrar el pago.",
    "body": null
}
```

**Error al generar recibo de ingreso:**

```json
{
    "success": false,
    "status": 500,
    "message": "Error al crear el recibo de ingreso para el pago de la factura.",
    "body": null
}
```

**Pago procesado sin confirmación de ID:**

```json
{
    "success": false,
    "status": 500,
    "message": "El pago se procesó pero no se pudo obtener el ID del registro de pago. Verifique manualmente en el sistema.",
    "body": null
}
```

#### **Códigos de Respuesta HTTP**

<div class="markdown-body" dir="auto" id="bkmrk-%2A%2Ac%C3%B3digo%2A%2A-%2A%2Adescrip"><table id="bkmrk-c%C3%B3digo-descripci%C3%B3n-2" style="width: 100%;"><thead><tr><th style="width: 9.41228%;">**Código**</th><th style="width: 90.5877%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 9.41228%;">200</td><td style="width: 90.5877%;">Pago registrado exitosamente. La respuesta incluye los IDs del pago, recibo y documento contable generados.</td></tr><tr><td style="width: 9.41228%;">400</td><td style="width: 90.5877%;">Error de validación en los parámetros enviados, forma de pago inexistente, o n\_comprobante con formato inválido.</td></tr><tr><td style="width: 9.41228%;">404</td><td style="width: 90.5877%;">La factura especificada no existe.</td></tr><tr><td style="width: 9.41228%;">422</td><td style="width: 90.5877%;"><div><div>Error de regla de negocio: factura no activa, monto excede saldo, factura sin detalles, forma de pago sin cuenta contable, periodo contable no activo, o no se pudo determinar forma de pago.</div></div></td></tr><tr><td style="width: 9.41228%;">500</td><td style="width: 90.5877%;">Error interno del servidor, error al generar recibo de ingreso, o pago procesado sin confirmación de ID.</td></tr></tbody></table>

</div>#### **Notas Importantes**

<div class="markdown-body" dir="auto" id="bkmrk-determinaci%C3%B3n-autom%C3%A1">1. **Determinación Automática de Forma de Pago:** Si no se proporciona `forma_pago_id`, el sistema intentará:
    
    
    - Primero, determinar la forma de pago basándose en el cliente OAuth autenticado (integración con pasarelas de pago).
    - Si no encuentra una pasarela asociada, buscará la forma de pago por defecto configurada con código DIAN 42 (Consignación bancaria).
2. **Estados de Factura:** Solo se pueden registrar pagos en facturas con estado "Facturada" (estado\_id = 1). Los estados posibles son:
    
    
    - 1: Facturada (permite pagos)
    - 2: Anulada
    - 3: Pagada
    - 5: Borrador
    - 6: Anulada por NC
3. **Pagos Parciales:** El sistema permite pagos parciales. El monto debe ser mayor a cero y no puede exceder el saldo pendiente de la factura. Tras un pago parcial, la respuesta incluye `saldo\_anterior` y `saldo\_actual` para verificar la diferencia.
4. **Formas de Pago:** Para obtener el listado de formas de pago disponibles, consulte el endpoint [Listar Formas de Pago](https://docs.nuby.ai/books/api-nuby-v2/page/listar-formas-de-pago-beta "Listar Formas de Pago").
5. **Verificación del Pago:** La respuesta exitosa incluye `pago\_id`, `recibo\_id` y `documento\_contable\_id` que permiten verificar que el pago, el recibo de ingreso y el asiento contable se crearon correctamente en el sistema.
6. **Estado de la Factura:** El campo `estado\_factura` en la respuesta indica el estado actualizado de la factura tras el pago. Si el saldo queda en 0, la factura pasará automáticamente a estado "Pagada".
7. **Validación de n\_comprobante:** El número de comprobante tiene las siguientes restricciones:
    
    
    - Máximo 100 caracteres.
    - Solo se permiten: letras (a-z, A-Z), números (0-9), guiones (-), guiones bajos (\\\_), puntos (.) y espacios.
    - No se permiten caracteres especiales como comillas, signos de mayor/menor, punto y coma, etc.
8. **Periodo Contable:** La fecha del pago debe corresponder a un periodo contable activo en el sistema. Si la fecha está fuera de un periodo activo, se retornará un error 422 indicando que debe verificarse la configuración de periodos en el módulo de contabilidad.
9. **Validación de forma\_pago\_id:** Si se proporciona el parámetro `forma\_pago\_id`, debe ser un número entero positivo.

</div>#### **Ejemplos**

<div class="markdown-body" dir="auto" id="bkmrk-curl-curl--x-post-%22h"><details id="bkmrk-curl-curl--x-post-%22h-1"><summary>Curl</summary>

```bash
curl -X POST "https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/register-payment" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AUTHENTICATION_TOKEN" \
  -d '{
    "factura_id": 366,
    "monto": 50000,
    "fecha_pago": "2026-02-05 10:00:00",
    "n_comprobante": "REF123456"
  }'
```

</details><details id="bkmrk-php-curl-%3C%3Fphp-%24inst"><summary>PHP Curl</summary>

```php
<?php

$instance = 'your_instance'; // Reemplace con su instancia actual
$token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido desde el servicio de login

// Datos del pago a registrar
$paymentData = [
    'factura_id' => 366,
    'monto' => 50000,
    'fecha_pago' => '2026-02-05 14:30:00',
    'forma_pago_id' => 1, // Opcional
    'n_comprobante' => 'REF123456' // Opcional
];

$url = "https://{$instance}.arrendasoft.co/service/v2/public/invoices/register-payment";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($paymentData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "HTTP Status Code: " . $http_code . "\n";
    echo "Response: " . $response . "\n";
    
    // Procesar la respuesta
    $result = json_decode($response, true);
    
    if ($result['success']) {
        echo "Pago registrado exitosamente.\n";
        echo "Factura: " . $result['body']['factura_id'] . "\n";
        echo "Pago ID: " . $result['body']['pago_id'] . "\n";
        echo "Recibo ID: " . $result['body']['recibo_id'] . "\n";
        echo "Documento Contable ID: " . $result['body']['documento_contable_id'] . "\n";
        echo "Monto pagado: " . $result['body']['monto_pagado'] . "\n";
        echo "Forma de pago: " . $result['body']['forma_pago'] . "\n";
        echo "Saldo anterior: " . $result['body']['saldo_anterior'] . "\n";
        echo "Saldo actual: " . $result['body']['saldo_actual'] . "\n";
        echo "Estado factura: " . $result['body']['estado_factura'] . "\n";
    } else {
        echo "Error: " . $result['message'] . "\n";
        if (isset($result['errors'])) {
            foreach ($result['errors'] as $error) {
                echo "- " . $error . "\n";
            }
        }
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-javascript-fetch"><summary>JavaScript Fetch</summary>

```javascript
const instance = 'your_instance'; // Reemplace con su instancia actual
const token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido

const paymentData = {
    factura_id: 366,
    monto: 50000,
    fecha_pago: '2026-02-05 14:30:00',
    n_comprobante: 'REF123456'
};

fetch(`https://${instance}.arrendasoft.co/service/v2/public/invoices/register-payment`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
    },
    body: JSON.stringify(paymentData)
})
.then(response => response.json())
.then(data => {
    if (data.success) {
        console.log('Pago registrado exitosamente');
        console.log('Factura:', data.body.factura_id);
        console.log('Pago ID:', data.body.pago_id);
        console.log('Recibo ID:', data.body.recibo_id);
        console.log('Documento Contable ID:', data.body.documento_contable_id);
        console.log('Monto pagado:', data.body.monto_pagado);
        console.log('Forma de pago:', data.body.forma_pago);
        console.log('Saldo anterior:', data.body.saldo_anterior);
        console.log('Saldo actual:', data.body.saldo_actual);
        console.log('Estado factura:', data.body.estado_factura);
    } else {
        console.error('Error:', data.message);
        if (data.errors) {
            data.errors.forEach(error => console.error('-', error));
        }
    }
})
.catch(error => console.error('Error de conexión:', error));
```

</details><div class="code-line" data-line="285">  
</div></div>

# Listar Formas de Pago [BETA]

<p class="callout info">**Funcionalidad en pruebas**  
Esta funcionalidad forma parte de un proceso de pruebas internas y no se encuentra disponible para usuarios del sistema.</p>

Permite obtener las formas de pago configuradas de la inmobiliaria. Solo devuelve las formas de pago que tengan una cuenta contable (PUC) relacionada.

**Endpoint:** https://<span style="color: rgb(241, 196, 15);">***{{instancia}}***</span>.arrendasoft.co/service/v2/public/invoices/payment-methods

**<span style="color: rgb(241, 196, 15);">{{instancia}}</span>:** Hace referencia a la instancia de cada inmobiliaria.

#### **Petición**

<div class="markdown-body" dir="auto" id="bkmrk-m%C3%A9todo-get-content-t"><table border="1" id="bkmrk-m%C3%A9todo-get-content-t-1" style="width: 100%;"><colgroup><col style="width: 39.4436%;"></col><col style="width: 60.5167%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login)</td></tr></tbody></table>

<table border="1" id="bkmrk-par%C3%A1metro-tipo-oblig" style="width: 100%; height: 168.208px;"><colgroup><col style="width: 12.1525%;"></col><col style="width: 7.38681%;"></col><col style="width: 11.4376%;"></col><col style="width: 16.6751%;"></col><col style="width: 52.3082%;"></col></colgroup><tbody><tr style="height: 29.4583px;"><td class="align-center" colspan="5" style="height: 29.4583px;">**Parámetros**</td></tr><tr style="height: 46.25px;"><td class="align-center" style="height: 46.25px;">**Parámetro**</td><td class="align-center" style="height: 46.25px;">**Tipo**</td><td class="align-center" style="height: 46.25px;">**Obligatorio**</td><td class="align-center" style="height: 46.25px;">**Valor por defecto**</td><td class="align-center" style="height: 46.25px;">**Descripción**</td></tr><tr style="height: 46.25px;"><td style="height: 46.25px;">codigo\_dian</td><td style="height: 46.25px;">string</td><td class="align-center" style="height: 46.25px;">No</td><td class="align-center" style="height: 46.25px;">-</td><td style="height: 46.25px;">Filtra formas de pago por el código DIAN del medio de pago (ej: 42 para Consignación bancaria).</td></tr><tr style="height: 46.25px;"><td style="height: 46.25px;">cuenta\_puc</td><td style="height: 46.25px;">string</td><td class="align-center" style="height: 46.25px;">No</td><td class="align-center" style="height: 46.25px;">-</td><td style="height: 46.25px;">Filtra formas de pago por código de cuenta PUC. La búsqueda es por prefijo (ej: 1110 retorna todas las cuentas que inicien con ese código).</td></tr></tbody></table>

</div>**Ejemplos de peticiones**

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods?codigo_dian=42
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods?cuenta_puc=1110
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods?codigo_dian=42&cuenta_puc=1110
```

#### **Respuesta**

Lista de formas de pago configuradas con información del medio de pago DIAN y cuenta contable asociada.

```json
{
    "success": true,
    "status": 200,
    "message": null,
    "body": [
        {
            "formaPagoId": 1,
            "nombre": "Consignación Bancolombia",
            "cuentaPuc": "11100501",
            "codigoDian": "42",
            "medioPago": "Consignación bancaria"
        },
        {
            "formaPagoId": 2,
            "nombre": "Transferencia Davivienda",
            "cuentaPuc": "11100502",
            "codigoDian": "31",
            "medioPago": "Transferencia débito bancaria"
        },
        {
            "formaPagoId": 3,
            "nombre": "Pago con tarjeta de crédito",
            "cuentaPuc": "11100503",
            "codigoDian": "48",
            "medioPago": "Tarjeta de crédito"
        }
    ],
    "filters_applied": null
}
```

##### Claves y Descripciones del JSON de Respuesta

Esta tabla enumera las claves presentes en el JSON principal de la respuesta y proporciona una breve descripción de cada una.

<div class="markdown-body" dir="auto" id="bkmrk-clave-tipo-descripci"><table id="bkmrk-clave-descripci%C3%B3n-co" style="width: 100%;"><thead><tr><th style="width: 16.4416%;">**Clave**</th><th style="width: 10.8398%;">**Tipo**</th><th style="width: 72.6789%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 16.4416%;">`success`</td><td style="width: 10.8398%;">Booleano</td><td style="width: 72.6789%;">Indica si la operación fue exitosa (true) o fallida (false).</td></tr><tr><td style="width: 16.4416%;">`status`</td><td style="width: 10.8398%;">Entero</td><td style="width: 72.6789%;">Código HTTP de la respuesta: 200 para exitoso, 500 para error interno.</td></tr><tr><td style="width: 16.4416%;">`message`</td><td style="width: 10.8398%;">Texto</td><td style="width: 72.6789%;">Mensaje descriptivo. Es nulo cuando hay resultados, o contiene un mensaje informativo cuando no se encontraron formas de pago.</td></tr><tr><td style="width: 16.4416%;">`body`</td><td style="width: 10.8398%;">Array</td><td style="width: 72.6789%;">Contiene el listado de formas de pago. Es un array vacío si no hay resultados.</td></tr><tr><td style="width: 16.4416%;">`filters_applied`</td><td style="width: 10.8398%;">Objeto</td><td style="width: 72.6789%;">Contiene los filtros que fueron aplicados en la consulta. Es nulo si no se aplicaron filtros.</td></tr></tbody></table>

</div>##### Cuerpo

Cada elemento dentro de la lista `body` tiene las siguientes claves:

<div class="markdown-body" dir="auto" id="bkmrk-clave-tipo-descripci-1"><table id="bkmrk-clave-descripci%C3%B3n-id" style="width: 100%; height: 193.542px;"><thead><tr style="height: 29.4583px;"><th style="width: 15.3693%; height: 29.4583px;">**Clave**</th><th style="width: 8.93122%; height: 29.4583px;">**Tipo**</th><th style="width: 75.6597%; height: 29.4583px;">**Descripción**</th></tr></thead><tbody><tr style="height: 46.25px;"><td style="width: 15.3693%; height: 46.25px;">`formaPagoId`</td><td style="width: 8.93122%; height: 46.25px;">Entero</td><td style="width: 75.6597%; height: 46.25px;">Identificador único de la forma de pago. Use este valor para el parámetro `forma\_pago\_id` al registrar un pago.</td></tr><tr style="height: 29.4583px;"><td style="width: 15.3693%; height: 29.4583px;">`nombre`</td><td style="width: 8.93122%; height: 29.4583px;">Texto</td><td style="width: 75.6597%; height: 29.4583px;">Nombre descriptivo de la forma de pago configurada por la inmobiliaria.</td></tr><tr style="height: 29.4583px;"><td style="width: 15.3693%; height: 29.4583px;">`cuentaPuc`</td><td style="width: 8.93122%; height: 29.4583px;">Texto</td><td style="width: 75.6597%; height: 29.4583px;">Código de la cuenta contable (PUC) asociada a la forma de pago.</td></tr><tr style="height: 29.4583px;"><td style="width: 15.3693%; height: 29.4583px;">`codigoDian`</td><td style="width: 8.93122%; height: 29.4583px;">Texto</td><td style="width: 75.6597%; height: 29.4583px;">Código del medio de pago según la clasificación DIAN.</td></tr><tr style="height: 29.4583px;"><td style="width: 15.3693%; height: 29.4583px;">`medioPago`</td><td style="width: 8.93122%; height: 29.4583px;">Texto</td><td style="width: 75.6597%; height: 29.4583px;">Nombre del medio de pago según la clasificación DIAN.</td></tr></tbody></table>

</div>##### Filtros Aplicados

El objeto `filters_applied` contiene los filtros que fueron utilizados en la consulta. Solo se incluye en la respuesta cuando se aplican filtros. Las posibles claves son:

<div class="markdown-body" dir="auto" id="bkmrk-clave-tipo-descripci-2"><table id="bkmrk-clave-tipo-descripci-3"><thead><tr><th>**Clave**</th><th>**Tipo**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>`codigo_dian`</td><td>Texto</td><td>Código DIAN del medio de pago utilizado como filtro.</td></tr><tr><td>`cuenta_puc`</td><td>Texto</td><td>Código de cuenta PUC utilizado como filtro (búsqueda por prefijo).</td></tr></tbody></table>

</div>#### **Respuesta con Filtros Aplicados**

```json
{
    "success": true,
    "status": 200,
    "message": null,
    "body": [
        {
            "formaPagoId": 1,
            "nombre": "Consignación Bancolombia",
            "cuentaPuc": "11100501",
            "codigoDian": "42",
            "medioPago": "Consignación bancaria"
        }
    ],
    "filters_applied": {
        "codigo_dian": "42"
    }
}
```

#### **Respuesta Sin Resultados**

```json
{
    "success": true,
    "status": 200,
    "message": "No se encontraron formas de pago con los criterios especificados.",
    "body": [],
    "filters_applied": {
        "codigo_dian": "99"
    }
}
```

#### **Respuesta de Error**

##### Error Interno (500)

Se retorna cuando ocurre un error inesperado en el servidor.

```json
{
    "success": false,
    "status": 500,
    "message": "Error interno del servidor al obtener las formas de pago.",
    "body": null,
    "filters_applied": null
}
```

#### **Códigos de Respuesta HTTP**

<div class="markdown-body" dir="auto" id="bkmrk-c%C3%B3digo-descripci%C3%B3n-2"><table id="bkmrk-c%C3%B3digo-descripci%C3%B3n-2-1" style="width: 100%;"><thead><tr><th style="width: 10.363%;">**Código**</th><th style="width: 89.7164%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 10.363%;">200</td><td style="width: 89.7164%;">Consulta exitosa. El cuerpo de la respuesta contiene las formas de pago (puede ser un array vacío si no hay resultados).</td></tr><tr><td style="width: 10.363%;">500</td><td style="width: 89.7164%;">Error interno del servidor.</td></tr></tbody></table>

</div>#### **Códigos DIAN de Medios de Pago**

Referencia de códigos DIAN comunes para medios de pago:

<table id="bkmrk-c%C3%B3digo-medio-de-pag"><thead><tr><th>Código</th><th>Medio de Pago</th></tr></thead><tbody><tr><td>10</td><td>Efectivo</td></tr><tr><td>31</td><td>Transferencia Débito</td></tr><tr><td>42</td><td>Consignación bancaria</td></tr><tr><td>47</td><td>Transferencia Débito Bancaria</td></tr><tr><td>48</td><td>Tarjeta Crédito</td></tr><tr><td>49</td><td>Tarjeta Débito</td></tr></tbody></table>

Para consultar el listado completo de códigos de medios de pago, visite la [Documentación Técnica de Factura Electrónica - DIAN](https://www.dian.gov.co/impuestos/factura-electronica/documentacion/Paginas/documentacion-tecnica.aspx).

#### **Notas Importantes**

<div class="markdown-body" dir="auto" id="bkmrk-solo-formas-de-pago-">1. **Solo formas de pago configuradas:** Este endpoint solo retorna las formas de pago que tengan una cuenta contable (PUC) asociada. Las formas de pago sin cuenta contable no aparecerán en los resultados.
2. **Uso con registro de pagos:** El `formaPagoId` retornado puede usarse como valor del parámetro `forma_pago_id` en el endpoint [Registrar Pago de Factura](https://docs.nuby.ai/books/api-nuby-v2/page/registrar-pago-de-factura-beta "Registrar Pago de Factura").
3. **Búsqueda por cuenta PUC:** El filtro `cuenta_puc` realiza una búsqueda por prefijo, lo que permite filtrar por grupos de cuentas (ej: `1110` retorna todas las cuentas PUC que inicien con ese código).

</div>#### **Ejemplos**

<div class="markdown-body" dir="auto" id="bkmrk-curl-curl--x-get-%22ht"><details id="bkmrk-curl-curl--x-get-%22h"><summary>Curl</summary>

```bash
curl -X GET "https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AUTHENTICATION_TOKEN"
```

**Con filtros:**

```bash
curl -X GET "https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/payment-methods?codigo_dian=42" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AUTHENTICATION_TOKEN"
```

</details><details id="bkmrk-php-curl-%3C%3Fphp-%24inst"><summary>PHP Curl</summary>

```php
<?php

$instance = 'your_instance'; // Reemplace con su instancia actual
$token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido desde el servicio de login

// Parámetros de filtro opcionales
$codigoDian = '42'; // Opcional: filtrar por código DIAN
$cuentaPuc = null;  // Opcional: filtrar por cuenta PUC

$url = "https://{$instance}.arrendasoft.co/service/v2/public/invoices/payment-methods";

// Agregar parámetros de filtro si existen
$queryParams = [];
if (!empty($codigoDian)) {
    $queryParams['codigo_dian'] = $codigoDian;
}
if (!empty($cuentaPuc)) {
    $queryParams['cuenta_puc'] = $cuentaPuc;
}
if (!empty($queryParams)) {
    $url .= '?' . http_build_query($queryParams);
}

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "HTTP Status Code: " . $http_code . "\n";
    echo "Response: " . $response . "\n";
    
    // Procesar la respuesta
    $result = json_decode($response, true);
    
    if ($result['success'] && !empty($result['body'])) {
        echo "Se encontraron " . count($result['body']) . " formas de pago.\n\n";
        
        foreach ($result['body'] as $formaPago) {
            echo "ID: " . $formaPago['formaPagoId'] . "\n";
            echo "Nombre: " . $formaPago['nombre'] . "\n";
            echo "Cuenta PUC: " . $formaPago['cuentaPuc'] . "\n";
            echo "Código DIAN: " . $formaPago['codigoDian'] . "\n";
            echo "Medio de Pago: " . $formaPago['medioPago'] . "\n";
            echo "---\n";
        }
    } else {
        echo $result['message'] ?? "No se encontraron formas de pago.\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-javascript-fetch"><summary>JavaScript Fetch</summary>

```javascript
const instance = 'your_instance'; // Reemplace con su instancia actual
const token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido

// Parámetros de filtro opcionales
const params = new URLSearchParams();
// params.append('codigo_dian', '42'); // Opcional: descomentar para filtrar
// params.append('cuenta_puc', '1110'); // Opcional: descomentar para filtrar

const url = `https://${instance}.arrendasoft.co/service/v2/public/invoices/payment-methods${params.toString() ? '?' + params.toString() : ''}`;

fetch(url, {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
    }
})
.then(response => response.json())
.then(data => {
    if (data.success && data.body.length > 0) {
        console.log(`Se encontraron ${data.body.length} formas de pago:`);
        data.body.forEach(formaPago => {
            console.log(`- ${formaPago.nombre} (ID: ${formaPago.formaPagoId})`);
            console.log(`  Cuenta PUC: ${formaPago.cuentaPuc}`);
            console.log(`  Medio DIAN: ${formaPago.medioPago} (${formaPago.codigoDian})`);
        });
    } else {
        console.log(data.message || 'No se encontraron formas de pago.');
    }
})
.catch(error => console.error('Error de conexión:', error));
```

</details><div class="code-line" data-line="277">  
</div></div>

# Listar Resoluciones [BETA]

<p class="callout info">**Funcionalidad en pruebas**  
Esta funcionalidad forma parte de un proceso de pruebas internas y no se encuentra disponible para usuarios del sistema.</p>

Permite obtener el listado de resoluciones de facturación configuradas en la inmobiliaria. Retorna tanto las resoluciones de facturación como las de documento soporte, con soporte para paginación y múltiples filtros.

**Endpoint:** https://<span style="color: rgb(241, 196, 15);">***{{instancia}}***</span>.arrendasoft.co/service/v2/public/invoices/resolutions

**<span style="color: rgb(241, 196, 15);">{{instancia}}</span>:** Hace referencia a la instancia de cada inmobiliaria.

#### **Petición**

<div class="markdown-body" dir="auto" id="bkmrk-m%C3%A9todo-get-content-t"><table border="1" style="width: 100%;"><colgroup><col style="width: 39.4436%;"></col><col style="width: 60.5167%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login)</td></tr></tbody></table>

<table border="1" style="width: 100%;"><colgroup><col style="width: 16%;"></col><col style="width: 8%;"></col><col style="width: 11%;"></col><col style="width: 13%;"></col><col style="width: 52%;"></col></colgroup><tbody><tr><td class="align-center" colspan="5">**Parámetros**</td></tr><tr><td class="align-center">**Parámetro**</td><td class="align-center">**Tipo**</td><td class="align-center">**Obligatorio**</td><td class="align-center">**Valor por defecto**</td><td class="align-center">**Descripción**</td></tr><tr><td>page</td><td>integer</td><td class="align-center">No</td><td class="align-center">1</td><td>Especifica la página de resultados que se desea recuperar al realizar la solicitud.</td></tr><tr><td>page\_size</td><td>integer</td><td class="align-center">No</td><td class="align-center">10</td><td>Especifica el número máximo de elementos que se deben devolver en la solicitud, el límite máximo es de 1000.</td></tr><tr><td>activa</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Filtra resoluciones por estado activo. Valores válidos: `SI` (activas) o `NO` (inactivas).</td></tr><tr><td>tipo\_doc\_id</td><td>integer</td><td class="align-center">No</td><td class="align-center">-</td><td>Filtra resoluciones por el ID del tipo de documento contable asociado.</td></tr><tr><td>fact\_electronica</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Filtra resoluciones por facturación electrónica. Valores válidos: `SI` o `NO`.</td></tr><tr><td>resolucion\_para</td><td>integer</td><td class="align-center">No</td><td class="align-center">-</td><td>Filtra resoluciones por tipo. Valores válidos: `1` (Factura de Venta) o `2` (Documento Soporte). Si no se especifica, retorna ambos tipos.</td></tr><tr><td>fecha\_desde</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Fecha mínima de la resolución. Formato: `YYYY-MM-DD` (ej: `2025-01-01`).</td></tr><tr><td>fecha\_hasta</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Fecha máxima de la resolución. Formato: `YYYY-MM-DD` (ej: `2026-12-31`).</td></tr><tr><td>fecha\_vigencia\_desde</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Fecha mínima de vigencia de la resolución. Formato: `YYYY-MM-DD`.</td></tr><tr><td>fecha\_vigencia\_hasta</td><td>string</td><td class="align-center">No</td><td class="align-center">-</td><td>Fecha máxima de vigencia de la resolución. Formato: `YYYY-MM-DD`.</td></tr></tbody></table>

</div>**Ejemplos de peticiones**

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?page=1&page_size=50
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?activa=SI
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?resolucion_para=1
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?resolucion_para=2&activa=SI
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?fact_electronica=SI&page_size=100
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?fecha_desde=2024-01-01&fecha_hasta=2026-12-31
```

```
https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?resolucion_para=1&activa=SI&fact_electronica=SI&page_size=50
```

#### **Respuesta**

Lista de resoluciones de facturación con información del tipo de documento asociado, datos de consecutivos, fechas, estado y metadatos de paginación.

```json
{
    "status": 200,
    "message": null,
    "body": [
        {
            "resolucion_id": 4,
            "tipo_doc_id": 7,
            "tipo_doc": "Factura",
            "resolucion_numero": "18700052960",
            "consecutivo_iniciar": 1,
            "consecutivo_inicial": 1,
            "consecutivo_final": 20000,
            "fecha": "2025-07-24",
            "fecha_vigencia": "2026-07-24",
            "prefijo": "FE",
            "dias_vencimiento": 5,
            "activa": "SI",
            "codigo_barra": "NO",
            "codigo_ean": null,
            "tipo_resolucion": null,
            "creadopor": 5,
            "fechacreacion": "2025-07-24 12:00:01",
            "modificadopor": null,
            "fechamodificacion": null,
            "fact_electronica": "SI",
            "resolucion_para": 1
        },
        {
            "resolucion_id": 2,
            "tipo_doc_id": 39,
            "tipo_doc": "Documento Soporte",
            "resolucion_numero": "18760000012",
            "consecutivo_iniciar": 1,
            "consecutivo_inicial": 1,
            "consecutivo_final": 1000000,
            "fecha": "2022-09-01",
            "fecha_vigencia": "2024-05-31",
            "prefijo": "DS",
            "dias_vencimiento": 5,
            "activa": "SI",
            "codigo_barra": "NO",
            "codigo_ean": null,
            "tipo_resolucion": null,
            "creadopor": 5,
            "fechacreacion": "2024-05-02 15:01:48",
            "modificadopor": 5,
            "fechamodificacion": "2024-05-06 15:05:23",
            "fact_electronica": "SI",
            "resolucion_para": 2
        }
    ],
    "pagination": {
        "total_records": 4,
        "total_pages": 2,
        "current_page": 1,
        "page_size": 2,
        "current_page_records": 2,
        "has_next_page": true,
        "has_previous_page": false
    },
    "filters_applied": null
}
```

##### Claves y Descripciones del JSON de Respuesta

Esta tabla enumera las claves presentes en el JSON principal de la respuesta y proporciona una breve descripción de cada una.

<table id="bkmrk-clave-tipo-descripci" style="width: 100%;"><thead><tr><th style="width: 16%;">**Clave**</th><th style="width: 8%;">**Tipo**</th><th style="width: 76%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 16%;">`status`</td><td style="width: 8%;">Entero</td><td style="width: 76%;">Código del estado de la respuesta: 200 para exitoso, 400 para errores de validación, 500 para error interno.</td></tr><tr><td style="width: 16%;">`message`</td><td style="width: 8%;">Texto</td><td style="width: 76%;">Cuando la respuesta es exitosa, es nulo, y cuando hay error o no se encontraron resultados, contiene el mensaje descriptivo.</td></tr><tr><td style="width: 16%;">`body`</td><td style="width: 8%;">Array</td><td style="width: 76%;">Contiene el listado de resoluciones retornadas por la API. Es un array vacío si no hay resultados.</td></tr><tr><td style="width: 16%;">`pagination`</td><td style="width: 8%;">Objeto</td><td style="width: 76%;">Contiene toda la información de paginación de la consulta.</td></tr><tr><td style="width: 16%;">`filters_applied`</td><td style="width: 8%;">Objeto</td><td style="width: 76%;">Contiene los filtros que fueron aplicados en la consulta. Es nulo si no se aplicaron filtros.</td></tr></tbody></table>

##### Cuerpo

Cada elemento dentro de la lista `body` tiene las siguientes claves:

<table id="bkmrk-clave-tipo-descripci-1" style="width: 100%;"><thead><tr><th style="width: 18%;">**Clave**</th><th style="width: 10%;">**Tipo**</th><th style="width: 72%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 18%;">`resolucion_id`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Identificador único de la resolución. Use este valor para el parámetro `resolucion_id` al filtrar facturas en el endpoint [Listar Facturas](https://docs.nuby.ai/books/api-nuby-v2/page/listar-facturas "Listar Facturas").</td></tr><tr><td style="width: 18%;">`tipo_doc_id`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Identificador del tipo de documento contable asociado a la resolución. Puede ser nulo.</td></tr><tr><td style="width: 18%;">`tipo_doc`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Nombre del tipo de documento contable (ej: "Factura", "Documento Soporte"). Puede ser nulo si no tiene tipo de documento asociado.</td></tr><tr><td style="width: 18%;">`resolucion_numero`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Número de la resolución asignado por la DIAN.</td></tr><tr><td style="width: 18%;">`consecutivo_iniciar`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Consecutivo a partir del cual se empezará a facturar. Debe estar entre el consecutivo inicial y final.</td></tr><tr><td style="width: 18%;">`consecutivo_inicial`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Consecutivo inicial autorizado por la DIAN.</td></tr><tr><td style="width: 18%;">`consecutivo_final`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Consecutivo final autorizado por la DIAN.</td></tr><tr><td style="width: 18%;">`fecha`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Fecha de expedición de la resolución. Formato: `YYYY-MM-DD`.</td></tr><tr><td style="width: 18%;">`fecha_vigencia`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Fecha de vigencia (vencimiento) de la resolución. Formato: `YYYY-MM-DD`.</td></tr><tr><td style="width: 18%;">`prefijo`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Prefijo asignado a la resolución (ej: "FE", "DS", "PR").</td></tr><tr><td style="width: 18%;">`dias_vencimiento`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Días de vencimiento configurados para las facturas generadas con esta resolución.</td></tr><tr><td style="width: 18%;">`activa`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Estado de la resolución: `SI` (activa) o `NO` (inactiva).</td></tr><tr><td style="width: 18%;">`codigo_barra`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Indica si la resolución tiene código de barras habilitado: `SI` o `NO`.</td></tr><tr><td style="width: 18%;">`codigo_ean`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Código EAN asociado a la resolución. Puede ser nulo si no se ha configurado.</td></tr><tr><td style="width: 18%;">`tipo_resolucion`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Tipo interno de la resolución. Puede ser nulo.</td></tr><tr><td style="width: 18%;">`creadopor`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Identificador del usuario que creó la resolución. Puede ser nulo.</td></tr><tr><td style="width: 18%;">`fechacreacion`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Fecha y hora de creación de la resolución. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td style="width: 18%;">`modificadopor`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Identificador del usuario que modificó la resolución por última vez. Puede ser nulo.</td></tr><tr><td style="width: 18%;">`fechamodificacion`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Fecha y hora de la última modificación de la resolución. Puede ser nulo. Formato: `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td style="width: 18%;">`fact_electronica`</td><td style="width: 10%;">Texto</td><td style="width: 72%;">Indica si la resolución es de facturación electrónica: `SI` o `NO`.</td></tr><tr><td style="width: 18%;">`resolucion_para`</td><td style="width: 10%;">Entero</td><td style="width: 72%;">Tipo de resolución: `1` = Factura de Venta, `2` = Documento Soporte (no obligados a facturar).</td></tr></tbody></table>

##### Paginación

El objeto `pagination` tiene las siguientes claves:

<table id="bkmrk-clave-tipo-descripci-2" style="width: 100%;"><thead><tr><th style="width: 21%;">**Clave**</th><th style="width: 11%;">**Tipo**</th><th style="width: 68%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 21%;">`total_records`</td><td style="width: 11%;">Numérico</td><td style="width: 68%;">Total de resoluciones que coinciden con los filtros aplicados.</td></tr><tr><td style="width: 21%;">`total_pages`</td><td style="width: 11%;">Numérico</td><td style="width: 68%;">Cantidad de páginas, corresponde al total de registros dividido por el tamaño de la página.</td></tr><tr><td style="width: 21%;">`current_page`</td><td style="width: 11%;">Numérico</td><td style="width: 68%;">Página actual de la consulta.</td></tr><tr><td style="width: 21%;">`page_size`</td><td style="width: 11%;">Numérico</td><td style="width: 68%;">Tamaño de la página, es decir, cantidad máxima de registros por consulta.</td></tr><tr><td style="width: 21%;">`current_page_records`</td><td style="width: 11%;">Numérico</td><td style="width: 68%;">Cantidad de registros retornados en la página actual.</td></tr><tr><td style="width: 21%;">`has_next_page`</td><td style="width: 11%;">Booleano</td><td style="width: 68%;">Verdadero si hay siguientes páginas que se pueden consultar, falso en otro caso.</td></tr><tr><td style="width: 21%;">`has_previous_page`</td><td style="width: 11%;">Booleano</td><td style="width: 68%;">Verdadero si existen páginas previas que se pueden consultar, falso en otro caso.</td></tr></tbody></table>

##### Filtros Aplicados

El objeto `filters_applied` contiene los filtros que fueron utilizados en la consulta. Solo se incluye en la respuesta cuando se aplican filtros. Las posibles claves son:

<div class="markdown-body" dir="auto" id="bkmrk-clave-tipo-descripci-3"><table><thead><tr><th>**Clave**</th><th>**Tipo**</th><th>**Descripción**</th></tr></thead><tbody><tr><td>`activa`</td><td>Texto</td><td>Estado activo utilizado como filtro: `SI` o `NO`.</td></tr><tr><td>`tipo_doc_id`</td><td>Entero</td><td>ID del tipo de documento contable utilizado como filtro.</td></tr><tr><td>`fact_electronica`</td><td>Texto</td><td>Filtro de facturación electrónica utilizado: `SI` o `NO`.</td></tr><tr><td>`resolucion_para`</td><td>Entero</td><td>Tipo de resolución utilizado como filtro: `1` (Factura) o `2` (Documento Soporte).</td></tr><tr><td>`fecha_desde`</td><td>Texto</td><td>Fecha mínima de resolución utilizada como filtro.</td></tr><tr><td>`fecha_hasta`</td><td>Texto</td><td>Fecha máxima de resolución utilizada como filtro.</td></tr><tr><td>`fecha_vigencia_desde`</td><td>Texto</td><td>Fecha mínima de vigencia utilizada como filtro.</td></tr><tr><td>`fecha_vigencia_hasta`</td><td>Texto</td><td>Fecha máxima de vigencia utilizada como filtro.</td></tr></tbody></table>

</div>#### **Respuesta con Filtros Aplicados**

```json
{
    "status": 200,
    "message": null,
    "body": [
        {
            "resolucion_id": 4,
            "tipo_doc_id": 7,
            "tipo_doc": "Factura",
            "resolucion_numero": "18700052960",
            "consecutivo_iniciar": 1,
            "consecutivo_inicial": 1,
            "consecutivo_final": 20000,
            "fecha": "2025-07-24",
            "fecha_vigencia": "2026-07-24",
            "prefijo": "FE",
            "dias_vencimiento": 5,
            "activa": "SI",
            "codigo_barra": "NO",
            "codigo_ean": null,
            "tipo_resolucion": null,
            "creadopor": 5,
            "fechacreacion": "2025-07-24 12:00:01",
            "modificadopor": null,
            "fechamodificacion": null,
            "fact_electronica": "SI",
            "resolucion_para": 1
        }
    ],
    "pagination": {
        "total_records": 3,
        "total_pages": 1,
        "current_page": 1,
        "page_size": 10,
        "current_page_records": 3,
        "has_next_page": false,
        "has_previous_page": false
    },
    "filters_applied": {
        "resolucion_para": 1,
        "activa": "SI"
    }
}
```

#### **Respuesta Sin Resultados**

```json
{
    "status": 200,
    "message": "No se encontraron resoluciones con los criterios especificados.",
    "body": [],
    "pagination": {
        "total_records": 0,
        "total_pages": 0,
        "current_page": 1,
        "page_size": 10,
        "current_page_records": 0,
        "has_next_page": false,
        "has_previous_page": false
    },
    "filters_applied": {
        "activa": "NO"
    }
}
```

#### **Respuesta de Error**

##### Error de Validación (400)

Se retorna cuando se envía un parámetro con un valor no válido.

```json
{
    "status": 400,
    "message": "El parámetro \"activa\" debe ser \"SI\" o \"NO\".",
    "body": null,
    "pagination": null,
    "filters_applied": null
}
```

```json
{
    "status": 400,
    "message": "El parámetro \"resolucion_para\" debe ser 1 (Factura) o 2 (Documento Soporte).",
    "body": null,
    "pagination": null,
    "filters_applied": null
}
```

```json
{
    "status": 400,
    "message": "El parámetro \"fecha_desde\" debe tener el formato Y-m-d (ej: 2026-01-15).",
    "body": null,
    "pagination": null,
    "filters_applied": null
}
```

##### Error Interno (500)

Se retorna cuando ocurre un error inesperado en el servidor.

```json
{
    "status": 500,
    "message": "Error interno del servidor al obtener las resoluciones.",
    "body": null,
    "pagination": null,
    "filters_applied": null
}
```

#### **Códigos de Respuesta HTTP**

<div class="markdown-body" dir="auto" id="bkmrk-c%C3%B3digo-descripci%C3%B3n-2"><table style="width: 100%;"><thead><tr><th style="width: 10%;">**Código**</th><th style="width: 90%;">**Descripción**</th></tr></thead><tbody><tr><td style="width: 10%;">200</td><td style="width: 90%;">Consulta exitosa. El cuerpo de la respuesta contiene las resoluciones (puede ser un array vacío si no hay resultados).</td></tr><tr><td style="width: 10%;">400</td><td style="width: 90%;">Error de validación. Algún parámetro tiene un valor no válido. El campo `message` indica el parámetro y los valores aceptados.</td></tr><tr><td style="width: 10%;">500</td><td style="width: 90%;">Error interno del servidor.</td></tr></tbody></table>

</div>#### **Valores de Referencia**

##### Valores de resolucion\_para

<table id="bkmrk-valor-descripci%C3%B3n-1-"><thead><tr><th>Valor</th><th>Descripción</th></tr></thead><tbody><tr><td>1</td><td>Factura de Venta — Resoluciones utilizadas para la emisión de facturas de venta</td></tr><tr><td>2</td><td>Documento Soporte — Resoluciones utilizadas para documento soporte de no obligados a facturar</td></tr></tbody></table>

##### Valores de activa

<table id="bkmrk-valor-descripci%C3%B3n-si"><thead><tr><th>Valor</th><th>Descripción</th></tr></thead><tbody><tr><td>SI</td><td>La resolución está activa y disponible para facturación</td></tr><tr><td>NO</td><td>La resolución está inactiva y no se puede usar para facturar</td></tr></tbody></table>

#### **Notas Importantes**

<div class="markdown-body" dir="auto" id="bkmrk-relaci%C3%B3n-con-factura">1. **Relación con facturas:** El `resolucion_id` retornado puede usarse como valor del parámetro `resolucion_id` en el endpoint [Listar Facturas](https://docs.nuby.ai/books/api-nuby-v2/page/listar-facturas "Listar Facturas") para filtrar facturas que pertenecen a una resolución específica.
2. **Tipo de resolución:** El campo `resolucion_para` diferencia las resoluciones de facturación (`1`) de las de documento soporte (`2`). En el sistema, las resoluciones de facturación se configuran en *Configuraciones &gt; Facturación* y las de documento soporte en *Configuraciones &gt; Facturas de Compra*.
3. **Filtros de fecha:** Los filtros `fecha_desde` / `fecha_hasta` aplican sobre la fecha de expedición de la resolución, mientras que `fecha_vigencia_desde` / `fecha_vigencia_hasta` aplican sobre la fecha de vigencia. Ambos rangos pueden combinarse en una misma consulta.
4. **Ordenamiento:** Las resoluciones se retornan ordenadas por `resolucion_id` de forma descendente (las más recientes primero).

</div>#### **Ejemplos**

<div class="markdown-body" dir="auto" id="bkmrk-curl-curl--x-get-%22ht"><details><summary>Curl</summary>

```bash
curl -X GET "https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AUTHENTICATION_TOKEN"
```

**Con filtros:**

```bash
curl -X GET "https://{{instancia}}.arrendasoft.co/service/v2/public/invoices/resolutions?resolucion_para=1&activa=SI&page_size=50" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AUTHENTICATION_TOKEN"
```

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

```php
<?php

$instance = 'your_instance'; // Reemplace con su instancia actual
$token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido desde el servicio de login

// Parámetros de ejemplo
$page = 1;
$pageSize = 50;

// Parámetros de filtro opcionales
$resolucionPara = 1;    // Opcional: 1 = Factura, 2 = Documento Soporte
$activa = 'SI';          // Opcional: 'SI' o 'NO'
$factElectronica = null; // Opcional: 'SI' o 'NO'

$url = "https://{$instance}.arrendasoft.co/service/v2/public/invoices/resolutions";

// Construir parámetros de consulta
$queryParams = [
    'page' => $page,
    'page_size' => $pageSize
];
if (!empty($resolucionPara)) {
    $queryParams['resolucion_para'] = $resolucionPara;
}
if (!empty($activa)) {
    $queryParams['activa'] = $activa;
}
if (!empty($factElectronica)) {
    $queryParams['fact_electronica'] = $factElectronica;
}
$url .= '?' . http_build_query($queryParams);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $token
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "HTTP Status Code: " . $http_code . "\n";
    echo "Response: " . $response . "\n";

    // Procesar la respuesta
    $result = json_decode($response, true);

    if ($http_code == 200 && !empty($result['body'])) {
        echo "Se encontraron " . $result['pagination']['total_records'] . " resoluciones.\n\n";

        foreach ($result['body'] as $resolucion) {
            echo "ID: " . $resolucion['resolucion_id'] . "\n";
            echo "Número: " . $resolucion['resolucion_numero'] . "\n";
            echo "Prefijo: " . $resolucion['prefijo'] . "\n";
            echo "Tipo: " . $resolucion['tipo_doc'] . "\n";
            echo "Activa: " . $resolucion['activa'] . "\n";
            echo "Vigencia: " . $resolucion['fecha_vigencia'] . "\n";
            echo "---\n";
        }
    } else {
        echo $result['message'] ?? "No se encontraron resoluciones.\n";
    }
}
curl_close($ch);

?>
```

</details><details><summary>JavaScript Fetch</summary>

```javascript
const instance = 'your_instance'; // Reemplace con su instancia actual
const token = 'YOUR_AUTHENTICATION_TOKEN'; // Reemplace con el token obtenido

// Parámetros de filtro opcionales
const params = new URLSearchParams();
params.append('page', '1');
params.append('page_size', '50');
params.append('resolucion_para', '1'); // Opcional: 1 = Factura, 2 = Documento Soporte
params.append('activa', 'SI');          // Opcional: 'SI' o 'NO'
// params.append('fact_electronica', 'SI'); // Opcional: descomentar para filtrar

const url = `https://${instance}.arrendasoft.co/service/v2/public/invoices/resolutions?${params.toString()}`;

fetch(url, {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
    }
})
.then(response => response.json())
.then(data => {
    if (data.status === 200 && data.body.length > 0) {
        console.log(`Se encontraron ${data.pagination.total_records} resoluciones:`);
        data.body.forEach(res => {
            console.log(`- ${res.prefijo} ${res.resolucion_numero} (ID: ${res.resolucion_id})`);
            console.log(`  Tipo: ${res.tipo_doc} | Activa: ${res.activa}`);
            console.log(`  Consecutivos: ${res.consecutivo_inicial} - ${res.consecutivo_final}`);
            console.log(`  Vigencia: ${res.fecha} a ${res.fecha_vigencia}`);
        });

        // Información de paginación
        console.log(`\nPágina ${data.pagination.current_page} de ${data.pagination.total_pages}`);
    } else {
        console.log(data.message || 'No se encontraron resoluciones.');
    }
})
.catch(error => console.error('Error de conexión:', error));
```

</details><div>  
</div></div>

# Contabilidad

<span>Bienvenido al </span>**libro contable digital**<span> de tu inmobiliaria. En este apartado centralizamos las herramientas de conexión para que tus plataformas externas consulten y sincronicen tu información financiera de forma automática.</span>

**¿Para qué sirve este módulo?**<span> El objetivo principal es eliminar los procesos manuales en la extracción de datos financieros. En lugar de descargar informes a mano, tus sistemas podrán consultar directamente el historial y los movimientos de tus cuentas contables. Podrás utilizar filtros estratégicos —como rangos de fechas o grupos de cuentas— para extraer exactamente la información que necesitas sin sobrecargar tus integraciones.</span>

Explora el listado a continuación para descubrir cómo alimentar tus tableros de análisis y mantener tus números perfectamente organizados, auditables y sincronizados.

# Reporte Auxiliar General

Permite obtener el reporte contable **Auxiliar General**, que presenta los movimientos detallados de cada cuenta del Plan Único de Cuentas (PUC) dentro de un período y rango de cuentas. Cada elemento incluye el saldo anterior, débitos, créditos, saldo actual, base de retención, y el desglose por tercero con sus respectivos documentos contables.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para alimentar reportes contables en tu ERP, conciliar saldos con sistemas externos, generar informes de auditoría, exportar movimientos detallados a Excel o Power BI, o validar la contabilidad de un período específico.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/accounting/general-ledger
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Envía los encabezados requeridos y opcionalmente los parámetros de filtro en la URL:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

**Parámetros de consulta (query string):**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 14%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 20%;"></col><col style="width: 46%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Por defecto</th><th>Descripción</th></tr></thead><tbody><tr><td>`fecha_ini`</td><td>string</td><td>No</td><td>Primer día del año en curso</td><td>Fecha inicial del rango a consultar. Formato: `YYYY-MM-DD`.</td></tr><tr><td>`fecha_fin`</td><td>string</td><td>No</td><td>Último día del mes en curso</td><td>Fecha final del rango a consultar. Formato: `YYYY-MM-DD`. Debe ser mayor o igual a `fecha_ini`.</td></tr><tr><td>`cuenta_ini`</td><td>string</td><td>No</td><td>1</td><td>Código inicial de cuenta PUC. Solo permite valores numéricos. Debe ser mayor o igual a `1`.</td></tr><tr><td>`cuenta_fin`</td><td>string</td><td>No</td><td>9</td><td>Código final de cuenta PUC. Solo permite valores numéricos. Debe ser mayor o igual a `cuenta_ini`.</td></tr></tbody></table>

**Ejemplos de petición:**

```http
GET https://mi-inmobiliaria.nuby.app/service/v2/public/accounting/general-ledger
GET https://mi-inmobiliaria.nuby.app/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01
GET https://mi-inmobiliaria.nuby.app/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01&fecha_fin=2025-06-30
GET https://mi-inmobiliaria.nuby.app/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01&fecha_fin=2025-06-30&cuenta_ini=1
GET https://mi-inmobiliaria.nuby.app/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01&fecha_fin=2025-06-30&cuenta_ini=1&cuenta_fin=4
```

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

Si tu Token es válido y los parámetros son correctos, el sistema te devolverá un objeto JSON con el listado de cuentas contables, sus terceros y los movimientos detallados de cada uno. La respuesta tiene una estructura jerárquica de tres niveles: **Cuenta → Tercero → Detalle**.

```json
{
    "error": false,
    "message": "",
    "body": [
        {
            "cuenta": "11050501",
            "nombre_cuenta": "Caja general moneda nacional",
            "saldo_anterior": 8750320.45,
            "debitos": 12480000,
            "creditos": 9230000,
            "saldo_actual": 12000320.45,
            "base_retencion": 0,
            "terceros": {
                "42": {
                    "documento_tercero": "80213654",
                    "nombre_tercero": "CARLOS EDUARDO PINEDA VARGAS",
                    "saldo_anterior": 3250120.45,
                    "debitos": 7500000,
                    "creditos": 4230000,
                    "saldo_actual": 6520120.45,
                    "base_retencion": 0,
                    "detalles": [
                        {
                            "fecha_documento": "2025-02-05",
                            "consecutivo_documento": "RC-10450",
                            "detalle_documento": "Pago canon arrendamiento febrero Apto 501",
                            "debitos": 2850000,
                            "creditos": 0,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-03-03",
                            "consecutivo_documento": "RC-10512",
                            "detalle_documento": "Pago canon arrendamiento marzo Apto 501",
                            "debitos": 2850000,
                            "creditos": 0,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-03-15",
                            "consecutivo_documento": "EG-4021",
                            "detalle_documento": "Consignación propietario marzo",
                            "debitos": 0,
                            "creditos": 4230000,
                            "base_retencion": 0
                        }
                    ]
                },
                "73": {
                    "documento_tercero": "1098745231",
                    "nombre_tercero": "JULIANA PATRICIA RÍOS MENDOZA",
                    "saldo_anterior": 1500200,
                    "debitos": 4980000,
                    "creditos": 5000000,
                    "saldo_actual": 1480200,
                    "base_retencion": 0,
                    "detalles": [
                        {
                            "fecha_documento": "2025-01-10",
                            "consecutivo_documento": "RC-10389",
                            "detalle_documento": "Pago canon arrendamiento enero Local 3",
                            "debitos": 4500000,
                            "creditos": 0,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-01-20",
                            "consecutivo_documento": "EG-3998",
                            "detalle_documento": "Consignación propietario enero",
                            "debitos": 0,
                            "creditos": 5000000,
                            "base_retencion": 0
                        }
                    ]
                }
            }
        },
        {
            "cuenta": "13050501",
            "nombre_cuenta": "Arrendamientos por cobrar",
            "saldo_anterior": 15400000,
            "debitos": 9350000,
            "creditos": 12480000,
            "saldo_actual": 12270000,
            "base_retencion": 0,
            "terceros": {
                "55": {
                    "documento_tercero": "43876123",
                    "nombre_tercero": "DIANA MARCELA OSPINA VELÁSQUEZ",
                    "saldo_anterior": 2400000,
                    "debitos": 3600000,
                    "creditos": 4800000,
                    "saldo_actual": 1200000,
                    "base_retencion": 0,
                    "detalles": [
                        {
                            "fecha_documento": "2025-01-01",
                            "consecutivo_documento": "FV-8901",
                            "detalle_documento": "Factura arrendamiento enero Cll 23 # 56 - 78",
                            "debitos": 1200000,
                            "creditos": 0,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-01-15",
                            "consecutivo_documento": "RC-10401",
                            "detalle_documento": "Recibo de caja pago enero",
                            "debitos": 0,
                            "creditos": 1200000,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-02-01",
                            "consecutivo_documento": "FV-8950",
                            "detalle_documento": "Factura arrendamiento febrero Cll 23 # 56 - 78",
                            "debitos": 1200000,
                            "creditos": 0,
                            "base_retencion": 0
                        },
                        {
                            "fecha_documento": "2025-02-10",
                            "consecutivo_documento": "RC-10465",
                            "detalle_documento": "Recibo de caja pago febrero",
                            "debitos": 0,
                            "creditos": 1200000,
                            "base_retencion": 0
                        }
                    ]
                }
            }
        },
        {
            "cuenta": "24080501",
            "nombre_cuenta": "Retención en la fuente arrendamientos 3.5%",
            "saldo_anterior": -875000,
            "debitos": 0,
            "creditos": 249375,
            "saldo_actual": -1124375,
            "base_retencion": 7125000,
            "terceros": {
                "65": {
                    "documento_tercero": "900456789",
                    "nombre_tercero": "INVERSIONES HORIZONTE S.A.S.",
                    "saldo_anterior": -875000,
                    "debitos": 0,
                    "creditos": 249375,
                    "saldo_actual": -1124375,
                    "base_retencion": 7125000,
                    "detalles": [
                        {
                            "fecha_documento": "2025-01-31",
                            "consecutivo_documento": "EG-3985",
                            "detalle_documento": "Retención arrendamiento enero Local 3",
                            "debitos": 0,
                            "creditos": 157500,
                            "base_retencion": 4500000
                        },
                        {
                            "fecha_documento": "2025-02-28",
                            "consecutivo_documento": "EG-4050",
                            "detalle_documento": "Retención arrendamiento febrero Local 3",
                            "debitos": 0,
                            "creditos": 91875,
                            "base_retencion": 2625000
                        }
                    ]
                }
            }
        }
    ]
}
```

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

<table border="1" id="bkmrk-campo-tipo-descripci" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 16%;"></col><col style="width: 12%;"></col><col style="width: 72%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`error`</td><td>boolean</td><td>Estado de la respuesta. `false` para exitoso, `true` cuando ocurre un error.</td></tr><tr><td>`message`</td><td>string</td><td>Cadena vacía cuando la respuesta es exitosa. Si no hay resultados, contiene un mensaje informativo. Si hay error, describe el problema presentado.</td></tr><tr><td>`body`</td><td>array | null</td><td>Listado de cuentas contables con sus movimientos. `null` cuando no hay resultados o hay un error.</td></tr></tbody></table>

##### **Campos de cada cuenta (body)**

Cada elemento dentro del arreglo `body` representa una cuenta contable y contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 12%;"></col><col style="width: 68%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`cuenta`</td><td>string</td><td>Código numérico de la cuenta en el Plan Único de Cuentas (PUC).</td></tr><tr><td>`nombre_cuenta`</td><td>string</td><td>Nombre descriptivo de la cuenta PUC.</td></tr><tr><td>`saldo_anterior`</td><td>number</td><td>Saldo acumulado de la cuenta antes de la fecha inicial del rango consultado. Puede ser negativo.</td></tr><tr><td>`debitos`</td><td>number</td><td>Suma total de los débitos de la cuenta en el período consultado.</td></tr><tr><td>`creditos`</td><td>number</td><td>Suma total de los créditos de la cuenta en el período consultado.</td></tr><tr><td>`saldo_actual`</td><td>number</td><td>Saldo resultante de la cuenta al final del período. El cálculo varía según la clase de cuenta: para activos, gastos y costos (clases 1, 5 y 6) es `saldo_anterior + débitos - créditos`; para las demás clases es `saldo_anterior + créditos - débitos`. Puede ser negativo.</td></tr><tr><td>`base_retencion`</td><td>number</td><td>Valor acumulado de la base de retención de la cuenta en el período.</td></tr><tr><td>`terceros`</td><td>object</td><td>Objeto que contiene los terceros vinculados a la cuenta. Cada clave del objeto es el `tercero_id` del sistema (o `"sin_tercero"` si el movimiento no tiene tercero asociado).</td></tr></tbody></table>

##### **Campos de cada tercero (terceros)**

Cada entrada dentro del objeto `terceros` contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-2" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 12%;"></col><col style="width: 68%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`documento_tercero`</td><td>string</td><td>Número de documento de identidad del tercero. Si no tiene tercero asociado, muestra `"Sin tercero"`.</td></tr><tr><td>`nombre_tercero`</td><td>string</td><td>Nombre completo del tercero. Si no tiene tercero asociado, muestra `"Sin tercero"`.</td></tr><tr><td>`saldo_anterior`</td><td>number</td><td>Saldo acumulado del tercero en esta cuenta antes de la fecha inicial. Puede ser negativo.</td></tr><tr><td>`debitos`</td><td>number</td><td>Suma total de los débitos del tercero en esta cuenta durante el período.</td></tr><tr><td>`creditos`</td><td>number</td><td>Suma total de los créditos del tercero en esta cuenta durante el período.</td></tr><tr><td>`saldo_actual`</td><td>number</td><td>Saldo resultante del tercero en esta cuenta al final del período. Mismo criterio de cálculo que el saldo de la cuenta.</td></tr><tr><td>`base_retencion`</td><td>number</td><td>Valor acumulado de la base de retención del tercero en esta cuenta.</td></tr><tr><td>`detalles`</td><td>array</td><td>Listado de documentos contables (movimientos individuales) del tercero en esta cuenta durante el período.</td></tr></tbody></table>

##### **Campos de cada detalle (detalles)**

Cada elemento dentro del arreglo `detalles` representa un documento contable individual:

<table border="1" id="bkmrk-campo-tipo-descripci-3" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 12%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`fecha_documento`</td><td>string</td><td>Fecha del documento contable en formato `YYYY-MM-DD`.</td></tr><tr><td>`consecutivo_documento`</td><td>string</td><td>Consecutivo del documento contable con su prefijo, en formato `PREFIJO-NÚMERO` (ej. `RC-10450`, `FV-8901`, `EG-4021`).</td></tr><tr><td>`detalle_documento`</td><td>string</td><td>Descripción u observaciones del documento contable.</td></tr><tr><td>`debitos`</td><td>number</td><td>Valor del débito del documento contable.</td></tr><tr><td>`creditos`</td><td>number</td><td>Valor del crédito del documento contable.</td></tr><tr><td>`base_retencion`</td><td>number</td><td>Valor de la base de retención del documento contable.</td></tr></tbody></table>

<p class="callout info">**Nota sobre resultados vacíos**  
Si no existen movimientos contables para los parámetros indicados, la respuesta tendrá HTTP `200` con `error: false`, `body: null` y un `message` informativo: `"No se encontraron registros con los parámetros indicados."`</p>

<p class="callout info">**Nota sobre el cálculo de saldos**  
El cálculo del `saldo_actual` depende de la clase contable de la cuenta (primer dígito del código PUC):  
— **Clases 1 (Activos), 5 (Gastos) y 6 (Costos)**: `saldo_anterior + débitos - créditos`  
— **Clases 2 (Pasivos), 3 (Patrimonio), 4 (Ingresos) y demás**: `saldo_anterior + créditos - débitos`  
Este comportamiento puede variar según la configuración del sistema (parámetro interno de la plataforma).</p>

---

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Si alguno de los parámetros no cumple con las validaciones, el sistema devolverá un error `400`. Por ejemplo:

```json
{
    "error": true,
    "message": "La fecha inicial no tiene un formato válido (Y-m-d) o no es una fecha válida.",
    "body": null
}
```

Posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`  
  
**Parámetros inválidos.** Posibles causas:  
— `fecha_ini` no tiene formato `YYYY-MM-DD` válido. Mensaje: `"La fecha inicial no tiene un formato válido (Y-m-d) o no es una fecha válida."`  
— `fecha_fin` no tiene formato `YYYY-MM-DD` válido. Mensaje: `"La fecha final no tiene un formato válido (Y-m-d) o no es una fecha válida."`  
— `fecha_ini` es posterior a `fecha_fin`. Mensaje: `"La fecha inicial debe ser menor o igual que la fecha final."`  
— `cuenta_ini` no es numérico. Mensaje: `"La cuenta inicial debe ser un valor numérico."`  
— `cuenta_fin` no es numérico. Mensaje: `"La cuenta final debe ser un valor numérico."`  
— `cuenta_ini` es mayor que `cuenta_fin`. Mensaje: `"La cuenta inicial debe ser menor o igual que la cuenta final."`  
— `cuenta_ini` es menor que `1`. Mensaje: `"La cuenta inicial debe ser mayor o igual que 1."`</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**. Mensaje: `"JWT Token expired."`</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr><tr><td>**500**</td><td>Error interno del servidor al procesar la consulta del auxiliar general. Mensaje: `"Ocurrió un error al tratar de obtener el auxiliar general."`</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-consultar-aux"><summary>cURL</summary>

```bash
# Consultar auxiliar general con parámetros por defecto (año actual, todas las cuentas)
curl -X GET "https://{{instancia}}/service/v2/public/accounting/general-ledger" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Consultar auxiliar general de enero a junio 2025, cuentas de activos y pasivos (1 a 2)
curl -X GET "https://{{instancia}}/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01&fecha_fin=2025-06-30&cuenta_ini=1&cuenta_fin=2" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login

// Parámetros de consulta
$fecha_ini = '2025-01-01';
$fecha_fin = '2025-06-30';
$cuenta_ini = '1';
$cuenta_fin = '4';

$queryParams = http_build_query([
    'fecha_ini' => $fecha_ini,
    'fecha_fin' => $fecha_fin,
    'cuenta_ini' => $cuenta_ini,
    'cuenta_fin' => $cuenta_fin
]);

$url = "https://{$instance}/service/v2/public/accounting/general-ledger?{$queryParams}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    $info = json_decode($response, true);
    $body = $info['body'] ?? [];

    if ($http_code === 200 && !empty($body)) {
        echo "Se consultaron " . count($body) . " cuentas contables.\n\n";

        foreach ($body as $cuenta) {
            echo "Cuenta: {$cuenta['cuenta']} - {$cuenta['nombre_cuenta']}\n";
            echo "  Saldo anterior: $" . number_format($cuenta['saldo_anterior'], 2) . "\n";
            echo "  Débitos: $" . number_format($cuenta['debitos'], 2) . "\n";
            echo "  Créditos: $" . number_format($cuenta['creditos'], 2) . "\n";
            echo "  Saldo actual: $" . number_format($cuenta['saldo_actual'], 2) . "\n";

            foreach ($cuenta['terceros'] as $terceroId => $tercero) {
                echo "    Tercero: {$tercero['documento_tercero']} - {$tercero['nombre_tercero']}\n";
                echo "      Movimientos: " . count($tercero['detalles']) . "\n";
            }
            echo "\n";
        }
    } else {
        echo "Mensaje: " . ($info['message'] ?? 'Sin resultados') . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 la dirección y los parámetros
url = f"https://{instancia}/service/v2/public/accounting/general-ledger"

params = {
    "fecha_ini": "2025-01-01",
    "fecha_fin": "2025-06-30",
    "cuenta_ini": "1",
    "cuenta_fin": "4"
}

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, params=params, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        info = response.json()
        body = info.get('body') or []

        if body:
            print(f"Cuentas encontradas: {len(body)}\n")
            for cuenta in body:
                print(f"Cuenta: {cuenta['cuenta']} - {cuenta['nombre_cuenta']}")
                print(f"  Saldo anterior: ${cuenta['saldo_anterior']:,.2f}")
                print(f"  Débitos: ${cuenta['debitos']:,.2f}")
                print(f"  Créditos: ${cuenta['creditos']:,.2f}")
                print(f"  Saldo actual: ${cuenta['saldo_actual']:,.2f}")

                for tercero_id, tercero in cuenta['terceros'].items():
                    print(f"    Tercero [{tercero_id}]: {tercero['documento_tercero']} - {tercero['nombre_tercero']}")
                    print(f"      Movimientos: {len(tercero['detalles'])}")
                print()
        else:
            print(f"Mensaje: {info.get('message', 'Sin resultados')}")
    else:
        print("Error al consultar el auxiliar general.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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. Prepara la dirección con parámetros
const params = new URLSearchParams({
    fecha_ini: '2025-01-01',
    fecha_fin: '2025-06-30',
    cuenta_ini: '1',
    cuenta_fin: '4'
});

const url = `https://${instancia}/service/v2/public/accounting/general-ledger?${params}`;

// 3. Función para consultar el auxiliar general
async function consultarAuxiliarGeneral() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const info = await response.json();
            const body = info.body || [];

            if (body.length > 0) {
                console.log(`Cuentas encontradas: ${body.length}\n`);
                body.forEach(cuenta => {
                    console.log(`Cuenta: ${cuenta.cuenta} - ${cuenta.nombre_cuenta}`);
                    console.log(`  Saldo anterior: $${cuenta.saldo_anterior.toLocaleString()}`);
                    console.log(`  Débitos: $${cuenta.debitos.toLocaleString()}`);
                    console.log(`  Créditos: $${cuenta.creditos.toLocaleString()}`);
                    console.log(`  Saldo actual: $${cuenta.saldo_actual.toLocaleString()}`);

                    for (const [terceroId, tercero] of Object.entries(cuenta.terceros)) {
                        console.log(`    Tercero [${terceroId}]: ${tercero.documento_tercero} - ${tercero.nombre_tercero}`);
                        console.log(`      Movimientos: ${tercero.detalles.length}`);
                    }
                    console.log('');
                });
            } else {
                console.log(`Mensaje: ${info.message || 'Sin resultados'}`);
            }
        } else {
            console.log('Error al consultar el auxiliar general.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarAuxiliarGeneral();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 la dirección con parámetros
    url = "https://" & instancia & "/service/v2/public/accounting/general-ledger?fecha_ini=2025-01-01&fecha_fin=2025-06-30&cuenta_ini=1&cuenta_fin=4",

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON
    jsonResponse = Json.Document(response),
    body = jsonResponse[body],

    // 5. Convierte el listado de cuentas en tabla
    tablaCuentas = Table.FromList(body, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandidoCuentas = Table.ExpandRecordColumn(tablaCuentas, "Column1",
        {"cuenta", "nombre_cuenta", "saldo_anterior", "debitos", "creditos", "saldo_actual", "base_retencion", "terceros"},
        {"Cuenta", "NombreCuenta", "SaldoAnterior", "Debitos", "Creditos", "SaldoActual", "BaseRetencion", "Terceros"}),

    // 6. (Opcional) Expandir terceros para obtener detalle por tercero
    // Nota: La estructura de terceros es un objeto con claves dinámicas.
    // Para un análisis más detallado, es recomendable procesar los terceros
    // con Record.FieldValues y luego expandir los detalles.
    tercerosList = Table.AddColumn(expandidoCuentas, "TercerosLista", each Record.FieldValues([Terceros])),
    expandidoTerceros = Table.ExpandListColumn(tercerosList, "TercerosLista"),
    expandidoTercerosCampos = Table.ExpandRecordColumn(expandidoTerceros, "TercerosLista",
        {"documento_tercero", "nombre_tercero", "saldo_anterior", "debitos", "creditos", "saldo_actual", "base_retencion"},
        {"DocTercero", "NombreTercero", "SaldoAntTercero", "DebitosTercero", "CreditosTercero", "SaldoActTercero", "BaseRetTercero"})
in
    expandidoTercerosCampos
```

</details>

# Contratos

<span>Bienvenido al </span>**archivador legal digital**<span> de tu inmobiliaria. En esta sección agrupamos todas las opciones de conexión para que tus plataformas externas interactúen con los </span>**acuerdos de arrendamiento**.

**¿Cuál es el propósito de este módulo?**<span> Facilitar la sincronización de tu ecosistema. Aquí encontrarás las herramientas necesarias para que tus sistemas consulten y extraigan automáticamente los detalles de cualquier contrato, eliminando por completo la necesidad de realizar búsquedas manuales o revisar documentos físicos en nuestra plataforma.</span>

Explora el listado de abajo para descubrir cómo consultar términos, información financiera, estados y fechas de tus inmuebles alquilados.

# Listar Contratos

Permite obtener la lista paginada de todos los contratos de arrendamiento registrados en el sistema. Cada elemento incluye la información completa del contrato: propiedad asociada, propietarios, inquilinos, valores económicos, fechas, estado y observaciones.

<p class="callout info">**¿Para qué sirve este servicio?**  
Úsalo para sincronizar el inventario de contratos con tu sistema externo, generar reportes de gestión inmobiliaria, alimentar dashboards con información contractual o consultar el estado general de los contratos administrados.</p>

---

#### **1. El Endpoint (La dirección web)**

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar <span style="color: rgb(241, 196, 15);">**{{instancia}}**</span> por la dirección web completa que utilizas para ingresar a tu plataforma.

```http
GET https://{{instancia}}/service/v2/public/contracts/list
```

<p class="callout info">**¿Qué debes colocar en {{instancia}}?**  
Es muy sencillo: corresponde a la **dirección web principal** que utilizas a diario para ingresar a tu plataforma (incluyendo la terminación `.nuby.app` o `.arrendasoft.co`).  
Por ejemplo, si para entrar a tu sistema escribes `inmobiliaria.nuby.app` o `inmobiliaria.arrendasoft.co` en tu navegador, esa será exactamente tu instancia. Solo asegúrate de no incluir el "https://" ni barras diagonales ("/") al final.</p>

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

Este servicio no requiere cuerpo en la petición. Envía los encabezados requeridos y opcionalmente los parámetros de paginación en la URL:

<table border="1" id="bkmrk-m%C3%A9todo-get-content-t" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 20%;"></col><col style="width: 80%;"></col></colgroup><tbody><tr><td>**Método**</td><td>GET</td></tr><tr><td>**Content-Type**</td><td>application/json</td></tr><tr><td>**Authorization**</td><td>**Bearer token**, Token obtenido al consumir el servicio [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login "Login")</td></tr></tbody></table>

<p class="callout warning">**¿Aún no tienes tu Token de acceso?**  
Para consumir este servicio necesitas un Token vigente. Consulta el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para aprender cómo obtenerlo.</p>

**Parámetros de consulta (query string):**

<table border="1" id="bkmrk-par%C3%A1metro-tipo-reque" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 10%;"></col><col style="width: 10%;"></col><col style="width: 12%;"></col><col style="width: 46%;"></col></colgroup><thead><tr><th>Parámetro</th><th>Tipo</th><th>Requerido</th><th>Por defecto</th><th>Descripción</th></tr></thead><tbody><tr><td>`page`</td><td>integer</td><td>No</td><td>1</td><td>Número de página de resultados que se desea recuperar. Debe ser un número positivo.</td></tr><tr><td>`page_size`</td><td>integer</td><td>No</td><td>10</td><td>Número máximo de contratos por página. Debe ser un número positivo. Valor máximo permitido: **1000**.</td></tr></tbody></table>

**Ejemplos de petición:**

```http
GET https://mi-inmobiliaria.nuby.app/service/v2/public/contracts/list
GET https://mi-inmobiliaria.nuby.app/service/v2/public/contracts/list?page=2
GET https://mi-inmobiliaria.nuby.app/service/v2/public/contracts/list?page_size=50
GET https://mi-inmobiliaria.nuby.app/service/v2/public/contracts/list?page=3&page_size=100
```

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

Si tu Token es válido, el sistema te devolverá un objeto JSON con el estado de la respuesta, el listado de contratos y la información de paginación. La respuesta se verá similar a esta:

```json
{
    "status": 200,
    "message": null,
    "body": [
        {
            "contrato_id": 45,
            "consecutivo": "45",
            "propiedad_id": 312,
            "propiedad": "312 - Cll 78 # 12 - 34 Apto 501",
            "estrato_propiedad": "Cuatro",
            "propietario": "[1] 52498731 - ANDREA MILENA CASTRO ROJAS",
            "propietarios_id": "18",
            "inquilino": "[1] 80213654 - CARLOS EDUARDO PINEDA VARGAS",
            "inquilinos_id": "42",
            "valor_canon_individual": "2850000",
            "canon_total": 2850000,
            "porcentaje_comision": "10.00 %",
            "periodicidad": "Mensual",
            "escenario": "CANON DE ARRENDAMIENTO SIN IVA, CON RETEFUENTE 3.5%, SIN RETEIVA, SIN RETEICA",
            "estado": "Activo",
            "estado_id": 1,
            "fecha_inicio": "2024-06-01",
            "fecha_fin": "2025-05-31",
            "fecha_terminacion": null,
            "observaciones": "Contrato renovado automáticamente por un año adicional.",
            "uso": "Vivienda",
            "fecha_creacion": "2024-05-28 14:32:10",
            "creado_por": "Sandra"
        },
        {
            "contrato_id": 46,
            "consecutivo": "46",
            "propiedad_id": 589,
            "propiedad": "589 - Cra 45 # 90 - 12 Local 3",
            "estrato_propiedad": "Comercial",
            "propietario": "[1] 900456789 - INVERSIONES HORIZONTE S.A.S.",
            "propietarios_id": "65",
            "inquilino": "[1] 1098745231 - JULIANA PATRICIA RÍOS MENDOZA",
            "inquilinos_id": "73",
            "valor_canon_individual": "4500000",
            "canon_total": 4500000,
            "porcentaje_comision": "8.50 %",
            "periodicidad": "Mensual",
            "escenario": "CANON DE ARRENDAMIENTO CON IVA 19%, CON RETEFUENTE 3.5%, CON RETEIVA 15%, SIN RETEICA",
            "estado": "Activo",
            "estado_id": 1,
            "fecha_inicio": "2023-09-01",
            "fecha_fin": "2025-08-31",
            "fecha_terminacion": null,
            "observaciones": null,
            "uso": "Comercial",
            "fecha_creacion": "2023-08-25 09:15:44",
            "creado_por": "Administrador"
        },
        {
            "contrato_id": 12,
            "consecutivo": "12",
            "propiedad_id": 104,
            "propiedad": "104 - Cll 23 # 56 - 78",
            "estrato_propiedad": "Tres",
            "propietario": "[1] 71654321 - HÉCTOR FABIO MORENO AGUILAR",
            "propietarios_id": "31",
            "inquilino": "[1] 43876123 - DIANA MARCELA OSPINA VELÁSQUEZ",
            "inquilinos_id": "55",
            "valor_canon_individual": "1200000",
            "canon_total": 1200000,
            "porcentaje_comision": "12.00 %",
            "periodicidad": "Mensual",
            "escenario": "CANON DE ARRENDAMIENTO SIN IVA, SIN RETEFUENTE, SIN RETEIVA, SIN RETEICA",
            "estado": "Terminado",
            "estado_id": 2,
            "fecha_inicio": "2022-01-15",
            "fecha_fin": "2023-01-14",
            "fecha_terminacion": "2022-11-30",
            "observaciones": "Terminación anticipada por mutuo acuerdo.",
            "uso": "Vivienda",
            "fecha_creacion": "2021-12-20 16:40:33",
            "creado_por": "Sandra"
        }
    ],
    "pagination": {
        "total_records": 347,
        "total_pages": 116,
        "current_page": 1,
        "page_size": 3,
        "current_page_records": 3,
        "has_next_page": true,
        "has_previous_page": false
    }
}
```

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

<table border="1" id="bkmrk-campo-tipo-descripci" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 22%;"></col><col style="width: 12%;"></col><col style="width: 66%;"></col></colgroup><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`status`</td><td>integer</td><td>Código del estado de la respuesta. `200` para exitoso, `400` para error de validación, `500` para error interno.</td></tr><tr><td>`message`</td><td>string | null</td><td>Cuando la respuesta es exitosa vale `null`. Si no se encuentran contratos, contiene el mensaje informativo. Si hay error, describe el problema.</td></tr><tr><td>`body`</td><td>array</td><td>Listado de contratos devueltos. Arreglo vacío `[]` si no hay resultados.</td></tr><tr><td>`pagination`</td><td>object</td><td>Información de paginación para recorrer los resultados.</td></tr></tbody></table>

##### **Campos de cada contrato (body)**

Cada elemento dentro del arreglo `body` contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-1" 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>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`contrato_id`</td><td>integer</td><td>Identificador único del contrato en el sistema.</td></tr><tr><td>`consecutivo`</td><td>string</td><td>Número consecutivo interno del contrato.</td></tr><tr><td>`propiedad_id`</td><td>integer</td><td>Identificador de la propiedad asociada al contrato.</td></tr><tr><td>`propiedad`</td><td>string</td><td>Etiqueta descriptiva de la propiedad en formato `{id} - {dirección}`.</td></tr><tr><td>`estrato_propiedad`</td><td>string</td><td>Estrato socioeconómico asignado a la propiedad (ej. "Tres", "Cuatro", "Comercial").</td></tr><tr><td>`propietario`</td><td>string</td><td>Cadena con el consecutivo del detalle, documento y nombre completo del propietario o propietarios. Formato: `[n] documento - NOMBRE`. Si hay varios, van separados por coma.</td></tr><tr><td>`propietarios_id`</td><td>string</td><td>ID(s) del/los propietario(s) en el sistema. Si hay varios, van separados por coma.</td></tr><tr><td>`inquilino`</td><td>string</td><td>Cadena con el consecutivo del detalle, documento y nombre completo del inquilino o inquilinos. Mismo formato que `propietario`.</td></tr><tr><td>`inquilinos_id`</td><td>string</td><td>ID(s) del/los inquilino(s) en el sistema. Si hay varios, van separados por coma.</td></tr><tr><td>`valor_canon_individual`</td><td>string</td><td>Valor del canon por cada detalle del contrato. Si hay varios detalles, los valores van separados por coma.</td></tr><tr><td>`canon_total`</td><td>number | null</td><td>Valor total del canon de arrendamiento del contrato.</td></tr><tr><td>`porcentaje_comision`</td><td>string</td><td>Porcentaje de comisión de la inmobiliaria con formato `"X.XX %"`.</td></tr><tr><td>`periodicidad`</td><td>string</td><td>Frecuencia de pago del canon (ej. "Mensual").</td></tr><tr><td>`escenario`</td><td>string</td><td>Descripción del escenario tributario y de facturación aplicado al contrato.</td></tr><tr><td>`estado`</td><td>string</td><td>Estado textual del contrato. Valores posibles: `Activo`, `Terminado`, `En Construcción`.</td></tr><tr><td>`estado_id`</td><td>integer</td><td>Identificador numérico del estado: `1` = Activo, `2` = Terminado, `3` = En Construcción.</td></tr><tr><td>`fecha_inicio`</td><td>string</td><td>Fecha de inicio del contrato en formato `YYYY-MM-DD`.</td></tr><tr><td>`fecha_fin`</td><td>string</td><td>Fecha de finalización prevista del contrato en formato `YYYY-MM-DD`.</td></tr><tr><td>`fecha_terminacion`</td><td>string | null</td><td>Fecha de terminación efectiva del contrato (si aplica). `null` si el contrato sigue vigente.</td></tr><tr><td>`observaciones`</td><td>string | null</td><td>Observaciones o notas asociadas al contrato. `null` si no hay.</td></tr><tr><td>`uso`</td><td>string</td><td>Tipo de uso de la propiedad: `Vivienda` o `Comercial`.</td></tr><tr><td>`fecha_creacion`</td><td>string</td><td>Fecha y hora de creación del registro en formato `YYYY-MM-DD HH:MM:SS`.</td></tr><tr><td>`creado_por`</td><td>string</td><td>Nombre del usuario que creó el contrato en el sistema.</td></tr></tbody></table>

##### **Campos de paginación (pagination)**

El objeto `pagination` contiene las siguientes claves:

<table border="1" id="bkmrk-campo-tipo-descripci-2" 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>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`total_records`</td><td>integer</td><td>Total de contratos registrados en el sistema.</td></tr><tr><td>`total_pages`</td><td>integer</td><td>Cantidad total de páginas disponibles (total de registros dividido por el tamaño de página).</td></tr><tr><td>`current_page`</td><td>integer</td><td>Número de la página actual consultada.</td></tr><tr><td>`page_size`</td><td>integer</td><td>Tamaño de la página (cantidad de registros solicitados por consulta).</td></tr><tr><td>`current_page_records`</td><td>integer</td><td>Cantidad de registros efectivamente devueltos en la página actual.</td></tr><tr><td>`has_next_page`</td><td>boolean</td><td>`true` si existen páginas posteriores que se pueden consultar.</td></tr><tr><td>`has_previous_page`</td><td>boolean</td><td>`true` si existen páginas anteriores que se pueden consultar.</td></tr></tbody></table>

<p class="callout info">**Nota sobre contratos sin resultados**  
Si no existen contratos registrados en el sistema, la respuesta tendrá HTTP `200` con `body` vacío (`[]`), un `message` informativo y los valores de paginación en cero.</p>

---

#### **4. Seguridad y Posibles Errores**

<p class="callout danger">**¡Tu pase tiene fecha de caducidad!**</p>

Por medidas de seguridad, el `token` que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expirará y el sistema te bloqueará el acceso devolviéndote un error `401`. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de [Login](https://docs.nuby.ai/books/api-nuby-v2/page/login) para pedir un pase nuevo y continuar trabajando.

Así se ve el error que te devolverá el sistema cuando tu token se haya vencido o intentes usar un pase inválido:

```json
{
    "statusCode": 401,
    "error": {
        "type": "SERVER_ERROR",
        "description": "JWT Token expired."
    }
}
```

Si alguno de los parámetros de paginación no cumple con las validaciones, el sistema devolverá un error `400` con la estructura estándar. Por ejemplo:

```json
{
    "status": 400,
    "message": "El parámetro \"page_size\" debe ser un número positivo.",
    "body": null,
    "pagination": null
}
```

Posibles errores:

<table border="1" id="bkmrk-c%C3%B3digo-http-descripc" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 12%;"></col><col style="width: 88%;"></col></colgroup><thead><tr><th>Código HTTP</th><th>Descripción</th></tr></thead><tbody><tr><td>**400**</td><td>**Token faltante o inválido.** Posibles causas:  
— No se envió el encabezado `Authorization`. Mensaje: `"JWT Token required."`  
— El encabezado no tiene el formato `Bearer {token}`. Mensaje: `"JWT Token not send."`  
— El token no fue encontrado en el sistema. Mensaje: `"JWT Token not found."`  
  
**Parámetros inválidos.** Posibles causas:  
— `page` no es numérico o no es positivo.  
— `page_size` no es numérico o no es positivo.</td></tr><tr><td>**401**</td><td>El token ha expirado. Debes generar uno nuevo consumiendo el servicio de **Login**. Mensaje: `"JWT Token expired."`</td></tr><tr><td>**403**</td><td>El cliente OAuth no tiene el scope necesario para esta operación. Para endpoints GET se requiere el scope `read`. Mensaje: `"Insufficient scope. Required: 'read', granted: '{scope_actual}'."`</td></tr><tr><td>**500**</td><td>Error interno del servidor al procesar la consulta de contratos.</td></tr></tbody></table>

---

#### **5. Ejemplos de integración**

Aquí tienes ejemplos de código listos para que tus desarrolladores los adapten a tu plataforma:

<details id="bkmrk-curl-%23-listar-contra"><summary>cURL</summary>

```bash
# Listar contratos con paginación por defecto
curl -X GET "https://{{instancia}}/service/v2/public/contracts/list" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Listar contratos página 3 con 100 registros por página
curl -X GET "https://{{instancia}}/service/v2/public/contracts/list?page=3&page_size=100" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
```

</details><details id="bkmrk-php-%3C%3Fphp-%24instance-"><summary>PHP</summary>

```php
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login

// Parámetros de paginación
$page = 1;
$page_size = 50;

$queryParams = http_build_query([
    'page' => $page,
    'page_size' => $page_size
]);

$url = "https://{$instance}/service/v2/public/contracts/list?{$queryParams}";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    "Authorization: Bearer {$token}"
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    echo 'Error: ' . curl_error($ch);
} else {
    echo "Código de estado HTTP: " . $http_code . "\n";

    $info = json_decode($response, true);
    $body = $info['body'] ?? [];

    if ($http_code === 200 && !empty($body)) {
        $pagination = $info['pagination'];
        echo "Contratos encontrados: {$pagination['total_records']} (página {$pagination['current_page']} de {$pagination['total_pages']})\n";

        foreach ($body as $contrato) {
            echo "  [{$contrato['consecutivo']}] {$contrato['propiedad']} - {$contrato['estado']} - Canon: \${$contrato['canon_total']}\n";
        }
    } else {
        echo "Mensaje: " . ($info['message'] ?? 'Sin resultados') . "\n";
    }
}
curl_close($ch);

?>
```

</details><details id="bkmrk-python-import-reques"><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 la dirección y los parámetros
url = f"https://{instancia}/service/v2/public/contracts/list"

params = {
    "page": 1,
    "page_size": 50
}

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {token}"
}

# 3. Envía la petición GET y procesa la respuesta
try:
    response = requests.get(url, params=params, headers=headers)

    print(f"Código de estado HTTP: {response.status_code}")

    if response.status_code == 200:
        info = response.json()
        body = info.get('body', [])
        pagination = info.get('pagination', {})

        if body:
            print(f"Contratos: {pagination['total_records']} total (página {pagination['current_page']} de {pagination['total_pages']})")
            for contrato in body:
                print(f"  [{contrato['consecutivo']}] {contrato['propiedad']} - {contrato['estado']} - Canon: ${contrato['canon_total']}")
        else:
            print(f"Mensaje: {info.get('message', 'Sin resultados')}")
    else:
        print("Error al consultar los contratos.")
        print(f"Detalle del error: {response.text}")

except Exception as e:
    print(f"Ocurrió un error de conexión: {e}")

```

</details><details id="bkmrk-javascript-%2F%2F-1.-con"><summary>JavaScript</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. Prepara la dirección con parámetros
const params = new URLSearchParams({
    page: 1,
    page_size: 50
});

const url = `https://${instancia}/service/v2/public/contracts/list?${params}`;

// 3. Función para consultar los contratos
async function consultarContratos() {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            }
        });

        console.log(`Código de estado HTTP: ${response.status}`);

        if (response.ok) {
            const info = await response.json();
            const body = info.body || [];
            const pagination = info.pagination || {};

            if (body.length > 0) {
                console.log(`Contratos: ${pagination.total_records} total (página ${pagination.current_page} de ${pagination.total_pages})`);
                body.forEach(contrato => {
                    console.log(`  [${contrato.consecutivo}] ${contrato.propiedad} - ${contrato.estado} - Canon: $${contrato.canon_total}`);
                });
            } else {
                console.log(`Mensaje: ${info.message || 'Sin resultados'}`);
            }
        } else {
            console.log('Error al consultar los contratos.');
            const errorData = await response.text();
            console.log(`Detalle del error: ${errorData}`);
        }
    } catch (error) {
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 4. Ejecutamos la función
consultarContratos();

```

</details><details id="bkmrk-power-query-m-%28excel"><summary>Power Query M (Excel / Power BI)</summary>

```powerquery
let
    // 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 la dirección de la petición con parámetros
    url = "https://" & instancia & "/service/v2/public/contracts/list?page=1&page_size=1000",

    // 3. Envía la petición GET
    response = Web.Contents(url, [
        Headers = [
            #"Content-Type" = "application/json",
            #"Authorization" = "Bearer " & token
        ]
    ]),

    // 4. Decodifica la respuesta JSON
    jsonResponse = Json.Document(response),
    body = jsonResponse[body],

    // 5. Convierte el listado en tabla
    tabla = Table.FromList(body, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"contrato_id", "consecutivo", "propiedad", "estrato_propiedad", "propietario", "inquilino", "canon_total", "porcentaje_comision", "periodicidad", "estado", "fecha_inicio", "fecha_fin", "fecha_terminacion", "uso", "creado_por"},
        {"ContratoID", "Consecutivo", "Propiedad", "Estrato", "Propietario", "Inquilino", "Canon", "Comision", "Periodicidad", "Estado", "FechaInicio", "FechaFin", "FechaTerminacion", "Uso", "CreadoPor"})
in
    expandido
```

</details>