heruAPI
Invoices

Issue an invoice

LiveServed by the v1 API in development with the same checks as production; production opens on the same contract. The capabilities from before v1 keep running in production at the path your account team gives you.

POST
/invoices

Issues a CFDI 4.0.

Who issues it

  • Your company: send nothing, or issuer.company_id to pick one of your companies.
  • A merchant: issuer.merchant_id.
  • A worker with their own CSD: issuer.worker_id.
  • heru, on a worker's behalf (the worker needs no CSD): third_party.worker_id.
  • Your company, on another taxpayer's behalf: third_party with their RFC.

Who receives it

  • One of your companies, a worker or a merchant: receiver.company_id, receiver.worker_id or receiver.merchant_id. heru fills their SAT data.
  • Anyone else: receiver with their RFC, name, regime and postal code.

Which companies can issue. It depends on the credential: see Companies.

Files. Get the XML or the PDF with GET /invoices/{id}/download, which needs the invoices:download scope.

Synchronous. heru stamps the CFDI with the PAC before answering, usually in 2 to 5 seconds, and returns it with its folio fiscal. Wait up to 30 seconds. If the PAC or the SAT do not answer in time you get 503 and nothing is created: retry after Retry-After with the same Idempotency-Key. If the connection drops or you get another 5xx, retry the same way: you get the CFDI that was already stamped, never a second one.

Needs the invoices:write scope.

Authorization

oauth2 invoices:write
headerAuthorizationBearer <token>

OAuth 2.0 client credentials. Exchange your client_id and client_secret at /oauth/token of the environment for a bearer token valid for one hour. The playground of every operation asks for your own client and keeps it in your browser tab only.

Scope: invoices:write

Header parameters

Idempotency-Key*string

Unique per operation. Retrying with the same key returns the original result for 24 hours.

Lengthlength <= 255

Request body

application/json
  1. body

A CFDI 4.0 of type ingreso: for your customers, for the general public, on behalf of a third party, or a global invoice.

external_id*string

Your own id for this invoice, e.g. your order number. Echoed back in every response and webhook.

Lengthlength <= 128
receiver*||||

Who receives the invoice: one of your companies, a worker, a merchant, a customer, or any taxpayer by their data. Name, postal code and regime must match the SAT records exactly.

items*array<>
Items1 <= items
payment_form*string

SAT c_FormaPago, e.g. 01 cash, 03 transfer, 04 credit card, 28 debit card. 99 (to be defined) only with PPD.

type?string

SAT c_TipoDeComprobante:

  • I Ingreso: a sale or a service. Available.
  • E Egreso: a credit note, discount or return on an earlier invoice. Planned.
  • P Pago: payment receipt (complemento de pagos) for an invoice issued with PPD. Planned.
  • T Traslado: moving goods without a sale (carta porte). Planned.
  • N Nómina: payroll. Planned.

Until a type is available, it answers 422 with INVOICE_TYPE_NOT_AVAILABLE.

Default"I"
Value in"I""E""P""T""N"
payment_method?string

SAT c_MetodoPago: PUE paid in one payment, PPD paid in installments or later. Payment receipts (type P) for PPD invoices are planned.

Default"PUE"
Value in"PUE""PPD"
cfdi_use?string

SAT c_UsoCFDI: what the receiver uses it for. G03 general expenses, S01 no tax effects (general public).

Default"G03"
issuer?||

Who issues and seals the CFDI with their CSD. Send exactly one id. Leave issuer out to issue as the company of your credential.

third_party?||

The taxpayer on whose behalf the CFDI is issued (por cuenta de terceros). The income is theirs, but they do not seal it, so they need no CSD.

place_of_issue?string

Postal code where the invoice is issued (LugarExpedicion). Defaults to the issuer's tax address; for a merchant, send its location's postal code.

Match^[0-9]{5}$
related_invoices?array<|>

Invoices this one is related to (CfdiRelacionados). To replace an invoice issued with errors: send it here with relationship 04, then cancel the old one with DELETE /invoices/{id}?reason=01&replacement_uuid=….

periodicity?string

SAT c_Periodicidad. Global invoices only, e.g. 04 monthly.

months?string

Global invoices only. 01 to 12 for a month, 13 to 18 for a two-month period.

Match^(0[1-9]|1[0-8])$
year?string

Year covered. Global invoices only.

Match^\d{4}$
metadata?

Your own key-value data. Returned as sent.

Response body

The invoice, stamped by the SAT.

application/json
  1. response
id*string
Match^inv_[0-7][0-9a-hjkmnp-tv-z]{25}$
external_id*string

Your own id for this invoice, as you sent it.

status*string

stamped once the SAT accepted it. After a cancellation: cancellation_requested while the receiver must accept it, then cancelled.

Value in"stamped""cancellation_requested""cancelled"
type*string

SAT c_TipoDeComprobante of the CFDI, as sent.

Value in"I""E""P""T""N"
uuid*string

Folio fiscal the SAT assigned.

Formatuuid
verification_url?string

SAT page that verifies the invoice.

Formaturi
stamp*

The SAT stamp (TimbreFiscalDigital). Print it on your own representation of the CFDI.

issuer*
receiver*
third_party?|

The taxpayer on whose behalf it was issued, or null.

place_of_issue?string

Postal code where it was issued.

items*array<>
related_invoices?array<>

Invoices this one is related to. Empty when there are none.

payment_method*string
Value in"PUE""PPD"
payment_form*string
cfdi_use*string
currency*"MXN"
Value in"MXN"
subtotal*string

Sum of the items before taxes.

Match^[0-9]+\.[0-9]{2}$
vat*string

VAT transferred.

Match^[0-9]+\.[0-9]{2}$
withholdings?|

