Skip to content
Documentation sections

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.

POST/invoice/retention
POST/invoice/cancelretention

The 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
curl -sS -X POST "$FD_API/invoice/retention" \
  -H "X-Api-Key: $FD_API_KEY" \
  --data-urlencode "json@retencion.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

Versionstringrequired
"2.0".
FolioIntstringrequired
Your internal folio for the certificate.
FechaExpstringoptional
AAAA-MM-DDThh:mm:ss. Empty or AUTO uses the current time at your place of issue.
LugarExpRetencstringrequired
Postal code where it's issued.
CveRetencstringrequired
c_CveRetenc key, for example 01 professional services. Several keys require their complement: 14 dividends, 16 interest, 18 payments to foreign residents (Reten20107).
DescRetencstringconditional
Required with key 25, other withholdings (Reten20106).
CfdiRetenRelacionadosobjectoptional
TipoRelacion and UUID of the certificate it replaces.

Emisor, Receptor and Periodo

Emisorobjectrequired
RfcE, NomDenRazSocE and RegimenFiscalE. Unlike create, here they're taken from the JSON: they must match your account's CSD.
Receptor.NacionalidadRstringrequired
Nacional or Extranjero.
Receptor.Nacionalobjectconditional
With a Mexican recipient: RfcR, NomDenRazSocR, CurpR (optional) and DomicilioFiscalR.
Receptor.Extranjeroobjectconditional
With a foreign recipient: NumRegIdTribR (optional) and NomDenRazSocR.
Periodoobjectrequired
MesIni, MesFin and Ejercicio.

Totales

MontoTotOperacion, MontoTotGrav, MontoTotExent, MontoTotRetstringrequired
Transaction, taxable, exempt and withheld amounts.
UtilidadBimestral, ISRCorrespondientestringoptional
For the keys that ask for them.
ImpRetenidosarrayoptional
A list, even with a single element: BaseRet, ImpuestoRet, MontoRet and TipoPagoRet. A single object in place of the list is rejected. TipoPagoRet goes with its tax: 03 or 04 with ISR (001), 01 with VAT (002), 02 with 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.

200
{
  "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

codeWhenWhat to do
400The json parameter didn't arrive, or it isn't valid JSON.Check the form body.
400 + json_type_validationA 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.
602Your account has no active CSD.Upload your CSD in Configuración.
601Your account has no folios.Buy folios.
702The XML doesn't meet the Retenciones 2.0 schema (errorType: cfdi_retenciones_schema_validation).errors[] carries the field and value; fix them.
400 + Reten20… keyThe SAT rejected the certificate under a rule in its matrix.Look it up in the error matrix (Retenciones 2.0 filter).
5034 / 5037Same as when stamping a CFDI: with 5037 nothing was sent; with 5034 it may have been stamped.See Responses and errors.

Cancel a certificate

POST/invoice/cancelretention

Same 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
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.