# 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

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 "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

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 "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

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>

# Crear factura en borrador [beta]

Este servicio crea una **factura de venta en borrador** en nuby. El documento nace en estado `5` (Borrador), **sin numerar**, con su contabilidad generada y dentro de una transacción con reversa: si algo falla, no queda nada a medias. nuby sigue siendo el dueño del documento; tu plataforma solo envía los datos de la operación.

Es el primer paso del ciclo de facturación. Después puedes **editar el borrador** mientras siga en ese estado y, cuando esté listo, **emitirlo a la DIAN**. Crear y emitir son dos operaciones distintas: no existe `emitir: true` en este servicio, y el borrador **no consume** un consecutivo real.

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

</div></div><p class="callout success">Para navegar esta página, haz clic sobre la sección que desees consultar. Cada sección se expande al dar clic.</p>

<div class="page-content" dir="auto" id="bkmrk-1.-%C2%BFpara-qu%C3%A9-sirve-e"><div dir="auto">  <details><summary>1. ¿Para qué sirve este servicio? 🎯</summary>

Sirve para **registrar una factura de venta sin emitirla todavía**. Tu sistema envía la operación comercial —cliente, fecha, vencimiento, ítems, impuestos— y nuby crea el documento completo: cabecera, detalle, totales, saldo y su asiento en contabilidad, todo dentro de una transacción con reversa. Lo que **no** hace es numerarla ni enviarla a la DIAN: eso ocurre al emitirla.

##### 🔹 **Casos de uso concretos**

- **Facturación recurrente desde tu plataforma.** Si administras los cánones y los servicios de tus inmuebles en un sistema propio, generas el borrador de la factura del mes por API y nuby se encarga de la contabilidad, del consecutivo y del envío a la DIAN.
- **Pre-facturación con revisión humana.** Creas el borrador, alguien lo revisa en la interfaz de nuby, se corrige con el servicio de edición y solo entonces se emite. El borrador no gasta consecutivo, así que puedes crear y descartar sin ensuciar la numeración.
- **Integración con tu CRM o con tu e-commerce.** Cada venta cerrada en tu plataforma se convierte en un borrador de factura en nuby, con la misma referencia externa que ya usas en tu sistema.
- **Cargas y migraciones.** Puedes registrar facturas pendientes de emisión que ya existen en otro sistema, una por petición, y emitirlas cuando corresponda.
- **Facturación de servicios periódicos.** Generas los borradores de un lote de clientes uno por uno (el servicio no acepta lotes) y controlas los duplicados con `referencia_externa`.

##### 🔹 **Resumen del servicio**

<table><thead><tr><th>Aspecto</th><th>Valor</th></tr></thead><tbody><tr><td>Método y ruta</td><td>`POST /service/v2/public/invoices`</td></tr><tr><td>Permiso (scope) requerido</td><td>`invoices:create`</td></tr><tr><td>Respuesta exitosa</td><td>`201` con `factura_id`, `estado_id`, `consecutivo`, `valor_total`, `valor_saldo` y `referencia_externa`</td></tr><tr><td>Efecto del documento</td><td>Estado `5` (Borrador), sin numerar, con contabilidad y saldo calculados</td></tr><tr><td>Protección contra duplicados</td><td>Idempotencia por `referencia_externa` + consumidor + operación</td></tr><tr><td>¿Envía a la DIAN?</td><td>**No**. El envío es la operación de emisión</td></tr></tbody></table>

##### 🔹 **Lo que este servicio NO hace**

- **No numera la factura.** El consecutivo real se asigna al emitir; en el borrador `consecutivo` es un marcador interno (cero o negativo).
- **No emite ni envía a la DIAN.** No existe `emitir: true`: la emisión es una acción explícita y separada.
- **No crea facturas de contrato.** Las facturas de arrendamiento nacen del flujo de contratos de nuby; esta API solo admite facturas de venta y rechaza los datos de contrato.
- **No completa los datos del tercero.** Si envías el objeto `tercero`, nuby no inventa direcciones, teléfonos ni correos faltantes.
- **No abre períodos contables.** Abrirlos es tarea del administrador de nuby.
- **No anula, no registra pagos y no acepta lotes.** Cada petición crea una sola factura.

##### 🔹 **Dónde encaja en el ciclo**

```text
1. Crear borrador         POST /invoices                              (esta página)
2. Editar borrador        PUT|PATCH /invoices/{factura_id}
3. Emitir a la DIAN       POST /invoices/{factura_id}/issue
4. Consultar detalle      GET /invoices/{factura_id}
5. Obtener el PDF         GET /invoices/{factura_id}/pdf
```

