The same API v5
Same endpoints, same fields and same responses as in production. Only the base URL and the key change.
The sandbox is a free test environment with the same API v5 as production. It stamps with a test PAC, so the CFDI you generate have no tax validity. When your integration works, you switch the base URL and the key.
json={"Version": "4.0","Serie": "A","Folio": "AUTO","Fecha": "AUTO","Receptor": {"Rfc": "XIA190128J61","Nombre": "XENON INDUSTRIAL ARTICLES","UsoCFDI": "G03"},"Conceptos": [ ... ],...}
{"message": "The document was generated successfully","code": 200,"cfdi": {"UUID": "6FA90F39-2D7A-4F1C-9C4D-AC2B11D9F6E0","FechaTimbrado": "2026-09-23T10:15:30","XmlBase64": "PD94bWwgdmVyc2lvbj0i...","PDF": "https://sandbox-app.facturadigital.com.mx/docs/pdf/6FA90F39-2D7A-4F1C-9C4D-AC2B11D9F6E0","XML": "https://sandbox-app.facturadigital.com.mx/docs/xml/..."}}
Sample interface with real API v5 calls against the sandbox; the values are examples. The full reference is at docs.facturadigital.com.mx.
What works the same as in production and what changes in the sandbox.
Same endpoints, same fields and same responses as in production. Only the base URL and the key change.
The sandbox always stamps with a test PAC. The CFDI you generate there have no tax validity.
The PDF of every test CFDI carries the marks “Timbrado de prueba” and “Sin validez fiscal”.
If you ask for email delivery (enviar_mail), the message doesn't reach the real recipient: outside production it's diverted to a test inbox.
Your sandbox key doesn't work in production and vice versa. If you mix them up, the error tells you which environment answered.
Your sandbox account is independent from production: its CFDI, keys and PDF templates don't mix.
Errors respond with HTTP 400 and an internal code in the body. You can reproduce these in the sandbox to test how your system reacts.
code 501The message ends with the environment that answered, for example [Environment: SANDBOX].
Call without the X-Api-Key header or with your production keycode 602To seal the XML, the account needs an active Certificado de Sello Digital.
POST /invoice/create before uploading your CSDcode 601Each stamped CFDI uses 1 credit; with no balance, nothing is stamped.
Stamp when GET /account/balance returns 0code 400The response says the JSON wasn't received: “Invalid or non received json in headers or body.”
POST /invoice/create without the json fieldcode 702It responds with errorType cfdi_schema_validation and the detail of each error in the errors field.
Send a CFDI that doesn't comply with Anexo 20code 400Cancellation takes its parameters (UUID, MOTIVO) as headers, not in the body.
POST /invoice/cancel without the UUID headerWhat you integrate in the sandbox works the same in production.
POST /invoice/create: you send the CFDI as JSON and the API builds the XML, seals it with your CSD and stamps it.
POST /invoice/stampxml (Base64) and /invoice/stampxmlfile (file) for XML you already sealed with your CSD.
POST /invoice/cancel with reasons 01 to 04, or /invoice/cancelwithcsd sending the CSD in the request.
GET /invoice/list, listextended, listpayments, listreceived, listbydaterange and listwithfilters.
GET /account/authorize to get your key and GET /account/balance to check your credits.
Success with HTTP 200 and code 200; validation, key, balance or certificate errors with HTTP 400 and an internal code (501, 601, 602, 702…).
Your code doesn't change: only the base URL and the key.
https://sandbox-app.facturadigital.com.mx/api/v5Configuración → CertificadosX-Api-Key: <production key>https://app.facturadigital.com.mx/api/v5The same code stamps in production with your folios, which never expire.
Notifications to your system when a CFDI is stamped or cancelled, or when a payment is recorded.
Libraries for Node.js, PHP and Python that call the same API v5.
Connect Claude, ChatGPT or Gemini to your account. The assistant prepares the invoice and you confirm.
No. The sandbox is free. It's a separate environment, so what you stamp there doesn't use the folios in your production account.
No. The sandbox always stamps with a test PAC: the CFDI have no tax validity and the PDF says so with the marks “Timbrado de prueba” and “Sin validez fiscal”.
By the base URL (https://sandbox-app.facturadigital.com.mx/api/v5 versus https://app.facturadigital.com.mx/api/v5) and by the key: each environment has its own. If you use one environment's key in the other, the API responds with code 501 and the message ends with the environment that answered, for example [Environment: SANDBOX].
The same way as in production, but in your sandbox account: copy it from Configuración → Datos de facturación or get it with GET /account/authorize by sending your username and password in the API-USUARIO and API-PASSWORD headers. It goes in the X-Api-Key header, Base64-encoded.
Not to your customers. Outside production, emails (for example, with enviar_mail) are diverted to a test inbox.
Yes. The SDKs call the same API v5; for the sandbox you use the test base URL and key.
Two: code 5037 means the PAC couldn't be reached; nothing was sent and you can retry. Code 5034 means the PAC didn't respond; the CFDI may have been stamped, so check with the SAT before retrying. The response includes the Serie and Folio that were used.
The sandbox is free and the API is included: in production you pay for folios that never expire.