Factura CFDI 4.0 desde tu sistema
Tu ERP, tu punto de venta o tu tienda en línea mandan la venta en JSON; Factúralo y Punto la timbra ante el SAT, guarda el XML y se la manda a tu cliente con su PDF. Los mensajes de error vienen en español, listos para enseñárselos a quien captura.
Todas las rutas en una página. También puedes bajar la referencia OpenAPI 3.1 (.yaml) para tu editor o tu herramienta para probar APIs.
Una factura, de tu sistema al SAT
- Tu sistema manda la venta
POST /facturascon la llave de la empresa - Se valida y se timbraResponde con el folio fiscal; si falta un dato, dice cuál
- Tu cliente la recibeEl PDF y el XML a su correo; el XML queda guardado
- Tu sistema se enteraCon el aviso
factura.timbrada, firmado
Lo que puedes hacer
Una llave por empresa y una sola API para todo lo que se timbra. Cada ruta va después de https://facturaloypunto.com/api/v1.
- FacturasTimbra facturas de ingreso con sus complementos: comercio exterior, Carta Porte, detallista, INE, notarios, colegiaturas, leyendas fiscales e impuestos locales.
POST /facturas - Complementos de pagoRegistra lo que te pagaron y se timbra su complemento. Si no dices qué facturas abona, se eligen por el folio o por el RFC.
POST /pagos - Factura globalJunta las ventas que nadie facturó en el periodo y las timbra a público en general.
POST /facturas/global - CancelarAnte el SAT, con los motivos 01 a 04 (el 01, con la factura que la sustituye; el 04, sólo la global). Te avisa cuando queda cancelada, aunque tu cliente tarde días en aceptarla.
POST /facturas/{id}/cancelar - XML y PDFEl XML timbrado, con su addenda o sin ella, y su PDF.
GET /facturas/{id}/xml · /pdf - Reenviar por correoLa factura otra vez, con su PDF y su XML, hasta a 10 correos.
POST /facturas/{id}/reenviar - Traslados con Carta PorteMercancía tuya que viaja por carretera, mar o aire, o que sale al extranjero con comercio exterior.
POST /traslados - RetencionesConstancias de retenciones e información de pagos 2.0: dividendos, intereses, pagos al extranjero, plataformas digitales…
POST /retenciones - Tickets de autofacturaciónCada venta con su código, la liga a tu portal y su QR para imprimirlo en el ticket. Lo que nadie facture entra a la global.
POST /tickets - Leer la ConstanciaRFC, nombre, código postal y régimen del cliente, del PDF de su Constancia de Situación Fiscal o de la foto de su QR.
POST /constancia - Catálogos del SATBusca claves de producto o servicio y de unidad, por clave o por palabras.
GET /catalogos/productos-servicios · /unidades - Saldo de foliosLos folios que te quedan y cuándo vencen, tu plan y la vigencia de tu sello.
GET /cuenta - Avisos firmadosTu sistema se entera cuando se timbra, se cancela, se registra un pago o un cliente se factura solo.
X-FacturaloYPunto-Firma
Empieza en tres pasos
Crea tu cuenta y sube tu sello
Crea la cuenta y sube el sello digital (CSD) de la empresa en Configuración › Empresa y sellos. El sello se queda guardado y cifrado en Factúralo y Punto: tu sistema nunca lo toca.
Crea la llave
En Negocio › Integraciones › «Para programadores», en «Llaves de la API», toca «Crear llave» y elige qué puede hacer: timbrar, consultar, cancelar, registrar pagos, ver clientes o crear tickets. Es de una sola empresa (un RFC) y se muestra una sola vez: guárdala en tu servidor.
Timbra tu primera factura
Manda la venta con tu llave y una
Idempotency-Key: el id de la operación en tu sistema, como el del pedido.POST /facturas curl -X POST https://facturaloypunto.com/api/v1/facturas \ -H "Authorization: Bearer tk_tu_llave" \ -H "Idempotency-Key: pedido-10432" \ -H "Content-Type: application/json" \ -d '{ "cliente": { "rfc": "EKU9003173C9", "nombre": "ESCUELA KEMPER URGATE", "codigoPostal": "42501", "regimenFiscal": "601", "usoCfdi": "G03", "correo": "pagos@ejemplo.test" }, "conceptos": [ { "descripcion": "Plan Pro mensual", "cantidad": 1, "precio": "1000.00", "claveProdServ": "81112100", "claveUnidad": "E48", "iva": "16" } ], "metodoPago": "PUE", "formaPago": "04", "enviarCorreo": false }'Responde
201con la factura timbrada:Respuesta 201 { "id": "5f0c…", "serie": "A", "folio": "1042", "uuid": "70B929A9-A7AC-4CC1-9B8E-75E4CDD04EB2", "total": "1160.00", "estado": "timbrado", "fecha": "2026-10-24T11:32:07", "pdf": "https://facturaloypunto.com/api/v1/facturas/5f0c…/pdf", "xml": "https://facturaloypunto.com/api/v1/facturas/5f0c…/xml" }Si mandas otra vez la misma
Idempotency-Key, recibes esta misma factura con200: nunca se timbra dos veces. Si el cliente ya está en tu catálogo, mandaclienteIden lugar de sus datos; un concepto puede ir conproductoId.
Reglas comunes
- Llave
- En cada petición,
Authorization: Bearer tk_…. Cada llave es de una empresa y sólo timbra con su RFC. - Idempotencia
- Todo lo que timbra pide
Idempotency-Key, de 8 a 120 caracteres; usa el id de la operación en tu sistema (el del pedido, el del pago de Stripe). Repetirla con los mismos datos devuelve lo mismo y nunca timbra dos veces; con otros datos responde409. Vale por llave y por recurso: el id de un pedido sirve para su factura y para la Carta Porte de su envío. Si recibes202o503, repite con la misma llave: con otra sería otra factura. - Importes como texto
- Los importes van como texto decimal:
"1160.00", sin comas ni signo. También se aceptan números, pero el texto evita redondeos. Lo que no se entiende se rechaza con el campo: nunca se cambia por otro valor. - Límite
- 120 peticiones por minuto por llave. Al pasarte responde
429conRetry-After: los segundos que hay que esperar. No se hizo nada, así que puedes reintentar con la mismaIdempotency-Key. - Errores en español
- El
mensajeya viene en español para enseñárselo tal cual a tu usuario, yproblemasdice qué dato corregir:Respuesta 422 { "error": { "codigo": "DATOS_INVALIDOS", "mensaje": "El descuento del concepto 1 («10%») es un importe en pesos, sin signo ni «%», por ejemplo \"200.00\". Si es un porcentaje, manda el importe que resulta.", "problemas": [{ "campo": "conceptos[0].descuento", "codigo": "DESCUENTO_INVALIDO", "mensaje": "El descuento del concepto 1 («10%») es un importe en pesos, …" }] } } - Bitácora
- Cada llamada queda 60 días en la bitácora de Negocio › Integraciones › «Para programadores», con su respuesta y el motivo de cualquier rechazo.
- Modo de pruebas
- Con el servidor en modo simulado se timbra sin llegar al SAT, con las mismas revisiones (RFC, código postal, claves del SAT); los folios de la cuenta de pruebas sí se descuentan, igual que en producción. En producción todo es real: cada factura llega al SAT y usa un folio.
Qué datos necesitas
Lo que lleva POST /facturas según el caso. Lo que no mandes toma el valor que se dice; lo que esté mal se rechaza con el campo.
- Una empresa o una persona de México
- En
cliente:rfc(con su dígito verificador correcto),nombretal como en su Constancia de Situación Fiscal (en mayúsculas y sin «S.A. de C.V.»),codigoPostalfiscal (como texto:"06700") yregimenFiscal(601para una empresa;612,605,626… para una persona).usoCfdies opcional:G03si no lo mandas. Si ya está en tu catálogo, bastaclienteId. - Una persona sin RFC
rfcXAXX010101000y sunombre. El régimen616, el usoS01y el código postal de tu lugar de expedición se ponen solos.- Tu factura global, con tus ventas
- El cliente
PUBLICO EN GENERALeinformacionGlobalconperiodicidad("01"diaria a"05"bimestral),mesesyanio. Si tus ventas son tickets de Factúralo y Punto, usaPOST /facturas/global. - Un cliente del extranjero
extranjero: true,nombre,pais(USA,CAN…) yregistroFiscal(su número de identificación fiscal). El RFC genérico, el régimen, el uso y el código postal se ponen solos.- De contado (PUE)
- Manda siempre
formaPagocomo texto de dos dígitos:"01"efectivo,"03"transferencia,"04"tarjeta de crédito,"28"de débito. Si falta, sale con03y la respuesta trae un aviso. - A crédito (PPD)
metodoPago"PPD": la forma de pago es99sola. Cada pago que recibas va conPOST /pagos(fecha y, en facturas, el id y el abono).- En dólares
moneda"USD"ytipoCambio(pesos por dólar).- Con retenciones
- Honorarios, arrendamiento y RESICO sólo los retiene una empresa cuando le paga a una persona: tu empresa debe ser persona física y tu cliente, persona moral. Para otra,
retencion"otra"con sus porcentajes. - Cada concepto
descripcion,preciosin impuestos (texto, sin comas) y, del catálogo del SAT,claveProdServyclaveUnidad(búscalas enGET /catalogos/…).iva:"16"si no lo mandas. ConproductoId, lo que falte sale de tu catálogo. El descuento es un importe en pesos, no un porcentaje.- Para cancelar
motivo:"02"si tiene errores,"03"si la venta no se hizo,"01"conuuidSustituto(el folio fiscal de la factura que la sustituye, hecha conrelacionadostipo04) y"04"sólo para la global.
Errores
Cada error trae un codigo que no cambia y un mensaje en español. El estado HTTP dice qué hacer: 422 es un dato por corregir, 401 pide volver a conectar, 403 lo arregla el dueño, y con 202, 429 o 503 se repite con la misma Idempotency-Key. La lista completa está en la referencia.
| Código | Qué pasó | Qué mostrarle al usuario |
|---|---|---|
DATOS_422 | Falta un dato o no está bien; «problemas» dice cuál, con el nombre del campo que mandaste. | El mensaje y cada problema junto a su campo, para que lo corrija y lo mande otra vez. |
PAC_422 | El SAT no aceptó un dato: por ejemplo, el nombre o el código postal no son los de la Constancia del cliente. | El mensaje tal cual: ya dice qué cambiar. |
CSD_422 | Falta el sello digital (o venció) o se acabaron los folios. | Que el dueño lo arregle en Factúralo y Punto; luego repite con la misma Idempotency-Key. |
IDEMPOTENCIA409 | Esa Idempotency-Key ya se usó con otros datos. | Nada: es de tu sistema. Si es otra venta, usa otra llave. |
EN_202 | La misma operación se está timbrando en otra petición. | «Se está timbrando»; repite con la misma llave en unos segundos. |
TIMBRADO_503 | El servicio de timbrado no contestó y no se sabe si timbró. | «Lo estamos confirmando»; repite con la MISMA llave después de Retry-After, nunca con otra. |
LLAVE_401 | La conexión ya no vale. | «Vuelve a conectar tu cuenta de Factúralo y Punto». |
SIN_403 | La llave no puede hacerlo, el plan no lo incluye o la cuenta está suspendida. | El mensaje tal cual: lo arregla el dueño. |
NO_404 | No existe en esa empresa. | «No encontramos esa factura». |
CANCELACION_409 | La factura tiene complementos de pago o notas de crédito vigentes. | Cuáles cancelar primero: vienen en «relacionados», con su id. |
CANCELACION_422 | El SAT no aplicó la cancelación. | El mensaje: la factura sigue vigente. |
DEMASIADAS_429 | Más peticiones por minuto de las que permite la llave. | Nada: espera Retry-After y repite. |
ERROR_500 | Una falla nuestra. | «Algo falló, inténtalo más tarde»; repite con la misma llave. |
Avisos firmados
Agrega la dirección de tu sistema en Negocio › Integraciones › «Para programadores» y elige qué quieres saber. Por cada evento llega un POST con { id, evento, empresaId, creado, datos }, y el evento también en el encabezado X-FacturaloYPunto-Evento.
factura.timbrada- Se timbró una factura.
factura.cancelada- Se canceló una factura: en ese momento o cuando tu cliente aceptó la cancelación.
factura.cancelacion_rechazada- Tu cliente rechazó la cancelación (o no procedió): la factura sigue vigente.
pago.registrado- Se registró un pago y se timbró su complemento.
ticket.facturado- Un cliente facturó su ticket en tu portal.
folios.por_acabarse- Tu saldo de folios bajó del mínimo que pusiste.
sello.por_vencer- A tu sello digital le quedan 30, 7 o 1 días, o venció hoy.
Cómo saber que el aviso es nuestro
El encabezado X-FacturaloYPunto-Firma trae t=<segundos>,v1=<firma>, donde v1 es el HMAC-SHA256 de t.cuerpo con tu secreto, en hexadecimal. Revisa la firma y que t no tenga más de 5 minutos:
import { createHmac, timingSafeEqual } from "node:crypto";
// cuerpo: el texto tal como llegó, antes de JSON.parse.
// firma: el encabezado X-FacturaloYPunto-Firma («t=…,v1=…»).
// secreto: el que te dimos al agregar tu dirección.
export function avisoValido(cuerpo, firma, secreto) {
const { t, v1 } = Object.fromEntries(firma.split(",").map((parte) => parte.split("=")));
// Sin firma o de hace más de 5 minutos: se descarta.
if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const esperada = createHmac("sha256", secreto).update(`${t}.${cuerpo}`).digest("hex");
return v1.length === esperada.length && timingSafeEqual(Buffer.from(v1), Buffer.from(esperada));
}Responde con un 2xx en menos de 8 segundos; si no, se reintenta hasta cinco veces, cada vez más espaciado (la última, 12 horas después). El id es el mismo en los reintentos: úsalo para no procesar dos veces el mismo aviso. Cada cambio se avisa una sola vez, también una cancelación que se resuelve días después. Las redirecciones no se siguen y la dirección debe ser pública y con https; para probar en tu computadora usa un túnel (cloudflared o ngrok).
Conecta a tus clientes
Para plataformas que atienden a muchos negocios: un ERP, un punto de venta, una plataforma de marketing. Cada negocio conecta su cuenta con un clic desde tu sistema y tú recibes la llave de su empresa, sin que nadie copie nada:
- Tu sistema manda al negocio a
https://facturaloypunto.com/conectarcon tu clave de plataforma (socio), unestadoal azar y una de tus direcciones de regreso (regreso); si quieres, también sucorreoy tu id delnegocio. - Ahí entra o crea su cuenta, elige su empresa, sube su sello (tu sistema nunca lo ve) y te autoriza.
- Regresa a tu dirección con tu mismo
estadoy uncodigoque sirve una sola vez y dura 60 segundos (o conerror=cancelado). - Tu servidor cambia el código por la llave de su empresa en
POST /socios/canjear, con tu secreto, y si quieres deja ahí la dirección para sus avisos. - Con
POST /sesionesle abres Factúralo y Punto ya con su sesión: una liga de un solo uso que dura 60 segundos. Si en ese navegador no estaba su sesión, confirma con un botón; esa sesión sólo sirve para su empresa y por unas horas. POST /socios/desconectarrevoca la llave, sus avisos y las sesiones que abriste. El negocio también te puede desconectar desde Negocio › Integraciones.
Cómo registrar tu plataforma
Crea tu cuenta de Factúralo y Punto y en Negocio › Integraciones › «Para programadores» › «Soy una plataforma» da de alta tu clave, tu nombre y tus direcciones de regreso (https; para probar, también http://localhost): te damos tu secreto una sola vez. Con eso ya conectas negocios y usas sus llaves. Para cancelar facturas por ellos y abrirles Factúralo y Punto con su sesión, verificamos tu plataforma: escríbenos a soporte@facturaloypunto.com.
Cada negocio le paga sus folios directo a Factúralo y Punto, a los mismos precios de abajo: tú no cobras comisión ni pagas por ellos. La conexión manual sigue sirviendo: el negocio crea su llave y su dirección de avisos en Negocio › Integraciones › «Para programadores» y las pega en tu sistema.