<p class="callout info">Si todavía no tienes el `tercero_id`, resuélvelo primero con la guía [**Crear o Resolver Tercero**](https://docs.nuby.ai/crear-o-resolver-tercero.html), o envía el objeto `tercero` dentro de esta misma petición (ver sección 3).</p>

</details>  <details><summary>2. El Endpoint (La dirección web) 🔐</summary>

Apunta tu sistema a la siguiente dirección de petición **POST**:

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

**¿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 escribes `inmobiliaria.nuby.app` en tu navegador, esa es exactamente tu instancia. Solo asegúrate de **no incluir** `https://` ni barras diagonales (`/`) al final.

##### 🔹 **Encabezados requeridos**

<table><thead><tr><th>Encabezado</th><th>Valor</th><th>Obligatorio</th></tr></thead><tbody><tr><td>`Content-Type`</td><td>`application/json`</td><td>Sí</td></tr><tr><td>`Authorization`</td><td>`Bearer <token>`, con el token obtenido en el servicio **Login**</td><td>Sí</td></tr></tbody></table>

##### 🔹 **Permiso requerido (scope)**

El cliente OAuth con el que se genera el token debe tener habilitado el permiso `invoices:create`. Hay dos rechazos distintos, y conviene no confundirlos:

- `403 CONSUMIDOR_NO_AUTENTICADO` → el token es válido pero no corresponde a un cliente OAuth habilitado para consumir la API. Mensaje: *El cliente autenticado no está autorizado para consumir este endpoint.*
- `403 RECURSO_NO_AUTORIZADO` → el cliente existe pero le falta el permiso `invoices:create`. Mensaje: *El consumidor no tiene habilitado el recurso solicitado.* Solicita el ajuste a tu administrador en nuby.

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

##### 🔹 **Precondiciones del sistema**

nuby evalúa estas condiciones **antes de escribir nada**. Ninguna se resuelve reintentando: son configuración o datos de tu cuenta.

<table><thead><tr><th>Precondición</th><th>Qué pasa si no se cumple</th></tr></thead><tbody><tr><td>La facturación electrónica está habilitada en nuby (`ENABLE_FACT_ELECT = 1`).</td><td>`422 FACTURACION_ELECTRONICA_DESHABILITADA`. No se invoca el motor de facturación ni se escribe nada.</td></tr><tr><td>La `fecha` cae en un período contable **abierto**, cuando la contabilidad de la facturación está habilitada (`FACTURACION_CONTABILIDAD`).</td><td>`422 PERIODO_CONTABLE_NO_ABIERTO` o `422 PERIODO_CONTABLE_CERRADO`.</td></tr><tr><td>Existe una resolución de **venta** activa, o envías una válida en `resolucion_id`.</td><td>`422 RESOLUCION_NO_DISPONIBLE` o `422 RESOLUCION_CONTRATO_NO_PERMITIDA`.</td></tr><tr><td>El tercero existe en nuby, o envías el objeto `tercero` con sus datos fiscales.</td><td>`422 VALIDATION_ERROR` (falta el tercero) o `422 DATOS_FACTURA_INVALIDOS` (el tercero existe pero está incompleto).</td></tr><tr><td>El payload cumple el contrato de entrada y el motor de facturación acepta el documento.</td><td>`422 VALIDATION_ERROR` (error de validación del payload) o `422 DATOS_FACTURA_INVALIDOS` (el motor rechazó el documento, con la causa en `message`).</td></tr></tbody></table>

<p class="callout warning">**El período contable no lo abre tu integración.** Abrirlo es una tarea del administrador de nuby: si recibes un código de período, avisa a tu contacto en nuby y usa una fecha con período abierto. El período **cerrado** pesa más que uno abierto: si la fecha cae en un período cerrado, el rechazo es `PERIODO_CONTABLE_CERRADO` aunque exista otro período abierto que también la contenga.</p>

</details>  <details><summary>3. La Petición (¿Qué debes enviarnos?) 📦</summary>

Envía un **objeto JSON** en el cuerpo. La raíz del JSON lleva la referencia de idempotencia y, al mismo nivel, la cabecera de la factura y sus ítems.

<table><thead><tr><th>Elemento</th><th>Valor</th></tr></thead><tbody><tr><td>Método</td><td>`POST`</td></tr><tr><td>`Content-Type`</td><td>`application/json`</td></tr><tr><td>`Authorization`</td><td>`Bearer <token>`</td></tr><tr><td>Cuerpo</td><td>Objeto JSON con la cabecera y el arreglo `items`</td></tr></tbody></table>

##### 🔹 **Cabecera de la factura**

<table><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>`referencia_externa`</td><td>texto</td><td>Sí</td><td>—</td><td>Identificador único de **tu** operación. Es la llave de idempotencia: un reintento con la misma referencia no crea una segunda factura. No puede venir vacía ni con solo espacios. Si falta: `422` con *El campo "referencia\_externa" es obligatorio.*</td></tr><tr><td>`tercero_id`</td><td>entero</td><td>Sí, o el objeto `tercero`</td><td>—</td><td>Identificador interno del tercero en nuby. Debe ser mayor que 0. Si envías `tercero_id` **y** `tercero`, gana `tercero_id`.</td></tr><tr><td>`tercero`</td><td>objeto</td><td>Sí, o `tercero_id`</td><td>—</td><td>Datos del tercero para resolverlo o crearlo en la misma operación (ver **Datos fiscales del tercero**). Sin ninguno de los dos: *Debe indicar tercero\_id o el objeto tercero.* Si no es un arreglo: *El objeto tercero debe ser un arreglo con los datos del tercero.*</td></tr><tr><td>`fecha`</td><td>texto `AAAA-MM-DD`</td><td>Sí</td><td>—</td><td>Fecha de la factura. Debe ser una fecha real y caer en un período contable utilizable. Si falta o está mal formada: *La fecha de la factura es obligatoria y debe tener el formato AAAA-MM-DD.*</td></tr><tr><td>`dias_vencimiento`</td><td>entero</td><td>Sí, salvo que uses `fecha_vencimiento` o `pago_total: true`</td><td>—</td><td>Días de plazo. Debe ser un entero **mayor o igual a 1**. Si falta: *Los días de vencimiento son obligatorios y deben ser un entero mayor o igual a 1.*</td></tr><tr><td>`fecha_vencimiento`</td><td>texto `AAAA-MM-DD`</td><td>No</td><td>—</td><td>Alternativa a `dias_vencimiento`: nuby deriva los días desde `fecha`. Si envías ambos y no coinciden: *La fecha de vencimiento no coincide con los días de vencimiento enviados.* Formato inválido: *La fecha de vencimiento debe tener el formato AAAA-MM-DD.*</td></tr><tr><td>`resolucion_id`</td><td>entero</td><td>No</td><td>resolución de venta activa</td><td>Resolución de facturación. Debe ser un entero positivo, existir, estar activa y ser de facturación (no de contrato). Si se omite, nuby elige la primera resolución activa de venta.</td></tr><tr><td>`moneda`</td><td>texto</td><td>No</td><td>`COP`</td><td>Código de la moneda del documento. Una cadena vacía equivale a no enviarla.</td></tr><tr><td>`tasa_cambio`</td><td>numérico</td><td>No</td><td>`null`</td><td>Tasa de cambio aplicable. Solo tiene sentido con moneda extranjera; se copia tal cual al documento.</td></tr><tr><td>`vendedor_id`</td><td>entero</td><td>No</td><td>`null`</td><td>Usuario de nuby que figura como vendedor del documento.</td></tr><tr><td>`centro_id`</td><td>entero</td><td>No</td><td>`null`</td><td>Centro de costo del documento.</td></tr><tr><td>`observaciones`</td><td>texto</td><td>No</td><td>`null`</td><td>Nota libre que queda guardada en la factura.</td></tr><tr><td>`pago_total`</td><td>booleano</td><td>No</td><td>`false`</td><td>Si es verdadero, la factura queda **de contado**: el vencimiento es igual a la fecha y `dias_vencimiento` **se ignora**.</td></tr><tr><td>`formas_de_pago`</td><td>arreglo de objetos</td><td>Sí, cuando `pago_total` es `true`</td><td>`[]`</td><td>Formas de pago del documento. Con `pago_total: true` debes enviar al menos una: *Debe agregar al menos una forma de pago cuando pago\_total es verdadero.* Si no es un arreglo: *formas\_de\_pago debe ser un arreglo de formas de pago.* Con `pago_total: true`, nuby usa el `tipo_pago_id` del payload o, si no lo envías, el de la primera forma de pago.</td></tr><tr><td>`anticipos[]`</td><td>arreglo</td><td>No</td><td>`[]`</td><td>Anticipos que se aplican a la factura. Acepta objetos (`[{"documento_id": 5}]`) o una lista plana de identificadores (`[5]`). Los identificadores no positivos se descartan. **Se aplican después** de guardar el borrador, porque necesitan el saldo ya persistido.</td></tr><tr><td>`items`</td><td>arreglo de objetos</td><td>Sí</td><td>—</td><td>Líneas del documento. Debe traer al menos una: *Debe enviar al menos un ítem en items.*</td></tr></tbody></table>

<p class="callout warning">**`tipo_factura` no se acepta.** nuby lo fija en `1` (venta). Si lo envías —incluso con el valor correcto— la respuesta es `422 CAMPO_NO_PERMITIDO`.</p>

<p class="callout warning">**El cuerpo debe ser un objeto JSON.** Un arreglo, un texto o un cuerpo vacío devuelven `400` con *El cuerpo de la solicitud debe ser un objeto JSON.* Los campos que no están en la superficie aceptada se ignoran: no se copian al documento.</p>

##### 🔹 **Ítems (`items[]`)**

Cada elemento del arreglo es una línea de la factura. Los campos se validan **todos antes** de invocar el motor de facturación: si un ítem es inválido, la factura no se crea.

<table><thead><tr><th>Campo</th><th>Tipo</th><th>Requerido</th><th>Descripción</th></tr></thead><tbody><tr><td>`producto_id`</td><td>entero</td><td>Sí</td><td>Producto o servicio facturado. Mayor que 0. Error: *producto\_id debe ser un entero mayor que 0.*</td></tr><tr><td>`cantidad`</td><td>entero</td><td>Sí</td><td>Cantidad facturada. Entero mayor que 0 (el motor la guarda como entero). Error: *cantidad debe ser un entero mayor que 0.*</td></tr><tr><td>`valor_unitario`</td><td>numérico</td><td>Sí</td><td>Precio unitario. Numérico y **distinto de cero**. Error: *valor\_unitario debe ser numérico y distinto de 0.*</td></tr><tr><td>`descripcion`</td><td>texto</td><td>No</td><td>Descripción de la línea. nuby la envía siempre al motor (vacía si no la mandas).</td></tr><tr><td>`por_descuento` / `descuento`</td><td>numérico</td><td>No</td><td>Porcentaje y valor del descuento de la línea.</td></tr><tr><td>`descuentos_id`</td><td>entero</td><td>No</td><td>Identificador de la regla de descuento aplicada.</td></tr><tr><td>`por_iva` / `iva`</td><td>numérico</td><td>No</td><td>Porcentaje y valor del IVA de la línea.</td></tr><tr><td>`por_retencion` / `retencion`</td><td>numérico</td><td>No</td><td>Porcentaje y valor de la retención en la fuente.</td></tr><tr><td>`por_reteiva` / `reteiva`</td><td>numérico</td><td>No</td><td>Porcentaje y valor de la retención de IVA.</td></tr><tr><td>`por_reteica` / `reteica`</td><td>numérico</td><td>No</td><td>Porcentaje y valor de la retención de ICA.</td></tr><tr><td>`otros_impuestos`</td><td>numérico</td><td>No</td><td>Otros impuestos de la línea.</td></tr><tr><td>`tercero_aplica_id`</td><td>entero</td><td>No</td><td>Tercero al que aplican las retenciones de la línea. nuby lo envía siempre al motor (`null` si no lo mandas).</td></tr><tr><td>`valor_unitario_ori`</td><td>numérico</td><td>No</td><td>Valor unitario en la moneda original. Si no lo envías, lo deriva el motor de facturación.</td></tr></tbody></table>

<p class="callout warning">**Por qué se rechazan los ítems inválidos:** el motor de facturación descarta en silencio las líneas que no cumplen las reglas de `producto_id`, `cantidad` y `valor_unitario`. Por eso nuby las valida antes: así tu factura nunca queda con menos líneas que las que enviaste. Si un ítem no es un objeto, el error por campo es *Cada ítem debe ser un arreglo con producto\_id, cantidad y valor\_unitario.* y la clave del error es `items.<indice>.<campo>`.</p>

##### 🔹 **Campos de contrato: rechazo con `warnings[]`**

Esta API solo crea facturas de venta. Si el payload —en la cabecera **o dentro de un ítem**— trae datos de contrato o de movimiento, la respuesta es `422 FACTURA_CONTRATO_NO_PERMITIDA` con la advertencia estructurada:

- `movimiento_id`, `contrato_id`, `procesado`, `documento_respaldo_id`, `inmobiliaria`.
- Enviarlos en `null`, `""` o `0` **no** es un error: es la forma natural de decir "no aplica". Solo se rechaza el campo que trae un vínculo real.

```json
{
  "success": false,
  "status": 422,
  "message": "El payload intenta crear o modificar una factura con datos de contrato (contrato_id). Esta API solo crea facturas de venta; las facturas de contrato se generan desde el flujo de contratos.",
  "error_code": "FACTURA_CONTRATO_NO_PERMITIDA",
  "errors": {
    "contrato_id": [
      "El payload no puede incluir el campo contrato_id en una factura de venta."
    ]
  },
  "warnings": [
    { "code": "FACTURA_CONTRATO_NO_PERMITIDA", "scope": "solo_facturas_de_venta" }
  ]
}
```

##### 🔹 **Campos protegidos: `422 CAMPO_NO_PERMITIDO`**

Solo los asigna nuby. Se evalúa la **presencia** de la clave: enviarla en `null` también se rechaza.

- `factura_id` (la creación siempre crea un documento nuevo; para editar un borrador existente se usa `PUT/PATCH /invoices/{factura_id}`), `estado_id`, `consecutivo`, `cufe`, `dian_id`, `estado_dian`, `creado_por`, `tipo_factura`.

```json
{
  "success": false,
  "status": 422,
  "message": "El payload intenta fijar el campo consecutivo, que solo el sistema puede asignar en una factura de venta.",
  "error_code": "CAMPO_NO_PERMITIDO",
  "errors": {
    "consecutivo": [
      "El campo consecutivo solo lo puede asignar el sistema."
    ]
  }
}
```

##### 🔹 **Vencimiento: las tres combinaciones válidas**

<table><thead><tr><th>Lo que envías</th><th>Resultado</th></tr></thead><tbody><tr><td>`dias_vencimiento: 30`</td><td>Vence 30 días después de `fecha`.</td></tr><tr><td>`fecha_vencimiento: "2026-11-20"`</td><td>nuby calcula los días entre `fecha` y esa fecha. Si la fecha es anterior a la factura: *La fecha de vencimiento no puede ser anterior a la fecha de la factura.* Si da 0 días en una factura a crédito: *La fecha de vencimiento debe ser posterior a la fecha de la factura.*</td></tr><tr><td>`pago_total: true`</td><td>Factura de contado: los días se fuerzan a 0 y el vencimiento es igual a la fecha. `dias_vencimiento` se ignora. Si además envías una `fecha_vencimiento` distinta a `fecha`: *Con pago total, la fecha de vencimiento debe ser igual a la fecha de la factura.*</td></tr></tbody></table>

##### 🔹 **Datos fiscales del tercero**

Con la facturación electrónica habilitada, la validación legal del documento exige que el tercero tenga completos estos datos. Si usas `tercero_id` y al tercero le falta uno, la factura **no se crea** (`422 DATOS_FACTURA_INVALIDOS` con la lista de campos faltantes en el mensaje). Si usas el objeto `tercero`, envíalos desde el inicio:

- `direccion1` — dirección principal.
- `telefono1` — teléfono principal.
- `municipio_id` — municipio (mayor que 0).
- `email` — correo electrónico (obligatorio con la facturación electrónica activa).
- `documento` — número de documento del tercero.

<p class="callout danger">**El tercero y la factura no comparten conexión.** Si nuby crea el tercero y la factura falla después, el tercero **queda creado**. No es un duplicado: el reintento lo resuelve por <span style="color: rgb(52, 73, 94);">`documento`</span>. Tenlo en cuenta al conciliar tus datos.</p>

##### 🔹 **Ejemplos de petición**

#### 📌 Ejemplo mínimo (tercero existente, factura a crédito)

```json
{
  "referencia_externa": "INV-2026-0001",
  "tercero_id": 4821,
  "fecha": "2026-10-21",
  "dias_vencimiento": 30,
  "moneda": "COP",
  "observaciones": "Administración octubre 2026",
  "pago_total": false,
  "items": [
    {
      "producto_id": 340,
      "descripcion": "Administración octubre 2026",
      "cantidad": 1,
      "valor_unitario": 1000000,
      "por_iva": 19,
      "iva": 190000
    }
  ]
}
```

#### 📌 Ejemplo con tercero incrustado y varios ítems

```json
{
  "referencia_externa": "INV-2026-0002",
  "tercero": {
    "documento": "900123456",
    "tipo_doc_id": 6,
    "nombre1": "ACME SAS",
    "direccion1": "Calle 10 # 20-30",
    "telefono1": "6044447417",
    "municipio_id": 1,
    "email": "facturacion@acme.com"
  },
  "fecha": "2026-10-21",
  "fecha_vencimiento": "2026-11-20",
  "moneda": "COP",
  "resolucion_id": 12,
  "observaciones": "Administración y servicios",
  "items": [
    {
      "producto_id": 340,
      "descripcion": "Administración octubre 2026",
      "cantidad": 1,
      "valor_unitario": 1000000,
      "por_iva": 19,
      "iva": 190000
    },
    {
      "producto_id": 512,
      "descripcion": "Servicio de aseo octubre 2026",
      "cantidad": 2,
      "valor_unitario": 150000,
      "por_iva": 19,
      "iva": 57000
    }
  ]
}
```

#### 📌 Ejemplo de contado, con formas de pago y anticipo

```json
{
  "referencia_externa": "INV-2026-0003",
  "tercero_id": 4821,
  "fecha": "2026-10-21",
  "pago_total": true,
  "formas_de_pago": [
    { "tipo_pago_id": 1, "valor": 1190000 }
  ],
  "anticipos": [ { "documento_id": 5 } ],
  "items": [
    {
      "producto_id": 340,
      "cantidad": 1,
      "valor_unitario": 1000000,
      "por_iva": 19,
      "iva": 190000
    }
  ]
}
```

</details>  <details><summary>4. La Respuesta (¿Qué te entregaremos?) ✅</summary>

Si todo es válido, nuby crea la factura en estado **borrador** con su contabilidad y responde `201`:

```json
{
  "success": true,
  "status": 201,
  "message": "Factura creada en borrador.",
  "body": {
    "factura_id": 10231,
    "estado_id": 5,
    "consecutivo": -1,
    "valor_total": 1190000,
    "valor_saldo": 1190000,
    "referencia_externa": "INV-2026-0001"
  },
  "idempotent_replay": false
}
```

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

<table><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`success`</td><td>booleano</td><td>`true` cuando la factura se creó. Los rechazos traen `false` y un `error_code`.</td></tr><tr><td>`status`</td><td>entero</td><td>Código HTTP replicado en el cuerpo. Aquí siempre `201`.</td></tr><tr><td>`message`</td><td>texto</td><td>Mensaje legible para la persona que opera la integración: *Factura creada en borrador.*</td></tr><tr><td>`body`</td><td>objeto</td><td>Resultado de la creación (tabla siguiente).</td></tr><tr><td>`idempotent_replay`</td><td>booleano</td><td>`false` en una creación nueva; `true` cuando la respuesta se recuperó de una solicitud anterior y no se ejecutó nada.</td></tr></tbody></table>

##### 🔹 **Campos de `body`**

<table><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`factura_id`</td><td>entero</td><td>Identificador interno del borrador. **Guárdalo**: es lo que necesitas para editarlo, emitirlo, consultar el detalle y pedir el PDF. **No** es el número de la factura.</td></tr><tr><td>`estado_id`</td><td>entero</td><td>Estado del documento. Aquí siempre `5` (Borrador).</td></tr><tr><td>`consecutivo`</td><td>entero</td><td>Marcador de "sin numerar": **cero o negativo**. El consecutivo real se asigna al emitir.</td></tr><tr><td>`valor_total`</td><td>numérico</td><td>Total del documento, calculado por nuby con los impuestos y descuentos del detalle.</td></tr><tr><td>`valor_saldo`</td><td>numérico</td><td>Saldo pendiente del documento. En un borrador recién creado coincide con el total; los anticipos aplicados lo reducen.</td></tr><tr><td>`referencia_externa`</td><td>texto</td><td>La misma referencia que enviaste, ya normalizada (sin espacios en los extremos). Queda asociada a la factura para el control de duplicados.</td></tr></tbody></table>

##### 🔹 **El borrador NO consume un consecutivo real**

En un borrador, `consecutivo` vale **cero o un número negativo** (por ejemplo `-1`). Ese valor es un marcador interno de "sin numerar": nuby lo asigna para que dos borradores nunca colisionen entre sí. **No lo interpretes como número de factura**, no lo muestres al cliente final y no lo uses como identificador de negocio. La garantía del contrato es que el borrador no gasta numeración; el valor exacto del marcador lo decide nuby, así que no lo compares con un número fijo.

##### 🔹 **Reintento de una solicitud ya completada (replay)**

Si repites la petición con la **misma** `referencia_externa` y el mismo contenido, nuby devuelve la respuesta original —con el mismo código HTTP— y le agrega la marca `idempotent_replay: true`. No se crea una segunda factura ni se consume contabilidad nueva:

```json
{
  "success": true,
  "status": 201,
  "message": "Factura creada en borrador.",
  "body": {
    "factura_id": 10231,
    "estado_id": 5,
    "consecutivo": -1,
    "valor_total": 1190000,
    "valor_saldo": 1190000,
    "referencia_externa": "INV-2026-0001"
  },
  "idempotent_replay": true
}
```

La marca viaja en la **raíz** de la respuesta. La misma referencia con un contenido distinto responde `409 IDEMPOTENCY_PAYLOAD_MISMATCH`: *La referencia externa ya fue usada con un payload distinto.* Usa una referencia nueva para una operación nueva.

##### 🔹 **Cómo leer los valores numéricos**

`valor_total` y `valor_saldo` llegan como números JSON; no los compares como texto. Para mostrarlos al usuario final, formatea con la moneda del documento (`moneda`, `COP` por defecto).

</details>  <details><summary>5. Seguridad y Posibles Errores ⚠️</summary>

##### 🔹 **¡Tu pase tiene fecha de caducidad!**

Por medidas de seguridad, el token que te entregamos **solo dura 1 hora**. Una vez transcurrido ese tiempo, el pase expira y el sistema bloquea el acceso. Cuando esto ocurra, tu sistema simplemente debe volver a consumir el servicio de **Login** para pedir un pase nuevo y reintentar la operación con la **misma** `referencia_externa`: la solicitud que no llegó a procesarse no consumió la clave.

Así se ve el error que devuelve el sistema cuando el token venció o el pase es inválido:

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

<p class="callout info">**Ese `401` no viene del servicio de facturas** sino del middleware de autenticación de la API, así que su forma es distinta a la de los demás errores: no trae `success` ni `error_code`. En cambio los rechazos de la operación —validación, permisos, idempotencia y reglas de negocio— sí usan el sobre uniforme que se describe más abajo.</p>

##### 🔹 **Sobre uniforme de error**

<table><thead><tr><th>Campo</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td>`success`</td><td>booleano</td><td>Siempre `false`.</td></tr><tr><td>`status`</td><td>entero</td><td>El código HTTP, replicado en el cuerpo.</td></tr><tr><td>`message`</td><td>texto</td><td>Explicación legible del rechazo.</td></tr><tr><td>`error_code`</td><td>texto</td><td>Código estable de negocio. **Programa contra este campo**, nunca contra el mensaje.</td></tr><tr><td>`errors`</td><td>objeto</td><td>Solo en rechazos de validación: causas por campo. En los ítems, la clave es `items.<indice>.<campo>`.</td></tr><tr><td>`warnings`</td><td>arreglo</td><td>Solo cuando la operación se rechaza o se condiciona por alcance. Cada elemento trae `code`, `scope` y, según el caso, `factura_id`.</td></tr></tbody></table>

##### 🔹 **Tabla de códigos HTTP, causas y mensajes**

<table><thead><tr><th>HTTP</th><th>`error_code`</th><th>Causa y mensaje exacto</th></tr></thead><tbody><tr><td>`400`</td><td>`VALIDATION_ERROR`</td><td>El cuerpo no es un objeto JSON. *El cuerpo de la solicitud debe ser un objeto JSON.*</td></tr><tr><td>`400`</td><td>—</td><td>El encabezado `Authorization` no tiene el formato `Bearer {token}`. *JWT Token not send.*</td></tr><tr><td>`401`</td><td>—</td><td>No se envió el encabezado `Authorization`. *JWT Token required.*</td></tr><tr><td>`401`</td><td>—</td><td>El token no existe en el sistema. *JWT Token not found.*</td></tr><tr><td>`401`</td><td>—</td><td>El token expiró (dura 1 hora). *JWT Token expired.* Vuelve a consumir **Login**.</td></tr><tr><td>`403`</td><td>`CONSUMIDOR_NO_AUTENTICADO`</td><td>El token es válido pero no corresponde a un cliente OAuth habilitado. *El cliente autenticado no está autorizado para consumir este endpoint.*</td></tr><tr><td>`403`</td><td>`RECURSO_NO_AUTORIZADO`</td><td>Al cliente OAuth le falta el permiso `invoices:create`. *El consumidor no tiene habilitado el recurso solicitado.*</td></tr><tr><td>`409`</td><td>`IDEMPOTENCY_IN_PROGRESS`</td><td>Hay una solicitud en curso con esa referencia. *La solicitud con esta referencia externa está en proceso.*</td></tr><tr><td>`409`</td><td>`IDEMPOTENCY_PAYLOAD_MISMATCH`</td><td>La referencia ya se usó con otro contenido. *La referencia externa ya fue usada con un payload distinto.*</td></tr><tr><td>`422`</td><td>`VALIDATION_ERROR`</td><td>Falta `referencia_externa` (*El campo "referencia\_externa" es obligatorio.*), el payload no cumple el formato (*El payload no es válido.*) o un ítem es inválido. Trae `errors` por campo.</td></tr><tr><td>`422`</td><td>`FACTURA_CONTRATO_NO_PERMITIDA`</td><td>El payload trae `movimiento_id`, `contrato_id`, `procesado`, `documento_respaldo_id` o `inmobiliaria` con valor. Incluye `warnings[]`. Mensaje: *El payload intenta crear o modificar una factura con datos de contrato ({campo}). Esta API solo crea facturas de venta; las facturas de contrato se generan desde el flujo de contratos.*</td></tr><tr><td>`422`</td><td>`CAMPO_NO_PERMITIDO`</td><td>El payload intenta fijar un campo del sistema. *El payload intenta fijar el campo {campo}, que solo el sistema puede asignar en una factura de venta.*</td></tr><tr><td>`422`</td><td>`FACTURACION_ELECTRONICA_DESHABILITADA`</td><td>`ENABLE_FACT_ELECT` no vale `1`. No se escribe nada. *La facturación electrónica no está habilitada en este sistema, así que no se pueden crear borradores de facturas de venta por API.*</td></tr><tr><td>`422`</td><td>`RESOLUCION_CONTRATO_NO_PERMITIDA`</td><td>El `resolucion_id` es una resolución de contrato. *La resolución {resolucion\_id} se usa para facturas de contrato. Esta API solo admite resoluciones de facturación de venta.*</td></tr><tr><td>`422`</td><td>`RESOLUCION_NO_DISPONIBLE`</td><td>No hay resolución de venta activa, o la enviada no existe o no está activa para facturación. *No hay una resolución de facturación de venta activa disponible para crear la factura.*</td></tr><tr><td>`422`</td><td>`PERIODO_CONTABLE_NO_ABIERTO`</td><td>La fecha no cae en ningún período contable abierto. *No existe un período contable abierto para la fecha {fecha}. Debe abrirse el período antes de facturar.*</td></tr><tr><td>`422`</td><td>`PERIODO_CONTABLE_CERRADO`</td><td>La fecha cae en un período contable cerrado. *El período contable de la fecha {fecha} está cerrado. No se pueden registrar movimientos.*</td></tr><tr><td>`422`</td><td>`DATOS_FACTURA_INVALIDOS`</td><td>El motor de facturación rechazó el documento (por ejemplo, un tercero con datos fiscales incompletos). El `message` trae la causa concreta.</td></tr><tr><td>`500`</td><td>`INTERNAL_ERROR`</td><td>Fallo técnico. El mensaje es genérico a propósito: *No fue posible crear la factura de venta. Intente nuevamente o contacte al administrador del sistema.*</td></tr><tr><td>`500`</td><td>`IDEMPOTENCY_STORAGE_ERROR`</td><td>No se pudo registrar la solicitud para controlar duplicados. *No se pudo registrar la solicitud de idempotencia.*</td></tr></tbody></table>

<p class="callout info">**Este servicio no devuelve `409` de estado ni `502` de la DIAN.** Aquí no hay factura previa que pueda estar fuera de borrador ni se envía nada a la DIAN: esos códigos aparecen al [**editar el borrador**](https://docs.nuby.ai/editar-factura-borrador.html) y al [**emitir la factura**](https://docs.nuby.ai/emitir-factura-dian.html).</p>

##### 🔹 **Ejemplo de rechazo de validación por campo**

```json
{
  "success": false,
  "status": 422,
  "message": "El payload no es válido.",
  "error_code": "VALIDATION_ERROR",
  "errors": {
    "dias_vencimiento": [
      "Los días de vencimiento son obligatorios y deben ser un entero mayor o igual a 1."
    ],
    "items.0.valor_unitario": [
      "valor_unitario debe ser numérico y distinto de 0."
    ]
  }
}
```

##### 🔹 **Reglas de reintento**

<table><thead><tr><th>Situación</th><th>Qué hace nuby con la referencia</th><th>Qué debes hacer</th></tr></thead><tbody><tr><td>Rechazo `422` de negocio</td><td>**Libera** la referencia externa</td><td>Corrige el payload y reintenta con la **misma** referencia.</td></tr><tr><td>Fallo `500` o `502`</td><td>Deja la solicitud **fallida**</td><td>Reintenta con la misma referencia.</td></tr><tr><td>Éxito `201`</td><td>Deja la solicitud **completada**</td><td>No la reutilices. Una operación nueva necesita una referencia nueva.</td></tr><tr><td>`403`, `401`, `400`</td><td>No se reserva ni se consume la referencia</td><td>Corrige el acceso, el token o el cuerpo y reintenta con la misma referencia.</td></tr></tbody></table>

</details>  <details><summary>6. Ejemplos de integración 💻</summary>

Aquí tienes ejemplos listos para que tus desarrolladores los adapten a tu plataforma. Todos guardan la relación `referencia_externa → factura_id`, que es lo que permite reintentar sin duplicar.

#### 📌 cURL

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

curl -X POST "https://${INSTANCIA}/service/v2/public/invoices" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "referencia_externa": "INV-2026-0001",
    "tercero_id": 4821,
    "fecha": "2026-10-21",
    "dias_vencimiento": 30,
    "moneda": "COP",
    "observaciones": "Administración octubre 2026",
    "pago_total": false,
    "items": [
      {
        "producto_id": 340,
        "descripcion": "Administración octubre 2026",
        "cantidad": 1,
        "valor_unitario": 1000000,
        "por_iva": 19,
        "iva": 190000
      }
    ]
  }'
```

#### 📌 PHP

```php
<?php

$instancia = 'mi-inmobiliaria.nuby.app'; // Reemplaza con tu dirección web completa
$token = 'TU_TOKEN_AQUI';                // Token obtenido del servicio Login

$url = "https://{$instancia}/service/v2/public/invoices";

$payload = [
    'referencia_externa' => 'INV-2026-0001',
    'tercero_id' => 4821,
    'fecha' => '2026-10-21',
    'dias_vencimiento' => 30,
    'moneda' => 'COP',
    'observaciones' => 'Administración octubre 2026',
    'pago_total' => false,
    'items' => [
        [
            'producto_id' => 340,
            'descripcion' => 'Administración octubre 2026',
            'cantidad' => 1,
            'valor_unitario' => 1000000,
            'por_iva' => 19,
            'iva' => 190000,
        ],
    ],
];

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

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

if (curl_errno($ch)) {
    // Timeout o caída de red: reintenta con la MISMA referencia externa.
    echo 'Error de conexión: ' . curl_error($ch);
} else {
    $info = json_decode($respuesta, true);

    if ($httpCode === 201) {
        $facturaId = $info['body']['factura_id'];

        echo "Borrador creado: factura_id={$facturaId}"
            . " consecutivo={$info['body']['consecutivo']}"
            . " total={$info['body']['valor_total']}\n";

        if (!empty($info['idempotent_replay'])) {
            echo "Nota: fue un reintento idempotente, no se creó otra factura.\n";
        }
    } else {
        echo "Rechazo HTTP {$httpCode}: {$info['message']}\n";
        echo "error_code: " . ($info['error_code'] ?? 'N/A') . "\n";

        if (!empty($info['errors'])) {
            print_r($info['errors']);
        }
    }
}

curl_close($ch);

?>
```

#### 📌 Python

```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 el cuerpo
url = f"https://{instancia}/service/v2/public/invoices"

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

payload = {
    "referencia_externa": "INV-2026-0001",
    "tercero_id": 4821,
    "fecha": "2026-10-21",
    "dias_vencimiento": 30,
    "moneda": "COP",
    "observaciones": "Administración octubre 2026",
    "pago_total": False,
    "items": [
        {
            "producto_id": 340,
            "descripcion": "Administración octubre 2026",
            "cantidad": 1,
            "valor_unitario": 1000000,
            "por_iva": 19,
            "iva": 190000
        }
    ]
}

# 3. Envía la petición y procesa la respuesta
try:
    response = requests.post(url, json=payload, headers=headers, timeout=30)

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

    if response.status_code == 201:
        info = response.json()
        body = info.get("body", {})

        print(f"Borrador creado: factura_id={body.get('factura_id')}")
        print(f"Estado: {body.get('estado_id')} | Consecutivo (sin numerar): {body.get('consecutivo')}")
        print(f"Total: {body.get('valor_total')} | Saldo: {body.get('valor_saldo')}")

        if info.get("idempotent_replay"):
            print("Nota: reintento idempotente, no se creó otra factura.")
    else:
        info = response.json()
        print(f"Mensaje: {info.get('message')}")
        print(f"error_code: {info.get('error_code')}")

        for campo, errores in (info.get("errors") or {}).items():
            print(f"  {campo}: {errores}")

except Exception as e:
    # Ante un timeout, reintenta con la MISMA referencia_externa.
    print(f"Ocurrió un error de conexión: {e}")
```

#### 📌 JavaScript (Node.js / navegador)

```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 url = `https://${instancia}/service/v2/public/invoices`;

const payload = {
    referencia_externa: 'INV-2026-0001',
    tercero_id: 4821,
    fecha: '2026-10-21',
    dias_vencimiento: 30,
    moneda: 'COP',
    observaciones: 'Administración octubre 2026',
    pago_total: false,
    items: [
        {
            producto_id: 340,
            descripcion: 'Administración octubre 2026',
            cantidad: 1,
            valor_unitario: 1000000,
            por_iva: 19,
            iva: 190000
        }
    ]
};

// 2. Función para crear el borrador
async function crearBorrador() {
    try {
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            },
            body: JSON.stringify(payload)
        });

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

        const info = await response.json();

        if (response.status === 201) {
            const body = info.body || {};

            console.log(`Borrador creado: factura_id=${body.factura_id}`);
            console.log(`Estado: ${body.estado_id} | Consecutivo (sin numerar): ${body.consecutivo}`);
            console.log(`Total: ${body.valor_total} | Saldo: ${body.valor_saldo}`);

            if (info.idempotent_replay) {
                console.log('Nota: reintento idempotente, no se creó otra factura.');
            }
        } else {
            console.log(`Mensaje: ${info.message}`);
            console.log(`error_code: ${info.error_code}`);

            Object.entries(info.errors || {}).forEach(([campo, errores]) => {
                console.log(`  ${campo}: ${errores}`);
            });
        }
    } catch (error) {
        // Ante un timeout, reintenta con la MISMA referencia_externa.
        console.error(`Ocurrió un error de conexión: ${error}`);
    }
}

