> ## Documentation Index
> Fetch the complete documentation index at: https://invoiceapi.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Error reference

> {/* GENERATED by pnpm openapi (scripts/generate-openapi.ts). Do not edit by hand. */}

Every error is `application/problem+json` (RFC 9457) with agent-first extensions:

```json theme={null}
{
  "type": "https://errors.invoiceapi.mx/cfdi_invalid_rfc",
  "title": "Receptor RFC failed SAT validation",
  "status": 422,
  "detail": "RFC 'XAXX010101ABC' is not registered at the SAT (CFDI40**).",
  "code": "cfdi.receptor_rfc_not_registered",
  "remediation": "Ask the customer for their Constancia de Situación Fiscal and use the RFC exactly as printed.",
  "pac": { "provider": "pac", "codigo": "402", "mensaje": "..." },
  "request_id": "req_..."
}
```

Switch on `code` (stable across releases), show `remediation` to the user or feed it to an agent, and log `request_id`. When the failure came from the PAC, the `pac` object carries the raw PAC/SAT `codigo`/`mensaje`. Every problem body also carries a `doc_url` that deep-links to the matching row below (dots in the code become dashes in the anchor).

## Complete error catalog (141 codes)

Every stable `code` the API can emit, generated by statically scanning the source (a build-time drift guard fails if any code is missing). `HTTP` is the status the code surfaces with. Anchor = `code` with dots replaced by dashes, matching the `doc_url` in every problem body.

