Withholdings
Stamp withholding and payment information certificates (Retenciones 2.0) by sending the certificate as JSON. The API builds the XML, seals it with your account's CSD and stamps it.
/invoice/retention/invoice/cancelretentionThe request
Same as invoice/create: the certificate goes in the json parameter of a form. Your account needs an uploaded CSD and a folio balance; each stamped certificate uses 1 folio.
curl -sS -X POST "$FD_API/invoice/retention" \
-H "X-Api-Key: $FD_API_KEY" \
--data-urlencode "json@retencion.json"{
"Version": "2.0",
"FolioInt": "R-1001",
"FechaExp": "AUTO",
"LugarExpRetenc": "64000",
"CveRetenc": "01",
"Emisor": {
"RfcE": "EKU9003173C9",
"NomDenRazSocE": "ESCUELA KEMPER URGATE",
"RegimenFiscalE": "601"
},
"Receptor": {
"NacionalidadR": "Nacional",
"Nacional": {
"RfcR": "XIA190128J61",
"NomDenRazSocR": "XENON INDUSTRIAL ARTICLES",
"DomicilioFiscalR": "76343"
}
},
"Periodo": { "MesIni": "10", "MesFin": "10", "Ejercicio": "2026" },
"Totales": {
"MontoTotOperacion": "10000.00",
"MontoTotGrav": "10000.00",
"MontoTotExent": "0.00",
"MontoTotRet": "1000.00",
"ImpRetenidos": [
{ "BaseRet": "10000.00", "ImpuestoRet": "001", "MontoRet": "1000.00", "TipoPagoRet": "04" }
]
}
}JSON structure
Root
Version"2.0".FolioInt- Your internal folio for the certificate.
FechaExpAAAA-MM-DDThh:mm:ss. Empty orAUTOuses the current time at your place of issue.LugarExpRetenc- Postal code where it's issued.
CveRetenc- c_CveRetenc key, for example
01professional services. Several keys require their complement:14dividends,16interest,18payments to foreign residents (Reten20107). DescRetenc- Required with key
25, other withholdings (Reten20106). CfdiRetenRelacionadosTipoRelacionandUUIDof the certificate it replaces.
Emisor, Receptor and Periodo
EmisorRfcE,NomDenRazSocEandRegimenFiscalE. Unlikecreate, here they're taken from the JSON: they must match your account's CSD.Receptor.NacionalidadRNacionalorExtranjero.Receptor.Nacional- With a Mexican recipient:
RfcR,NomDenRazSocR,CurpR(optional) andDomicilioFiscalR. Receptor.Extranjero- With a foreign recipient:
NumRegIdTribR(optional) andNomDenRazSocR. PeriodoMesIni,MesFinandEjercicio.
Totales
MontoTotOperacion, MontoTotGrav, MontoTotExent, MontoTotRet- Transaction, taxable, exempt and withheld amounts.
UtilidadBimestral, ISRCorrespondiente- For the keys that ask for them.
ImpRetenidos- A list, even with a single element:
BaseRet,ImpuestoRet,MontoRetandTipoPagoRet. A single object in place of the list is rejected.TipoPagoRetgoes with its tax:03or04with ISR (001),01with VAT (002),02with IEPS (003) (Reten20135).
The certificate's complements go in Complemento: Dividendos, EnajenaciondeAcciones, Intereses or Pagosaextranjeros. The Postman collection has an example of each one in the “Crear CFDI de Retenciones” request.
The response
Watch out: this endpoint responds with keys in Spanish. Success carries mensaje and codigo in place of message and code; errors carry both versions.
{
"mensaje": "Timbrado exitoso",
"codigo": 200,
"cfdi": {
"NoCertificado": "30001000000500003416",
"Nacionalidad": "Nacional",
"NomDenRazSocR": "XENON INDUSTRIAL ARTICLES",
"DomicilioFiscalR": "76343",
"UUID": "0B7D4E21-5A6C-4F38-9E12-7C3A5B9D1F40",
"FechaTimbrado": "2026-11-03T11:02:10",
"RfcProvCertif": "AAA010101AAA",
"SelloCFD": "Q2V4...Zm9vYmFy",
"NoCertificadoSAT": "30001000000500003456",
"SelloSAT": "Tm9w...ZGF0YQ==",
"XmlBase64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4...",
"PDF": "https://app.facturadigital.com.mx/docs/pdf_retencion/0B7D4E21-5A6C-4F38-9E12-7C3A5B9D1F40",
"XML": "https://app.facturadigital.com.mx/docs/xml_retencion/0B7D4E21-5A6C-4F38-9E12-7C3A5B9D1F40"
}
}The certificate goes to your issued withholdings, not to your CFDIs: it doesn't appear in the invoice/list* listings and you can't send it with invoice/send.
Errors
| code | When | What to do |
|---|---|---|
| 400 | The json parameter didn't arrive, or it isn't valid JSON. | Check the form body. |
400 + json_type_validation | A node has another type: for example Emisor as text or an ImpRetenidos element as text. Nothing was sent or charged. | errors[] says which field; fix the type. |
| 602 | Your account has no active CSD. | Upload your CSD in Configuración. |
| 601 | Your account has no folios. | Buy folios. |
| 702 | The XML doesn't meet the Retenciones 2.0 schema (errorType: cfdi_retenciones_schema_validation). | errors[] carries the field and value; fix them. |
| 400 + Reten20… key | The SAT rejected the certificate under a rule in its matrix. | Look it up in the error matrix (Retenciones 2.0 filter). |
| 5034 / 5037 | Same as when stamping a CFDI: with 5037 nothing was sent; with 5034 it may have been stamped. | See Responses and errors. |
Cancel a certificate
/invoice/cancelretentionSame headers and reasons as cancelling a CFDI: UUID, MOTIVO (02 if you don't send it) and FOLIOSUSTITUCION with reason 01. It uses your account's CSD and no folio, though it requires a balance above zero.
curl -sS -X POST "$FD_API/invoice/cancelretention" \
-H "X-Api-Key: $FD_API_KEY" \
-H "UUID: 0B7D4E21-5A6C-4F38-9E12-7C3A5B9D1F40" \
-H "MOTIVO: 02"Checked against the production API v5 on 2026-11-03.