Reasons 01 to 04
02 if you send no reason; 01 with the replacing UUID; 03 if the transaction didn't happen; 04 for a named transaction included in a global invoice.
Send the UUID and the reason, and the API files the cancellation with the SAT using your CSD. The response includes the result and the SAT acknowledgment in Base64. Cancelling uses no folio, and if you stamp already-sealed XML, you cancel by sending your CSD in the request.
The full CFDI 4.0 cancellation process, from your own system.
02 if you send no reason; 01 with the replacing UUID; 03 if the transaction didn't happen; 04 for a named transaction included in a global invoice.
If the request is accepted, you get the acknowledgment in Base64 and the CFDI is marked cancelled in your account, with its acknowledgment stored.
/invoice/cancel uses the CSD you uploaded. /invoice/cancelwithcsd takes your .cer, your .key and the password in the request.
Neither operation deducts folios. /invoice/cancel does require your account balance to be above zero.
GET /validator/cfdi asks the SAT for the CFDI's status, whether it can be cancelled and its cancellation status.
Withholding certificates are cancelled with /invoice/cancelretention, with the same headers and the same reasons.
A cancellation with reason 02. Parameters go in HTTP headers, not in the body; the key goes in X-Api-Key, like everywhere else in the API.
# FD_API=https://sandbox-app.facturadigital.com.mx/api/v5
curl -X POST "$FD_API/invoice/cancel" \
-H "X-Api-Key: $FD_API_KEY" \
-H "UUID: 6FA90F39-2D7A-4F1C-9B3E-5C1D8A0E7B42" \
-H "MOTIVO: 02"{
"message": "Solicitud de cancelación exitosa * Se considera una solicitud de cancelación exitosa, sin embargo esto no asegura su cancelación",
"code": 200,
"acuse": "PD94bWwgdmVyc2lvbj0iMS4wIj8+PEFjdXNlLi4u",
"date": "2026-09-28 10:20:00",
"uuid": "6FA90F39-2D7A-4F1C-9B3E-5C1D8A0E7B42",
"uuid_estatus": 201,
"env_mode": "Sandbox",
"estatus_uuid": 201,
"msg_error": null,
"msg_error_detailt": null
}# Reason 01 with your CSD in the request (the new CFDI is already stamped)
curl -X POST "$FD_API/invoice/cancelwithcsd" \
-H "X-Api-Key: $FD_API_KEY" \
--data-urlencode "uuid=6FA90F39-2D7A-4F1C-9B3E-5C1D8A0E7B42" \
--data-urlencode "motivo=01" \
--data-urlencode "folioSustitucion=0B7C2E51-8A4D-4E0F-A1C3-7D9E6F2B5A10" \
--data-urlencode "b64Cer@csd-cer.b64" \
--data-urlencode "b64Key@csd-key.b64" \
--data-urlencode "passwordCSD=$CSD_PASSWORD"From the reason to the confirmation with the SAT.
02 if the CFDI has errors and you won't replace it. 01 if you replace it: first stamp the new one with CfdiRelacionadosTipoRelacion "04" and the original UUID in CfdiRelacionados.
POST /invoice/cancel with the UUID and MOTIVO headers, plus FOLIOSUSTITUCION if the reason is 01. If there's no CSD in your account, use /invoice/cancelwithcsd.
The response is HTTP 200 even if the SAT doesn't accept the request. code 200 means accepted; with any other value, check message, msg_error and msg_error_detailt.
An accepted request doesn't guarantee the cancellation. Check the status with GET /validator/cfdi and the uuid, rfcemisor, rfcreceptor and total parameters.
Errors in your request (key, UUID, balance, parameters) respond with HTTP 400. The cancellation result comes with HTTP 200 and its code in the body.
Stamp income and transfer CFDI with the Carta Porte complement, with SAT rules checked before stamping.
Stamp the REP for your PPD invoices with the same endpoint and the same key.
Test cancellations for free with the same API v5 as production.
Let your system know what happens in your account without polling the API.
Libraries to call API v5 from your language, with the same endpoints.
Authentication, endpoints and the three ways to stamp: JSON, Base64 XML or an XML file.
Something missing? Message us or check the full reference.
No. Neither /invoice/cancel nor /invoice/cancelwithcsd deducts folios. /invoice/cancel does require a balance above zero (otherwise it responds with code 601); /invoice/cancelwithcsd doesn't check the balance.
01: document issued with errors, with a relation; it requires the replacing UUID. 02: document issued with errors, without a relation; it's the default if you send no reason. 03: the transaction didn't happen. 04: named transaction included in a global invoice.
First stamp the new one with CfdiRelacionadosTipoRelacion "04" and the original's UUID in CfdiRelacionados. Then cancel the original with MOTIVO 01 and the new one's UUID in FOLIOSUSTITUCION.
Because the response carries the result of the request, whatever it is. Read code: 200 means accepted; any other value comes with the reason in message, msg_error and msg_error_detailt. Errors in your request, like an invalid key or a missing UUID, do respond with HTTP 400.
It means the SAT accepted the request (uuid_estatus 201), and that doesn't guarantee the cancellation. If the cancellation needs your customer's acceptance, it stays in process until they respond. Check the status with GET /validator/cfdi: escancelable and estatuscancelacion tell you where it stands.
Yes, with /invoice/cancelwithcsd. Send uuid, motivo, folioSustitucion, b64Cer, b64Key and passwordCSD in the form-encoded body, not in headers, because the certificate is large. The issuer's RFC is read from the .cer.
Yes. In the sandbox the cancellation is a test one and the response says so with env_mode Sandbox. Your sandbox account is separate, so nothing you cancel there touches your production CFDI.
It's free and uses the same API v5 as production. Cancelling uses no folio.