Skip to content

Invoices

An invoice’s full lifecycle from your system: draft, issue, send, collect and cancel.

Overview

An invoice is born as a draft and only becomes final when you issue it. Issuing is an explicit, irreversible action: it uses your plan’s stamping when it applies (CFDI in Mexico) and gives the invoice its number. Creating never issues on its own.

The invoices API is available on every plan, including Free, with standard invoices (pro forma in Mexico and Spain). Integrated tax issuing (CFDI in Mexico, and Verifactu in Spain with the electronic certificate uploaded) requires Starter or higher: requesting document_mode: "fiscal" without that plan responds 400 invalid_request.

List invoices

GET /api/v1/facturas with these optional filters:

Parameter What it does
estado draft, open, paid, void, uncollectible or overdue (open and past their due date).
cliente Client id.
desde, hasta Range by creation date, YYYY-MM-DD, both ends inclusive.
q Searches by number, tax folio, originating quote folio or client name.
limit From 1 to 200; defaults to 50.
cursor The previous page’s next_cursor.

Pagination is cursor-based, not offset-based: a new invoice never shifts the page you are reading.

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 comes as a display date (15 sep 2026), not an ISO date; vence is YYYY-MM-DD.

Field Values
estado draft, open (issued and awaiting payment), paid, void or uncollectible.
estado_fiscal pending, issued (registered with the tax provider), cancelled or error.
tipo cfdi_40 (income CFDI, Mexico), cfdi_egreso (CFDI credit note), proforma (commercial document in Mexico, Spain, and countries with authorized invoices), commercial_invoice (commercial invoice), commercial_credit_note (commercial credit note), verifactu_invoice or verifactu_credit_note (Spain with Verifactu). With issuing through the tax authority active: arca_invoice (Argentina), nfse_invoice and nfe_invoice (Brazil), sii_invoice (Chile), dian_invoice (Colombia), and sunat_invoice (Peru), with their *_credit_note credit notes and, in Chile, sii_debit_note.
language Read-only. The language in which the client receives the invoice, its PDF, its link, and its emails: es, en, pt, fr, or de. The invoice takes it when issued, from the client or, if they have none, from your organization; a credit note inherits its invoice’s. null on a draft.

Create a draft

POST /api/v1/facturas creates a draft. It needs a write key and accepts Idempotency-Key.

Field Required Detail
cliente_id Yes A client in your organization.
items Yes From 1 to 200 line items. Each with descripcion and cantidad; optional precio_unitario, precio_negociado, producto_id, costo_unitario, tax_rate, exemption_reason and, in Mexico, clave_sat and clave_unidad_sat.
currency No Invoice currency; defaults to your account’s.
due_date No Due date as YYYY-MM-DD.
notas No Up to 1000 characters.
iva_incluido No true if prices already include tax.
document_mode No commercial or fiscal. Without it, Cord issues a tax document if your plan includes it and your country has it enabled, and a commercial one otherwise. fiscal without the plan or an enabled country responds 400 invalid_request.
fx_buffer_pct No Coverage in percentage points over the reference exchange rate when currency differs from your accounting currency (2 = +2%, capped at 25). Defaults to 0.
descuento No Document discount before tax: { "tipo": "porcentaje", "valor": 10 } or { "tipo": "monto", "valor": 2500 }. Cord calculates the amount and spreads it across the line items. See Discounts and coupons.
cupon No A coupon code from your account. It wins over descuento. Its use is counted when the invoice is issued.
service_date, service_date_end No Date or period of supply, YYYY-MM-DD. The end requires the start and can’t be earlier. Without it, the invoice says it matches the issue date (required in Germany).
buyer_reference No Buyer reference (BT-10 of the European e-invoice; in Germany, the public body’s Leitweg-ID). Without it, the client’s. If the client’s electronic address is a Leitweg-ID, its check digits are verified and one that fails responds 400.
purchase_order No The client’s purchase order number (BT-13).

