Saltar al contenido
Secciones de la documentación

Retenciones

Timbra constancias de retenciones e información de pagos 2.0 enviando la constancia en JSON. La API arma el XML, lo sella con el CSD de tu cuenta y lo timbra.

POST/invoice/retention
POST/invoice/cancelretention

La petición

Igual que invoice/create: la constancia va en el parámetro json de un formulario. Tu cuenta necesita un CSD cargado y saldo de folios; cada constancia timbrada usa 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" }
    ]
  }
}

Estructura del JSON

Raíz

Versionstringobligatorio
"2.0".
FolioIntstringobligatorio
Tu folio interno de la constancia.
FechaExpstringopcional
AAAA-MM-DDThh:mm:ss. Vacío o AUTO usa la hora actual de tu lugar de expedición.
LugarExpRetencstringobligatorio
Código postal donde se expide.
CveRetencstringobligatorio
Clave de c_CveRetenc, por ejemplo 01 servicios profesionales. Varias claves exigen su complemento: 14 Dividendos, 16 Intereses, 18 Pagos a extranjeros (Reten20107).
DescRetencstringcondicional
Obligatoria con la clave 25, otro tipo de retenciones (Reten20106).
CfdiRetenRelacionadosobjectopcional
TipoRelacion y UUID de la constancia que sustituye.

Emisor, Receptor y Periodo

Emisorobjectobligatorio
RfcE, NomDenRazSocE y RegimenFiscalE. A diferencia de create, aquí se toman del JSON: tienen que ser los del CSD de tu cuenta.
Receptor.NacionalidadRstringobligatorio
Nacional o Extranjero.
Receptor.Nacionalobjectcondicional
Con receptor nacional: RfcR, NomDenRazSocR, CurpR (opcional) y DomicilioFiscalR.
Receptor.Extranjeroobjectcondicional
Con receptor extranjero: NumRegIdTribR (opcional) y NomDenRazSocR.
Periodoobjectobligatorio
MesIni, MesFin y Ejercicio.

Totales

MontoTotOperacion, MontoTotGrav, MontoTotExent, MontoTotRetstringobligatorio
Montos de la operación, gravado, exento y retenido.
UtilidadBimestral, ISRCorrespondientestringopcional
Para las claves que los piden.
ImpRetenidosarrayopcional
Una lista, aunque sea de un solo elemento: BaseRet, ImpuestoRet, MontoRet y TipoPagoRet. Un objeto suelto en lugar de la lista se rechaza. TipoPagoRet va con su impuesto: 03 o 04 con ISR (001), 01 con IVA (002), 02 con IEPS (003) (Reten20135).

Los complementos de la constancia van en Complemento: Dividendos, EnajenaciondeAcciones, Intereses o Pagosaextranjeros. La colección de Postman trae un ejemplo de cada uno en la petición «Crear CFDI de Retenciones».

La respuesta

Ojo: este endpoint responde con llaves en español. El éxito trae mensaje y codigo en lugar de message y code; los errores traen las dos versiones.

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"
  }
}

La constancia queda en tus retenciones emitidas, no en tus CFDI: no aparece en los listados de invoice/list* ni se puede enviar con invoice/send.

Errores

codeCuándo pasaQué hacer
400No llegó el parámetro json, o no es un JSON válido.Revisa el cuerpo del formulario.
400 + json_type_validationUn nodo tiene otro tipo: por ejemplo Emisor como texto o un elemento de ImpRetenidos como texto. No se envió nada ni se cobró.errors[] dice qué campo; corrige el tipo.
602Tu cuenta no tiene un CSD activo.Carga tu CSD en Configuración.
601Tu cuenta no tiene folios.Compra folios.
702El XML no cumple el esquema de Retenciones 2.0 (errorType: cfdi_retenciones_schema_validation).errors[] trae campo y valor; corrígelos.
400 + clave Reten20…El SAT rechazó la constancia por una regla de su matriz.Búscala en la matriz de errores (filtro Retenciones 2.0).
5034 / 5037Igual que al timbrar un CFDI: 5037 no se envió nada; 5034 pudo haberse timbrado.Ver Respuestas y errores.

Cancelar una constancia

POST/invoice/cancelretention

Mismos encabezados y motivos que la cancelación de un CFDI: UUID, MOTIVO (02 si no lo mandas) y FOLIOSUSTITUCION con el motivo 01. Usa el CSD de tu cuenta y no usa folio, aunque pide saldo mayor a cero.

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"

Revisado contra la API v5 en producción el 2026-11-03.