Total withheld. Null when nothing is withheld.

total*string

subtotal + vat − withholdings.

Match^[0-9]+\.[0-9]{2}$
periodicity?string

Global invoices only.

months?string

Global invoices only.

year?string

Global invoices only.

cancellation?|

Null until you request a cancellation.

metadata?

As you sent it.

created_at*string
Formatdate-time
stamped_at*string
Formatdate-time
updated_at*string
Formatdate-time
curl -X POST 'https://api.dev.b2b.heru.app/v1/invoices' \  -H 'Idempotency-Key: try-it-0001' \  -H 'Content-Type: application/json' \  -d '{  "external_id": "INV-2026-000245",  "receiver": {    "rfc": "HEGL900101K44",    "name": "JOSE LUIS HERNANDEZ GARCIA",    "tax_regime": "612",    "postal_code": "06600",    "email": "joseluis.hernandez@cliente.example"  },  "items": [    {      "description": "Servicio de consultoría",      "quantity": 1,      "unit_code": "E48",      "unit_price": "1000.00",      "product_code": "84111506",      "tax_object": "02"    }  ],  "payment_form": "03"}'
{  "id": "inv_01m4ra8w8mfa8svf5396b2p5e1",  "external_id": "INV-2026-000245",  "status": "stamped",  "type": "I",  "uuid": "5829F7E9-4996-450C-BE13-9EE83FD56065",  "verification_url": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=5829F7E9-4996-450C-BE13-9EE83FD56065&re=PDE180514R21&rr=HEGL900101K44&tt=1160.00&fe=ydyupw==",  "stamp": {    "sat_certificate_number": "00001000000509465028",    "issuer_certificate_number": "00001000000712345678",    "pac_rfc": "SPR190613I52",    "issuer_seal": "GHbnil3a0FVwE7ynElV7a/eMdiNsWGBg72T2sHjC6CSRg4CIP947uTmefzvTKPcAoTI9NKFKCAVRf/i6w0HP+Op7Twhh/i2cHOGUUMfWDh/ILDldff/tt7OVzRiunV/Mb8FIWL7yjvU4qWeLzhKSi3WhAAKI9wJW9DBBsid3Q9566BqAldbGgN9YIoPNTdFKPLj9CXK5uSWqnt5jcllVUx3CscBVdoxpCHXfGUN9blsdOXKQ8SV3lv4weMup2+moMzsHXiNTXR6iAkk+WycILJfBGOXk3EIu8+a2fp/IOW+KL6wmPcEEqumiNkK8LeXXtljmVnFMi236w0Fuydyupw==",    "sat_seal": "i0o/7TJngD+XRxvsWYHvdAEuw4ozKSJToKkCo6M054CavGKcbwBzzoDvmKQXHsgOCtyRdv9aOGG/UrqBnAffWF36C2TatEaD1b4Y5A6X7KIROheWwr/5zbddOflrlufSQIySnPEzCmE+sgQ7So7RqXJmtpEGW+eXwjRH1YoF2h0TQ5jqGkpTSTjiyoRvMWvC/FPC9O9HJtsXiRHLxWWzQGvsWAXdYNwFYVvI4oXzj38quDonetE+bUi+Qu7KA/xJQdEwsvhdUn7JLoqzXqcKnp2306uy7GFD7Wl/1tMIBPiJqX8x06qXWMEa0WFWM3gWzI0PVtXRoBjYDF8pdwoHpA==",    "original_chain": "||1.1|5829F7E9-4996-450C-BE13-9EE83FD56065|2026-10-12T09:04:08|SPR190613I52|GHbnil3a0FVwE7ynElV7a/eMdiNsWGBg72T2sHjC6CSRg4CIP947uTmefzvTKPcAoTI9NKFKCAVRf/i6w0HP+Op7Twhh/i2cHOGUUMfWDh/ILDldff/tt7OVzRiunV/Mb8FIWL7yjvU4qWeLzhKSi3WhAAKI9wJW9DBBsid3Q9566BqAldbGgN9YIoPNTdFKPLj9CXK5uSWqnt5jcllVUx3CscBVdoxpCHXfGUN9blsdOXKQ8SV3lv4weMup2+moMzsHXiNTXR6iAkk+WycILJfBGOXk3EIu8+a2fp/IOW+KL6wmPcEEqumiNkK8LeXXtljmVnFMi236w0Fuydyupw==|00001000000509465028||"  },  "issuer": {    "rfc": "PDE180514R21",    "name": "PLATAFORMA DEMO",    "tax_regime": "601",    "postal_code": "11000"  },  "receiver": {    "rfc": "HEGL900101K44",    "name": "JOSE LUIS HERNANDEZ GARCIA",    "tax_regime": "612",    "postal_code": "06600",    "email": "joseluis.hernandez@cliente.example"  },  "third_party": null,  "place_of_issue": "11000",  "items": [    {      "description": "Servicio de consultoría",      "quantity": 1,      "unit_code": "E48",      "unit_price": "1000.00",      "product_code": "84111506",      "tax_object": "02",      "vat_rate": "0.16",      "subtotal": "1000.00",      "vat": "160.00",      "withholdings": null    }  ],  "related_invoices": [],  "payment_method": "PUE",  "payment_form": "03",  "cfdi_use": "G03",  "currency": "MXN",  "subtotal": "1000.00",  "vat": "160.00",  "withholdings": null,  "total": "1160.00",  "cancellation": null,  "metadata": {},  "created_at": "2026-10-12T15:04:05.208Z",  "stamped_at": "2026-10-12T15:04:08.422Z",  "updated_at": "2026-10-12T15:04:08.422Z"}
© 2026 Kuarto Inc. (heru)heru.appQuestions about your integration? Contact your heru account team.