auth.key_revoked | 401 | API key revoked | Mint a replacement key with POST /v1/api_keys and update your credentials. |
auth.unauthorized | 401 | Authentication required | Send Authorization: Bearer sk_test_... (or sk_live_…) with a valid API key. |
autofactura.driver_unavailable | job | The Crawlee autofactura driver is not installed | Run pnpm install (crawlee+playwright are optionalDependencies) then pnpm exec playwright install chromium, or set AUTOFACTURA_DRIVER=simulated. |
autofactura.option_not_found | job | No matching option in the portal dropdown | The portal may label this dropdown differently than the SAT code. Check the value sent for regimen/usoCfdi against the portal options. |
autofactura.portal_unknown | job | No self-invoice portal could be resolved from the ticket | Ensure the ticket photo shows the merchant self-invoice URL, or pass portal_url on the request. |
autofactura.vision_empty_response | job | The vision model returned no text | Retry; if it persists the model may not support image input — check AUTOFACTURA_VISION_MODEL. |
autofactura.vision_error | job | The vision model request failed | Check AUTOFACTURA_VISION_API_KEY and AUTOFACTURA_VISION_MODEL; retry on 429/5xx. |
autofactura.vision_parse_error | job | The vision model did not return parseable ticket JSON | Retry; if it persists, the prompt/model pairing may need adjustment. |
billing.already_subscribed | 409 | Organization already has a subscription | Use POST /v1/billing/portal_sessions (or the dashboard) to change or cancel the plan. |
billing.free_limit_reached | 402 | Free plan live-stamp limit reached | Upgrade in the dashboard (Billing) or via POST /v1/billing/checkout_sessions. Test-mode stamping stays unlimited. |
billing.no_billing_account | 409 | No billing account yet | Subscribe first via POST /v1/billing/checkout_sessions. |
billing.subscription_required | 402 | Live downloads need a subscription | Subscribe in the dashboard (Billing) or via POST /v1/billing/checkout_sessions, then retry. Test-mode downloads stay free. |
cancel.already_cancelled | 422 | Previously cancelled | The CFDI was already cancelled. Treat as cancelled — no further action needed. |
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. |
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. |
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. |
cancel.motivo_invalid | 422 | Motivo not valid | The motivo is not valid. Use one of 01-04 per the SAT catalog. |
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). |
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. |
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. |
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. |
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. |
cancel.outside_annual_declaration | 422 | Outside the annual declaration window | The cancellation falls outside the allowed annual declaration window and is no longer permitted. |
cancel.relation_invalid | 422 | Relation invalid | The declared relation is invalid. Verify the related CFDI and relationship type. |
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. |
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. |
cancel.sat_service_unavailable | 502 | SAT error during query | The SAT returned an error during the status query. Retry with backoff. |
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. |
cancel.substitution_folio_not_required | 422 | Substitute folio not required | This motivo does not require a substitute folio. Remove folioSustitucion. |
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. |
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). |
catalog.not_found | 404 | Unknown catalog | Use one of: the slugs listed by GET /v1/catalogs. GET /v1/catalogs lists them all. |
cfdi.csd_expired | 422 | Invalid invoice | Renew the CSD at the SAT portal; an expired/not-yet-valid certificate cannot stamp. |
cfdi.csd_rfc_mismatch | 422 | Invalid invoice | Use the CSD (certificado de sello digital) issued to the emitter RFC. |
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. |
cfdi.fecha_in_future | 422 | Invalid invoice | Generate Fecha at stamp time; it must not be in the future. |
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). |
cfdi.fecha_too_old | 422 | Invalid invoice | Re-issue the invoice; CFDI must be stamped within 72h of Fecha. |
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. |
cfdi.invalid_fecha | 422 | Invalid invoice | Pass date as ‘YYYY-MM-DDTHH:mm:ss’ (SAT forbids a timezone suffix). |
cfdi.invalid_input | 422 | Invalid invoice | Fix every field listed in errors and resubmit. See /openapi.json for the schema. |
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. |
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. |
cfdi.missing_tax_rate | 422 | Invalid invoice | Provide rate (e.g. 0.16) for Tasa/Cuota taxes. |
cfdi.missing_uso | 422 | Invalid invoice | Set use at invoice level or customer.use. |
cfdi.no_tfd | 422 | Invalid invoice | Only stamped CFDIs (with a TFD) have a TFD cadena. |
cfdi.not_a_csd | 422 | Invalid invoice | Sign CFDIs with the CSD; the FIEL is only for descarga masiva. |
cfdi.not_comprobante | 422 | Invalid invoice | Pass a CFDI 4.0 Comprobante XML. |
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. |
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). |
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’. |
cfdi.parse_error | 422 | Invalid invoice | Provide a well-formed CFDI XML string. |
cfdi.pdf_dependencies_missing | 422 | Invalid invoice | Install the optional PDF peer dependencies (the CFDI PDF renderer and @xmldom/xmldom) on the server. |
cfdi.pdf_requires_stamp | 422 | Invalid invoice | Stamp the CFDI with the PAC first; the PDF shows the fiscal folio (UUID). |
cfdi.retencion_exento | 422 | Invalid invoice | Use factor Tasa or Cuota for withholdings, or make it a traslado. |
cfdi.sello_injection_failed | 422 | Invalid invoice | Ensure the XML is a well-formed CFDI 4.0 Comprobante. |
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. |
cfdi.status_indeterminate | 502 | Indeterminate state | The SAT could not determine the state. Retry the status query later. |
cfdi.unknown_currency | 422 | Invalid invoice | Use a valid ISO 4217 currency code present in c_Moneda. |
connect.account_disabled | 403 | Connected account disabled | Re-enable the account via PATCH /v1/accounts/:id {“disabled”: false}. |
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. |
connect.nesting_not_allowed | 403 | Connected accounts cannot own connected accounts | Create connected accounts from the top-level platform organization. |
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. |
dashboard.email_in_use | 409 | Email already registered | Sign in at /signin, or use a different email. |
dashboard.invalid_credentials | 401 | Invalid email or password | Check your credentials and try again. |
dashboard.pages_unavailable | 503 | Dashboard pages unavailable | Deploy the web/ assets alongside the API, then retry. |
dashboard.session_required | 401 | Sign in required | Sign in at /signin to obtain a session cookie. |
dashboard.too_many_attempts | 429 | Too many sign-in attempts | Wait 15 minutes before trying again. |
dashboard.too_many_signups | 429 | Too many sign-ups | Wait an hour before trying again, or sign in to an existing account. |
download.concurrent_request | 409 | An identical download was just created | — |
download.fiel_required | 422 | Fiscal profile has no SAT password or FIEL | Save the RFC’s SAT password with POST /v1/fiscal_profiles/:id/sat_credential and wait for it to verify, or upload a FIEL via PATCH /v1/fiscal_profiles/:id, then retry. |
download.invalid_range | 422 | Invalid date range | Provide date_from <= date_to. |
download.no_request_id | job | Download has no SAT request id | The solicitud never registered with the PAC — create the download again. |
download.overlapping_in_progress | 409 | An overlapping download is still running | Wait for that download to finish, then send this request again. Invoices it delivers are skipped and not charged twice. |
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. |
download.range_too_large | 422 | Date range is too wide | Split the range into requests of at most {MAX_RANGE_DAYS} days each. |
download.range_too_old | 422 | Date range starts too early | Request invoices issued on or after {EARLIEST_DATE}. |
download.request_failed | 502 | SAT descarga masiva request failed | — |
download.unknown_error | job | Download failed (unclassified) | Read the download error.message; if it looks transient, create a new download for the same range. |
fiscal_document.concurrent_request | 409 | Another request for this document just finished | — |
fiscal_document.credential_expired | 422 | The SAT credential has expired | — |
fiscal_document.credential_missing | 422 | Fiscal profile has no SAT credential | — |
fiscal_document.credential_pending | 422 | The SAT credential is still being checked | Wait for the fiscal_profile.sat_credential_verified webhook or poll GET /v1/fiscal_profiles/:id/sat_credential, then retry. |
fiscal_document.credential_replaced | 422 | The SAT credential was replaced | Create a new fiscal_document; it will use the credential saved now. |
fiscal_document.credential_unverified | 422 | The SAT credential is not verified | Confirm the RFC and SAT password with the taxpayer before saving it again: do not retry the same password automatically. {saveRemediation} |
fiscal_document.deadline_exceeded | job | The request ran out of time | Create a new fiscal_document. If it keeps happening, contact support. |
fiscal_document.expired | 410 | The PDF is no longer stored | Create a new fiscal_document to get a current PDF. |
fiscal_document.free_quota_exceeded | 402 | The free constancia for this quarter has been used | The next free constancia for this RFC is available from {nextStartsOn} (America/Mexico_City). Until then, use the PDF you already have. |
fiscal_document.invalid_artifact | job | The document service did not return a PDF | Create a new fiscal_document. If it keeps happening, contact support. |
fiscal_document.not_ready | 409 | The PDF is not available | Wait for the fiscal_document.ready webhook or poll GET /v1/fiscal_documents/:id; if it ended in another state, read its error and create a new request. |
fiscal_document.rfc_in_progress | 409 | A constancia for this RFC is already in progress | Wait for that request to finish; if it does not deliver a PDF, retry this one. |
fiscal_document.simulate_test_only | 422 | simulate is only available in test mode | Remove simulate, or use a sk_test_ key. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
fiscal_profile.manifest_required | 409 | Carta manifiesto not signed | Sign the carta manifiesto for this RFC first: POST /v1/fiscal_profiles/{id}/manifest with the FIEL (e.firma). This is a one-time authorization per profile. Next action → { “type”: “sign_manifest”, “endpoint”: “POST /v1/fiscal_profiles/{id}/manifest”, “requires”: [“fiel”] }. |
fiscal_profile.sandbox_expired | 422 | The test-mode sandbox certificate has expired | Register your own test fiscal profile with POST /v1/fiscal_profiles (RFC + CSD) and pass its id as fiscal_profile_id. |
fiscal_profile.sandbox_not_supported | 422 | Not available on the sandbox fiscal profile | Register your own test fiscal profile with POST /v1/fiscal_profiles (RFC + CSD) and use its id. The sandbox issuer only stamps test invoices. |
fiscal_profile.sandbox_retired | 422 | The sandbox fiscal profile is no longer available | Pass the id of your test fiscal profile as fiscal_profile_id (GET /v1/fiscal_profiles). |
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. |
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. |
idempotency.replay_unavailable | 409 | The original response for this Idempotency-Key cannot be replayed | The original request succeeded but its one-time secret cannot be recovered. Find the resource with a list call, delete or revoke it, and create a new one with a fresh Idempotency-Key. |
internal.error | 500 | Internal server error | — |
invoice.already_stamped | 409 | Invoice already stamped | — |
invoice.cancellation_in_progress | 409 | Cancellation already requested | — |
invoice.cancellation_rejected | 422 | Cancellation rejected | Check the UUID is vigente and the motivo/substitute are correct; retrieve the acuse for details. |
invoice.folio_contention | 409 | Could not assign a folio | Retry the request; concurrent invoice creation on this serie is heavy. |
invoice.folio_taken | 409 | Folio already used | — |
invoice.no_xml | 422 | Invoice has no XML to stamp | Recreate the invoice; the signed XML is missing. |
invoice.not_stampable | 409 | Invoice cannot be stamped | — |
invoice.not_stamped | 409 | Only stamped invoices can be cancelled | — |
invoice.pdf_requires_stamp | 409 | PDF is only available for stamped invoices | — |
invoice.profile_missing_csd | 422 | Fiscal profile has no CSD | Upload the CSD (.cer + .key + password) to the fiscal profile before issuing invoices. |
invoice.substitute_not_stamped | 422 | Substitute invoice is not stamped | Stamp the replacement invoice before referencing it as a substitute. |
invoice.substitute_required | 422 | Substitute invoice required | Pass substitute_invoice_id pointing to the stamped CFDI that replaces this one, or use motivo ‘02’. |
invoice.xml_requires_stamp | 409 | XML is only available for stamped invoices | — |
manifest.email_required | 422 | An email is required for the manifiesto | Provide email in the request or set the MANIFEST_EMAIL config default. |
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. |
manifiesto.bad_request | 422 | Petición inválida o parámetros incorrectos | The request was missing or had incorrect parameters (cert, key, keyPass, correo). |
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. |
manifiesto.certificate_error | 422 | Error en el certificado | There was an error with the certificate. Verify the FIEL files and password, then retry. |
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. |
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. |
manifiesto.contract_not_valid | 422 | El contrato no es válido | The signing service reports the signing contract is not valid. Contact support. |
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. |
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. |
manifiesto.invalid_response | 422 | Manifiesto signing service returned a non-XML response: {message} | The manifiesto signing service returned a non-XML body (usually an HTML error or login page). This is typically a misconfigured firmado base URL, a manifiesto service not provisioned for the PADE account, or bad platform credentials — verify the PRODIGIA_FIRMADO_* config and that the account is provisioned for manifiesto signing. |
manifiesto.malformed_contract | 422 | Contrato mal formado | The manifiesto contract payload was malformed. Contact support. |
manifiesto.malformed_xml | 422 | XML mal formado | The signing service could not parse the request. Retry; if it persists, contact support. |
manifiesto.network_error | 502 | Manifiesto signing request failed | The manifiesto signing request could not reach the signing service. Retry with backoff. |
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. |
manifiesto.signed | 422 | Firma exitosa | — |
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. |
org.bootstrap_disabled | 403 | Organization bootstrap is disabled | Enable ALLOW_ORG_BOOTSTRAP or provision organizations out-of-band. |
org.not_found | 404 | Organization not found | Check the organization id. |
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). |
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. |
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. |
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. |
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. |
pac.fiel_not_assembled | 422 | FIEL could not be packaged as a PKCS#12 | The FIEL stored on this fiscal profile could not be packaged as a PKCS#12, so nothing was sent to the PAC or the SAT. Usually the key password does not match the .key, or the .key is not a FIEL private key. Upload fiel_cer, fiel_key and fiel_password again, then retry. If they are correct, contact support with the request_id: the server’s PKCS#12 packaging is failing. |
pac.internal_error | 502 | PAC internal error | The service reported a transient internal error. Retry with backoff. |
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. |
pac.maintenance | 502 | PAC offline for maintenance | The stamping service is temporarily offline for maintenance. Retry with backoff after a short delay. |
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. |
pac.ok | 422 | Comprobante found | No action needed — the comprobante was found. |
pac.query_incomplete | 502 | General error, query not completed | The status query did not complete. Retry with backoff. |
pac.sandbox_duplicate | 422 | Duplicate reported for a sandbox invoice | Create a new invoice: POST /v1/invoices assigns a new folio. The duplicate response was discarded. |
pac.stamp_outcome_unknown | 422 | Stamping outcome unknown | Do not create this invoice again: it may already be a real CFDI. Find it with GET /v1/invoices?status=stamp_failed and call POST /v1/invoices/:id/stamp with a new Idempotency-Key, within 3 months. That re-sends the same serie and folio, so an existing stamp is returned instead of a second CFDI; after 3 months the PAC no longer matches the folio, so check the SAT status first. |
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. |
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. |
request.error | 500 | Request error | — |
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. |
request.invalid_expand | 422 | Invalid expand parameter | Use only the expand values the endpoint documents (e.g. fiscal_profile). Remove unsupported values. |
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. |
request.invalid_version | 400 | Unknown API version | Send a supported version in the Invoice-Version header, or omit it to use the current version. |
request.method_not_allowed | 405 | Method not allowed | — |
request.validation_failed | 422 | Request validation failed | Fix the fields listed in errors and resubmit. See /openapi.json for the schema. |
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). |
sat_credential.concurrent_update | 409 | SAT credential was changed by another request | — |
sat_credential.csd_is_not_fiel | 422 | CSD supplied where a FIEL is required | Send the taxpayer’s FIEL (e.firma). SAT does not accept a CSD for this. |
sat_credential.fiel_expired | 422 | FIEL is expired or not yet valid | Renew the e.firma with SAT and send the new certificate and key. |
sat_credential.fiel_rfc_mismatch | 422 | FIEL does not belong to this profile’s RFC | Send the FIEL issued to {rfc}, or use the fiscal profile for {rfc}. |
sat_credential.invalid_fiel | 422 | Invalid FIEL certificate or password | Check that cer_base64 is the .cer, key_base64 is the matching .key, and password is the private-key password of the e.firma. |
sat_service.artifact_checksum_mismatch | 502 | SAT document failed its integrity check | Read the job again and retry the download; the document can change while a job is still updating it. |
sat_service.artifact_not_ready | 409 | SAT document is not ready | Poll the document job and download once it reports an artifact is available. |
sat_service.auth_failed | 503 | SAT document service rejected this deployment | A server-side configuration issue, not a problem with your request. Operators must check SAT_API_KEY; do not retry until it is corrected. |
sat_service.auth_method_unsupported | 422 | Credential type cannot request this document | Register a CIEC credential for this document type. |
sat_service.capacity_reached | 429 | SAT document service is at capacity | Retry later with backoff; document jobs run with limited concurrency. |
sat_service.captcha_failed | job | The SAT CAPTCHA could not be solved | Submit the document request again later. |
sat_service.conflict | 409 | SAT document request conflicts with an earlier one | An Idempotency-Key was reused with a different document type, credential, range or deadline. Reuse a key only for identical retries; use a new key for a new request. |
sat_service.credential_rejected | job | SAT rejected the credential | Ask the taxpayer to confirm their RFC and SAT password, then register the credential again. Do not retry the same password automatically. |
sat_service.deadline_exceeded | job | The SAT document job ran out of time | Submit a new request. For invoices, use a shorter date range; a job cannot outlive its credential. |
sat_service.invalid_request | 422 | SAT document service refused the request | Check the RFC, the password length (1 to 256 characters) and any date range, then send a corrected request. |
sat_service.invalid_response | 502 | SAT document service returned an unexpected response | Retry with backoff. If it persists, contact support with the request_id. |
sat_service.job_failed | job | The SAT document job failed | Submit a new request. If it persists, contact support with the request_id. |
sat_service.needs_review | job | The SAT request needs manual review | Contact support with the request_id so the request can be reviewed. |
sat_service.not_configured | 503 | SAT document service is not configured | Live SAT access is not enabled on this deployment. Operators must set SAT_SERVICE_URL and SAT_API_KEY; until then, use a sk_test_ key to exercise this flow against simulated data. |
sat_service.not_found | 404 | SAT credential or job not found | The credential or document job does not exist or is no longer retained. Register the credential again or submit a new job. |
sat_service.portal_changed | job | The SAT portal did not look as expected | Contact support with the request_id; this needs a fix on our side. |
sat_service.sat_unavailable | job | SAT was unavailable or slow | Submit the document request again later; SAT outages are usually temporary. |
sat_service.unavailable | 503 | SAT document service is unavailable | The request did not complete. Retry with backoff; for a request that creates something, resend the same Idempotency-Key. |
sat_service.verification_inconclusive | job | The credential check was inconclusive | The check could not establish whether the password is valid (for example an outage or a CAPTCHA problem). Register the credential again later. |
sat.download_accepted | 422 | Download request accepted | No action needed — poll the request status until packages are ready. |
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. |
sat.download_expired | job | SAT marked the solicitud as expired | Package URLs expire quickly — create a new download for the same range. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
sat.download_uncontrolled_error | 503 | Uncontrolled error | An uncontrolled error occurred on the descarga masiva service. Retry with backoff; if it persists, contact support. |
sync.auth_failed | 422 | Sync-service credentials rejected | The sync-service credentials were rejected. This is a server-side configuration issue: contact support so the environment credentials can be verified. |
sync.download_url_error | 503 | Error al generar la URL de descarga | The download URL could not be generated. Retry with backoff. |
sync.fiel_required | 422 | FIEL required to enable SAT sync | Attach the taxpayer’s FIEL to this fiscal profile (fiel_cer / fiel_key / fiel_password), then enable sync again. |
sync.in_process | 503 | Solicitud en proceso | The request is still being processed. Keep polling with backoff; this is the normal in-flight state, not a failure. |
sync.information_expired | 422 | Información expirada | The prepared result expired before it was collected. Issue a fresh request for the same range. |
sync.information_not_found | 422 | No se encontró la información solicitada | The referenced request no longer exists. Issue a fresh request rather than polling this one. |
sync.internal_error | 503 | Error interno del servicio de sincronización | The sync service failed internally. Retry with backoff. |
sync.invalid_fiel | 422 | Problema con el PFX de la FIEL | The FIEL (e.firma) could not be read. Verify the .cer/.key are a current e.firma (not a CSD) and that the password matches the private key. NOTE: the SAT does not validate the certificate at registration time — a revoked or expired FIEL registers successfully and only fails later when data is requested, so confirm the certificate is active at the SAT’s certificate-status portal. |
sync.no_documents | 422 | No se encontraron comprobantes | No CFDIs matched the filters. This is a terminal, successful, EMPTY result — do not retry the same query. |
sync.ok | 422 | Solicitud exitosa | No action needed. |
sync.request_created | 422 | Solicitud creada | No action needed — the request was created; poll for the result. |
sync.request_creation_failed | 503 | Error al crear la solicitud | The request could not be created. Retry with backoff. |
sync.request_expired | 422 | Solicitud vencida | The request expired before it was collected. Issue a new request for the same range. |
sync.rfc_already_registered | 422 | El RFC ya existe | This RFC is already registered for automatic SAT synchronization. Do not register it twice — update the existing profile instead. |
sync.rfc_disabled | 422 | RFC deshabilitado | Automatic synchronization is disabled for this RFC. Re-enable sync on the fiscal profile before querying its documents. |
sync.uuid_not_found | 422 | No se encontró el UUID | The folio fiscal is not in the synced store. It may not have been issued yet, may fall outside the synced date range, or may not belong to this RFC. |
sync.zip_error | 503 | Error al crear el ZIP | The document archive could not be built. Retry with backoff. |
ticket_invoice.failed | job | The merchant portal refused the ticket | The ticket was already invoiced, or the folio/portal is wrong — verify and submit a corrected ticket. |
ticket_invoice.fiscal_profile_not_found | 400 | fiscal_profile_id does not reference a known fiscal profile | Create a fiscal profile first (POST /v1/fiscal_profiles) and pass its id as fiscal_profile_id. |
ticket_invoice.invalid_metadata_json | 422 | metadata is not valid JSON | Send metadata as a JSON string, e.g. metadata={“trip”:“CDMX”}. |
ticket_invoice.needs_review | job | The ticket could not be invoiced automatically | Finish the invoice on the merchant portal manually (captcha/ambiguous form/low OCR confidence), then record the CFDI. |
ticket_invoice.photo_missing | job | The ticket photo is no longer available to process | Submit a new ticket invoice with the photo attached. |
ticket_invoice.xml_unavailable | 409 | XML is only available for a completed ticket invoice | — |
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. |
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. |
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. |