Cobros
Cuentas por cobrar (CxC): registra el dinero que recibes de un cliente y aplícalo contra una o varias facturas a crédito (abono parcial o pago consolidado). Lo que no se aplica queda como anticipo (saldo a favor del cliente) para aplicarlo después, y un cobro también puede cancelarse con cruce contra cuentas contables. Incluye reportes de cartera por antigüedad y estado de cuenta por cliente.
Autenticación
X-API-Key con una API key que tenga permisos sobre el
recurso cobros. Igual que el resto de la API, el tenant se
resuelve por la propia key (no hace falta X-Tenant-Id en
integraciones vía API pública).
Registrar un cobro
POST /api/v1/cobros — Crea un cobro y sus aplicaciones a factura(s)
Body
| Parámetro | Tipo | Descripción |
|---|---|---|
cliente_id required | integer | Id del cliente (PersonaEmpresa con es_cliente=true). |
fecha required | datetime | Fecha en que se recibió el dinero (ISO 8601). No puede ser futura ni caer en un período contable cerrado (400). Ver fechas contables. |
medio required | string | Medio de pago — código de la Tabla 24 SRI (ej. '01' efectivo, '16' t. débito, '19' t. crédito). '15' (compensación de deudas) para un cobro con cruce. |
monto required | number | Dinero recibido. Σ aplicaciones.monto_aplicado debe ser ≤ monto (±0.01); lo que sobra queda como anticipo (monto_anticipo). Las retenciones no cuentan contra el monto. |
referencia optional | string | Referencia libre (n° de depósito, transferencia, etc). Máx 120 caracteres. |
notas optional | string | Notas internas. |
cuenta_dinero_id optional | integer | Cuenta de caja/banco donde ingresó el dinero: crea el movimiento en ella (ver Cuentas y bancos). Si se omite y la empresa tiene una sola cuenta activa del tipo que corresponde al medio ('01' caja, '16'/'19' tarjeta, '20' banco), se usa esa. No se admite en un cobro con cruce. |
sucursal_id optional | integer | Sucursal de trazabilidad. Si se omite, se infiere del usuario. |
aplicaciones optional | array | Documentos que cancela. Puede ir vacío (anticipo puro, con monto > 0). Default []. |
cruce optional | array | Líneas contables de un cobro con cruce (ver más abajo). Default []. |
Forma de aplicaciones[]
| Parámetro | Tipo | Descripción |
|---|---|---|
factura_id optional | integer | Factura a la que se aplica. Exactamente uno de factura_id o nota_debito_id. |
nota_debito_id optional | integer | Nota de débito a la que se aplica. |
monto_aplicado required | number | Monto aplicado a ese documento. Con las retenciones de la línea, no puede superar su saldo pendiente. |
retencion_renta / retencion_iva optional | number | Retención recibida del cliente: reduce el saldo del documento pero no es dinero (no cuenta contra monto). |
import { Emitoo } from "emitoo";
const client = new Emitoo(); // lee la API key de EMITOO_API_KEY
const cobro = await client.cobros.crear({
cliente_id: 12,
fecha: new Date().toISOString(),
medio: "01",
monto: 150.0,
referencia: "DEP-88213",
aplicaciones: [
{ factura_id: 177, monto_aplicado: 100.0 },
{ factura_id: 181, monto_aplicado: 50.0 },
],
});from emitoo import EmitooClient
client = EmitooClient() # lee la API key de EMITOO_API_KEY
cobro = client.cobros.crear({
"cliente_id": 12,
"fecha": "2026-07-06T15:00:00",
"medio": "01",
"monto": 150.00,
"referencia": "DEP-88213",
"aplicaciones": [
{"factura_id": 177, "monto_aplicado": 100.00},
{"factura_id": 181, "monto_aplicado": 50.00},
],
})client, err := emitoo.New("") // lee la API key de EMITOO_API_KEY
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
cobro, err := client.Cobros.Crear(ctx, emitoo.M{
"cliente_id": 12,
"fecha": time.Now().Format(time.RFC3339),
"medio": "01",
"monto": 150.0,
"referencia": "DEP-88213",
"aplicaciones": []emitoo.M{
{"factura_id": 177, "monto_aplicado": 100.0},
{"factura_id": 181, "monto_aplicado": 50.0},
},
})
if err != nil {
log.Fatal(err)
}curl -X POST https://api.emitoo.io/api/v1/cobros \
-H "X-API-Key: $EMITOO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cliente_id": 12,
"fecha": "2026-07-06T15:00:00",
"medio": "01",
"monto": 150.00,
"referencia": "DEP-88213",
"aplicaciones": [
{ "factura_id": 177, "monto_aplicado": 100.00 },
{ "factura_id": 181, "monto_aplicado": 50.00 }
]
}'Respuesta (201 Created)
{
"id": 88,
"fecha": "2026-07-06T15:00:00",
"cliente_id": 12,
"medio": "01",
"monto": 150.0,
"referencia": "DEP-88213",
"notas": null,
"cuenta_dinero_id": null,
"anulado": false,
"anulado_motivo": null,
"anulado_en": null,
"monto_anticipo": 0,
"saldo_anticipo": 0,
"cruce_lineas": [],
"creado_en": "2026-07-06T15:00:03",
"aplicaciones": [
{ "id": 101, "factura_id": 177, "monto_aplicado": 100.0, "desde_anticipo": false, "fecha_aplicacion": null },
{ "id": 102, "factura_id": 181, "monto_aplicado": 50.0, "desde_anticipo": false, "fecha_aplicacion": null }
]
}Errores
| Código | Cuándo ocurre |
|---|---|
400 | fecha futura o en un período contable cerrado; una línea de cruce inválida (ver cobros con cruce). |
404 | El cliente no existe, o alguna de las facturas referenciadas en aplicaciones no existe. |
409 | Una factura no está AUTORIZADA, o el monto_aplicado de una línea supera su saldo pendiente. |
422 | El medio no es un código válido de la Tabla 24 SRI, Σ(aplicaciones) supera monto, no hay aplicaciones y monto es 0, o un cruce que no cumple sus reglas de forma. |
Listar cobros
GET /api/v1/cobros?cliente_id=&desde=&hasta=&limit=&offset= — Listado con filtros opcionales
| Parámetro | Tipo | Descripción |
|---|---|---|
cliente_id optional | integer | Filtra por cliente. |
desde optional | date | Fecha inicial (inclusive). |
hasta optional | date | Fecha final (inclusive). |
limit optional | integer | Default 50. |
offset optional | integer | Default 0. |
Obtener un cobro
GET /api/v1/cobros/{id} — Detalle completo, con sus aplicaciones a factura
Anular un cobro
POST /api/v1/cobros/{id}/anular — Anula el cobro y revierte sus aplicaciones (el saldo de las facturas vuelve a subir)
Body
| Parámetro | Tipo | Descripción |
|---|---|---|
motivo required | string | Motivo de la anulación. Máx 300 caracteres. |
fecha optional | date | Fecha del reverso (asiento espejo y movimiento inverso en el banco), YYYY-MM-DD. Si se omite: la del cobro si su período sigue abierto; si no, hoy. Dada: no futura, no anterior al cobro, en un período abierto y fuera de una conciliación bancaria cerrada (400). |
Cuándo no se puede anular
409, igual
que anular un cobro cuyo anticipo ya se aplicó a documentos (primero
deshaz esas aplicaciones) o cuyo ingreso al banco
está en una conciliación bancaria cerrada. Si necesitas corregir el monto o
las facturas aplicadas, anula y crea un cobro nuevo; si solo está mal la
fecha, cámbiala.
Cambiar la fecha de un cobro
PATCH /api/v1/cobros/{id}/fecha — Corrige la fecha del cobro, de su ingreso en el banco y de su asiento (sin rehacerlo)
| Parámetro | Tipo | Descripción |
|---|---|---|
fecha required | date | Body. Nueva fecha (YYYY-MM-DD); se conserva la hora original. |
{
"fecha": "2026-09-28T15:00:00",
"asiento_movido": true,
"avisos": []
} asiento_movido indica si el cobro tenía asiento y se movió con
él (mismo número); avisos lista efectos colaterales (por
ejemplo, el ingreso se desmarcó de una conciliación en curso). Si parte del
anticipo ya se aplicó, el cobro no puede quedar después de esa aplicación.
Reglas comunes en fechas
contables: 400 por fecha inválida, 409 si el
cobro está anulado o el cambio toca una conciliación bancaria cerrada.
Cobros con cruce
Un cobro con cruce cancela facturas o notas de débito
contra una o varias cuentas contables en vez de caja o bancos (por ejemplo,
compensar con lo que le debes a ese cliente). No mueve dinero y genera el
asiento Debe las cuentas del cruce / Haber cuentas por cobrar. Las líneas
tienen la misma forma y reglas que en
pagos con cruce:
medio "15", sin cuenta_dinero_id,
Σ cruce[].monto igual a monto al centavo y
aplicado completo a documentos (no deja anticipo); si no, 422.
La cuenta no puede ser de caja/bancos ni la propia cuenta por cobrar a
clientes (400). El cobro trae las líneas en
cruce_lineas.
{
"cliente_id": 12,
"fecha": "2026-10-06T10:00:00",
"medio": "15",
"monto": 300.00,
"aplicaciones": [
{ "factura_id": 205, "monto_aplicado": 300.00 }
],
"cruce": [
{ "cuenta_id": 2210, "monto": 300.00, "tercero_id": 12, "descripcion": "Compensación con CxP al cliente" }
]
}Anticipos (saldo a favor)
Un cobro que recibe más de lo que aplica deja la diferencia como
anticipo: monto_anticipo es lo que quedó sin
aplicar al crearlo y saldo_anticipo lo que falta aplicar.
Contablemente es un pasivo (201.10 Anticipos de clientes) hasta que se
aplica a una factura o nota de débito del mismo cliente. Aplicarlo baja el
saldo del documento sin mover dinero y genera su propio
asiento con la fecha de aplicación.
Registrar un anticipo y aplicarlo después
Registrar un anticipo emite el evento cobro.registrado de
siempre; aplicarlo emite factura.pagada (o
nota_debito.pagada) si el documento queda en cero. No hay
eventos propios de anticipos.
const cobro = await client.cobros.crear({
cliente_id: 12,
fecha: new Date().toISOString(),
medio: "20",
monto: 1000.0,
cuenta_dinero_id: 3,
aplicaciones: [], // todo queda como anticipo
});
// Cuando emites la factura:
await client.cobros.aplicarAnticipo(cobro.id, {
fecha: "2026-09-15",
aplicaciones: [{ factura_id: 190, monto_aplicado: 400.0 }],
});cobro = client.cobros.crear({
"cliente_id": 12,
"fecha": "2026-09-01T10:00:00",
"medio": "20",
"monto": 1000.00,
"cuenta_dinero_id": 3,
"aplicaciones": [], # todo queda como anticipo
})
# Cuando emites la factura:
client.cobros.aplicar_anticipo(cobro["id"], {
"fecha": "2026-09-15",
"aplicaciones": [{"factura_id": 190, "monto_aplicado": 400.00}],
})cobro, err := client.Cobros.Crear(ctx, emitoo.M{
"cliente_id": 12,
"fecha": time.Now().Format(time.RFC3339),
"medio": "20",
"monto": 1000.0,
"cuenta_dinero_id": 3,
"aplicaciones": []emitoo.M{}, // todo queda como anticipo
})
if err != nil {
log.Fatal(err)
}
// Cuando emites la factura:
_, err = client.Cobros.AplicarAnticipo(ctx, int(cobro["id"].(float64)), emitoo.M{
"fecha": "2026-09-15",
"aplicaciones": []emitoo.M{{"factura_id": 190, "monto_aplicado": 400.0}},
})curl -X POST https://api.emitoo.io/api/v1/cobros \
-H "X-API-Key: $EMITOO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cliente_id": 12,
"fecha": "2026-09-01T10:00:00",
"medio": "20",
"monto": 1000.00,
"referencia": "TRF-1",
"cuenta_dinero_id": 3,
"aplicaciones": []
}'Anticipos por aplicar
GET /api/v1/cobros/anticipos?cliente_id= — Cobros no anulados con saldo_anticipo > 0, del más antiguo al más reciente
[
{
"cobro_id": 95,
"fecha": "2026-09-01T10:00:00",
"cliente_id": 12,
"cliente_nombre": "ACME S.A.",
"referencia": "TRF-1",
"monto_anticipo": 1000.0,
"saldo_anticipo": 600.0
}
]Aplicar un anticipo
POST /api/v1/cobros/{id}/aplicar-anticipo — Aplica el anticipo del cobro a facturas o notas de débito del mismo cliente
{
"fecha": "2026-09-15",
"aplicaciones": [
{ "factura_id": 190, "monto_aplicado": 400.00 }
]
}
Devuelve el cobro con la nueva aplicación (desde_anticipo: true
y su fecha_aplicacion).
| Código | Cuándo ocurre |
|---|---|
404 | El cobro o un documento no existen (o no son del tenant). |
409 | Cobro anulado; Σ aplicado supera saldo_anticipo; documento de otro cliente o no cobrable; monto mayor al saldo del documento; fecha anterior a la del cobro. |
400 | Una aplicación trae factura y nota de débito a la vez, o ninguna; fecha futura o en un período cerrado. |
Deshacer una aplicación del anticipo
DELETE /api/v1/cobros/{id}/aplicaciones/{aplicacion_id}?fecha= — Devuelve el saldo al documento y al anticipo, y revierte su asiento
Solo para aplicaciones hechas desde el anticipo (409 si la
aplicación se hizo con el cobro). fecha (query, opcional) es
la del reverso del asiento; sin ella, la de la aplicación si su período
sigue abierto (400 si no es válida). Devuelve el cobro
actualizado.
Cartera por antigüedad
GET /api/v1/cobros/cartera — Saldo pendiente agrupado en buckets 0-30 / 31-60 / 61-90 / 90+ días
Los días se cuentan desde fecha_vencimiento de cada factura
a crédito con saldo pendiente.
{
"buckets": [
{ "dias": "0-30", "total": 1240.50, "cantidad": 8 },
{ "dias": "31-60", "total": 430.00, "cantidad": 3 },
{ "dias": "61-90", "total": 0, "cantidad": 0 },
{ "dias": "90+", "total": 210.00, "cantidad": 1 }
],
"total_general": 1880.50
}Estado de cuenta de un cliente
GET /api/v1/cobros/estado-cuenta/{cliente_id} — Facturas, cobros y notas de crédito aplicadas, con saldo corrido
saldo_a_favor es la suma de los anticipos del cliente aún sin
aplicar; se informa aparte y no se resta de saldo_pendiente.
{
"cliente_id": 12,
"cliente_razon_social": "ACME S.A.",
"cliente_identificacion": "0991234567001",
"lineas": [
{
"factura_id": 177,
"numero_comprobante": "001-001-000000177",
"fecha_emision": "2026-07-03T10:12:34",
"fecha_vencimiento": "2026-08-02",
"total": 150.0,
"total_cobrado": 100.0,
"total_nc_aplicadas": 0,
"saldo": 50.0
}
],
"total_facturado": 150.0,
"total_cobrado": 100.0,
"total_nc": 0,
"total_retenido": 0,
"saldo_pendiente": 50.0,
"saldo_a_favor": 600.0
}Exportar a CSV
GET /api/v1/cobros/estado-cuenta/{cliente_id}?format=csv — Mismo reporte, como archivo CSV descargable
Como todas las descargas CSV de la API, el archivo empieza con el BOM UTF-8
para que Excel muestre bien las tildes y la ñ. Si lo lees por código, usa
utf-8-sig (Python) o descarta el primer carácter
\uFEFF.
Exportar a PDF
GET /api/v1/cobros/estado-cuenta/{cliente_id}/pdf — El mismo reporte, como PDF (Content-Type: application/pdf)
Eventos
Este módulo emite los siguientes eventos:
| Evento | Cuándo se dispara |
|---|---|
cobro.registrado | Se creó un cobro (POST /cobros). |
cobro.anulado | Se anuló un cobro (POST /cobros/{id}/anular). |
factura.pagada | El saldo de una factura llegó a 0 tras aplicar un cobro, un anticipo o una nota de crédito. |
factura.por_vencer | Una factura a crédito con saldo vence en 3 días. Lo emite un job diario a las 07:00 (America/Guayaquil). |
factura.vencida | Una factura a crédito con saldo venció ayer. Mismo job diario a las 07:00 (America/Guayaquil). |
// POST https://tu-app.com/webhooks/emitoo
// X-Emitoo-Event: cobro.registrado
{
"evento": "cobro.registrado",
"data": {
"id": 88,
"cliente_id": 12,
"medio": "01",
"monto": 150.0,
"referencia": "DEP-88213",
"aplicaciones": [
{ "factura_id": 177, "monto_aplicado": 100.0 },
{ "factura_id": 181, "monto_aplicado": 50.0 }
]
}
}Recordatorios automáticos de cobro
factura.por_vencer con un
workflow y el nodo de acción de email
para enviar recordatorios de pago automáticos a tus clientes 3 días antes
del vencimiento, sin escribir código.