Ir al contenido principal

Obtener Cartera [Beta]

Funcionalidad en pruebas
Esta funcionalidad forma parte de un proceso de pruebas internas y no se encuentra disponible para usuarios del sistema.

Permite a una pasarela de pagos autenticada (por ejemplo, Palomma) consultar la cartera pagable de un tercero: facturas pendientes, conceptos facturables, conceptos no facturables e intereses de mora adjuntos a facturas de canon. El sistema aplica automáticamente la configuración de filtros avanzados registrada para la pasarela autenticada.

¿Para qué sirve este servicio?
Está pensado exclusivamente para integraciones con pasarelas de pago. La pasarela lo consume para mostrarle al deudor los ítems que puede pagar en línea (facturas, conceptos e intereses), respetando la configuración comercial de la inmobiliaria (qué incluir, qué excluir, qué resoluciones se admiten, etc.).

Endpoint restringido a pasarelas registradas
Este endpoint solo puede ser consumido por clientes OAuth2 cuyo client_name esté registrado como una pasarela activa en la inmobiliaria. Cualquier otro cliente recibirá 403 Forbidden.


1. El Endpoint (La dirección web)

Apunta tu sistema a la siguiente dirección. Recuerda reemplazar {{instancia}} por la dirección web completa que utilizas para ingresar a tu plataforma.

GET https://{{instancia}}/service/v2/public/gateways/portfolio

¿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.

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

Este servicio requiere autenticación mediante un Token JWT obtenido por OAuth2. La pasarela se identifica automáticamente a partir del client_name del token; no debes enviarlo en el body ni como query string.

Método GET
Content-Type application/json
Authorization Bearer token, Token obtenido al consumir el servicio Login con un cliente OAuth2 registrado como pasarela activa.

Autenticación requerida
Este servicio requiere un Token de autenticación válido. Debes incluir el encabezado Authorization: Bearer TU_TOKEN en cada petición. El token se obtiene consumiendo el servicio de Login. El cliente OAuth además debe estar registrado como pasarela activa; en caso contrario el endpoint responderá 403.

Parámetros de consulta (query string):

Parámetro Tipo Requerido Por defecto Descripción
documento string No Número de documento del tercero (deudor) cuya cartera se desea consultar. Si se omite, se devolverá la cartera de todos los terceros que cumplan los demás filtros.
page integer No 1 Número de página de resultados que se desea recuperar.
page_size integer No 10 Número máximo de ítems por página. Valor máximo permitido: 1000.
pendientes boolean No true Si es true, se devuelven únicamente ítems con estado = "pendiente" y saldo > 0.
incluir_borrador boolean No false Si es true, incluye facturas en estado Borrador en el resultado.
incluir_conceptos_no_factura boolean No false Si es true, incluye conceptos pagables que aún no tienen factura emitida.
incluir_conceptos_futuros boolean No false Si es true, incluye conceptos cuyo periodo de aplicación es posterior a la fecha actual (cobros anticipados).
rango_conceptos_futuros_meses integer No null Cantidad de meses hacia adelante en los que se admite incluir conceptos futuros. Solo aplica si incluir_conceptos_futuros = true. Use null para no acotar.
incluir_intereses_mora boolean No false Si es true, los intereses de mora de una factura se devuelven adjuntos como ítems internos de su factura padre.
resolucion_ids array | string No Lista de IDs de resoluciones de facturación admitidas. Acepta un arreglo o una cadena separada por comas (por ejemplo: "3,7,12"). Solo se devuelven facturas emitidas con esas resoluciones.

Filtros avanzados de la pasarela
Los filtros enviados por el caller se combinan con la configuración de filtros avanzados registrada para la pasarela autenticada en la inmobiliaria. Si la pasarela no tiene configuración propia, se aplica el comportamiento por defecto (solo facturas con estado pendiente, sin borradores, sin conceptos sueltos ni intereses adjuntos). Los filtros realmente aplicados se devuelven en la respuesta dentro de filters_applied.

