Skip to main content
POST
Request cancellation of a stamped CFDI
Requests cancellation of a stamped CFDI 4.0 before the SAT. Unlike Create Invoice and List Invoices, this is a flat route — it does not carry /organizations/{organizationId}/ in the URL. The invoice’s uuid (its folio fiscal, globally unique across all organizations) is enough to resolve the owning organization server-side, combined with the caller’s own auth context (session or API key).

Authentication

Accepts either:
  • A Supabase Bearer session (Authorization: Bearer <token>) — the authenticated user must be a member of the invoice’s organization.
  • An API key (X-API-Key: sk_...) with the write:invoices scope — the key’s own organization must match the invoice’s organization, or the request is rejected with 403 Forbidden.

Path Parameters

Request Body

* Required when motivo is 01 (sustitución). Must be the folio fiscal of an existing, vigente invoice belonging to the same organization, and cannot be the invoice being cancelled itself — an arbitrary or unverified UUID is rejected with a 400. Ignored for motivo 02, 03, and 04, even if sent.

motivo codes

How eligibility is determined

Timbrix computes, from the invoice’s own data, whether the cancellation applies directly or requires the receptor’s approval — this follows the SAT’s own rule and you never send it yourself; it’s returned in the response as requiresApproval. The cancellation is direct (no approval needed) when at least one of these is true:
  • tipoComprobante is E (Egreso) or T (Traslado)
  • total is ≤ $5,000 MXN
  • rfcReceptor is XAXX010101000 (público en general) or XEXX010101000 (residente extranjero)
  • The invoice was issued 3 business days ago or less (Mon–Fri, America/Mexico_City calendar)
Otherwise, the cancellation requires receptor approval: the SAT notifies the receptor, who has 3 business days to accept or reject it through the SAT portal.
Timbrix cannot poll the SAT in real time for the receptor’s response. A cancellation that requires approval comes back with cancellationStatus: "pendiente" and a respondBy deadline — the invoice stays vigente until you confirm the actual outcome yourself, after checking the SAT portal, via Resolve Cancellation.
A direct cancellation, by contrast, is resolved synchronously in the same request: the response comes back with cancellationStatus: "aceptada" and the invoice’s status flips to cancelado immediately.

Mass cancellation limit

Organizations on the Starter or Pro plan are limited to 50 cancellation requests per calendar day; the 51st request that day returns 400 Bad Request. Business and Enterprise plans have no daily limit.

Example Request

cURL
TypeScript
Sustitución (motivo: "01") — replacing this CFDI with an already-stamped corrected one:
cURL

Example Response

Direct cancellation — resolved immediately:
Cancellation requiring receptor approval — still pending:

Common Errors

400 Bad Request

motivo is invalid; folioSustitucion is missing when motivo is 01, is not a vigente invoice of the same organization, or is the same invoice being cancelled; the invoice is already cancelado; or the organization has hit the daily mass-cancellation limit (Starter/Pro plans).

401 Unauthorized

Missing or invalid Bearer token / API key.

403 Forbidden

The authenticated user is not a member of the invoice’s organization, or the API key does not have the write:invoices scope / belongs to a different organization than the one that owns the invoice.

404 Not Found

uuid does not match any invoice, or (when motivo is 01) folioSustitucion does not match any invoice belonging to the same organization.

409 Conflict

A cancellation is already pendiente for this invoice. Resolve it via Resolve Cancellation — or wait for the receptor to respond — before requesting another.

Authorizations

X-API-Key
string
header
required

API Key for authentication (format: sk_...)

Path Parameters

uuid
string
required

Folio fiscal UUID of the invoice to cancel

Body

application/json
motivo
enum<string>
required

01 = emitido con errores con relación (requiere folioSustitucion), 02 = emitido con errores sin relación, 03 = no se llevó a cabo la operación, 04 = operación nominativa relacionada en factura global

Available options:
01,
02,
03,
04
Example:

"02"

folioSustitucion
string

UUID fiscal del CFDI que sustituye a este. Requerido cuando motivo=01, debe ser una factura vigente de la misma organización.

Example:

"d3bfbc57-44af-4390-a064-f0afab85e5df"

Response

id
string
required
Example:

"6a1b2c3d-4e5f-4890-9abc-def012345678"

invoiceId
string
required

Timbrix invoice record ID

Example:

"0f2a1c3e-1a2b-4c3d-9e8f-1234567890ab"

motivo
enum<string>
required
Available options:
01,
02,
03,
04
Example:

"02"

requiresApproval
boolean
required
Example:

false

cancellationStatus
enum<string>
required
Available options:
pendiente,
aceptada,
rechazada
Example:

"aceptada"

createdAt
string<date-time>
required
Example:

"2026-08-09T15:50:03.412Z"

folioSustitucion
string | null
Example:

null

respondBy
string<date-time> | null
Example:

null

requestedBy
string | null
Example:

"9f8e7d6c-5b4a-3210-fedc-ba9876543210"

resolvedBy
string | null
Example:

null

resolvedAt
string<date-time> | null
Example:

null