Documentación / API / Notas de crédito

Timbrar una nota de crédito (CFDI de egreso)

POSThttps://api.cfdi.express/v1/credit_notesAPI keyIdempotency-Key

Timbra un CFDI 4.0 de egreso para una devolución, un reembolso o un descuento posterior a la factura.

Relaciona la nota con la factura original de dos formas: con relatedInvoiceId si el CFDI de ingreso se timbró aquí (el receptor se copia solo), o con relatedUuid si se timbró en otro sistema (en ese caso el receiver es obligatorio).

El resultado es un recurso invoice con kind: "credit_note": lo consultas con GET /v1/invoices/{id} y lo listas con GET /v1/invoices?kind=credit_note.

Igual que el timbrado de facturas, espera hasta 20 segundos por el UUID y requiere Idempotency-Key.

Los conceptos aceptan pedimentos igual que en la factura de ingreso (información aduanera, v1.28.0). La guía está en cómo facturar con pedimento.

Desde la v1.36.0 puedes mandar fecha para timbrar la nota con una fecha anterior. Las reglas son las mismas que en POST /v1/invoices: hora local de Ciudad de México, hasta 70 horas atrás, no futura, y el CSD del emisor vigente en esa fecha. Si no la mandas, se usa la hora de timbrado. Por MCP, create_credit_note acepta el mismo campo.

Desde la v1.37.0 puedes mandar serie (1 a 25 caracteres, sin |). Si la omites, la nota se timbra con NC. El ejemplo es NCB. El folio numérico interno se comparte entre series: para una numeración propia manda también folio. Una serie inválida responde 400 validation_error. create_credit_note acepta el mismo campo.

Autenticación
Authorization: Bearer sk_test_... | sk_live_...

El header x-account-id indica la cuenta. Si no eres miembro, la respuesta es 403.

Parámetros

Headers

CampoTipoDescripción
Idempotency-KeyreqstringLlave única por devolución. Los replays devuelven la nota original.

Cuerpo (JSON)

CampoTipoDescripción
merchantIdreqstringEmisor de la nota. Debe ser el mismo que timbró la factura relacionada.
fechastringFecha de emisión del CFDI, en hora local de Ciudad de México (UTC-6, todo el año desde 2022), sin zona. Formato YYYY-MM-DDTHH:mm:ss, por ejemplo 2026-10-13T09:30:00. No mandes Z ni -06:00. Si la omites, se usa la hora de timbrado. Hasta 70 horas atrás, inclusive: el SAT acepta 72 horas antes de la certificación y el margen de 2 horas cubre el timbrado asíncrono. No puede ser futura (la hora actual sí). El CSD del emisor tiene que haber estado vigente en ese instante. Desde la v1.36.0.
relatedInvoiceIdstringId de la factura de ingreso timbrada aquí. Usa este o relatedUuid.
relatedUuidstringUUID de un CFDI de ingreso timbrado fuera de esta API. Exige receiver explícito.
tipoRelacionstring01 nota de crédito de los documentos relacionados (default) o 03 devolución de mercancía.
usoCfdistringDefault G02 (devoluciones, descuentos o bonificaciones).
formaPagoreqstringCómo se devuelve el dinero (03 transferencia, 01 efectivo…). Usa 15 condonación o 99 cuando no hay movimiento de dinero.
seriestringSerie que se timbra en la nota. Opcional, de 1 a 25 caracteres, sin el carácter |. Ejemplo: NCB. Si la omites, se usa NC. El folio numérico interno se comparte entre series; para numeración propia por serie manda también folio. Desde la v1.37.0. Vacía, de más de 25 caracteres o con | responde 400 validation_error.
foliostringFolio visible, por ejemplo tu número de devolución (RET-1001). El folio numérico interno se sigue asignando y se comparte entre series.
receiverobjectReceptor (rfc, name, zip, regimenFiscal). Se hereda de la factura relacionada cuando usas relatedInvoiceId.
items[]reqarrayLa mercancía devuelta, o un solo concepto por el monto acreditado. Misma forma que en facturas.
items[].pedimentosstring[]Igual que en POST /v1/invoices. Números de pedimento de la mercancía importada que vendes de primera mano (InformacionAduanera). Opcional. De 1 a 100 cadenas de 15 dígitos — año (2), aduana (2), patente (4) y consecutivo (7) — con o sin espacios; ejemplo: "25 47 3807 5001234". Se emite en 21 caracteres del SAT, con dos espacios entre grupos. Los duplicados se descartan.
pricesIncludeTaxbooleantrue por default.

Ejemplos

cURL — devolución de una factura timbrada aquí
curl -X POST https://api.cfdi.express/v1/credit_notes \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: return_1001" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "mkq2f8v3x1t7p9d4n6c0b5rz",
    "relatedInvoiceId": "inv7k3q9x2m4v1t8p6d0n5cb",
    "tipoRelacion": "03",
    "formaPago": "03",
    "folio": "RET-1001",
    "items": [
      {
        "productCode": "43201808",
        "unitCode": "H87",
        "description": "Teclado mecánico 75% (devolución)",
        "quantity": 1,
        "unitPrice": 1740.00
      }
    ]
  }'
