Emitir CFDI
Timbrar facturas
El CFDI de ingreso completo: conceptos, impuestos, moneda, factura global, relacionados y traslados.
POST /api/authenticated/{org}/invoices
Scope: invoices.create. Devuelve 201 con el CFDI ya timbrado.
Un solo endpoint emite todos los tipos de comprobante. El campo type decide qué
más se espera en el cuerpo:
type | Comprobante | Página |
|---|---|---|
ingreso | Factura de venta | esta |
egreso | Nota de crédito | Notas de crédito |
traslado | Traslado de mercancías | esta, al final |
nomina | Recibo de nómina | Nómina |
Antes de la primera llamada
Confirma con GET /context que fiscal.csd.state sea "active" y que
stampingMode sea el ambiente que crees. Sin CSD válido la respuesta es 412 y
no hay nada que tu código pueda hacer al respecto: el usuario tiene que subirlo en
Facty.
CFDI de ingreso
Campos del comprobante
| Campo | Requerido | Descripción |
|---|---|---|
type | sí | "ingreso" |
clientId | sí | cuid del cliente receptor. |
items | sí | Al menos un concepto. Ver abajo. |
idempotencyKey | sí | 8–128 caracteres, derivada de tu registro. Ver Idempotencia. |
usoCfdi | sí | Clave de c_UsoCFDI compatible con el régimen del receptor. |
formaPago | sí | Clave de 2 dígitos de c_FormaPago. |
metodoPago | sí | "PUE" o "PPD". |
serie | no | Sobrescribe la serie configurada en Facty. 1–25 caracteres. |
moneda | no | Código de 3 letras. Default "MXN". |
tipoCambio | no | Requerido si moneda no es MXN. |
exportacion | no | Clave de c_Exportacion (2 caracteres). Default "01" (no aplica). |
informacionGlobal | no | Para el CFDI global. Ver abajo. |
cfdiRelacionados | no | Ver "CFDI relacionados". |
observaciones | no | Texto libre, máx. 1000. No es un atributo del XML: se guarda con el documento y se imprime en el PDF. |
numeroOrden | no | Tu número de orden o pedido, máx. 100. Mismo tratamiento que observaciones. |
allowRetryOnFailed | no | Permite reusar una llave de idempotencia que ya falló. |
Lo que no mandas, porque sale de tu perfil fiscal en Facty: el emisor, su
régimen, el lugar de expedición, la serie y el folio (salvo que sobrescribas
serie), y por supuesto el sello y el timbre.
Conceptos (items)
Cada concepto es o bien una referencia a tu catálogo, o bien un concepto completo:
{ "productId": "clxp01…", "quantity": 2 }
{
"claveProdServ": "81111500",
"claveUnidad": "E48",
"description": "Servicios de desarrollo de software",
"quantity": 1,
"unitPrice": 10000,
"iva": 0.16
}
| Campo | Requerido | Descripción |
|---|---|---|
quantity | sí | Siempre. Mayor a cero. |
productId | condicional | Si lo mandas, todo lo demás se hereda del producto. |
claveProdServ, claveUnidad, description, unitPrice | condicional | Requeridos los cuatro si no mandas productId. |
iva | no | 0, 0.08 o 0.16. Cualquier otro valor da 422. |
ivaExento | no | Booleano. Excluyente con una tasa de iva distinta de cero. |
ieps | no | Tasa decimal. |
iepsCuota | no | IEPS de cuota, pesos por unidad. Excluyente con ieps. |
retIsr | no | Tasa de retención de ISR. Máximo 0.35. |
retIva, retIeps | no | Tasas de retención. |
descuento | no | Tasa: 0.10 es 10%. |
objetoImp | no | Clave de c_ObjetoImp (01–08). Si la omites: 02 cuando hay impuestos, 01 cuando no. |
noIdentificacion | no | SKU o número de parte que se imprime. |
cuentaPredial | no | Hasta 25 dígitos. Arrendamiento de inmuebles. |
numerosPedimento | no | Arreglo de números de pedimento aduanal. |
cuentaAcTerceroRfc + Nombre + Regimen + Cp | no | ACuentaTerceros. Los cuatro o ninguno. |
Cualquier campo que mandes explícitamente gana sobre el default del producto.
Ejemplo completo
curl -s -X POST "$FACTY_HOST/api/authenticated/$FACTY_ORG/invoices" \
-H "X-API-Key: $FACTY_KEY" -H "Content-Type: application/json" \
-d '{
"type": "ingreso",
"clientId": "clx9aa…",
"usoCfdi": "G03",
"formaPago": "03",
"metodoPago": "PUE",
"moneda": "MXN",
"numeroOrden": "OC-2026-0442",
"idempotencyKey": "mi-erp:prod:factura:4471",
"items": [
{
"claveProdServ": "81111500",
"claveUnidad": "E48",
"description": "Desarrollo de software a la medida — agosto 2026",
"quantity": 1,
"unitPrice": 48000,
"iva": 0.16,
"retIsr": 0.10,
"retIva": 0.106667
},
{ "productId": "clxp02…", "quantity": 5, "descuento": 0.15 }
]
}' | jq
Respuesta
{
"id": "clxi7…",
"uuid": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
"serie": "F",
"folio": 118,
"status": "stamped",
"total": 51840,
"moneda": "MXN",
"stampedAt": "2026-08-28T18:04:11.000Z",
"timbresRemaining": 1239
}
Trae serie, folio y UUID en la misma respuesta justamente para que no tengas
que encadenar un GET y escribir tu registro local a medias.
timbresRemaining es el saldo tras este timbrado; puede venir null si la
lectura del saldo falló — eso nunca convierte en error una petición cuyo CFDI ya
se emitió.
Moneda extranjera
{
"type": "ingreso",
"moneda": "USD",
"tipoCambio": 18.42,
"…": "…"
}
tipoCambio es obligatorio cuando la moneda no es MXN: es el valor de una
unidad de esa moneda en pesos. Los unitPrice van en la moneda del comprobante,
no en pesos.
Factura global (público en general)
Para consolidar ventas al público en un solo CFDI, manda informacionGlobal con
un receptor genérico (XAXX010101000, régimen 616, uso S01):
{
"type": "ingreso",
"clientId": "clxpublico…",
"usoCfdi": "S01",
"formaPago": "01",
"metodoPago": "PUE",
"informacionGlobal": { "periodicidad": "04", "meses": "08", "anio": 2026 },
"idempotencyKey": "pos:prod:global:2026-08",
"items": [ /* … */ ]
}
| Campo | Valores |
|---|---|
periodicidad | 01 diario, 02 semanal, 03 quincenal, 04 mensual, 05 bimestral |
meses | 01–12 para meses; 13–18 para bimestres |
anio | 2021–2099 |
CFDI relacionados
Para vincular este comprobante con otros ya emitidos:
{
"cfdiRelacionados": [
{
"tipoRelacion": "04",
"uuids": ["A1B2C3D4-…", "E5F6A7B8-…"]
}
]
}
tipoRelacion es una clave de 2 dígitos de c_TipoRelacion:
| Clave | Significado |
|---|---|
01 | Nota de crédito de los documentos relacionados |
02 | Nota de débito de los documentos relacionados |
03 | Devolución de mercancía sobre facturas o traslados previos |
04 | Sustitución de los CFDI previos |
06 | Factura generada por los traslados previos |
07 | CFDI por aplicación de anticipo |
05 (traslados de mercancías facturados previamente) sólo aplica a un CFDI de
traslado y se rechaza aquí.
Aplica igual a una factura global: para
sustituir una global, manda tipoRelacion: "04" con el UUID de la original
junto con su informacionGlobal.
Reglas:
- Un solo
tipoRelacionpor comprobante, con uno o más UUID. Si mandas dos entradas con el mismo tipo, se unen; con tipos distintos, la respuesta es422. Si necesitas relacionar con dos tipos, emite un CFDI por cada uno. - Cada UUID debe ser una factura de tu organización timbrada en Facty; si no,
422. - La relación queda en el XML timbrado y en
GET /invoices/{id}(cfdiRelacionadosUuid,cfdiRelacionadosTipoRelacion). - En una nota de crédito este nodo es obligatorio — ver Notas de crédito.
- Un traslado no admite CFDI relacionados.
CFDI de traslado
Un traslado (type: "traslado") ampara el movimiento de mercancía propia; no
tiene efecto de venta.
{
"type": "traslado",
"clientId": "clx9aa…",
"idempotencyKey": "wms:prod:embarque:9931",
"items": [
{
"claveProdServ": "43211500",
"claveUnidad": "H87",
"description": "Equipo de cómputo",
"quantity": 12,
"unitPrice": 0
}
]
}
- No lleva
usoCfdi,formaPagonimetodoPago: Facty los fija por ti. - Sus conceptos no admiten
iva,ivaExento,ieps,iepsCuotanidescuento. Mandar cualquiera de ellos da422en vez de descartarlos en silencio. - Un traslado por carretera federal necesita además el complemento Carta Porte.
Consulta
complements.cartaPorteen/contextantes de intentarlo: si vienefalse, este ambiente todavía no lo emite.
Consultar lo que timbraste
GET /api/authenticated/{org}/invoices
Scope: invoices.read
| Filtro | Descripción |
|---|---|
status | draft, pending, stamped, failed, cancelled |
type | ingreso, egreso, pago, nomina, retencion, traslado |
clientId | cuid del cliente |
uuid | Folio fiscal. No distingue mayúsculas. |
idempotencyKey | Tu llave. La vía preferente para reconciliar. |
dateFrom, dateTo | YYYY-MM-DD o ISO-8601 con offset |
limit | 1–100. Default 25. |
cursor | Paginación |
{
"invoices": [
{
"id": "clxi7…",
"serie": "F",
"folio": 118,
"type": "ingreso",
"status": "stamped",
"uuid": "A1B2C3D4-…",
"idempotencyKey": "mi-erp:prod:factura:4471",
"receptorRfc": "ACM980101ABC",
"receptorName": "ACME SA DE CV",
"total": 51840,
"moneda": "MXN",
"createdAt": "2026-08-28T18:04:09.000Z",
"stampedAt": "2026-08-28T18:04:11.000Z"
}
],
"nextCursor": null
}
El detalle completo, con conceptos e impuestos desglosados:
GET /api/authenticated/{org}/invoices/{invoiceId}