Facturas
El ciclo completo de una factura desde tu sistema: borrador, emisión, envío, cobro y cancelación.
Descripción general
Una factura nace como borrador y solo se vuelve definitiva cuando la emites. Emitir es una acción explícita e irreversible: consume el timbrado de tu plan cuando aplica (CFDI en México) y deja la factura con su número. Crear nunca emite por sí solo.
La API de facturas está disponible en todos los planes, incluido Gratis, con facturas comerciales (proforma en México y España). La emisión fiscal integrada (CFDI en México, y Verifactu en España con el certificado electrónico cargado) requiere Starter o superior: pedir document_mode: "fiscal" sin ese plan responde 400 invalid_request.
Listar facturas
GET /api/v1/facturas con estos filtros opcionales:
| Parámetro | Qué hace |
|---|---|
estado |
draft, open, paid, void, uncollectible u overdue (abiertas con el vencimiento ya pasado). |
cliente |
Id del cliente. |
desde, hasta |
Rango por fecha de creación, YYYY-MM-DD, ambos extremos incluidos. |
q |
Busca por número, folio fiscal, folio de la cotización de origen o nombre del cliente. |
limit |
De 1 a 200; por defecto 50. |
cursor |
El next_cursor de la página anterior. |
La paginación es por cursor, no por desplazamiento: una factura nueva no mueve la página que estás leyendo.
curl "https://cordhq.app/api/v1/facturas?limit=20" \
-H "Authorization: Bearer sk_live_tU..."
{
"data": [
{
"id": "f3a1c7e9-2b4d-4f6a-8c0e-5d7b9a1c3e24", "numero": "F-0231", "folio_fiscal": "6F1C2A9E-7B4D-4E6A-8C2F-1D5B9E3A7C40", "cliente": "Aceros del Norte",
"estado": "open", "estado_fiscal": "issued", "pais": "MX", "tipo": "cfdi_40",
"moneda": "MXN", "total": 184300, "pagado": 0, "saldo": 184300,
"vence": "2026-10-15", "vencida": false, "cotizacion_id": "2a9d8e4f-6b1c-4d7a-9e3f-5c8b1a2d4e6f", "creada": "15 sep 2026", "language": "es"
}
],
"meta": { "next_cursor": null }
}
creada llega como fecha de presentación (15 sep 2026), no como fecha ISO; vence sí es AAAA-MM-DD.
| Campo | Valores |
|---|---|
estado |
draft (borrador), open (emitida y por cobrar), paid (pagada), void (anulada) o uncollectible (incobrable). |
estado_fiscal |
pending, issued (registrada ante el proveedor fiscal), cancelled o error. |
tipo |
cfdi_40 (CFDI de ingreso, México), cfdi_egreso (nota de crédito CFDI), proforma (documento comercial en México, España y los países con factura autorizada), commercial_invoice (factura comercial), commercial_credit_note (nota de crédito comercial), verifactu_invoice o verifactu_credit_note (España con Verifactu). Con la emisión ante la autoridad activa: arca_invoice (Argentina), nfse_invoice y nfe_invoice (Brasil), sii_invoice (Chile), dian_invoice (Colombia) y sunat_invoice (Perú), con sus notas de crédito *_credit_note y, en Chile, sii_debit_note. |
language |
Solo lectura. El idioma en que el cliente recibe la factura, su PDF, su link y sus correos: es, en, pt, fr o de. La factura lo toma al emitirse, del cliente o, si no tiene uno, de tu organización; una nota de crédito lo hereda de su factura. null en un borrador. |
Crear un borrador
POST /api/v1/facturas crea un borrador. Requiere una llave con escritura y acepta Idempotency-Key.
| Campo | Obligatorio | Detalle |
|---|---|---|
cliente_id |
Sí | Un cliente de tu organización. |
items |
Sí | De 1 a 200 conceptos. Cada uno con descripcion y cantidad; opcionales precio_unitario, precio_negociado, producto_id, costo_unitario, tax_rate, exemption_reason y, en México, clave_sat y clave_unidad_sat. |
currency |
No | Divisa de la factura; por defecto la de tu cuenta. |
due_date |
No | Vencimiento en YYYY-MM-DD. |
notas |
No | Hasta 1000 caracteres. |
iva_incluido |
No | true si los precios ya traen el impuesto. |
document_mode |
No | commercial o fiscal. Sin él, Cord emite fiscal si tu plan lo incluye y tu país lo tiene habilitado, y comercial en otro caso. fiscal sin el plan o el país habilitado responde 400 invalid_request. |
fx_buffer_pct |
No | Cobertura en puntos porcentuales sobre el tipo de cambio de referencia cuando currency difiere de tu divisa contable (2 = +2%, tope 25). Por defecto 0. |
descuento |
No | Descuento de documento antes de impuestos: { "tipo": "porcentaje", "valor": 10 } o { "tipo": "monto", "valor": 2500 }. Cord calcula el importe y lo reparte entre los conceptos. Ver Descuentos y cupones. |
cupon |
No | Código de un cupón de tu cuenta. Manda sobre descuento. Su uso se cuenta al emitir la factura. |
service_date, service_date_end |
No | Fecha o periodo de prestación, YYYY-MM-DD. El fin requiere el inicio y no puede ser anterior. Sin ella, la factura indica que coincide con la fecha de emisión (obligatoria en Alemania). |
buyer_reference |
No | Referencia del comprador (BT-10 de la factura electrónica europea; en Alemania, el Leitweg-ID de la administración pública). Sin ella, la del cliente. Si la dirección electrónica del cliente es un Leitweg-ID, se comprueban sus dígitos de control y uno que no pase responde 400. |
purchase_order |
No | Número de la orden de compra del cliente (BT-13). |
tax_rate es una fracción (0.16, no 16) y se valida contra tu catálogo de impuestos: no puedes declarar una línea exenta en una venta gravada. 0 significa exenta a propósito; omitirla usa la tasa de tu cuenta. clave_sat y clave_unidad_sat ganan sobre las claves del producto; sin ninguna, el CFDI usa 01010101 y H87. Una clave con forma inválida responde 400.
curl -X POST "https://cordhq.app/api/v1/facturas" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: factura-pedido-8812" \
-d '{
"cliente_id": "9b2e4c6a-8d1f-4a3b-b5c7-0e2d4f6a8c91",
"currency": "MXN",
"due_date": "2026-10-15",
"items": [{ "descripcion": "Varilla 3/8\"", "cantidad": 120, "precio_unitario": 42, "tax_rate": 0.16 }]
}'
{ "data": { "id": "f3a1c7e9-2b4d-4f6a-8c0e-5d7b9a1c3e24" } }
Si la factura va en otra divisa que tu divisa contable y no se puede obtener un tipo de cambio verificable, responde 503 con code: "fx_unavailable": reintenta más tarde, Cord no inventa una tasa.
Consultar una factura
GET /api/v1/facturas/{id} devuelve los campos del listado más subtotal, impuestos, moneda_contable, tipo_cambio, total_contable, notas, nota_credito_de, emisor, receptor, descuento, conceptos y pagos.
| Campo | Detalle |
|---|---|
descuento |
null, o { tipo, valor, cupon, monto, moneda }: la definición, el cupón del que salió y el importe antes de impuestos. subtotal ya es neto. |
conceptos[].precio_unitario |
Precio unitario neto, después del descuento de documento, sin impuesto. |
conceptos[].subtotal |
Base neta del concepto. |
conceptos[].descuento |
La parte del descuento de documento que le tocó a ese concepto; 0 si no hay. |
conceptos[].clave_sat, conceptos[].clave_unidad_sat |
México: las claves del SAT con que se timbró el concepto; null fuera de México. |
pagos |
Cada pago con monto, moneda, metodo, referencia y cuando. Un cobro que pagó varias facturas aparece en cada una con la parte que le tocó. |
Cambiar el estado
POST /api/v1/facturas/{id} con action:
action |
Qué hace | Campos |
|---|---|---|
finalize |
Emite la factura. Irreversible; timbra el CFDI en México cuando aplica. | — |
send |
Envía el correo de la factura con su PDF al cliente, en el idioma de la factura (language). Exige una factura emitida y un cliente con correo. |
— |
payment |
Registra un pago, total o parcial. | monto, moneda, metodo (por defecto manual), referencia |
void |
Anula la factura. | motivo |
credit_note |
Emite una nota de crédito sobre la factura. | monto (opcional; sin él, por el total), motivo |
payment responde con lo pagado, el saldo y el estado resultante. Un pago que liquida la factura dispara el evento invoice.paid.
Si una factura ya timbrada no puede anularse directamente, void responde 409 con code: "credit_note_required": emite una nota de crédito.
En México:
voidpide la cancelación del CFDI con el motivo 02 del SAT. Si el SAT todavía no la confirma, responde202con{ "data": { "id": "…", "estado": "open", "cancelacion": "pendiente" } }y la factura sigue vigente; no se disparainvoice.voidedhasta que se confirma. La sustitución con el motivo 01 y la factura global solo están en la app.paymentsobre un CFDI PPD dispara el complemento de pago automático de ese cobro.
Errores frecuentes
| Código | Cuándo |
|---|---|
invalid_request (400) |
Falta cliente_id o items, una línea no trae descripción o cantidad, due_date no es YYYY-MM-DD, el descuento no tiene la forma { tipo, valor } o un Leitweg-ID no pasa sus dígitos de control. |
coupon_no_existe (404) |
El cupón no existe en tu cuenta. |
coupon_inactivo, coupon_vencido, coupon_aun_no_vigente, coupon_agotado, coupon_agotado_cliente, coupon_moneda, coupon_requiere_cliente (409) |
El cupón no aplica a esta factura; el mensaje dice por qué. |
invalid_state (409) |
La acción no aplica al estado actual (por ejemplo, enviar un borrador). Enviar a un cliente sin correo responde 400 con este mismo código. |
credit_note_required (409) |
La factura ya timbrada no se puede anular directamente: emite una nota de crédito. |
not_found (404) |
La factura no existe en tu organización. |
provider_error (502) |
El proveedor fiscal rechazó la emisión; el mensaje dice por qué. |
send_failed (502) |
No se pudo enviar el correo de la factura. Reintenta send. |
fx_unavailable, tax_catalog_unavailable (503) |
No hay tipo de cambio verificable o no se pudo leer tu catálogo de impuestos. Reintenta. |