cURL — fecha anterior (v1.36.0)
curl -X POST https://api.cfdi.express/v1/credit_notes \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: return_1001_fecha" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "mkq2f8v3x1t7p9d4n6c0b5rz",
    "fecha": "2026-10-13T09:30:00",
    "relatedInvoiceId": "inv7k3q9x2m4v1t8p6d0n5cb",
    "tipoRelacion": "03",
    "formaPago": "03",
    "folio": "RET-1001",
    "items": [
      {
        "productCode": "43201808",
        "unitCode": "H87",
        "description": "Teclado mecánico 75% (devolución)",
        "quantity": 1,
        "unitPrice": 1740.00
      }
    ]
  }'
cURL — CFDI externo por UUID
curl -X POST https://api.cfdi.express/v1/credit_notes \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: return_ext_88" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "mkq2f8v3x1t7p9d4n6c0b5rz",
    "relatedUuid": "9f1b2c3d-4e5f-4a6b-8c9d-0e1f2a3b4c5d",
    "tipoRelacion": "01",
    "formaPago": "99",
    "receiver": {
      "rfc": "XIA190128J61",
      "name": "XENON INDUSTRIAL ARTICLES",
      "zip": "01160",
      "regimenFiscal": "601"
    },
    "items": [
      {
        "productCode": "01010101",
        "unitCode": "ACT",
        "description": "Bonificación comercial",
        "quantity": 1,
        "unitPrice": 500.00
      }
    ]
  }'

Respuesta

201 Created
{
  "id": "cnt4m9x2q7v1p8d3t6n0c5br",
  "object": "invoice",
  "livemode": false,
  "status": "stamped",
  "kind": "credit_note",
  "uuid": "2b7d5a11-93c4-4f0e-b6a8-77c1e9d43f10",
  "serie": "A",
  "folio": 129,
  "folioText": "RET-1001",
  "fecha": "2026-08-18T12:10:02",
  "metodoPago": "PUE",
  "formaPago": "03",
  "usoCfdi": "G02",
  "currency": "MXN",
  "subtotal": 1500.00,
  "discount": 0,
  "total": 1740.00,
  "saldoPendiente": null,
  "tipoRelacion": "03",
  "relatedUuid": "9f1b2c3d-4e5f-4a6b-8c9d-0e1f2a3b4c5d",
  "relatedInvoiceId": "inv7k3q9x2m4v1t8p6d0n5cb",
  "receiver": {
    "rfc": "XIA190128J61",
    "name": "XENON INDUSTRIAL ARTICLES",
    "zip": "01160",
    "regimenFiscal": "601"
  },
  "merchantId": "mkq2f8v3x1t7p9d4n6c0b5rz",
  "files": { "status": "ready" },
  "cancellation": null,
  "stampedAt": "2026-08-18T18:15:02.441Z",
  "createdAt": "2026-08-18T18:15:00.902Z"
}
400 — fecha fuera de rango
{
  "type": "https://api.cfdi.express/docs/errors/validation_error",
  "title": "Validation error",
  "status": 400,
  "code": "validation_error",
  "detail": "fecha can be at most 70 hours in the past (the SAT allows 72 hours before stamping)",
  "subcode": "fecha_out_of_range",
  "errors": [
    {
      "path": "fecha",
      "message": "fecha can be at most 70 hours in the past (the SAT allows 72 hours before stamping)"
    }
  ]
}

Errores

StatuscodeCuándo aparece
400validation_errorFaltan relatedInvoiceId y relatedUuid, el receptor no viene con relatedUuid, algún concepto es inválido, fecha no pasa, o la serie no es válida. Con subcode fecha_out_of_range y errors[{path:'fecha'}], la fecha es inválida, futura, de más de 70 horas o el CSD no estaba vigente. Un formato distinto de YYYY-MM-DDTHH:mm:ss es el mismo code, sin ese subcode. Una serie vacía, de más de 25 caracteres o con | es el mismo code.
401unauthorizedFalta el header Authorization o la llave es inválida.
402insufficient_creditsNo hay saldo suficiente para el timbre.
404not_foundEl emisor o la factura relacionada no existen.
409request_in_flightOtra petición con el mismo Idempotency-Key está en proceso.
422sat_rejectedEl SAT rechazó la nota de crédito.
503pac_unavailableEl PAC no está disponible.

Notas

  • Una nota de crédito no cancela la factura: la corrige contablemente. Si lo que quieres es anular el comprobante, usa la cancelación.
  • items[].pedimentos queda en el XML como Concepto/InformacionAduanera/@NumeroPedimento y también se imprime en el PDF. El servidor MCP lo acepta igual: create_invoice y create_credit_note llevan el mismo arreglo, así que un agente de IA puede timbrar con el pedimento de cada concepto.
  • Si omites fecha, el worker usa la hora de timbrado y le resta 5 minutos por desfase de reloj del PAC. Si la fecha pedida queda a menos de 5 minutos de ese momento, la ajusta a ese margen. Ya con el CFDI armado, el recurso expone la Fecha del comprobante. En el ejemplo 201, stampedAt 2026-08-18T18:15:02.441Z son las 12:15:02 en Ciudad de México.

Continuar