| `code`                                                                                    | HTTP | Title                                                        | Remediation                                                                                                                                                                                                                                                |
| ----------------------------------------------------------------------------------------- | :--: | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <a id="auth-key_revoked" />`auth.key_revoked`                                             |  401 | API key revoked                                              | Mint a replacement key with POST /v1/api\_keys and update your credentials.                                                                                                                                                                                |
| <a id="auth-unauthorized" />`auth.unauthorized`                                           |  401 | Authentication required                                      | Send `Authorization: Bearer sk_test_...` (or sk\_live\_...) with a valid API key.                                                                                                                                                                          |
| <a id="cancel-already_cancelled" />`cancel.already_cancelled`                             |  422 | Previously cancelled                                         | The CFDI was already cancelled. Treat as cancelled — no further action needed.                                                                                                                                                                             |
| <a id="cancel-date_after_declaration" />`cancel.date_after_declaration`                   |  422 | Request date after declaration date                          | The cancellation request date is after the SAT declaration date for the period. Cancellation is no longer permitted for this CFDI.                                                                                                                         |
| <a id="cancel-global_invoice_deadline" />`cancel.global_invoice_deadline`                 |  422 | Past the global-invoice deadline                             | The deadline to cancel this factura global has passed. This CFDI can no longer be cancelled.                                                                                                                                                               |
| <a id="cancel-in_process" />`cancel.in_process`                                           |  422 | Cancellation in process                                      | The cancellation is in process awaiting the receptor’s response. Keep polling the status; it resolves within 72 business hours.                                                                                                                            |
| <a id="cancel-motivo_invalid" />`cancel.motivo_invalid`                                   |  422 | Motivo not valid                                             | The motivo is not valid. Use one of 01-04 per the SAT catalog.                                                                                                                                                                                             |
| <a id="cancel-motivo_missing" />`cancel.motivo_missing`                                   |  422 | Motivo not specified or invalid                              | The cancellation motivo is missing or invalid. Provide a valid motivo 01-04 (01 requires a substitute folio).                                                                                                                                              |
| <a id="cancel-no_acuse" />`cancel.no_acuse`                                               |  422 | CFDI not cancelled — acuse unavailable                       | The acuse cannot be retrieved because the CFDI is not cancelled (or was not cancelled through this service). Confirm the cancellation completed before requesting the acuse.                                                                               |
| <a id="cancel-not_applicable" />`cancel.not_applicable`                                   |  422 | Folio not applicable to cancellation                         | This folio cannot be cancelled (e.g. it is referenced by another live CFDI). Query related CFDIs to find the blocker before retrying.                                                                                                                      |
| <a id="cancel-not_cancellable" />`cancel.not_cancellable`                                 |  422 | Not cancellable                                              | The SAT reports this CFDI as "No Cancelable" (e.g. it is referenced by other live documents). Query related CFDIs to find and resolve the blocker.                                                                                                         |
| <a id="cancel-not_primary_sector" />`cancel.not_primary_sector`                           |  422 | UUID is not a Sector Primario CFDI                           | The requested cancellation flow requires a Sector Primario CFDI, which this is not. Use the standard cancellation motivo for this document type.                                                                                                           |
| <a id="cancel-outside_annual_declaration" />`cancel.outside_annual_declaration`           |  422 | Outside the annual declaration window                        | The cancellation falls outside the allowed annual declaration window and is no longer permitted.                                                                                                                                                           |
| <a id="cancel-relation_invalid" />`cancel.relation_invalid`                               |  422 | Relation invalid                                             | The declared relation is invalid. Verify the related CFDI and relationship type.                                                                                                                                                                           |
| <a id="cancel-request_received" />`cancel.request_received`                               |  422 | Cancellation request received                                | The SAT received the cancellation request. If the CFDI is "cancelable con aceptación", the receptor has 72 business hours to accept or reject; poll the status until it resolves.                                                                          |
| <a id="cancel-rfc_mismatch" />`cancel.rfc_mismatch`                                       |  422 | Emisor RFC does not match                                    | The emisor RFC on the request does not match the CFDI. Send the cancellation from the RFC that issued the CFDI, signed with that RFC’s CSD.                                                                                                                |
| <a id="cancel-sat_service_unavailable" />`cancel.sat_service_unavailable`                 |  502 | SAT error during query                                       | The SAT returned an error during the status query. Retry with backoff.                                                                                                                                                                                     |
| <a id="cancel-substitution_folio_invalid" />`cancel.substitution_folio_invalid`           |  422 | Substitute folio not valid                                   | The substitute folio is not valid. For motivo 01, supply the UUID of a valid, already-stamped replacement CFDI.                                                                                                                                            |
| <a id="cancel-substitution_folio_not_required" />`cancel.substitution_folio_not_required` |  422 | Substitute folio not required                                | This motivo does not require a substitute folio. Remove folioSustitucion.                                                                                                                                                                                  |
| <a id="cancel-user_invalid" />`cancel.user_invalid`                                       |  422 | User not valid for cancellation                              | The user is not authorized for this cancellation. Verify credentials and that the signing CSD belongs to the emisor RFC.                                                                                                                                   |
| <a id="cancel-uuid_not_found" />`cancel.uuid_not_found`                                   |  422 | Folio fiscal does not exist                                  | The UUID does not exist at the SAT. Verify the folio fiscal is correct and that the CFDI was actually stamped in this environment (test vs live).                                                                                                          |
| <a id="cfdi-csd_expired" />`cfdi.csd_expired`                                             |  422 | Invalid invoice                                              | Renew the CSD at the SAT portal; an expired/not-yet-valid certificate cannot stamp.                                                                                                                                                                        |
| <a id="cfdi-csd_rfc_mismatch" />`cfdi.csd_rfc_mismatch`                                   |  422 | Invalid invoice                                              | Use the CSD (certificado de sello digital) issued to the emitter RFC.                                                                                                                                                                                      |
| <a id="cfdi-emisor_not_in_lco" />`cfdi.emisor_not_in_lco`                                 |  422 | Taxpayer not in LCO / obligations negative                   | The emitter is not in the SAT’s Lista de Contribuyentes Obligados or its fiscal obligations validation is negative. The taxpayer must resolve their status with the SAT (e.g. active CSD, up-to-date obligations) before stamping.                         |
| <a id="cfdi-fecha_in_future" />`cfdi.fecha_in_future`                                     |  422 | Invalid invoice                                              | Generate Fecha at stamp time; it must not be in the future.                                                                                                                                                                                                |
| <a id="cfdi-fecha_out_of_range" />`cfdi.fecha_out_of_range`                               |  422 | Fecha outside the allowed window                             | The CFDI Fecha is outside the SAT-allowed window (must be within roughly the last 72 hours and not in the future, in Mexico time). Regenerate the CFDI with a fresh timestamp and re-sign it (the sello changes with Fecha).                               |
| <a id="cfdi-fecha_too_old" />`cfdi.fecha_too_old`                                         |  422 | Invalid invoice                                              | Re-issue the invoice; CFDI must be stamped within 72h of Fecha.                                                                                                                                                                                            |
| <a id="cfdi-invalid_expression" />`cfdi.invalid_expression`                               |  422 | Invalid expression                                           | The status query expression is invalid. Check the Total formatting (decimals must match the CFDI exactly) and the RFCs.                                                                                                                                    |
| <a id="cfdi-invalid_fecha" />`cfdi.invalid_fecha`                                         |  422 | Invalid invoice                                              | Pass date as 'YYYY-MM-DDTHH:mm:ss' (SAT forbids a timezone suffix).                                                                                                                                                                                        |
| <a id="cfdi-invalid_input" />`cfdi.invalid_input`                                         |  422 | Invalid invoice                                              | Fix every field listed in `errors` and resubmit. See /openapi.json for the schema.                                                                                                                                                                         |
| <a id="cfdi-malformed_sello" />`cfdi.malformed_sello`                                     |  422 | Malformed sello                                              | The Sello attribute is not valid base64 or has the wrong length. Recompute the sello: RSA-SHA256 over the cadena original, base64-encoded, using the emitter CSD private key.                                                                              |
| <a id="cfdi-malformed_xml" />`cfdi.malformed_xml`                                         |  422 | Malformed CFDI XML                                           | The CFDI XML is not well-formed or violates the SAT schema. Rebuild the XML — check element order, required attributes, and that special characters are escaped.                                                                                           |
| <a id="cfdi-missing_tax_rate" />`cfdi.missing_tax_rate`                                   |  422 | Invalid invoice                                              | Provide `rate` (e.g. 0.16) for Tasa/Cuota taxes.                                                                                                                                                                                                           |
| <a id="cfdi-missing_uso" />`cfdi.missing_uso`                                             |  422 | Invalid invoice                                              | Set `use` at invoice level or `customer.use`.                                                                                                                                                                                                              |
| <a id="cfdi-no_tfd" />`cfdi.no_tfd`                                                       |  422 | Invalid invoice                                              | Only stamped CFDIs (with a TFD) have a TFD cadena.                                                                                                                                                                                                         |
| <a id="cfdi-not_a_csd" />`cfdi.not_a_csd`                                                 |  422 | Invalid invoice                                              | Sign CFDIs with the CSD; the FIEL is only for descarga masiva.                                                                                                                                                                                             |
| <a id="cfdi-not_comprobante" />`cfdi.not_comprobante`                                     |  422 | Invalid invoice                                              | Pass a CFDI 4.0 Comprobante XML.                                                                                                                                                                                                                           |
| <a id="cfdi-not_found" />`cfdi.not_found`                                                 |  422 | Comprobante not found                                        | The comprobante was not found at the SAT. Verify the UUID and that emisor RFC, receptor RFC and Total exactly match the CFDI.                                                                                                                              |
| <a id="cfdi-objeto_imp_02_without_taxes" />`cfdi.objeto_imp_02_without_taxes`             |  422 | Invalid invoice                                              | Provide at least one tax for this item, or set tax\_object to '01' (no objeto de impuesto).                                                                                                                                                                |
| <a id="cfdi-objeto_imp_dr_02_without_taxes" />`cfdi.objeto_imp_dr_02_without_taxes`       |  422 | Invalid invoice                                              | Provide at least one tax on the related document, or set its tax\_object to '01'.                                                                                                                                                                          |
| <a id="cfdi-parse_error" />`cfdi.parse_error`                                             |  422 | Invalid invoice                                              | Provide a well-formed CFDI XML string.                                                                                                                                                                                                                     |
| <a id="cfdi-pdf_dependencies_missing" />`cfdi.pdf_dependencies_missing`                   |  422 | Invalid invoice                                              | Install the optional PDF peer dependencies (the CFDI PDF renderer and @xmldom/xmldom) on the server.                                                                                                                                                       |
| <a id="cfdi-pdf_requires_stamp" />`cfdi.pdf_requires_stamp`                               |  422 | Invalid invoice                                              | Stamp the CFDI with the PAC first; the PDF shows the fiscal folio (UUID).                                                                                                                                                                                  |
| <a id="cfdi-retencion_exento" />`cfdi.retencion_exento`                                   |  422 | Invalid invoice                                              | Use factor Tasa or Cuota for withholdings, or make it a traslado.                                                                                                                                                                                          |
| <a id="cfdi-sello_injection_failed" />`cfdi.sello_injection_failed`                       |  422 | Invalid invoice                                              | Ensure the XML is a well-formed CFDI 4.0 Comprobante.                                                                                                                                                                                                      |
| <a id="cfdi-sello_mismatch" />`cfdi.sello_mismatch`                                       |  422 | Sello does not match                                         | The sello does not correspond to the CFDI content or certificate. This means the cadena original was built incorrectly or a different key signed it. Regenerate the cadena original from the final XML and re-sign with the matching CSD private key.      |
| <a id="cfdi-status_indeterminate" />`cfdi.status_indeterminate`                           |  502 | Indeterminate state                                          | The SAT could not determine the state. Retry the status query later.                                                                                                                                                                                       |
| <a id="cfdi-unknown_currency" />`cfdi.unknown_currency`                                   |  422 | Invalid invoice                                              | Use a valid ISO 4217 currency code present in c\_Moneda.                                                                                                                                                                                                   |
| <a id="connect-account_disabled" />`connect.account_disabled`                             |  403 | Connected account disabled                                   | Re-enable the account via PATCH /v1/accounts/:id \{"disabled": false}.                                                                                                                                                                                     |
| <a id="connect-account_not_authorized" />`connect.account_not_authorized`                 |  403 | Not a connected account of this platform                     | Create the connected account with POST /v1/accounts (using your platform key, no Invoice-Account header), then pass its id as Invoice-Account.                                                                                                             |
| <a id="connect-nesting_not_allowed" />`connect.nesting_not_allowed`                       |  403 | Connected accounts cannot own connected accounts             | Create connected accounts from the top-level platform organization.                                                                                                                                                                                        |
| <a id="connect-not_supported_here" />`connect.not_supported_here`                         |  400 | Acting as a connected account is not supported here          | Drop the Invoice-Account header. Manage API keys with your platform key directly.                                                                                                                                                                          |
| <a id="dashboard-email_in_use" />`dashboard.email_in_use`                                 |  409 | Email already registered                                     | Sign in at /signin, or use a different email.                                                                                                                                                                                                              |
| <a id="dashboard-invalid_credentials" />`dashboard.invalid_credentials`                   |  401 | Invalid email or password                                    | Check your credentials and try again.                                                                                                                                                                                                                      |
| <a id="dashboard-pages_unavailable" />`dashboard.pages_unavailable`                       |  503 | Dashboard pages unavailable                                  | Deploy the web/ assets alongside the API, then retry.                                                                                                                                                                                                      |
| <a id="dashboard-session_required" />`dashboard.session_required`                         |  401 | Sign in required                                             | Sign in at /signin to obtain a session cookie.                                                                                                                                                                                                             |
| <a id="dashboard-too_many_attempts" />`dashboard.too_many_attempts`                       |  429 | Too many sign-in attempts                                    | Wait 15 minutes before trying again.                                                                                                                                                                                                                       |
| <a id="download-fiel_required" />`download.fiel_required`                                 |  422 | Fiscal profile has no FIEL                                   | Upload the FIEL to the profile via PATCH /v1/fiscal\_profiles/:id (fiel.cer\_base64, fiel.key\_base64, fiel.password), or sign the carta manifiesto with an inline FIEL via POST /v1/fiscal\_profiles/:id/manifest, then retry.                            |
| <a id="download-invalid_range" />`download.invalid_range`                                 |  422 | Invalid date range                                           | Provide date\_from \<= date\_to.                                                                                                                                                                                                                           |
| <a id="download-no_request_id" />`download.no_request_id`                                 |  job | Download has no SAT request id                               | The solicitud never registered with the PAC — create the download again.                                                                                                                                                                                   |
| <a id="download-poll_timeout" />`download.poll_timeout`                                   |  job | Download gave up waiting for the PAC                         | The SAT package was not ready within the polling window. Create a new download, and fragment very large date ranges.                                                                                                                                       |
| <a id="download-request_failed" />`download.request_failed`                               |  502 | SAT descarga masiva request failed                           | —                                                                                                                                                                                                                                                          |
| <a id="download-unknown_error" />`download.unknown_error`                                 |  job | Download failed (unclassified)                               | Read the download `error.message`; if it looks transient, create a new download for the same range.                                                                                                                                                        |
| <a id="fiscal_profile-csd_expired" />`fiscal_profile.csd_expired`                         |  422 | CSD is expired or not yet valid                              | Renew the CSD at the SAT portal (Certificados de Sello Digital) and register the new pair. An expired certificate cannot stamp live CFDIs.                                                                                                                 |
| <a id="fiscal_profile-csd_is_fiel" />`fiscal_profile.csd_is_fiel`                         |  422 | FIEL supplied where a CSD is required                        | Register the CSD under `csd` (used to sign CFDIs). If you also have a FIEL for descarga masiva, send it under `fiel`.                                                                                                                                      |
| <a id="fiscal_profile-csd_rfc_mismatch" />`fiscal_profile.csd_rfc_mismatch`               |  422 | Rotated CSD belongs to a different RFC                       | Rotate to a CSD issued to the same RFC. To register a different taxpayer, create a new fiscal\_profile.                                                                                                                                                    |
| <a id="fiscal_profile-fiel_required" />`fiscal_profile.fiel_required`                     |  422 | A FIEL is required to sign the manifiesto                    | Send the FIEL under `fiel: { cer_base64, key_base64, password }` in this request, or register it on the profile first.                                                                                                                                     |
| <a id="fiscal_profile-in_use" />`fiscal_profile.in_use`                                   |  409 | Fiscal profile is in use                                     | A fiscal profile with issued invoices is retained for tax-record integrity. Rotate its CSD instead of deleting, or delete dependent records first.                                                                                                         |
| <a id="fiscal_profile-invalid_csd" />`fiscal_profile.invalid_csd`                         |  422 | Invalid CSD certificate or password                          | Verify cer\_base64 is the .cer, key\_base64 is the .key, and password is the private-key passphrase (clave privada). Re-download the CSD from the SAT if unsure.                                                                                           |
| <a id="fiscal_profile-invalid_fiel" />`fiscal_profile.invalid_fiel`                       |  422 | Invalid FIEL certificate or password                         | Verify the FIEL (e.firma) files and password; it is only used for descarga masiva.                                                                                                                                                                         |
| <a id="fiscal_profile-invalid_metadata_json" />`fiscal_profile.invalid_metadata_json`     |  422 | metadata is not valid JSON                                   | Send `metadata` as a JSON string, e.g. metadata=\{"order\_id":"123"}. Keys and values must be strings.                                                                                                                                                     |
| <a id="idempotency-key_processing" />`idempotency.key_processing`                         |  409 | A request with this Idempotency-Key is still being processed | Retry once the in-flight request with this Idempotency-Key completes.                                                                                                                                                                                      |
| <a id="idempotency-key_reuse" />`idempotency.key_reuse`                                   |  409 | Idempotency-Key reused with a different request body         | Reuse an Idempotency-Key only for byte-identical retries; use a fresh key for a new request.                                                                                                                                                               |
| <a id="internal-error" />`internal.error`                                                 |  500 | Internal server error                                        | —                                                                                                                                                                                                                                                          |
| <a id="invoice-already_stamped" />`invoice.already_stamped`                               |  409 | Invoice already stamped                                      | —                                                                                                                                                                                                                                                          |
| <a id="invoice-cancellation_in_progress" />`invoice.cancellation_in_progress`             |  409 | Cancellation already requested                               | —                                                                                                                                                                                                                                                          |
| <a id="invoice-cancellation_rejected" />`invoice.cancellation_rejected`                   |  422 | Cancellation rejected                                        | Check the UUID is vigente and the motivo/substitute are correct; retrieve the acuse for details.                                                                                                                                                           |
| <a id="invoice-folio_contention" />`invoice.folio_contention`                             |  409 | Could not assign a folio                                     | Retry the request; concurrent invoice creation on this serie is heavy.                                                                                                                                                                                     |
| <a id="invoice-folio_taken" />`invoice.folio_taken`                                       |  409 | Folio already used                                           | —                                                                                                                                                                                                                                                          |
| <a id="invoice-no_xml" />`invoice.no_xml`                                                 |  422 | Invoice has no XML to stamp                                  | Recreate the invoice; the signed XML is missing.                                                                                                                                                                                                           |
| <a id="invoice-not_stampable" />`invoice.not_stampable`                                   |  409 | Invoice cannot be stamped                                    | —                                                                                                                                                                                                                                                          |
| <a id="invoice-not_stamped" />`invoice.not_stamped`                                       |  409 | Only stamped invoices can be cancelled                       | —                                                                                                                                                                                                                                                          |
| <a id="invoice-pdf_requires_stamp" />`invoice.pdf_requires_stamp`                         |  409 | PDF is only available for stamped invoices                   | —                                                                                                                                                                                                                                                          |
| <a id="invoice-profile_missing_csd" />`invoice.profile_missing_csd`                       |  422 | Fiscal profile has no CSD                                    | Upload the CSD (.cer + .key + password) to the fiscal profile before issuing invoices.                                                                                                                                                                     |
| <a id="invoice-substitute_not_stamped" />`invoice.substitute_not_stamped`                 |  422 | Substitute invoice is not stamped                            | Stamp the replacement invoice before referencing it as a substitute.                                                                                                                                                                                       |
| <a id="invoice-substitute_required" />`invoice.substitute_required`                       |  422 | Substitute invoice required                                  | Pass substitute\_invoice\_id pointing to the stamped CFDI that replaces this one, or use motivo '02'.                                                                                                                                                      |
| <a id="invoice-xml_requires_stamp" />`invoice.xml_requires_stamp`                         |  409 | XML is only available for stamped invoices                   | —                                                                                                                                                                                                                                                          |
| <a id="manifest-email_required" />`manifest.email_required`                               |  422 | An email is required for the manifiesto                      | Provide `email` in the request or set the MANIFEST\_EMAIL config default.                                                                                                                                                                                  |
| <a id="manifiesto-already_signed" />`manifiesto.already_signed`                           |  422 | Contrato firmado previamente                                 | The carta manifiesto was already signed for this RFC — no action needed. The profile is authorized for CFDI certification.                                                                                                                                 |
| <a id="manifiesto-bad_request" />`manifiesto.bad_request`                                 |  422 | Petición inválida o parámetros incorrectos                   | The request was missing or had incorrect parameters (cert, key, keyPass, correo).                                                                                                                                                                          |
| <a id="manifiesto-bad_sello" />`manifiesto.bad_sello`                                     |  422 | Sello del emisor mal formado o inválido                      | The FIEL sello could not be validated. Re-download the FIEL (e.firma) from the SAT and try again.                                                                                                                                                          |
| <a id="manifiesto-certificate_error" />`manifiesto.certificate_error`                     |  422 | Error en el certificado                                      | There was an error with the certificate. Verify the FIEL files and password, then retry.                                                                                                                                                                   |
| <a id="manifiesto-certificate_not_sat" />`manifiesto.certificate_not_sat`                 |  422 | El certificado del emisor no fue emitido por el SAT          | The certificate was not issued by the SAT. Upload the taxpayer’s real FIEL/e.firma certificate.                                                                                                                                                            |
| <a id="manifiesto-certificate_not_valid" />`manifiesto.certificate_not_valid`             |  422 | El certificado del emisor no es válido                       | The FIEL certificate is not valid (expired or revoked). Renew the e.firma at the SAT and retry.                                                                                                                                                            |
| <a id="manifiesto-contract_not_valid" />`manifiesto.contract_not_valid`                   |  422 | El contrato no es válido                                     | The signing service reports the signing contract is not valid. Contact support.                                                                                                                                                                            |
| <a id="manifiesto-invalid_certificate" />`manifiesto.invalid_certificate`                 |  422 | Certificado del emisor mal formado o inválido                | The FIEL certificate is malformed or invalid. Ensure cert is the .cer of a current SAT e.firma (not a CSD) and key is its matching .key.                                                                                                                   |
| <a id="manifiesto-invalid_credentials" />`manifiesto.invalid_credentials`                 |  422 | Usuario, contraseña o contrato del asociado inválido         | The manifiesto signing service rejected the request credentials. Verify the FIEL password and that the account is provisioned for manifiesto signing.                                                                                                      |
| <a id="manifiesto-invalid_response" />`manifiesto.invalid_response`                       |  502 | Manifiesto SOAP response had no \<return> payload            | The signing service returned an unexpected manifiesto response shape. Retry; if it persists, contact support.                                                                                                                                              |
| <a id="manifiesto-malformed_contract" />`manifiesto.malformed_contract`                   |  422 | Contrato mal formado                                         | The manifiesto contract payload was malformed. Contact support.                                                                                                                                                                                            |
| <a id="manifiesto-malformed_xml" />`manifiesto.malformed_xml`                             |  422 | XML mal formado                                              | The signing service could not parse the request. Retry; if it persists, contact support.                                                                                                                                                                   |
| <a id="manifiesto-network_error" />`manifiesto.network_error`                             |  502 | Manifiesto signing request failed                            | The manifiesto signing request could not reach the signing service. Retry with backoff.                                                                                                                                                                    |
| <a id="manifiesto-provider_error" />`manifiesto.provider_error`                           |  502 | Error al procesar la firma del contrato                      | The signing service hit an internal error signing the manifiesto. Retry with backoff; if it persists, contact support.                                                                                                                                     |
| <a id="manifiesto-signed" />`manifiesto.signed`                                           |  422 | Firma exitosa                                                | —                                                                                                                                                                                                                                                          |
| <a id="manifiesto-xml_generation_error" />`manifiesto.xml_generation_error`               |  502 | Error al generar el xml                                      | The signing service failed to generate the signed XML. Retry with backoff; if it persists, contact support.                                                                                                                                                |
| <a id="org-bootstrap_disabled" />`org.bootstrap_disabled`                                 |  403 | Organization bootstrap is disabled                           | Enable ALLOW\_ORG\_BOOTSTRAP or provision organizations out-of-band.                                                                                                                                                                                       |
| <a id="pac-auth_failed" />`pac.auth_failed`                                               |  422 | PAC credentials invalid                                      | The stamping-service credentials were rejected. Do NOT retry — repeated failures can lock the account. This is a server-side configuration issue: contact support so the environment credentials can be verified (test and live credentials are separate). |
| <a id="pac-certificate_invalid" />`pac.certificate_invalid`                               |  422 | Certificate invalid                                          | The certificate is invalid. Verify the emitter CSD is current and matches the emitter RFC, then re-register it.                                                                                                                                            |
| <a id="pac-certificate_revoked" />`pac.certificate_revoked`                               |  422 | Certificate revoked or expired                               | The emitter CSD is revoked or outside its validity window. The taxpayer must obtain a new Certificado de Sello Digital from the SAT and re-register it on the fiscal profile. Do not retry with the same certificate.                                      |
| <a id="pac-contract_invalid" />`pac.contract_invalid`                                     |  422 | Contract invalid or expired                                  | The stamping account is not found, is expired, or has no available stamping credits. This is a server-side account issue: contact support to renew the account or top up stamp credits.                                                                    |
| <a id="pac-duplicate" />`pac.duplicate`                                                   |  422 | Comprobante already exists                                   | This exact comprobante was already stamped (SAT forbids stamping identical CFDIs twice). Treat as a success-replay: use the previously stamped UUID/XML rather than re-stamping. This is the idempotency path — surface the prior stamp to the caller.     |
| <a id="pac-internal_error" />`pac.internal_error`                                         |  502 | PAC internal error                                           | The stamping service reported a transient internal error. Retry with backoff. If it persists, the CFDI was almost certainly NOT stamped — safe to resubmit (idempotency guards against duplicates).                                                        |
| <a id="pac-invalid_parameter" />`pac.invalid_parameter`                                   |  422 | Invalid or missing parameter                                 | A required parameter was missing or malformed (also returned for a malformed JSON body). Do not retry unchanged — inspect the request payload against the timbrarCfdi contract.                                                                            |
| <a id="pac-maintenance" />`pac.maintenance`                                               |  502 | PAC offline for maintenance                                  | The stamping service is temporarily offline for maintenance. Retry with backoff after a short delay.                                                                                                                                                       |
| <a id="pac-no_default_certificate" />`pac.no_default_certificate`                         |  422 | No default certificate for cancellation                      | No CSD was available to sign the cancellation. Provide the emitter CSD (cerPem/keyPem/keyPassword) on the cancel request, since cancellations are signed.                                                                                                  |
| <a id="pac-ok" />`pac.ok`                                                                 |  422 | Comprobante found                                            | No action needed — the comprobante was found.                                                                                                                                                                                                              |
| <a id="pac-query_incomplete" />`pac.query_incomplete`                                     |  502 | General error, query not completed                           | The status query did not complete. Retry with backoff.                                                                                                                                                                                                     |
| <a id="pac-unknown" />`pac.unknown`                                                       |  422 | Unmapped PAC/SAT code                                        | The stamping service returned a code not in our mapping. Inspect the `pac` message; treat as a definitive failure unless it is clearly transient.                                                                                                          |
| <a id="rate_limit-exceeded" />`rate_limit.exceeded`                                       |  429 | Too many requests                                            | Back off and retry after the number of seconds in the Retry-After header; batch work or lower your request rate.                                                                                                                                           |
| <a id="request-error" />`request.error`                                                   |  500 | Request error                                                | —                                                                                                                                                                                                                                                          |
| <a id="request-invalid_date" />`request.invalid_date`                                     |  422 | Invalid date filter                                          | Pass \$\{field} as an ISO-8601 date or datetime, e.g. 2026-07-10 or 2026-07-10T00:00:00Z.                                                                                                                                                                  |
| <a id="request-invalid_expand" />`request.invalid_expand`                                 |  422 | Invalid expand parameter                                     | Use only the expand values the endpoint documents (e.g. fiscal\_profile). Remove unsupported values.                                                                                                                                                       |
| <a id="request-invalid_pagination" />`request.invalid_pagination`                         |  422 | Conflicting pagination cursors                               | Pass only one cursor: starting\_after for the next (older) page, or ending\_before for the previous (newer) page.                                                                                                                                          |
| <a id="request-invalid_version" />`request.invalid_version`                               |  400 | Unknown API version                                          | Send a supported version in the Invoice-Version header, or omit it to use the current version.                                                                                                                                                             |
| <a id="request-method_not_allowed" />`request.method_not_allowed`                         |  405 | Method not allowed                                           | —                                                                                                                                                                                                                                                          |
| <a id="request-validation_failed" />`request.validation_failed`                           |  422 | Request validation failed                                    | Fix the fields listed in `errors` and resubmit. See /openapi.json for the schema.                                                                                                                                                                          |
| <a id="resource-not_found" />`resource.not_found`                                         |  404 | Resource not found                                           | Verify the id and that you are using the matching-mode key (a test id needs a test key, a live id needs a live key).                                                                                                                                       |
| <a id="sat-download_accepted" />`sat.download_accepted`                                   |  422 | Download request accepted                                    | No action needed — poll the request status until packages are ready.                                                                                                                                                                                       |
| <a id="sat-download_duplicate" />`sat.download_duplicate`                                 |  422 | Duplicate request                                            | An identical request already exists. Reuse the existing request’s id, or vary the date range to create a distinct request.                                                                                                                                 |
| <a id="sat-download_expired" />`sat.download_expired`                                     |  job | SAT marked the solicitud as expired                          | Package URLs expire quickly — create a new download for the same range.                                                                                                                                                                                    |
| <a id="sat-download_generation_error" />`sat.download_generation_error`                   |  503 | Request generation error                                     | The stamping service failed to generate the SAT request. Retry with backoff; if it persists, verify the FIEL, dates and RFC.                                                                                                                               |
| <a id="sat-download_no_data" />`sat.download_no_data`                                     |  422 | No data for the filters                                      | The SAT found no CFDIs for these filters — this is a terminal, successful, empty result. Do not retry; the range simply has no documents.                                                                                                                  |
| <a id="sat-download_package_not_found" />`sat.download_package_not_found`                 |  422 | Package not found                                            | The requested package was not found — its download URL likely expired (URLs live \~5 minutes). Re-poll the request status to re-mint the package URLs and download immediately.                                                                            |
| <a id="sat-download_packaging_error" />`sat.download_packaging_error`                     |  503 | Packaging error                                              | The SAT failed to package the result. Retry the status poll; if it persists, re-issue the request with a smaller date range.                                                                                                                               |
| <a id="sat-download_rejected" />`sat.download_rejected`                                   |  job | SAT rejected the solicitud                                   | Verify the FIEL matches the requesting RFC and role (issued/received); a mismatch yields a SAT "tercero no autorizado" rejection.                                                                                                                          |
| <a id="sat-download_request_limit" />`sat.download_request_limit`                         |  422 | Lifetime request limit reached                               | SAT allows at most 2 lifetime requests with identical parameters. Do NOT retry the identical query — fragment or vary the date range (e.g. split the month into weeks) to make a distinct request.                                                         |
| <a id="sat-download_too_large" />`sat.download_too_large`                                 |  422 | Result exceeds SAT size cap                                  | The request exceeds the SAT cap (200,000 XMLs / 1,000,000 metadata records). Fragment the date range into smaller windows and issue separate requests.                                                                                                     |
| <a id="sat-download_unauthorized" />`sat.download_unauthorized`                           |  422 | Third party not authorized                                   | SAT "tercero no autorizado": the FIEL does not match the requested RFC. Ensure the FIEL PFX belongs to the RFC being downloaded and that side (issued/received) matches that RFC’s role.                                                                   |
| <a id="sat-download_uncontrolled_error" />`sat.download_uncontrolled_error`               |  503 | Uncontrolled error                                           | An uncontrolled error occurred on the descarga masiva service. Retry with backoff; if it persists, contact support.                                                                                                                                        |
| <a id="validation-empty_xml" />`validation.empty_xml`                                     |  400 | Decoded XML is empty                                         | Provide base64-encoded CFDI XML in `xml_base64`, or send raw XML with Content-Type application/xml.                                                                                                                                                        |
| <a id="webhook-event_type_not_enabled" />`webhook.event_type_not_enabled`                 |  422 | Endpoint does not subscribe to this event type               | Subscribe the endpoint to this event type (or a matching wildcard) via PATCH /v1/webhook\_endpoints/:id.                                                                                                                                                   |
| <a id="webhook-https_required" />`webhook.https_required`                                 |  400 | Webhook URL must use https in live mode                      | Use an https\:// URL, or a sk\_test\_ key for http\:// endpoints in development.                                                                                                                                                                           |

