Skip to content

CFDI cancellation API, cancel from your own system

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.

What the cancellation API takes care of

The full CFDI 4.0 cancellation process, from your own system.

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.

SAT acknowledgment

If the request is accepted, you get the acknowledgment in Base64 and the CFDI is marked cancelled in your account, with its acknowledgment stored.

With or without a CSD in your account

/invoice/cancel uses the CSD you uploaded. /invoice/cancelwithcsd takes your .cer, your .key and the password in the request.

Cancelling uses no folio

Neither operation deducts folios. /invoice/cancel does require your account balance to be above zero.

Status with the SAT

GET /validator/cfdi asks the SAT for the CFDI's status, whether it can be cancelled and its cancellation status.

Withholdings

Withholding certificates are cancelled with /invoice/cancelretention, with the same headers and the same reasons.

Cancelling an invoice, from request to response

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.

Endpoints
POST /invoice/cancel
Headers UUID, MOTIVO (02 if you don't send it) and, with reason 01, FOLIOSUSTITUCION. Uses your account's CSD.
POST /invoice/cancelwithcsd
Form-encoded body: uuid, motivo, folioSustitucion, b64Cer, b64Key and passwordCSD. No uploaded CSD needed.
GET /validator/cfdi
With uuid, rfcemisor, rfcreceptor and total: status, cancellability and cancellation status with the SAT.
  • The response is HTTP 200 even if the request is rejected: the result is in code.
  • code 200 means the request was accepted (uuid_estatus 201).
  • acuse is the SAT acknowledgment XML, in Base64.
  • env_mode tells you whether the cancellation ran in Sandbox or Productivo.
Production
https://app.facturadigital.com.mx/api/v5
Sandbox
https://sandbox-app.facturadigital.com.mx/api/v5
cancel.shSample data
# 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"
response-200.jsonSample data
{
  "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
}
cancel-with-csd.shSample data
# 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"

Integrate it in 4 steps

From the reason to the confirmation with the SAT.

  1. 01

    Pick the reason

    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.

  2. 02

    Send the request

    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.

  3. 03

    Read code, not just HTTP

    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.

  4. 04

    Confirm with the SAT

    An accepted request doesn't guarantee the cancellation. Check the status with GET /validator/cfdi and the uuid, rfcemisor, rfcreceptor and total parameters.

Common errors and how to fix them

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.

code 202The UUID was already cancelled.The CFDI was already cancelled with the SAT; there's no need to repeat the request.
code 203The UUID doesn't belong to the issuer.The UUID isn't from your RFC: use the key of the account that issued the CFDI.
code 205The UUID can't be cancelled yet. This happens with freshly stamped CFDI: the SAT can take up to 48 hours to show them as valid.Wait and send the request again.
code 207 · 208 · 209The reason isn't valid, the substitution UUID isn't valid, or it was sent when the reason doesn't need it.FOLIOSUSTITUCION only goes with reason 01 and is the UUID of the replacing CFDI.
601/invoice/cancel with no folios left in your account.Cancelling deducts no folios, but this endpoint requires a balance above zero. Buy folios or use /invoice/cancelwithcsd.
400The UUID header is missing: “UUID to be cancelled (folio fiscal) not found in the headers.”Send UUID, MOTIVO and FOLIOSUSTITUCION as headers, not in the body.
400On /invoice/cancelwithcsd: an invalid uuid format, a reason outside 01 to 04, reason 01 without folioSustitucion, or a .cer whose RFC can't be read.The message tells you which parameter to fix.
501The X-Api-Key is invalid or belongs to another environment; the message ends with [Environment: …].Use the key for the environment you're calling: sandbox and production have separate keys.

Keep going

Carta Porte 3.1

Stamp income and transfer CFDI with the Carta Porte complement, with SAT rules checked before stamping.

Payment complement

Stamp the REP for your PPD invoices with the same endpoint and the same key.

Sandbox

Test cancellations for free with the same API v5 as production.

Webhooks

Let your system know what happens in your account without polling the API.

Official SDKs

Libraries to call API v5 from your language, with the same endpoints.

API v5

Authentication, endpoints and the three ways to stamp: JSON, Base64 XML or an XML file.

Cancellation API questions

Something missing? Message us or check the full reference.

Does cancelling via API use folios?

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.

Which cancellation reason should I use?

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.

How do I cancel an invoice to replace it?

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.

Why do I get HTTP 200 if the cancellation didn't go through?

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.

If I get code 200, is the CFDI already cancelled?

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.

Can I cancel without uploading my CSD to the account?

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.

Can I test cancellations in the sandbox?

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.

Test your cancellations in the sandbox

It's free and uses the same API v5 as production. Cancelling uses no folio.