// 3. Ejecutamos la función
crearBorrador();
```

#### 📌 Power Query M (Excel / Power BI)

Power Query convierte la respuesta en una tabla de una fila con los datos del borrador. Si la petición devuelve un error HTTP, `Web.Contents` genera una excepción: captúrala con `try ... otherwise` para poder registrar el `error_code`.

```text
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/invoices",

    // 3. Construye el cuerpo JSON
    cuerpo = Json.FromValue([
        referencia_externa = "INV-2026-0001",
        tercero_id = 4821,
        fecha = "2026-10-21",
        dias_vencimiento = 30,
        moneda = "COP",
        observaciones = "Administración octubre 2026",
        pago_total = false,
        items = {
            [
                producto_id = 340,
                descripcion = "Administración octubre 2026",
                cantidad = 1,
                valor_unitario = 1000000,
                por_iva = 19,
                iva = 190000
            ]
        }
    ]),

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

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

    // 6. Convierte el resultado en tabla
    tabla = Table.FromRecords({body}),
    expandido = Table.ExpandRecordColumn(tabla, "Column1",
        {"factura_id", "estado_id", "consecutivo", "valor_total", "valor_saldo", "referencia_externa"},
        {"FacturaID", "EstadoID", "ConsecutivoSinNumerar", "ValorTotal", "ValorSaldo", "ReferenciaExterna"})
in
    expandido
```

<p class="callout info">**Siguiente paso:** con el `factura_id` en mano, revisa [**Editar Factura en Borrador**](https://docs.nuby.ai/editar-factura-borrador.html) para ajustar el documento y [**Emitir Factura a la DIAN**](https://docs.nuby.ai/emitir-factura-dian.html) para convertirlo en documento legal. Para consultarlo, revisa [**Ver Detalle de una Factura**](https://docs.nuby.ai/ver-detalle-factura.html).</p>

</details></div></div>