## PAC / SAT numeric code mapping

Source of truth: `src/pac/error-map.ts`. Every numeric PAC/SAT code below normalizes to a stable `code`. `Retryable` means a transient failure safe to retry with backoff (idempotency guards against duplicate stamps); non-retryable codes require a change before resubmitting.

### Timbrado (stamping)

Returned by `POST /v1/invoices` and `POST /v1/invoices/:id/stamp`. Code `307` (duplicate) is NOT surfaced as an error — it is resolved as a success-replay of the prior stamp.

| PAC/SAT code | Our `code`                   | Retryable | Remediation                                                                                                                                                                                                                                                                            |
| ------------ | ---------------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`          | `pac.ok`                     |     no    | No action needed — the CFDI was stamped.                                                                                                                                                                                                                                               |
| `1`          | `pac.auth_failed`            |     no    | The stamping-service credentials were rejected. Do NOT retry — repeated failures can lock the account. This is a server-side configuration issue: contact support so the environment credentials can be verified (test and live credentials are separate).                             |
| `2`          | `pac.contract_invalid`       |     no    | The stamping account is not found, is expired, or has no available stamping credits. This is a server-side account issue: contact support to renew the account or top up stamp credits.                                                                                                |
| `3`          | `pac.invalid_parameter`      |     no    | A required parameter was missing or malformed (also returned for a malformed JSON body). Do not retry unchanged — inspect the request payload against the timbrarCfdi contract.                                                                                                        |
| `4`          | `pac.internal_error`         |    yes    | The stamping service reported a transient internal error. Retry with backoff. If it persists, the CFDI was almost certainly NOT stamped — safe to resubmit (idempotency guards against duplicates).                                                                                    |
| `5`          | `pac.maintenance`            |    yes    | The stamping service is temporarily offline for maintenance. Retry with backoff after a short delay.                                                                                                                                                                                   |
| `20`         | `pac.no_default_certificate` |     no    | The PAC has no default CSD for this user (only relevant when relying on CALCULAR\_SELLO). This API signs locally and embeds the certificate, so this indicates a misconfiguration — ensure the CFDI carries a valid NoCertificado/Certificado and you are not sending CALCULAR\_SELLO. |
| `301`        | `cfdi.malformed_xml`         |     no    | The CFDI XML is not well-formed or violates the SAT schema. Rebuild the XML — check element order, required attributes, and that special characters are escaped.                                                                                                                       |
| `302`        | `cfdi.malformed_sello`       |     no    | The Sello attribute is not valid base64 or has the wrong length. Recompute the sello: RSA-SHA256 over the cadena original, base64-encoded, using the emitter CSD private key.                                                                                                          |
| `303`        | `cfdi.sello_mismatch`        |     no    | The sello does not correspond to the CFDI content or certificate. This means the cadena original was built incorrectly or a different key signed it. Regenerate the cadena original from the final XML and re-sign with the matching CSD private key.                                  |
| `304`        | `pac.certificate_revoked`    |     no    | The emitter CSD is revoked or outside its validity window. The taxpayer must obtain a new Certificado de Sello Digital from the SAT and re-register it on the fiscal profile. Do not retry with the same certificate.                                                                  |
| `305`        | `pac.certificate_invalid`    |     no    | The certificate is invalid (wrong type, not a CSD, or does not belong to the emitter RFC). Ensure the fiscal profile holds the emitter’s CSD (not a FIEL) issued for the emitter RFC.                                                                                                  |
| `306`        | `pac.certificate_invalid`    |     no    | The certificate could not be validated. Re-upload the emitter CSD (.cer as delivered by the SAT) on the fiscal profile.                                                                                                                                                                |
| `307`        | `pac.duplicate`              |     no    | This exact comprobante was already stamped (SAT forbids stamping identical CFDIs twice). Treat as a success-replay: use the previously stamped UUID/XML rather than re-stamping. This is the idempotency path — surface the prior stamp to the caller.                                 |
| `308`        | `pac.certificate_invalid`    |     no    | The certificate is invalid. Re-register a valid emitter CSD on the fiscal profile.                                                                                                                                                                                                     |
| `309`        | `pac.certificate_invalid`    |     no    | The certificate is invalid. Verify the emitter CSD is current and matches the emitter RFC, then re-register it.                                                                                                                                                                        |
| `401`        | `cfdi.fecha_out_of_range`    |     no    | The CFDI Fecha is outside the SAT-allowed window (must be within roughly the last 72 hours and not in the future, in Mexico time). Regenerate the CFDI with a fresh timestamp and re-sign it (the sello changes with Fecha).                                                           |
| `402`        | `cfdi.emisor_not_in_lco`     |     no    | The emitter is not in the SAT’s Lista de Contribuyentes Obligados or its fiscal obligations validation is negative. The taxpayer must resolve their status with the SAT (e.g. active CSD, up-to-date obligations) before stamping.                                                     |

### Cancellation — invocation/global codes

Global (non per-UUID) codes returned when submitting `POST /v1/invoices/:id/cancel`.

| PAC/SAT code | Our `code`                       | Retryable | Remediation                                                                                                                                                                                                                                                |
| ------------ | -------------------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`          | `pac.ok`                         |     no    | No action needed — poll the cancellation status to confirm the final SAT verdict.                                                                                                                                                                          |
| `1`          | `pac.auth_failed`                |     no    | The stamping-service credentials were rejected. Do NOT retry — repeated failures can lock the account. This is a server-side configuration issue: contact support so the environment credentials can be verified (test and live credentials are separate). |
| `2`          | `pac.contract_invalid`           |     no    | The stamping account is not found, is expired, or has no available stamping credits. This is a server-side account issue: contact support to renew the account or top up stamp credits.                                                                    |
| `3`          | `pac.invalid_parameter`          |     no    | A required parameter was missing or malformed (also returned for a malformed JSON body). Do not retry unchanged — inspect the request payload against the timbrarCfdi contract.                                                                            |
| `4`          | `pac.internal_error`             |    yes    | The stamping service reported a transient internal error. Retry with backoff. If it persists, the CFDI was almost certainly NOT stamped — safe to resubmit (idempotency guards against duplicates).                                                        |
| `5`          | `pac.maintenance`                |    yes    | The stamping service is temporarily offline for maintenance. Retry with backoff after a short delay.                                                                                                                                                       |
| `7`          | `cancel.sat_service_unavailable` |    yes    | The SAT cancellation web service is temporarily unavailable. Retry with backoff; SAT outages can last minutes to hours.                                                                                                                                    |
| `20`         | `pac.no_default_certificate`     |     no    | No CSD was available to sign the cancellation. Provide the emitter CSD (cerPem/keyPem/keyPassword) on the cancel request, since cancellations are signed.                                                                                                  |
| `21`         | `cancel.no_acuse`                |     no    | The acuse cannot be retrieved because the CFDI is not cancelled (or was not cancelled through this service). Confirm the cancellation completed before requesting the acuse.                                                                               |