Exclusión de facturas a propietario
El endpoint excluye automáticamente las facturas cuyos detalles estén asociados a movimientos de tipo FACTURA_PROPIETARIO (por ejemplo, comisiones del contrato facturadas al propietario). Estas facturas siguen una lógica contable distinta —generan EGRESO_PROPIETARIO en lugar de INGRESO_INQUILINO— y no son pagables vía pasarela en esta versión. No se incluyen en la respuesta ni en el conteo total.

Ejemplos de peticiones:

GET https://{{instancia}}/service/v2/public/gateways/portfolio
GET https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050
GET https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050&pendientes=true&page=1&page_size=20
GET https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050&incluir_intereses_mora=true&incluir_conceptos_futuros=true&rango_conceptos_futuros_meses=3
GET https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050&resolucion_ids=3,7

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

El sistema devolverá una respuesta JSON con los ítems pagables del tercero, los filtros realmente aplicados y la información de paginación. Cada ítem se entrega con la misma estructura canónica, sin importar si representa una factura de contrato, una factura de venta, un concepto facturable, un concepto no facturable o una factura con intereses adjuntos.

{
    "success": true,
    "status": 200,
    "message": "La cartera de la pasarela fue consultada correctamente.",
    "body": [
        {
            "factura_id": 4521,
            "factura_numero": "291",
            "contrato_id": 187,
            "contrato_numero": "C-000187",
            "tercero_id": 272,
            "tercero_documento": "1020304050",
            "tercero_nombre": "ANA MARÍA PÉREZ RODRÍGUEZ",
            "fecha_vencimiento": "2026-04-30",
            "observaciones": "Canon de arrendamiento abril 2026, Administración abril 2026",
            "valor_total": 1750000.00,
            "saldo": 1750000.00,
            "estado": "pendiente",
            "items": [
                {
                    "movimiento_id": 98231,
                    "valor_unitario": 1600000.00,
                    "cantidad": 1,
                    "valor_iva": 0.00,
                    "valor_retencion": 0.00,
                    "valor_reteiva": 0.00,
                    "valor_reteica": 0.00,
                    "valor_descuento": 0.00
                },
                {
                    "movimiento_id": 98232,
                    "valor_unitario": 150000.00,
                    "cantidad": 1,
                    "valor_iva": 0.00,
                    "valor_retencion": 0.00,
                    "valor_reteiva": 0.00,
                    "valor_reteica": 0.00,
                    "valor_descuento": 0.00
                },
                {
                    "movimiento_id": 98410,
                    "valor_unitario": 35000.00,
                    "cantidad": 1,
                    "valor_iva": 0.00,
                    "valor_retencion": 0.00,
                    "valor_reteiva": 0.00,
                    "valor_reteica": 0.00,
                    "valor_descuento": 0.00
                }
            ]
        },
        {
            "factura_id": null,
            "factura_numero": null,
            "contrato_id": 187,
            "contrato_numero": "C-000187",
            "tercero_id": 272,
            "tercero_documento": "1020304050",
            "tercero_nombre": "ANA MARÍA PÉREZ RODRÍGUEZ",
            "fecha_vencimiento": "2026-05-15",
            "observaciones": "Reparación locativa baño principal",
            "valor_total": 280000.00,
            "saldo": 280000.00,
            "estado": "pendiente",
            "items": [
                {
                    "movimiento_id": 98515,
                    "valor_unitario": 280000.00,
                    "cantidad": 1,
                    "valor_iva": 0.00,
                    "valor_retencion": 0.00,
                    "valor_reteiva": 0.00,
                    "valor_reteica": 0.00,
                    "valor_descuento": 0.00
                }
            ]
        }
    ],
    "filters_applied": {
        "documento": "1020304050",
        "pendientes": true,
        "incluir_borrador": false,
        "incluir_conceptos_no_factura": true,
        "incluir_conceptos_futuros": false,
        "incluir_intereses_mora": true
    },
    "pagination": {
        "total_records": 2,
        "total_pages": 1,
        "current_page": 1,
        "page_size": 10,
        "current_page_records": 2,
        "has_next_page": false,
        "has_previous_page": false
    }
}
Campos de la respuesta
Clave Descripción
success Indica si la operación fue exitosa (true) o no (false).
status Código HTTP devuelto (debe coincidir con el código real de la respuesta).
message Mensaje descriptivo del resultado de la operación.
body Arreglo de ítems pagables (ver tabla detallada abajo). Puede ser vacío si no hay cartera.
filters_applied Objeto con los filtros realmente aplicados (combinación de los filtros del caller + la configuración de la pasarela).
pagination Objeto con la información de paginación (ver tabla detallada abajo).
Estructura de cada ítem (body[])
Clave Descripción
factura_id Identificador interno de la factura (PK en base de datos). null cuando el ítem corresponde a un concepto sin factura emitida (concepto facturable o no facturable). No es el número visible al usuario; ver factura_numero.
factura_numero Número consecutivo visible de la factura (mismo valor que se muestra como "Factura N°" en la interfaz de nuby). null cuando el ítem es un concepto sin factura emitida.
contrato_id Identificador del contrato asociado. null para facturas de venta sin contrato.
contrato_numero Número/código visible del contrato. null si no aplica.
tercero_id Identificador del tercero (deudor) al que pertenece el ítem.
tercero_documento Número de documento de identificación del tercero.
tercero_nombre Nombre completo (o razón social) del tercero.
fecha_vencimiento Fecha de vencimiento del ítem. Formato: YYYY-MM-DD.
observaciones Texto descriptivo del ítem (concatena los conceptos/productos cobrados).
valor_total Valor total original del ítem (suma de los renglones internos).
saldo Saldo pendiente por pagar a la fecha de la consulta.
estado Estado lógico del ítem. Valores posibles: "pendiente", "pagada", "anulada". Las facturas con estados internos fuera de alcance se omiten del resultado.
items Arreglo de renglones internos del ítem (ver tabla detallada abajo). Para facturas, contiene los movimientos que la componen y, si aplica, los intereses de mora adjuntos.
Mapeo de estados de factura
Estado interno Estado expuesto Descripción
1 (Facturada) "pendiente" Factura emitida y aún sin pagar.
5 (Borrador) "pendiente" Factura en estado borrador. Solo aparece si incluir_borrador = true.
2 (Anulada) "anulada" Factura anulada manualmente.
6 (Anulada por NC) "anulada" Factura anulada por nota crédito.
3 (Pagada) "pagada" Factura ya cancelada en su totalidad.
4, 7 Estados fuera de alcance. La factura se excluye del resultado.
Estructura de cada renglón interno (body[].items[])
Clave Descripción
movimiento_id Identificador del movimiento de contrato asociado al renglón. Puede ser null o 0 para renglones de facturas de venta sin movimiento.
valor_unitario Valor unitario del renglón (base, sin IVA ni retenciones).
cantidad Cantidad facturada.
valor_iva Valor del IVA aplicado al renglón.
valor_retencion Valor de la retención en la fuente aplicada.
valor_reteiva Valor de la retención de IVA aplicada.
valor_reteica Valor de la retención de ICA aplicada.
valor_descuento Valor del descuento aplicado al renglón.
Información de paginación (pagination)
Clave Descripción
total_records Cantidad total de ítems pagables que cumplen los filtros (sin paginar).
total_pages Cantidad total de páginas calculadas con el page_size solicitado.
current_page Página actualmente devuelta.
page_size Tamaño de página efectivamente aplicado.
current_page_records Cantidad de ítems devueltos en la página actual.
has_next_page true si existe una página siguiente.
has_previous_page true si existe una página anterior.

