Saltar al contenido
oden.tax docs
POST /v1/mx/invoices

Crear una factura

Crea y timbra un CFDI 4.0 en una sola llamada. La respuesta llega cuando el PAC devuelve el UUID: la llamada es síncrona, así que cuando te contestamos el comprobante ya está presentado o ya sabemos por qué no.

Manda siempre Idempotency-Key. Si repites la llamada con la misma clave te devolvemos la factura original en vez de timbrar dos veces, con la cabecera Idempotency-Replayed: true.

Parámetros

customer objeto · requerido si no mandas customer_id
El receptor. Lleva tax_id, legal_name, tax_regime y postal_code; opcionales default_cfdi_use, email, tax_residency y foreign_tax_id. Ver Clientes. Lo buscamos entre los clientes del emisor que timbra. El comprobante sale con lo que mandes, y al timbrarse guardamos esos datos en el cliente; un rechazo lo deja como estaba. Con XAXX010101000 ponemos el código postal del emisor, que es el único que el SAT acepta.
customer_id entero · requerido si no mandas customer
Un cliente que ya tienes guardado, por su id. Lo buscamos entre los clientes del emisor que timbra: el id de un cliente de otro emisor contesta not_found.
issuer_id entero · requerido si tienes más de un emisor
Con qué RFC se timbra. Si tu cuenta tiene un solo emisor lo puedes omitir; con dos o más lo pedimos, porque adivinarlo sería timbrar con el RFC equivocado.
cfdi_use string · opcional
Clave del catálogo de uso del CFDI, por ejemplo G03 para gastos en general. Si lo omites usamos el uso predeterminado del cliente. Lo validamos contra el régimen y el tipo de persona del receptor: un uso que no le aplica contesta validation_failed sin llamar al PAC.
payment_method string · opcional
PUE cuando el pago ya se hizo en una sola exhibición; PPD cuando queda a crédito y se liquidará después con un complemento de pago. Por omisión, PUE.
payment_form string · opcional
Clave del catálogo de formas de pago del SAT, por ejemplo 03 para transferencia electrónica de fondos. Por omisión, 03. Con payment_method PPD tiene que ser 99 (Por definir): el SAT rechaza cualquier otra, y contestamos 422 antes de timbrar.
items arreglo · requerido
Los conceptos. Cada uno lleva description, quantity y unit_price, más product_service_key y unit_key. Si mandas product_id, la descripción, el precio y las dos claves salen del producto guardado; lo que mandes en la partida gana. quantity es 1 si no la dices. El producto tiene que ser del emisor que timbra, o contestamos not_found.
items[].tax_object string · opcional
El ObjetoImp de la partida, del catálogo c_ObjetoImp: 01, 02, 03 o 04. Sin él, el del producto, y si no 02.
items[].discount decimal · opcional
El descuento de la partida, en la moneda del comprobante. No puede ser mayor que su importe. El descuento del comprobante es la suma de los de las partidas.
items[].vat_rate / withholding_rate / vat_withholding_rate decimal · opcionales
Las tasas de esa partida, con los mismos valores que las del comprobante. Sin ellas, la partida usa las del comprobante. Una factura puede mezclar tasas.
items[].vat_withheld decimal · opcional
El IVA retenido de esa partida tal como lo calcula tu cliente, cuando no es el de la tasa. Calculamos la tasa de seis decimales que lo da exacto y es la que se timbra. Si ninguna lo da, contestamos 422 con las dos cifras más cercanas que sí se pueden timbrar.
items[].tax_factor string · opcional
Tasa o Exento. Exento es una partida que es objeto del impuesto y no lo causa; no es lo mismo que vat_rate 0, que es tasa cero.
items[].identification_number string · opcional
El NoIdentificacion del concepto: tu clave del producto o su número de serie. En una factura global va el folio del comprobante de venta que ampara cada concepto (regla 2.7.1.21 de la RMF). Hasta 100 caracteres y sin |.
items[].ieps_rate / ieps_quota decimal · opcionales
El IEPS de la partida, a tasa o a cuota, nunca los dos: el traslado lleva un solo factor. A tasa va sobre la base; a cuota se multiplica por la cantidad, porque grava por unidad de medida y no por importe. Manda ieps_in_vat_base: false si el IEPS no debe entrar en la base del IVA; omitirlo lo deja dentro, que es lo ordinario.
relations arreglo · opcional
Los comprobantes que éste relaciona, cada uno con uuid y relation_type del catálogo c_TipoRelacion (01 a 07). Un sustituto relaciona con 04 al que reemplaza. Después cancelas el original con motivo 01 y el UUID del sustituto en substitute_uuid. Una nota de crédito relaciona con 01 la factura que corrige.
voucher_type string · opcional
I, ingreso, por omisión. E para una nota de crédito: tiene que llevar relations con la factura que corrige (relation_type 01), o contestamos validation_failed. Cualquier otro valor contesta invalid_parameter.
global_information objeto · opcional
Para una factura global: periodicity (01 diario, 02 semanal, 03 quincenal, 04 mensual, 05 bimestral), month (01 a 12, o 13 a 18 si es bimestral) y year (2019 en adelante). Van los tres juntos y el receptor es XAXX010101000, público en general. En cada concepto, identification_number lleva el folio de la venta que ampara.
series / vat_rate string / decimal · opcionales
La serie es A si no dices otra, y el folio siempre lo asignamos nosotros: es lo que mantiene la secuencia del emisor sin huecos. vat_rate acepta 0.16, 0.08 (franja fronteriza) o 0; por omisión, 0.16.
tax_included booleano · opcional
Manda true si tus precios ya traen el IVA adentro, como se ven en un menú o en una etiqueta. Nosotros separamos la base y el traslado, y el total del comprobante queda exactamente en lo que cobraste. Sin esto, bajar los precios a la base por tu cuenta desfasa el total un centavo seguido: $59 y $89 son $148 en la caja y $147.99 en la factura.
withholding_rate decimal · opcional
ISR retenido: 0.0125, 0.10 o 0. Por omisión, 0. Un emisor RESICO (régimen 626) retiene 1.25% cuando le factura a una persona moral; una persona física que cobra honorarios a una moral, 10%. Va explícito y no lo deducimos del régimen: quién retiene depende del receptor, y esa decisión es tuya.
vat_withholding_rate decimal · opcional
IVA retenido. Por omisión, 0. Las tasas de ley son 0.106667 (dos terceras partes del 16%: honorarios, renta o comisiones de una persona física), 0.04 (flete), 0.06 (servicios especializados) y la tasa del IVA completa (desperdicios). En la región fronteriza, dos tercios del 8% son 0.053333. Se acepta una tasa a menos de 0.0001 de una de ésas, como 0.10667, porque así la calculan muchos clientes; más lejos es un error. Nunca puede retener más IVA del que traslada la partida. Va junto con withholding_rate y no en su lugar: el mismo recibo retiene ISR e IVA.
currency string · opcional
Clave del catálogo c_Moneda: MXN, USD, EUR, CAD, GBP, CHF, AUD, CNY, BRL, COP, ARS, PEN, CLP, JPY, KWD. Por omisión, MXN. Los importes de items van en esta moneda y el comprobante los escribe tal cual, sin convertirlos a pesos.
exchange_rate decimal · condicional
Los pesos que costaba una unidad de esa moneda el día de la emisión, hasta seis decimales. Requerido en cuanto currency no es MXN, y no se acepta cuando sí lo es: el SAT pide TipoCambio en toda moneda extranjera y lo rechaza en pesos. En MXN aceptamos 1 y lo descartamos. No lo consultamos por ti — el tipo de cambio de un comprobante es el de su fecha, y queda escrito con él.
issued_at string · opcional
La fecha del comprobante en ISO 8601, para facturar hoy algo de ayer. Por omisión, el instante del timbrado. El artículo 29-A la limita a las 72 horas anteriores y no admite fechar hacia adelante, así que fuera de ese rango contestamos 422 sin llamar al PAC y sin gastarte un timbre. Sin offset la leemos en la zona horaria de tu código postal de expedición, que es contra la que el SAT valida el Fecha: 2026-08-25T14:30 son las 14:30 de donde expides. Con offset explícito manda el offset.

