Referencia de la API

La API de CFDI Express timbra CFDI 4.0 ante el SAT desde cualquier sistema que hable HTTPS: facturas PUE, PPD y globales, complementos de pago REP, notas de crédito y cancelaciones con acuse. Es independiente de Shopify y sigue convenciones estilo Stripe, así que si ya integraste Stripe alguna vez, esto te va a resultar familiar.

Empezar en 4 pasos

  1. Crea tu cuenta en dash.cfdi.express y copia tu llave sk_test_. Viene con saldo de pruebas.
  2. Registra tu emisor con POST /v1/merchants y sube su CSD con POST /v1/merchants/{id}/csd.
  3. Timbra tu primer CFDI con POST /v1/invoices.
  4. Entrega el XML y el PDF con las URLs firmadas que devuelve GET /v1/invoices/{id}.
Tu primer request
curl https://api.cfdi.express/v1/balance \
  -H "Authorization: Bearer sk_test_..."

URL base

Todos los endpoints viven bajo https://api.cfdi.express y los de la versión 1 llevan el prefijo /v1. Sólo se aceptan conexiones HTTPS.

Autenticación

Cada request lleva tu llave secreta como bearer token:

Header
Authorization: Bearer sk_live_...

La llave define el modo: sk_test_ timbra contra el sandbox del PAC sin costo y sk_live_ emite CFDIs reales con validez fiscal. Cada modo tiene su propio saldo, sus propios emisores y sus propios documentos; ningún recurso cruza de un modo al otro. Todos los recursos traen el campo livemode para que sepas en cuál estás.

  • Las llaves son secretas: úsalas sólo desde tu servidor, nunca desde el navegador o una app móvil.
  • El sandbox es gratis e ilimitado. Prueba ahí todo el flujo antes de recargar saldo.

Idempotencia

Los endpoints que timbran o cancelan requieren el header Idempotency-Key. Manda un valor estable por operación lógica —el id de tu pedido, de tu devolución o de tu transacción— y los reintentos son seguros:

SituaciónRespuesta
Misma llave, mismo cuerpo, petición ya resueltaLa respuesta original con el header Idempotency-Replayed: true. No gasta otro timbre.
Misma llave, otra petición todavía en proceso409 request_in_flight
Misma llave, cuerpo distinto422 idempotency_key_reuse

Paginación

Las listas usan paginación por cursor: pide hasta limit=100 elementos y, mientras has_more sea true, manda el id del último elemento en starting_after.

Siguiente página
curl -G https://api.cfdi.express/v1/invoices \
  -H "Authorization: Bearer sk_live_..." \
  --data-urlencode "limit=100" \
  --data-urlencode "starting_after=inv7k3q9x2m4v1t8p6d0n5cb"

Errores

Los errores siguen application/problem+json (RFC 7807) con un code estable pensado para que tu integración —o tu agente de IA— reaccione sin parsear textos:

400 Bad Request
{
  "type": "https://api.cfdi.express/docs/errors/validation_error",
  "title": "Validation error",
  "status": 400,
  "code": "validation_error",
  "detail": "Request validation failed",
  "errors": [
    { "path": "receiver.zip", "message": "String must match pattern ^\\d{5}$" }
  ]
}
StatuscodeCuándo aparece
400validation_errorAlgún campo no pasó validación. Incluye errors[] con el path de cada problema, o subcode al validar un CSD.
401unauthorizedFalta el header Authorization o la llave no es válida.
403forbiddenLa llave no tiene acceso a ese recurso.
404not_foundEl recurso no existe en tu cuenta y modo.
402insufficient_creditsNo hay saldo suficiente para el timbre. Recarga y reintenta.
402monthly_limit_reachedAlcanzaste el límite mensual configurado en tu cuenta.
409request_in_flightOtra petición con el mismo Idempotency-Key sigue en proceso.
422idempotency_key_reuseReusaste una llave de idempotencia con un cuerpo distinto.
422sat_rejectedEl SAT rechazó el comprobante. El detalle trae el código del SAT.
429rate_limitedExcediste el límite de requests por minuto.
503pac_unavailableEl PAC está temporalmente fuera de servicio. Reintenta con la misma llave.
500internal_errorError inesperado de nuestro lado.

Límites

  • 300 requests por minuto por cuenta (configurable). Al excederlo recibes 429 con Retry-After; las respuestas traen X-RateLimit-Limit y X-RateLimit-Remaining.
  • El cuerpo de la petición no puede exceder 1 MB.
  • Hasta 500 conceptos por factura.
  • Las URLs de XML, PDF, ZIP, acuses y logos son firmadas y expiran a los 15 minutos: vuelve a pedir el recurso cuando necesites unas nuevas.

Precio

$1 MXN por timbre con descuentos por volumen, saldo prepagado, sin mensualidad. Cada timbre reserva saldo y lo confirma al recibir el UUID; si el SAT rechaza o el PAC falla, el reembolso es automático y queda registrado en el ledger de transacciones. Las cancelaciones también consumen un timbre. El modo de pruebas es gratis.

Para agentes de IA

Además de REST, la API expone un servidor MCP en https://api.cfdi.express/mcp (y https://api.cfdi.express/mcp/test para pruebas) que le da a claude.ai, ChatGPT, Claude Code, Cursor o a tu propio agente 14 herramientas para timbrar, cancelar y consultar. Ver la guía del servidor MCP.

Todos los endpoints

Meta

Endpoints públicos de salud del servicio. No requieren llave y sirven para monitoreo.

Saldo y facturación

Consulta tu saldo prepagado, recarga con tarjeta vía Stripe y audita cada centavo con el ledger de transacciones.

Emisores (merchants)

Cada emisor es un RFC con su propio CSD, serie y logo. Una cuenta puede tener varios emisores activos al mismo tiempo.

Facturas

Timbrado de CFDI 4.0 de ingreso: nominativas PUE y PPD, y facturas globales al público en general.

Notas de crédito

CFDI de egreso para devoluciones, reembolsos y descuentos posteriores a la factura.

Complementos de pago (REP)

Pagos 2.0 contra facturas PPD, con parcialidades y saldos calculados en el servidor.

Catálogos SAT

Claves de producto/servicio, unidades, usos de CFDI, regímenes fiscales y formas de pago servidos desde nuestra base local.

Referencias