4. Seguridad y Posibles Errores

El sistema realiza validaciones de autenticación, autorización por pasarela y parámetros. Si alguna falla, devolverá un error con su respectivo código HTTP. La estructura del cuerpo de error siempre incluye success: false, status, message y body: [].

Código HTTP Descripción
400 Token faltante o inválido. Posibles causas:
— No se envió el encabezado Authorization.
— El encabezado no tiene el formato Bearer {token}.
— El token no fue encontrado en el sistema.

Parámetros inválidos. Posibles causas:
page no es un entero positivo.
page_size no es un entero positivo.
401 El token ha expirado. Debes generar uno nuevo consumiendo el servicio de Login.
403 El cliente OAuth autenticado no está registrado como pasarela activa en la inmobiliaria. Mensaje: "El cliente autenticado no esta autorizado para consumir este endpoint."
500 Error interno al resolver la cartera. El detalle se registra en el canal de log PASARELAS y al caller solo se le devuelve un mensaje genérico.

5. Ejemplos de integración

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

cURL
# Consultar la cartera del tercero con documento 1020304050
curl -X GET "https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050&pendientes=true&page=1&page_size=20" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"

# Cartera incluyendo intereses de mora y conceptos futuros (3 meses)
curl -X GET "https://{{instancia}}/service/v2/public/gateways/portfolio?documento=1020304050&incluir_intereses_mora=true&incluir_conceptos_futuros=true&rango_conceptos_futuros_meses=3" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_TOKEN_AQUI"
PHP
<?php