### Cancellation — per-UUID SAT codes

SAT verdicts on the specific CFDI being cancelled (polled asynchronously).

| PAC/SAT code | Our `code`                               | Retryable | Remediation                                                                                                                                                                       |
| ------------ | ---------------------------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `94`         | `cancel.not_cancellable`                 |     no    | The SAT reports this CFDI as "No Cancelable" (e.g. it is referenced by other live documents). Query related CFDIs to find and resolve the blocker.                                |
| `96`         | `cancel.in_process`                      |     no    | The cancellation is in process awaiting the receptor’s response. Keep polling the status; it resolves within 72 business hours.                                                   |
| `201`        | `cancel.request_received`                |     no    | The SAT received the cancellation request. If the CFDI is "cancelable con aceptación", the receptor has 72 business hours to accept or reject; poll the status until it resolves. |
| `202`        | `cancel.already_cancelled`               |     no    | The CFDI was already cancelled. Treat as cancelled — no further action needed.                                                                                                    |
| `203`        | `cancel.rfc_mismatch`                    |     no    | The emisor RFC on the request does not match the CFDI. Send the cancellation from the RFC that issued the CFDI, signed with that RFC’s CSD.                                       |
| `204`        | `cancel.not_applicable`                  |     no    | This folio cannot be cancelled (e.g. it is referenced by another live CFDI). Query related CFDIs to find the blocker before retrying.                                             |
| `205`        | `cancel.uuid_not_found`                  |     no    | The UUID does not exist at the SAT. Verify the folio fiscal is correct and that the CFDI was actually stamped in this environment (test vs live).                                 |
| `206`        | `cancel.not_primary_sector`              |     no    | The requested cancellation flow requires a Sector Primario CFDI, which this is not. Use the standard cancellation motivo for this document type.                                  |
| `207`        | `cancel.motivo_missing`                  |     no    | The cancellation motivo is missing or invalid. Provide a valid motivo 01-04 (01 requires a substitute folio).                                                                     |
| `208`        | `cancel.substitution_folio_invalid`      |     no    | The substitute folio (folioSustitucion) is invalid. For motivo 01 it must be the UUID of an already-stamped replacement CFDI.                                                     |
| `209`        | `cancel.substitution_folio_not_required` |     no    | A substitute folio was supplied but this motivo does not require one. Omit folioSustitucion for motivos 02/03/04.                                                                 |
| `210`        | `cancel.date_after_declaration`          |     no    | The cancellation request date is after the SAT declaration date for the period. Cancellation is no longer permitted for this CFDI.                                                |
| `211`        | `cancel.global_invoice_deadline`         |     no    | The deadline to cancel this factura global has passed. This CFDI can no longer be cancelled.                                                                                      |
| `212`        | `cancel.relation_invalid`                |     no    | The declared relation is invalid or does not exist. Verify the related/substitute CFDI exists and is correctly related.                                                           |
| `300`        | `cancel.user_invalid`                    |     no    | The user is not authorized for this cancellation. Verify credentials and that the signing CSD belongs to the emisor RFC.                                                          |
| `310`        | `cancel.motivo_invalid`                  |     no    | The motivo is not valid. Use one of 01-04 per the SAT catalog.                                                                                                                    |
| `311`        | `cancel.substitution_folio_invalid`      |     no    | The substitute folio is not valid. For motivo 01, supply the UUID of a valid, already-stamped replacement CFDI.                                                                   |
| `312`        | `cancel.substitution_folio_not_required` |     no    | This motivo does not require a substitute folio. Remove folioSustitucion.                                                                                                         |
| `313`        | `cancel.outside_annual_declaration`      |     no    | The cancellation falls outside the allowed annual declaration window and is no longer permitted.                                                                                  |
| `314`        | `cancel.relation_invalid`                |     no    | The declared relation is invalid. Verify the related CFDI and relationship type.                                                                                                  |