Respuesta

Devolvemos 201 con el UUID en cuanto el PAC responde. Si el PAC rechaza el timbrado devolvemos 422 con su motivo traducido a un código estable, y la factura en estado error dentro de details: el borrador se queda, para que puedas leer el rechazo contra un folio real.

id entero
Identificador de la factura dentro de oden.tax.
status string
draft, stamping, stamped, error o canceled.
uuid string
Folio fiscal del SAT, 36 caracteres. Llega en null si todavía no hay timbre.
series / number string / entero
La serie y el folio consecutivo dentro de ella.
folio string
Las dos anteriores juntas, que es como se lee un comprobante: A-1044.
cfdi_use / payment_form / payment_method string
Lo que lleva el comprobante, ya con los valores por omisión resueltos.
vat_rate / withholding_rate / vat_withholding_rate string
Las tasas del comprobante.
issued_at / stamped_at / canceled_at string
Fecha del comprobante, del timbrado y de la cancelación, en ISO 8601 con zona horaria. null mientras no haya pasado.
subtotal / transferred_taxes / total string
Importes con dos decimales. Van como texto a propósito: un número en JSON es un flotante. transferred_taxes es el IVA más el IEPS, igual que el TotalImpuestosTrasladados del comprobante: los dos son impuestos trasladados y el SAT los pide en un solo total.
withheld_taxes string
ISR retenido, ya restado del total. 0.00 en un comprobante sin retención.
vat_withheld_taxes string
IVA retenido, ya restado del total. Va aparte del anterior porque son dos impuestos distintos, y sumarlos deja un importe que no corresponde a ninguno.
currency string
Clave del catálogo c_Moneda con que se timbró el comprobante.
exchange_rate string
El TipoCambio del comprobante, hasta seis decimales. Llega en null cuando la moneda es MXN.
issuer objeto
El emisor tal como quedó en el comprobante: id, tax_id, legal_name, tax_regime y postal_code (el del lugar de expedición).
customer objeto
El receptor tal como quedó en el comprobante: id, tax_id, legal_name, tax_regime y postal_code, más tax_residency y foreign_tax_id cuando es extranjero.
items arreglo
Los conceptos: product_service_key, unit_key, description, quantity, unit_price y amount, con sus importes ya calculados.
items[].transferred_taxes string
Lo que trasladó esa partida: su IVA más su IEPS, con el mismo criterio que el campo de arriba. Las partidas suman el total del comprobante, que es lo que hace que se pueda conciliar línea por línea. Si necesitas los dos por separado, la tasa que mandaste los reconstruye; dínoslo y los devolvemos partidos.
xml_url / pdf_url string
Sólo cuando hay comprobante. Son estables: puedes guardarlas.
error objeto
Sólo en una factura rechazada, con code y message.
cancellation objeto
Sólo si se pidió cancelarla. Ver Cancelar una factura.