$instance = 'tu_instancia'; // Reemplaza con tu instancia real
$token = 'TU_TOKEN_AQUI'; // Token obtenido del servicio Login (cliente OAuth registrado como pasarela)

$queryParams = http_build_query([
    'documento' => '1020304050',
    'pendientes' => 'true',
    'incluir_intereses_mora' => 'true',
    'page' => 1,
    'page_size' => 20,
]);

$url = "https://{$instance}/service/v2/public/gateways/portfolio?{$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);
curl_close($ch);

echo "Código HTTP: {$http_code}\n";

if ($http_code === 200) {
    $data = json_decode($response, true);
    echo "Total ítems: " . ($data['pagination']['total_records'] ?? 0) . "\n";
    foreach ($data['body'] as $item) {
        $tipo = $item['factura_id'] ? "Factura #{$item['factura_id']}" : "Concepto";
        echo "  [{$tipo}] {$item['tercero_nombre']} - Saldo: {$item['saldo']} - Vence: {$item['fecha_vencimiento']}\n";
    }
} else {
    echo "Error consultando la cartera:\n{$response}\n";
}

?>
Python
import requests

# 1. Configura tus datos de acceso
instancia = 'mi-inmobiliaria.nuby.app'
token = 'TU_TOKEN_AQUI'  # Token de un cliente OAuth registrado como pasarela

# 2. Prepara la dirección y los parámetros
url = f"https://{instancia}/service/v2/public/gateways/portfolio"

params = {
    "documento": "1020304050",
    "pendientes": "true",
    "incluir_intereses_mora": "true",
    "page": 1,
    "page_size": 20,
}

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 HTTP: {response.status_code}")

    if response.status_code == 200:
        data = response.json()
        print(f"Total ítems: {data['pagination']['total_records']}")
        for item in data['body']:
            tipo = f"Factura #{item['factura_id']}" if item['factura_id'] else "Concepto"
            print(f"  [{tipo}] {item['tercero_nombre']} - Saldo: {item['saldo']} - Vence: {item['fecha_vencimiento']}")
    else:
        print("Error consultando la cartera.")
        print(response.text)
except Exception as e:
    print(f"Error de conexión: {e}")
JavaScript
// 1. Configura tus datos de acceso
const instancia = 'mi-inmobiliaria.nuby.app';
const token = 'TU_TOKEN_AQUI'; // Token de un cliente OAuth registrado como pasarela

// 2. Prepara la dirección con parámetros
const params = new URLSearchParams({
    documento: '1020304050',
    pendientes: 'true',
    incluir_intereses_mora: 'true',
    page: 1,
    page_size: 20,
});

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

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

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

        if (response.ok) {
            const data = await response.json();
            console.log(`Total ítems: ${data.pagination.total_records}`);
            data.body.forEach(item => {
                const tipo = item.factura_id ? `Factura #${item.factura_id}` : 'Concepto';
                console.log(`  [${tipo}] ${item.tercero_nombre} - Saldo: ${item.saldo} - Vence: ${item.fecha_vencimiento}`);
            });
        } else {
            const errorData = await response.text();
            console.log('Error consultando la cartera.');
            console.log(errorData);
        }
    } catch (error) {
        console.error(`Error de conexión: ${error}`);
    }
}

consultarCartera();