Skip to main content
Cancelling a CFDI is not a delete — it is a SAT-mediated request that may require the receptor’s acceptance and always produces an acuse de cancelación. This API models it as an async lifecycle on the invoice.

Request

Response is the invoice with an updated cancellation object:

Motivos de cancelación (SAT)

For 01, first stamp the corrected invoice, then cancel the original referencing it:
Sending a substitute for 02/03/04 (or omitting it for 01) is rejected by the SAT — see the cancel.substitution_folio_* and cancel.motivo_* codes in ../errors.md.

The cancellation lifecycle

  • cancelled immediately when the CFDI is cancelable sin aceptación — e.g. low-amount invoices, or a receptor of XAXX010101000 (público en general). The SAT accepts on submission.
  • cancel_pending when the CFDI is cancelable con aceptación. The receptor has 72 business hours to accept or reject in their SAT buzón; if they do nothing it auto-cancels at the deadline. The API polls consultarEstatusComprobante on a job and finalizes the status.
  • cancel_rejected when the receptor rejects, or the SAT returns a definitive negative verdict (e.g. the UUID is referenced by another live CFDI → cancel.not_applicable / cancel.not_cancellable).

The receptor-acceptance flow (con aceptación)

  1. You submit the cancellation → cancel_pending.
  2. The receptor sees a solicitud de cancelación in their SAT portal and accepts or rejects it.
  3. The worker’s cancellation-poll job re-queries SAT status until it resolves, then updates the invoice and emits a webhook: invoice.cancelled or invoice.cancel_rejected.
Subscribe to those events instead of polling yourself:

The acuse

Once status is cancelled, cancellation.acuse_available becomes true. The acuse is the SAT’s XML receipt of the cancellation — retain it as proof for your accounting.

Notes

  • Only a stamped invoice can be cancelled; drafts have no UUID at the SAT.
  • Cancellation is signed with the emitter’s CSD (handled server-side from the fiscal profile).
  • Time-window rules apply: cancellations past the period’s declaration date, or past the global-invoice deadline, are refused (cancel.date_after_declaration, cancel.global_invoice_deadline).
  • The same lifecycle runs in test mode — a público-en-general receptor cancels sin aceptación (resolves immediately), while a normal receptor stays cancel_pending until it accepts, rejects, or the 72h window lapses — so you can rehearse both paths before going live.