Responses and errors
Every response is JSON with code and message. The HTTP status only tells success (200) from error (400); what happened is in code.
Success and error
{
"message": "The document was generated successfully",
"code": 200,
"cfdi": { "UUID": "6F1A2B3C-4D5E-4F60-8172-93A4B5C6D7E8", "…": "…" }
}{
"message": "El CFDI no cumple con el esquema del SAT. Se encontró 1 error de validación. Revisa el campo 'errors' para el detalle.",
"code": 702,
"errorType": "cfdi_schema_validation",
"errors": [
{ "severity": "error", "field": "Rfc", "value": "ZKA010101JWY", "message": "Elemento 'Receptor', campo 'Rfc': …" }
]
}Error body
message- What happened, in English or Spanish depending on the error. Some rejections include the SAT text.
code- The API code (601, 702, 5034…). It isn't the HTTP status.
errorType- A stable category for your code to check:
cfdi_schema_validation,json_type_validation,cartaporte_validation,timbre_previo… errors- The details, one per problem, with
field,valueandmessagewhen they apply. context- Extra data, for example
{ "uuid": "…" }when the CFDI already exists.
| HTTP | When |
|---|---|
| 200 | Success. Also "not found" in the self-invoicing and catalog queries, which respond 200 with code "404". |
| 400 | Any error in the request, your account, the schema or the SAT. Read code. |
| 401 / 403 | Only GET /account/authorize: wrong username or password, or a block after too many attempts. |
| 405 | The HTTP method doesn't exist on that path (for example GET on /invoice/create). |
| 429 | Brake on identical retries (code 4290). See fair use. |
API codes
| code | What it means | Retry? |
|---|---|---|
| 400 | A parameter is missing or has another format, or the SAT rejected the CFDI (the key is in message). | No: fix it first. |
| 501 | The key is missing, doesn't exist or belongs to the other environment. | No: check the key. |
| 502 | A required parameter is missing (in listings and the validator). | No. |
| 601 | Your account has no folios or credits. | After you buy more. |
| 602 | Your account has no active CSD. | After you upload it. |
| 625 | The UUID isn't in your account (invoice/send). | No. |
| 702 | The XML doesn't meet the SAT schema. | No: errors[] tells you which field. |
| 706 | Your CSD couldn't be used. | After you upload it again. |
| 4290 | Brake on an identical request that was already rejected. | No: honor Retry-After. |
| 5034 | The CFDI may have been stamped without a readable response. | Check first. |
| 5037 | The API couldn't connect to the stamping provider; nothing was sent. | Yes. |
| 5040 | A server problem before stamping; nothing was sent. | Let us know. |
They're all in the error matrix with their exact message, next to the SAT keys.
SAT rejections
When the SAT or the stamping provider rejects a CFDI, code is 400 and the SAT matrix key goes at the start of message. Split the key from the text with an expression like ^([A-Za-z]+\d+)\s*-.
{
"message": "CFDI40143 - Este RFC del receptor no existe en la lista de RFC inscritos no cancelados del SAT.",
"code": 400
}The text after the key can change when the SAT updates its matrix; the key doesn't. A SAT rejection uses no folio and repeats as long as the value stays the same.
Uncertain response: 5034
A 5034 means the request reached the stamping provider and no readable response came back. The CFDI may be stamped with the SAT. The response carries the series and folio that were used and, if it could be read, context.uuid.
{
"message": "El PAC no respondió a tiempo: tu factura pudo haberse timbrado en el SAT aunque no aparezca en tus CFDIs emitidos. Revisa tu buzón o el portal del SAT antes de volver a intentar. Se usó la serie A folio 1001.",
"code": 5034,
"Serie": "A",
"Folio": "1001"
}- If
context.uuidis there, the CFDI exists: store it and don't resend it. - If not, look it up by its series and folio in your listings (
GET /invoice/listbydaterange) a few minutes later, or on the SAT portal. - Retry only if it doesn't show up. If you retry with the same
FechaandFolioyou sent before and the first one did get stamped, the API respondstimbre_previowith its UUID instead of duplicating it.
Fair use
Each account gets 10,000 rejection responses a day at no cost. A rejection is a 4xx response to a request with a valid key. SAT rejections caused by the captured data (CFDI40xxx keys) and 702s for a malformed value don't count, and neither do the requests the platform's own screens make.
If your integration goes over the limit, we let you know before any charge. While an overage is pending, a brake can be turned on by hand: the API responds HTTP 429 with code 4290 and the Retry-After header to a request identical to one it already rejected in the last 24 hours. New or different requests keep working. The details are in the API fair use policy.
Format
- JSON in UTF-8. Send
Accept: application/jsonor noAcceptat all. - Dates are in central Mexico time with no time zone:
2026-11-03 10:15:42or2026-11-03T10:15:42. - Listings return database values as text:
"1160.000000","1". - Call the API from server to server. Many parameters go in headers a browser can't send to another domain, and the key must never be in the browser.
Checked against the production API v5 on 2026-11-03.