Ir al contenido

FISCALISTO / API

Constancias de retenciones

Timbre la constancia de retenciones e información de pagos (CFDI de Retenciones 2.0) de lo que retuvo a un proveedor: honorarios, arrendamiento, dividendos, intereses o pagos al extranjero.

Cuando una empresa le paga a una persona física por honorarios o arrendamiento, le retiene ISR e IVA y debe darle una constancia de retenciones: un CFDI de Retenciones 2.0, distinto de una factura, con lo que pagó y lo que retuvo en el periodo. Con la API la timbra con los mismos folios (RET1, RET2…), revisiones y timbres que Retenciones en la app. Cada constancia usa un timbre; cancelarla no cuesta.

Timbrar una

Lo que le retuvo en septiembre a un abogado por $10,000 de honorarios: 10% de ISR y dos terceras partes del IVA.

curl https://api.fiscalisto.com/v1/retentions \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ret-2026-09-gora" \
  -d '{
    "code": "01",
    "recipient": {
      "tax_id": "GORA800101AB1",
      "legal_name": "ANA GÓMEZ RUIZ",
      "zip": "06000"
    },
    "period": { "year": 2026, "month": 9 },
    "totals": { "operation": 10000 },
    "taxes": [
      { "tax": "isr", "base": 10000, "amount": 1000 },
      { "tax": "iva", "base": 10000, "amount": 1066.67 }
    ],
    "send_email": true,
    "email": "ana@example.com"
  }'

La respuesta es la constancia (ret_…) con status: "valid", su uuid, su folio en internal_folio y el total retenido en totals.withheld. Llega también el webhook retention.stamped. Con send_email el receptor recibe el PDF y el XML en email.

CampoQué es
codeLa clave de la retención (c_CveRetenc): 01 servicios profesionales, 05 arrendamiento, 14 dividendos, 16 intereses, 18 pagos a residentes en el extranjero, 25 otro tipo (con description), y las demás del catálogo. Las que llevan complemento están abajo.
recipientA quién le retuvo: su RFC, su nombre y su código postal como en su constancia de situación fiscal (el SAT los compara). Un residente en el extranjero va con foreign: true, su número de identificación fiscal en tax_id y sin código postal.
periodEl mes (month) o los meses (from_month y to_month) del año que cubre, ya terminados o el que corre. Una constancia anual de un proveedor va con from_month: 1 y to_month: 12.
totalsEl monto de la operación; taxed y exempt si una parte está exenta (sin ellos, todo es gravado).
taxesCada impuesto retenido: isr, iva o ieps, su base y el monto. payment_type es el tipo de pago del SAT (c_TipoPagoRet); por omisión 04 para ISR (pago provisional), 01 para IVA y 02 para IEPS.

Las claves que el SAT pide con complemento llevan su objeto, con los nombres de la referencia:

codeObjetoComplemento del SAT
14dividendsDividendos 1.0
16interestIntereses 1.0
17trust_leaseArrendamiento en fideicomiso 1.0
18foreign_paymentPagos a extranjeros 1.0
19share_saleEnajenación de acciones 1.0
20prizePremios 1.0 (state y los montos de totals)
21trustFideicomiso no empresarial 1.0
22retirement_planPlanes de retiro 1.1
23mortgage_interestIntereses hipotecarios 1.0
24financial_derivativesOperaciones con derivados 1.0

Cada objeto va solo con su clave; con otra contesta 400. Sin él, la constancia contesta 422 retention_invalid y dice qué falta. La clave 26 (servicios mediante plataformas tecnológicas) aún no se puede emitir: contesta 422.

{
  "code": "20",
  "recipient": { "tax_id": "PEPJ800101AB1", "legal_name": "JUAN PEREZ", "zip": "06700" },
  "period": { "year": 2026, "month": 9 },
  "totals": { "operation": 50000 },
  "taxes": [{ "tax": "isr", "base": 50000, "amount": 500, "payment_type": "03" }],
  "prize": { "state": "09" }
}

La misma Idempotency-Key otra vez contesta la misma constancia, sin timbrar otra. Si el SAT la rechaza, contesta 422 retention_rejected con su código en sat_code, y llega retention.failed.

Mandarla por correo después

curl https://api.fiscalisto.com/v1/retentions/ret_PhBIUaMpw23r7krC5Vs3pDT6dB7C2wuY0D/send \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "ana@example.com, contabilidad@example.com" }'

Sin to, va al correo que tiene guardado el receptor. Si no se pudo mandar, contesta email_failed y dice por qué; dos envíos a la vez de la misma constancia también (el segundo no se manda).

Descargarla

GET /v1/retentions/{id}/pdf da el PDF y /xml el XML timbrado. GET /v1/retentions las lista, las más recientes primero, y filtra por status (valid, canceled, rejected, processing), por recipient (un RFC) y por year.

Cancelarla

curl https://api.fiscalisto.com/v1/retentions/ret_PhBIUaMpw23r7krC5Vs3pDT6dB7C2wuY0D/cancel \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "motive": "02" }'

Una constancia se cancela de inmediato: el receptor no tiene que aceptarlo. Llega retention.canceled. Con el motivo 01 (tenía errores y otra la sustituye), timbre antes la correcta y mándela en substitution (su ret_… o su UUID): debe ser otra constancia vigente del mismo emisor.