tax_rate is a fraction (0.16, not 16) and is validated against your tax catalog: you cannot declare an exempt line on a taxed sale. 0 means deliberately exempt; omitting it uses your account’s rate. clave_sat and clave_unidad_sat win over the product’s keys; with neither, the CFDI uses 01010101 and H87. A key with an invalid format responds 400.

curl -X POST "https://cordhq.app/api/v1/facturas" \
     -H "Authorization: Bearer sk_live_tU..." \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: invoice-order-8812" \
     -d '{
       "cliente_id": "9b2e4c6a-8d1f-4a3b-b5c7-0e2d4f6a8c91",
       "currency": "USD",
       "due_date": "2026-10-15",
       "items": [{ "descripcion": "Rebar 3/8\"", "cantidad": 120, "precio_unitario": 4.2, "tax_rate": 0.0825 }]
     }'
{ "data": { "id": "f3a1c7e9-2b4d-4f6a-8c0e-5d7b9a1c3e24" } }

If the invoice is in a currency other than your ledger currency and no verifiable exchange rate can be obtained, it responds 503 with code: "fx_unavailable": retry later, Cord never makes up a rate.

Get an invoice

GET /api/v1/facturas/{id} returns the list fields plus subtotal, impuestos, moneda_contable, tipo_cambio, total_contable, notas, nota_credito_de, emisor, receptor, descuento, conceptos and pagos.

Field Details
descuento null, or { tipo, valor, cupon, monto, moneda }: the definition, the coupon it came from, and the amount before tax. subtotal is already net.
conceptos[].precio_unitario Net unit price, after the document discount, before tax.
conceptos[].subtotal The line’s net base.
conceptos[].descuento The share of the document discount that went to that line; 0 if there’s none.
conceptos[].clave_sat, conceptos[].clave_unidad_sat Mexico: the SAT keys the line was stamped with; null outside Mexico.
pagos Each payment with monto, moneda, metodo, referencia, and cuando. A charge that paid several invoices shows up on each one with its share.

Change status

POST /api/v1/facturas/{id} with action:

action What it does Fields
finalize Issues the invoice. Irreversible; stamps the CFDI in Mexico when it applies. —
send Emails the invoice with its PDF to the client, in the invoice’s language (language). Requires an issued invoice and a client with an email. —
payment Records a full or partial payment. monto, moneda, metodo (defaults to manual), referencia
void Voids the invoice. motivo
credit_note Issues a credit note against the invoice. monto (optional; without it, for the total), motivo

payment responds with the amount paid, the balance and the resulting status. A payment that settles the invoice fires the invoice.paid event.

If an already stamped invoice cannot be voided directly, void responds 409 with code: "credit_note_required": issue a credit note instead.

In Mexico:

  • void requests the CFDI’s cancellation under SAT reason 02. If the SAT hasn’t confirmed it yet, it responds 202 with { "data": { "id": "…", "estado": "open", "cancelacion": "pendiente" } } and the invoice stays valid; invoice.voided isn’t fired until it’s confirmed. Replacement under reason 01 and the global invoice are only in the app.
  • payment on a PPD CFDI triggers the automatic payment complement for that payment.

Common errors

Code When
invalid_request (400) cliente_id or items is missing, a line has no description or quantity, due_date is not YYYY-MM-DD, the discount isn’t shaped { tipo, valor }, or a Leitweg-ID fails its check digits.
coupon_no_existe (404) The coupon doesn’t exist on your account.
coupon_inactivo, coupon_vencido, coupon_aun_no_vigente, coupon_agotado, coupon_agotado_cliente, coupon_moneda, coupon_requiere_cliente (409) The coupon doesn’t apply to this invoice; the message says why.
invalid_state (409) The action does not apply to the current status (for example, sending a draft). Sending to a client with no email responds 400 with this same code.
credit_note_required (409) The invoice is already stamped and can’t be voided directly: issue a credit note.
not_found (404) The invoice doesn’t exist in your organization.
provider_error (502) The tax provider rejected issuing; the message says why.
send_failed (502) The invoice email couldn’t be sent. Retry send.
fx_unavailable, tax_catalog_unavailable (503) No verifiable exchange rate, or your tax catalog could not be read. Retry.