Errores comunes

Todos tienen la misma forma: {"error": {"code", "message"}}, con el code en inglés para que puedas hacer switch y el mensaje en español para mostrarlo.

unauthorized
Falta la llave o ya fue revocada. Va como Authorization: Bearer.
invoice_limit_reached
Con el plan Básico, tu cuenta ya timbró 100 facturas este mes. 429, con Retry-After hasta el día 1.
payment_required
La cuenta tiene un pago pendiente.
issuer_required
Tienes más de un emisor y la llamada no dijo cuál.
issuer_not_ready
Al emisor le falta su RFC, su régimen, su código postal o su CSD.
not_found
El issuer_id, customer_id o product_id no es de tu cuenta o de ese emisor, o no existe. 404.
missing_parameter
Falta un campo obligatorio, como items o el receptor. El mensaje dice cuál.
invalid_parameter
Un campo no se puede usar: una cantidad o una tasa que no es número, una fecha que no es fecha.
validation_failed
Algún dato no pasó nuestras validaciones. details trae cada campo con sus motivos. No se crea borrador.
folio_conflict
Otra factura tomó el folio al mismo tiempo. 409. Reintenta.
csd_revoked
Tu certificado venció o fue revocado. Sube uno vigente en Configuración o por la API.
csd_not_from_sat
El certificado no lo expidió el SAT. Es lo que pasa con un CSD de prueba en producción.
date_out_of_range
El PAC dice que la fecha quedó fuera de las 72 horas. Pasa cuando un borrador envejeció antes de timbrarse; un issued_at fuera de rango en la llamada llega como validation_failed.
invalid_seal
El sello no coincide con la cadena original (CFDI40102).
duplicate_cfdi
Ese comprobante ya tiene un timbre previo.
pac_unavailable
El PAC no contestó a tiempo y pudo haber timbrado. Reintenta con la misma Idempotency-Key: le preguntamos al PAC antes de timbrar otra vez.
stamping_unconfirmed
No pudimos confirmar si el PAC timbró una factura que quedó sin respuesta. Búscala en el SAT y, si no aparece, timbra con otra Idempotency-Key.
schema_invalid
El XML no pasó el esquema del SAT. No llegó al PAC ni costó timbre. 422.
stamping_failed
No pudimos preparar o terminar el timbrado por un motivo nuestro. Reintenta.