Auto CFDI
Auto CFDI permite que tus clientes generen su factura a partir del ticket de compra, sin que tu equipo intervenga. Tu punto de venta registra cada venta pagada como ticket e imprime su código y un QR; tu cliente lo escanea, captura sus datos fiscales en tu portal de autofactura y recibe su CFDI.
Cómo funciona
Cada ticket recorre el mismo camino, y cada paso es una llamada estándar de la API:
| Paso | Quién | Qué ocurre |
|---|---|---|
| 1 | Tu punto de venta | Registra la venta con Crear ticket y recibe el código y la URL del QR. |
| 2 | Tu punto de venta | Imprime el código y el QR en el comprobante de la venta. |
| 3 | Tu cliente | Abre el QR, captura su RFC y sus datos fiscales y descarga su factura. Fiscalapi la timbra con los datos del ticket. |
| 4 | Tú | Al cierre del periodo, incluyes los tickets que nadie facturó en la factura global de tickets. |
La autofactura usa los conceptos, impuestos y totales que registraste en el ticket: tu cliente no los puede cambiar. Fiscalapi valida la estructura, los catálogos del SAT y la aritmética; los impuestos que declaras son tu responsabilidad.
Contratación y créditos
Auto CFDI es un módulo de tu suscripción y requiere Emisión CFDI. El owner de la cuenta lo agrega en Compras en línea > Módulos adicionales del Dashboard y compra los créditos de ticket en Compras en línea > Tienda en línea.
El cobro tiene dos partes independientes:
| Concepto | Cuándo se consume | De quién |
|---|---|---|
| Crédito de ticket | Al registrar un ticket, aunque nunca se facture. Un rechazo (4xx), una repetición con la misma llave o un duplicado no consumen. | De la persona autenticada que registra el ticket. |
| Timbre | Al timbrar cada CFDI: la autofactura, la factura global y su sustituta. | De la persona emisora del ticket en la autofactura, y de la persona autenticada en la global. |
Los créditos de ticket son el tipo de crédito 3. Los transfieres y retiras entre las personas de tu cuenta con Transferir timbres y ese valor en creditType, y el saldo de cada persona aparece en balances de la persona. Un crédito de ticket consumido no se devuelve, aunque canceles el ticket.
Permisos y suscripción
Consultar tus tickets y tu configuración no exige Auto CFDI: si das de baja el módulo, sigues viendo lo que registraste. Lo que registra, cancela o cambia algo sí lo exige, y la configuración solo la administra el owner.
| Permiso | Qué permite | Exige Auto CFDI |
|---|---|---|
| Tickets.Read | Consultar tickets y el reporte de consumo. | No |
| Tickets.Create | Registrar tickets. | Sí |
| Tickets.Cancel | Cancelar tickets. | Sí |
| AutoInvoice.Read | Consultar la configuración y el nombre del portal. | No |
| AutoInvoice.Manage | Cambiar la configuración y el nombre del portal. Solo el owner. | Sí |
La factura global de tickets y su cancelación usan los permisos de facturación de siempre. Sin el permiso, o sin el módulo en tu suscripción, el endpoint responde 403:
| Estado | Cuándo ocurre | Mensaje |
|---|---|---|
| 403 | Registras un ticket y tu suscripción no incluye Auto CFDI. | Para ingerir tickets tu suscripción debe incluir: Auto CFDI. |
| 403 | Cancelas un ticket y tu suscripción no incluye Auto CFDI. | Para cancelar tickets tu suscripción debe incluir: Auto CFDI. |
| 403 | Cambias la configuración o el nombre del portal, o consultas si un nombre está disponible, y tu suscripción no incluye Auto CFDI. | Para administrar la configuración de Auto CFDI tu suscripción debe incluir: Auto CFDI. |
| 403 | Cambias la configuración o el nombre del portal, o consultas si un nombre está disponible, y no eres el owner. | No tienes permiso para administrar la configuración de Auto CFDI. |
Si tu suscripción tampoco incluye Emisión CFDI, el mensaje lista los dos módulos; por ejemplo, Para ingerir tickets tu suscripción debe incluir: Auto CFDI, Emisión CFDI.
Código y QR
Cada ticket tiene un código de 12 caracteres, distinto en cada registro y difícil de adivinar. Crear ticket lo devuelve sin guiones en ticketCode; imprímelo en tres grupos de 4 separados por guiones, que son más fáciles de leer y dictar. El portal acepta el código con o sin guiones y en mayúsculas o minúsculas.
La URL del QR (qrUrl) abre el ticket directamente en el portal y no depende del nombre de tu portal, así que los comprobantes impresos siguen funcionando aunque cambies el nombre:
| Ambiente | URL del QR |
|---|---|
| Pruebas | https://test.factura.fiscalapi.com/t/ seguida del código |
| Producción | https://live.factura.fiscalapi.com/t/ seguida del código |
Para reimprimir un comprobante, recupera el código con Obtener código de ticket.
Vigencia de la autofactura
La configuración define hasta cuándo tu cliente puede autofacturar un ticket, contado desde la fecha del pago en hora de México. Fiscalapi calcula la vigencia en cada consulta con la configuración vigente, así que un cambio aplica de inmediato a todos tus tickets, incluidos los ya registrados.
allowBillingOutsideMonth | allowBillingOutsideYear | Hasta cuándo se autofactura |
|---|---|---|
false | false | Hasta el último día del mes del pago. Es la configuración por omisión. |
true | false | Hasta el 31 de diciembre del año del pago. |
true | true | Sin límite. |
Los tickets devuelven la vigencia en selfInvoiceEligible y eligibleUntil. Un ticket fuera de su vigencia sigue en pending y lo puedes incluir en la factura global de tickets.
Los plazos fiscales para expedir el CFDI de una venta, y para incluirla en una factura global, son responsabilidad de tu negocio. Fiscalapi aplica la vigencia que configuras y no la ajusta a ningún plazo del SAT: elige la configuración que cumpla con tus obligaciones.
Obtener configuración
Este endpoint devuelve la configuración de Auto CFDI de tu cuenta. Si nunca la guardaste, responde la configuración por omisión: vigencia hasta el fin del mes del pago y sin aviso de privacidad.
Respuesta
- Name
allowBillingOutsideMonth- Type
- boolean?
- Description
truesi un ticket pagado en otro mes todavía se puede autofacturar.
- Name
allowBillingOutsideYear- Type
- boolean?
- Description
truesi un ticket pagado en otro año todavía se puede autofacturar.
- Name
privacyNoticeUrl- Type
- string?
- Description
URL del aviso de privacidad que muestra tu portal, o
nullsi no la has configurado.
Request
curl --location 'https://test.fiscalapi.com/api/v4/auto-invoice/settings' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": {
"allowBillingOutsideMonth": false,
"allowBillingOutsideYear": false,
"privacyNoticeUrl": null
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Actualizar configuración
Este endpoint reemplaza la configuración completa de Auto CFDI de tu cuenta: un campo que no envías toma su valor por omisión. Solo el owner lo usa y exige Auto CFDI en tu suscripción.
Tu portal atiende a tus clientes cuando tu suscripción incluye Auto CFDI, tienes un nombre de portal y configuraste el aviso de privacidad. Sin alguno de los tres, el portal muestra que no ofreces facturación en línea y no timbra.
Modelo
- Name
allowBillingOutsideMonth- Type
- boolean?
- Description
truepara permitir autofacturar un ticket pagado en otro mes. Ver Vigencia de la autofactura.Default:false
- Name
allowBillingOutsideYear- Type
- boolean?
- Description
truepara permitir autofacturar un ticket pagado en otro año. ExigeallowBillingOutsideMonthentrue.Default:false
- Name
privacyNoticeUrl- Type
- string?
- Description
URL https de tu aviso de privacidad, de hasta 2048 caracteres. Tu portal la muestra a tus clientes.
Errores
Las fallas llegan como falla de validación en el campo.
| Estado | Cuándo ocurre | Mensaje |
|---|---|---|
| 400 | Permites otro año sin permitir otro mes. | Para permitir facturar fuera del año también debes permitir facturar fuera del mes. |
| 400 | La URL no es una URL https válida. | La URL del aviso de privacidad debe ser una URL https válida. |
| 400 | La URL pasa de 2048 caracteres. | La URL del aviso de privacidad no puede exceder 2048 caracteres. |
| 403 | No eres el owner. | No tienes permiso para administrar la configuración de Auto CFDI. |
| 403 | Tu suscripción no incluye Auto CFDI. Ver Permisos y suscripción. | Para administrar la configuración de Auto CFDI tu suscripción debe incluir: Auto CFDI. |
Request
curl --location --request PUT 'https://test.fiscalapi.com/api/v4/auto-invoice/settings' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
"allowBillingOutsideMonth": true,
"allowBillingOutsideYear": false,
"privacyNoticeUrl": "https://www.example.com/aviso-de-privacidad"
}'
Response
{
"data": {
"allowBillingOutsideMonth": true,
"allowBillingOutsideYear": false,
"privacyNoticeUrl": "https://www.example.com/aviso-de-privacidad"
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Nombre del portal
El nombre del portal es la dirección de tu portal de autofactura en cada ambiente: https://test.factura.fiscalapi.com/ o https://live.factura.fiscalapi.com/ seguida del nombre. Es único en el ambiente y Fiscalapi lo normaliza a minúsculas y sin espacios al inicio ni al final. El nombre cumple estas reglas:
| Regla | Detalle |
|---|---|
| Largo | De 3 a 40 caracteres. |
| Caracteres | Letras minúsculas sin acentos, números y guiones. Empieza con letra, no lleva dos guiones seguidos y no termina en guion. |
| Reservados | No puede ser un nombre reservado, como portal, factura, api o tickets, ni empezar con fiscalapi. |
| Cambios | Puedes cambiarlo una vez cada 30 días. El primer nombre no tiene espera. |
Al cambiarlo, el nombre anterior queda reservado para tu cuenta y redirige al nuevo, así que los enlaces que ya compartiste siguen funcionando. Un nombre nunca se libera, ni al dar de baja Auto CFDI.
Obtener nombre del portal
Este endpoint devuelve el nombre vigente de tu portal. Si todavía no tienes uno, sus campos van en null.
Respuesta
- Name
name- Type
- string?
- Description
Nombre vigente del portal, o
null.
- Name
assignedAt- Type
- string?
- Description
Fecha y hora en que el nombre pasó a vigente, o
null.
- Name
nextChangeAllowedAt- Type
- string?
- Description
Desde cuándo puedes volver a cambiar el nombre, o
nullsi puedes cambiarlo ya.
Request
curl --location 'https://test.fiscalapi.com/api/v4/auto-invoice/portal-name' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": {
"name": "escuela-kemper",
"assignedAt": "2026-10-01T09:15:00.000",
"nextChangeAllowedAt": "2026-10-31T09:15:00.000"
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Consultar disponibilidad del nombre
Este endpoint indica si puedes usar un nombre de portal. Un nombre inválido, reservado o de otra cuenta no es un error: responde available en false con su razón. Un nombre que ya es tuyo, vigente o anterior, está disponible. Solo el owner lo usa y exige Auto CFDI en tu suscripción.
Query parameters
- Name
name- Type
- string
- required
- Description
Nombre que quieres consultar.
Respuesta
- Name
name- Type
- string?
- Description
Nombre normalizado, el que se guardaría.
- Name
available- Type
- boolean?
- Description
truesi puedes usar el nombre.
- Name
reason- Type
- string?
- expandible
- Description
Por qué no está disponible, o
nullsi lo está.- Type
- enum:
- Values
- "invalidFormat""reserved""taken"
Errores
| Estado | Cuándo ocurre | Mensaje |
|---|---|---|
| 403 | No eres el owner. | No tienes permiso para administrar la configuración de Auto CFDI. |
| 403 | Tu suscripción no incluye Auto CFDI. Ver Permisos y suscripción. | Para administrar la configuración de Auto CFDI tu suscripción debe incluir: Auto CFDI. |
Request
curl --location 'https://test.fiscalapi.com/api/v4/auto-invoice/portal-names/availability?name=escuela-kemper' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": {
"name": "escuela-kemper",
"available": true,
"reason": null
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Cambiar nombre del portal
Este endpoint asigna el nombre de tu portal. El nombre anterior queda reservado para tu cuenta y redirige al nuevo. Solo el owner lo usa y exige Auto CFDI en tu suscripción.
Modelo
- Name
name- Type
- string
- required
- Description
Nuevo nombre del portal. Ver las reglas en Nombre del portal.
Errores
En el mensaje del cambio anticipado, <fecha> es el día, en hora de México, desde el que puedes volver a cambiarlo.
| Estado | Cuándo ocurre | Mensaje |
|---|---|---|
| 400 | El nombre no cumple el formato. Llega como falla de validación en Name. | El nombre debe tener de 3 a 40 caracteres (minúsculas, números y guiones), empezar con letra y no llevar "--" ni terminar en guion. |
| 400 | El nombre está reservado. Llega como falla de validación en Name. | Ese nombre está reservado. Elige otro. |
| 400 | No han pasado 30 días desde el último cambio. | Solo puedes cambiar el nombre una vez cada 30 días. Próximo cambio disponible: <fecha>. |
| 403 | No eres el owner. | No tienes permiso para administrar la configuración de Auto CFDI. |
| 403 | Tu suscripción no incluye Auto CFDI. Ver Permisos y suscripción. | Para administrar la configuración de Auto CFDI tu suscripción debe incluir: Auto CFDI. |
| 409 | Otra cuenta tiene el nombre. | Ese nombre ya está en uso. Elige otro. |
| 409 | Hay otro cambio del nombre en curso. Repite la solicitud. | Hay otro cambio del nombre del portal en curso. Intenta de nuevo en unos segundos. |
Request
curl --location --request PUT 'https://test.fiscalapi.com/api/v4/auto-invoice/portal-name' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api_key>' \
--data-raw '{
"name": "escuela-kemper"
}'
Response
{
"data": {
"name": "escuela-kemper",
"assignedAt": "2026-10-01T09:15:00.000",
"nextChangeAllowedAt": "2026-10-31T09:15:00.000"
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}
Obtener reporte de consumo
Este endpoint devuelve el consumo de Auto CFDI de un periodo en dos bloques: los tickets pagados en el periodo por persona emisora y estado, y los créditos de ticket que consumió cada persona que registró tickets. Son bloques distintos porque quien registra el ticket puede no ser su emisor. No exige Auto CFDI en tu suscripción.
Query parameters
- Name
from- Type
- string
- required
- Description
Primer día del periodo, incluido, como fecha civil de México con el formato YYYY-MM-DD.
- Name
to- Type
- string
- required
- Description
Último día del periodo, incluido, con el mismo formato. El periodo dura como máximo 366 días.
- Name
personId- Type
- string?
- Description
ID de una persona de tu cuenta: el reporte solo trae sus tickets como emisora y sus créditos como quien los registró.
Respuesta
- Name
from- Type
- string?
- Description
Primer día del periodo.
- Name
to- Type
- string?
- Description
Último día del periodo.
- Name
issuers- Type
- array of objects?
Una fila por persona emisora con tickets pagados en el periodo, ordenadas por RFC. Los cinco contadores de estado suman
ingested.- Name
personId- Type
- string?
- Description
ID de la persona emisora.
- Name
tin- Type
- string?
- Description
RFC de la persona emisora.
- Name
legalName- Type
- string?
- Description
Razón social de la persona emisora.
- Name
ingested- Type
- integer?
- Description
Tickets pagados en el periodo.
- Name
pending- Type
- integer?
- Description
Tickets que esperan autofactura o factura global.
- Name
inProgress- Type
- integer?
- Description
Tickets que se están timbrando, en
invoicingoglobalizing.
- Name
invoiced- Type
- integer?
- Description
Tickets autofacturados.
- Name
globalized- Type
- integer?
- Description
Tickets en una factura global.
- Name
cancelled- Type
- integer?
- Description
Tickets cancelados.
- Name
payers- Type
- array of objects?
Una fila por persona que consumió créditos de ticket en el periodo, ordenadas por RFC.
- Name
personId- Type
- string?
- Description
ID de la persona que registró los tickets.
- Name
tin- Type
- string?
- Description
RFC de la persona, si lo tiene.
- Name
legalName- Type
- string?
- Description
Razón social de la persona.
- Name
ticketCreditsConsumed- Type
- integer?
- Description
Créditos de ticket consumidos en el periodo.
- Name
totals- Type
- object?
- Description
Suma de los contadores de
issuersy deticketCreditsConsumeddepayers.
Errores
Las fallas de validación llegan en ValidationFailure con el parámetro. En los mensajes, <id> es el id enviado.
| Estado | Cuándo ocurre | Mensaje |
|---|---|---|
| 400 | Falta from. | 'from' es obligatorio: una fecha YYYY-MM-DD de México. |
| 400 | Falta to. | 'to' es obligatorio: una fecha YYYY-MM-DD de México. |
| 400 | La fecha de from no tiene el formato YYYY-MM-DD. | 'from' debe ser una fecha YYYY-MM-DD. |
| 400 | La fecha de to no tiene el formato YYYY-MM-DD. | 'to' debe ser una fecha YYYY-MM-DD. |
| 400 | El inicio del periodo es posterior al fin. | 'from' no puede ser posterior a 'to'. |
| 400 | El periodo pasa de 366 días. | El periodo de 'from' a 'to' no puede pasar de 366 días. |
| 404 | La persona no existe en tu cuenta. | No such resource for the given Id: <id> |
Request
curl --location 'https://test.fiscalapi.com/api/v4/auto-invoice/reports/consumption?from=2026-10-01&to=2026-10-31' \
--header 'X-TENANT-KEY: <tenant_key>' \
--header 'X-TIME-ZONE: America/Mexico_City' \
--header 'X-API-KEY: <api_key>'
Response
{
"data": {
"from": "2026-10-01",
"to": "2026-10-31",
"issuers": [
{
"personId": "4b1c2d3e-5f60-4a7b-8c9d-0e1f2a3b4c5d",
"tin": "EKU9003173C9",
"legalName": "ESCUELA KEMPER URGATE",
"ingested": 120,
"pending": 30,
"inProgress": 0,
"invoiced": 45,
"globalized": 40,
"cancelled": 5
}
],
"payers": [
{
"personId": "4b1c2d3e-5f60-4a7b-8c9d-0e1f2a3b4c5d",
"tin": "EKU9003173C9",
"legalName": "ESCUELA KEMPER URGATE",
"ticketCreditsConsumed": 120
}
],
"totals": {
"ingested": 120,
"pending": 30,
"inProgress": 0,
"invoiced": 45,
"globalized": 40,
"cancelled": 5,
"ticketCreditsConsumed": 120
}
},
"succeeded": true,
"message": "",
"details": "",
"httpStatusCode": 200
}