### Status query (`consultarEstatusComprobante`)

Codes from the SAT status query used during cancellation polling and validation enrichment.

| PAC/SAT code | Our `code`                       | Retryable | Remediation                                                                                                                                                                                                                                                |
| ------------ | -------------------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`          | `pac.ok`                         |     no    | No action needed.                                                                                                                                                                                                                                          |
| `1`          | `pac.auth_failed`                |     no    | The stamping-service credentials were rejected. Do NOT retry — repeated failures can lock the account. This is a server-side configuration issue: contact support so the environment credentials can be verified (test and live credentials are separate). |
| `2`          | `pac.contract_invalid`           |     no    | The stamping account is not found, is expired, or has no available stamping credits. This is a server-side account issue: contact support to renew the account or top up stamp credits.                                                                    |
| `3`          | `pac.invalid_parameter`          |     no    | A required parameter was missing or malformed (also returned for a malformed JSON body). Do not retry unchanged — inspect the request payload against the timbrarCfdi contract.                                                                            |
| `4`          | `pac.internal_error`             |    yes    | The stamping service reported a transient internal error. Retry with backoff. If it persists, the CFDI was almost certainly NOT stamped — safe to resubmit (idempotency guards against duplicates).                                                        |
| `5`          | `pac.maintenance`                |    yes    | The stamping service is temporarily offline for maintenance. Retry with backoff after a short delay.                                                                                                                                                       |
| `6`          | `pac.query_incomplete`           |    yes    | The status query did not complete. Retry with backoff.                                                                                                                                                                                                     |
| `7`          | `cancel.sat_service_unavailable` |    yes    | The SAT returned an error during the status query. Retry with backoff.                                                                                                                                                                                     |
| `90`         | `cfdi.not_found`                 |     no    | The comprobante was not found at the SAT. Verify the UUID and that emisor RFC, receptor RFC and Total exactly match the CFDI.                                                                                                                              |
| `91`         | `pac.ok`                         |     no    | No action needed — the comprobante was found.                                                                                                                                                                                                              |
| `92`         | `cfdi.invalid_expression`        |     no    | The status query expression is invalid. Check the Total formatting (decimals must match the CFDI exactly) and the RFCs.                                                                                                                                    |
| `93`         | `cfdi.status_indeterminate`      |    yes    | The SAT could not determine the state. Retry the status query later.                                                                                                                                                                                       |

### CFDI lifecycle status (`estatusCfdi`)

These are *states*, not errors. The SAT reports one of these when you query a CFDI; we map it to a normalized `cancel_status` bucket surfaced on the invoice `cancellation` object and on `POST /v1/validations`.

| SAT code | Meaning                                            | Normalized `cancel_status` |
| -------- | -------------------------------------------------- | -------------------------- |
| `0`      | Desconocido                                        | `unknown`                  |
| `1`      | CFDI no existe                                     | `unknown`                  |
| `2`      | Vigente (aceptación indeterminada)                 | `none`                     |
| `3`      | Vigente con aceptación                             | `none`                     |
| `4`      | Vigente sin aceptación                             | `none`                     |
| `5`      | Vigente no cancelable                              | `none`                     |
| `6`      | Cancelado (medio no especificado)                  | `cancelled`                |
| `7`      | Cancelación en proceso (espera respuesta receptor) | `pending`                  |
| `8`      | Cancelado con aceptación                           | `cancelled`                |
| `9`      | Cancelado sin aceptación                           | `cancelled`                |
| `10`     | Cancelado por plazo vencido                        | `cancelled`                |
| `99`     | Indeterminado (SAT no disponible)                  | `unknown`                  |

### Descarga masiva (massive download)

Codes from the SAT descarga masiva service (`POST /v1/downloads`). Note the lifetime/size limits — see /guides/massive-download.

| PAC/SAT code | Our `code`                        | Retryable | Remediation                                                                                                                                                                                        |
| ------------ | --------------------------------- | :-------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `404`        | `sat.download_uncontrolled_error` |    yes    | An uncontrolled error occurred on the descarga masiva service. Retry with backoff; if it persists, contact support.                                                                                |
| `5000`       | `sat.download_accepted`           |     no    | No action needed — poll the request status until packages are ready.                                                                                                                               |
| `5001`       | `sat.download_unauthorized`       |     no    | SAT "tercero no autorizado": the FIEL does not match the requested RFC. Ensure the FIEL PFX belongs to the RFC being downloaded and that side (issued/received) matches that RFC’s role.           |
| `5002`       | `sat.download_request_limit`      |     no    | SAT allows at most 2 lifetime requests with identical parameters. Do NOT retry the identical query — fragment or vary the date range (e.g. split the month into weeks) to make a distinct request. |
| `5003`       | `sat.download_too_large`          |     no    | The request exceeds the SAT cap (200,000 XMLs / 1,000,000 metadata records). Fragment the date range into smaller windows and issue separate requests.                                             |
| `5004`       | `sat.download_no_data`            |     no    | The SAT found no CFDIs for these filters — this is a terminal, successful, empty result. Do not retry; the range simply has no documents.                                                          |
| `5005`       | `sat.download_duplicate`          |     no    | An identical request already exists. Reuse the existing request’s id, or vary the date range to create a distinct request.                                                                         |
| `5007`       | `sat.download_package_not_found`  |     no    | The requested package was not found — its download URL likely expired (URLs live \~5 minutes). Re-poll the request status to re-mint the package URLs and download immediately.                    |
| `5010`       | `sat.download_packaging_error`    |    yes    | The SAT failed to package the result. Retry the status poll; if it persists, re-issue the request with a smaller date range.                                                                       |
| `8000`       | `sat.download_generation_error`   |    yes    | The stamping service failed to generate the SAT request. Retry with backoff; if it persists, verify the FIEL, dates and RFC.                                                                       |

### Descarga masiva lifecycle (`estado`)

SAT download-request lifecycle states, mapped to our public `download.status`.

| SAT estado | Meaning              | Our `status` |
| ---------- | -------------------- | ------------ |
| `1`        | Aceptada             | `pending`    |
| `2`        | En proceso           | `pending`    |
| `3`        | Terminada / lista    | `pending`    |
| `4`        | Descargando paquetes | `pending`    |
| `5`        | Rechazada            | `rejected`   |
| `6`        | Vencida / expirada   | `expired`    |
| `7`        | Paquetes listos      | `ready`      |

***

*Regenerate this file with `pnpm openapi`.*
