Tirilla en un punto de venta
Un punto de venta emite la factura, espera el resultado e imprime una tirilla en papel térmico. Esta guía dice qué pedir, qué hacer con cada respuesta y qué va en la tirilla. Está pensada también para el punto de venta sin operador (una terminal de autoservicio): ahí nadie atiende un error, así que cada rama debe terminar sola.
El código de este flujo, con sus pruebas, está en la receta de punto de venta.
Cuándo usarla
Sección titulada «Cuándo usarla»- Vendes al detal y entregas la factura impresa en el momento.
- Casi todas tus ventas son a consumidor final.
- Armas tu propia tirilla (32 o 42 columnas). El PDF de foliios es tamaño carta: sirve para el correo, no para la impresora térmica.
Si solo necesitas emitir y enviar por correo, basta con emitir una factura.
El flujo recomendado
Sección titulada «El flujo recomendado»- Guarda la venta con su
Idempotency-Keyantes de llamar. Una clave por venta, derivada de la venta (por ejemploventa-1042). Si el programa se reinicia, repite la misma solicitud con la misma clave (idempotencia). - Emite con
?wait=Nexplícito.POST /v1/companies/{company_id}/documents?wait=20. Sinwaitaplica el valor por defecto del ambiente, que puede ser 0: en ese caso la respuesta es siempre202, sinprint. No dependas del valor por defecto. - Usa un tiempo de espera HTTP mayor que
wait. Conwait=20, 30 segundos. El tope dewaites 23. - Solo la primera solicitud espera. Cualquier repetición va con la misma clave, el mismo cuerpo y
?wait=0, y después se consulta conGET. - Decide por el código de la respuesta, con esta tabla.
| Respuesta | Qué pasó | Qué haces | Qué imprimes |
|---|---|---|---|
201, accepted |
La DIAN validó la factura. | Nada más. | Tirilla completa. |
201, contingency |
La DIAN no respondió y la factura se expidió en contingencia. | Nada más. | Tirilla completa, con la leyenda de contingencia. |
200, rejected o failed |
No hay factura válida. | Avisa a una persona: corregir y reenviar. | Nada que parezca una factura. |
202 |
El documento existe y sigue en proceso. | Consulta con GET la URL de Location, tras Retry-After. No emitas de nuevo. |
Lo que diga el GET; si se acaba tu plazo, comprobante provisional. |
202 con outcome_code: dian_outcome_uncertain |
La DIAN puede tener el documento. | Lo mismo que cualquier 202. Nunca otra Idempotency-Key. |
Igual que 202. |
429 con limit: sync_open |
Todos los cupos de espera de tu empresa están ocupados. No se creó nada. | Repite de inmediato con la misma clave y ?wait=0; luego consulta con GET. |
Lo que diga el GET. |
Otro 429, o 503 |
Límite de frecuencia o servicio no disponible. | Espera Retry-After y repite con la misma clave y ?wait=0. |
Si la espera no cabe en tu plazo, comprobante provisional. |
| Sin respuesta (red, tiempo agotado) | No sabes si llegó. | Repite con la misma clave y ?wait=0. |
Si sigue sin respuesta, comprobante provisional. |
400, 401, 403, 409, 422 |
La solicitud se rechazó. No hay número ni documento. | Avisa a una persona. No reintentes sin corregir. | Nada que parezca una factura. |
Un 202 y un 429 no son errores de la venta. Significan «todavía no lo sé: consulta». Con 429 no hay un id que consultar; por eso se repite el POST con la misma clave y ?wait=0, que no ocupa cupo y devuelve el documento, nuevo o ya existente.
Como árbol de decisión
Sección titulada «Como árbol de decisión»POST ?wait=20 (Idempotency-Key de la venta)├─ 201 ─ print presente ──────────────► tirilla completa│ print null ──────────────────► GET otra vez; si sigue null, provisional├─ 200 (rejected, failed) ────────────► nada; avisar a una persona├─ 202 ───────────────────────────────► GET hasta estado final o fin del plazo│ ├─ accepted / contingency ───► tirilla completa│ ├─ rejected / failed ────────► nada; avisar a una persona│ └─ fin del plazo ────────────► provisional; seguir consultando después├─ 429 sync_open ─────────────────────► POST ?wait=0, misma clave ─► como 202├─ 429 / 503 / sin respuesta ─────────► esperar; POST ?wait=0, misma clave│ └─ fin del plazo ────────────► provisional; repetir después└─ 400 / 401 / 403 / 409 / 422 ───────► nada; avisar a una persona«Fin del plazo» es el tiempo que decides que el comprador puede esperar frente a la máquina. La receta usa 45 segundos.
El comprobante provisional
Sección titulada «El comprobante provisional»Cuando el plazo se acaba sin un estado final, no hay factura que imprimir todavía. Imprime un comprobante que diga claramente que no es la factura electrónica de venta, con la referencia de tu venta y cómo pedirla después.
- No imprimas CUFE, QR ni leyenda de validación: el documento no los tiene.
- Usa tu referencia de venta, no el
numberdel documento: si la DIAN lo rechaza, ese número puede pasar a otro documento (numeración). - Deja la venta en una cola propia. Un proceso de fondo repite la misma solicitud (misma clave, mismo cuerpo,
?wait=0) o consulta conGEThasta un estado final; con webhooks no hace falta consultar en bucle. - Cuando quede
accepted, la tirilla se puede reimprimir o enviar por correo si el comprador lo dejó.
Qué entregar al comprador mientras tanto es una decisión de tu negocio. foliios solo te dice que la factura aún no existe.
Cuando no hay factura
Sección titulada «Cuando no hay factura»Con 200 (rejected, failed) o un 4xx, la venta ocurrió pero no hay factura. En un punto de venta sin operador nadie lo verá si no avisas:
- Registra la venta como pendiente de factura y alerta a una persona.
- Un
rejectedse corrige y reenvía con el mismo número. La cola de errores esGET .../documents?errors_only=true. - Un
failedsuele ser de configuración: miradian.failure_codeylinks.retry. - Un
422es un cuerpo inválido: repetirlo igual falla igual.
El bloque print
Sección titulada «El bloque print»Un documento accepted o en contingency trae print. Ejemplo de una factura validada (datos ficticios):
{ "id": "01JD3XEJEMPLO00000000000000", "environment": "live", "type": "invoice", "number": "KA1042", "status": "accepted", "issued_at": "2026-11-11T14:32:07-05:00", "validated_at": "2026-11-11T14:32:09-05:00", "customer": {"name": "consumidor final", "identification": {"type": "citizenship_card", "number": "222222222222"}}, "currency": "COP", "totals": {"line_extension_amount": "4000.00", "tax_exclusive_amount": "4000.00", "tax_inclusive_amount": "4760.00", "payable_amount": "4760.00"}, "print": { "cufe": "9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c", "qr_text": "NumFac: KA1042\nFecFac: 2026-11-11\nHorFac: 14:32:07-05:00\nNitFac: 900000001\nDocAdq: 222222222222\nValFac: 4000.00\nValIva: 760.00\nValOtroIm: 0.00\nValTolFac: 4760.00\nCUFE: 9f3c9f3c…9f3c\nhttps://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=9f3c9f3c…9f3c", "qr_url": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=9f3c9f3c…9f3c", "validated_at": "2026-11-11T14:32:09-05:00", "status_label": "Documento validado por la DIAN el 11/11/2026 a las 14:32:09", "software": { "name": "Caja Ejemplo", "manufacturer_name": "Software de Ejemplo S.A.S.", "manufacturer_id": "900000002-7", "software_id": "56f2ae4e-9812-4fad-9255-08fcfcd5ccb0" }, "numbering_authorization": { "number": "18760000001", "prefix": "KA", "from": 1, "to": 50000, "valid_from": "2026-01-01", "valid_to": "2027-12-31" } }}El documento trae más campos; aquí están los que usa la tirilla. En el ejemplo el CUFE se acorta con … dentro de qr_text y qr_url; en la respuesta real va completo.
Cuándo puedes contar con print
Sección titulada «Cuándo puedes contar con print»| Situación | print |
|---|---|
accepted o contingency |
Presente. Es el caso normal y la tirilla depende de él. |
pending, sending, dian_unavailable, rejected, failed |
Siempre null: no hay nada que imprimir. |
accepted o contingency, pero no se pudo armar |
null. Es una anomalía, no un estado: el documento se lee igual, con su status. |
Para el tercer caso: vuelve a leer con GET. Si sigue null, trata la venta como provisional y contacta a soporte. No armes la tirilla solo con number y cufe: le faltarían el QR, la leyenda y el software.
Qué garantiza frente al PDF
Sección titulada «Qué garantiza frente al PDF»print se arma con los mismos datos que la representación gráfica en PDF del documento: el mismo texto del QR, la misma leyenda y el mismo software y fabricante. El software y el fabricante quedan fijos cuando el documento se emite. Lo que tu tirilla dice con print coincide con el PDF que recibiría el comprador por correo.
print no trae todo lo que lleva el PDF. Esto lo pone tu punto de venta, porque ya lo tiene:
- Los datos del emisor: razón social, NIT, responsabilidades fiscales, dirección.
- Las líneas de la venta y la discriminación de impuestos por tarifa.
- La forma y el medio de pago.
- Si el software está registrado ante la DIAN con el NIT de un proveedor tecnológico distinto del emisor, el PDF agrega «Proveedor tecnológico: NIT …».
printno trae ese NIT. - En habilitación (
environment: test) el PDF dice «Habilitación DIAN: sin efecto fiscal».printno trae esa leyenda: miraenvironment.
Contenido de la tirilla
Sección titulada «Contenido de la tirilla»Estos son los datos de la tirilla del ejemplo de abajo y de dónde sale cada uno.
| Dato | De dónde sale |
|---|---|
| La denominación «factura electrónica de venta». | Texto fijo, según type. |
| Nombre o razón social y NIT del vendedor. | Tu configuración. La respuesta no lo trae. |
| Identificación del adquirente, o consumidor final. | customer.name y customer.identification.number. |
| Número consecutivo y la autorización de numeración: número, rango y vigencia. | number y print.numbering_authorization. El prefix puede venir vacío. |
| Fecha y hora de generación. | issued_at (hora de Colombia). |
| Cantidad y descripción de lo vendido. | Tu venta: las lines que enviaste. |
| Valor total de la venta. | totals.payable_amount. |
| Forma de pago. | Tu venta: payment.form (por defecto, de contado). |
| Medio de pago. | Tu venta: payment.means (por defecto, efectivo). |
| Calidad de retenedor, autorretenedor, gran contribuyente o régimen simple. | Tu configuración: las responsabilidades fiscales del emisor. |
| Discriminación del IVA y de los demás impuestos, con su tarifa. | Tu venta: los taxes de cada línea. totals da la base (tax_exclusive_amount) y el total con impuestos (tax_inclusive_amount). |
| El CUFE. | print.cufe. |
| La dirección de internet de la DIAN donde se consulta la factura, contenida en el QR. | print.qr_text en el QR; print.qr_url es esa dirección. |
| Nombre y NIT del fabricante del software y nombre del software. | print.software.name, manufacturer_name y manufacturer_id. |
Imprime también la leyenda de validación: print.status_label ya la trae con su fecha y hora, y es lo que el PDF muestra.
Detalles que conviene respetar:
manufacturer_idpuede sernull. La clave está siempre. Si esnull, imprime el fabricante sin NIT, como hace el PDF: «Software: … · Fabricante: …».software_idno hace falta en la tirilla. Es el identificador que la DIAN asignó al software; el PDF tampoco lo imprime.- Las notas (
credit_note,debit_note) no traennumbering_authorizationy su código es un CUDE. - Fuera de producción, dilo en la tirilla. En el sandbox
status_labelyqr_textya dicen que el documento es simulado; en habilitación agrega tu propia leyenda «sin validez fiscal».
Ejemplo de tirilla (42 columnas)
Sección titulada «Ejemplo de tirilla (42 columnas)» FACTURA ELECTRÓNICA DE VENTA Tienda de Ejemplo S.A.S. NIT 900000001-9 Responsable de IVA Calle 1 # 2-3, Ciudad Ejemplo------------------------------------------No. KA1042Generación 2026-11-11 14:32:07Adquirente: consumidor final 222222222222------------------------------------------1 x Cuaderno argollado 4000.00------------------------------------------IVA 19% base 4000.00 760.00Subtotal 4000.00TOTAL COP 4760.00Pago: Contado · Efectivo
[ código QR ]
Documento validado por la DIAN el11/11/2026 a las 14:32:09CUFE: 9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3c9f3cConsulte en catalogo-vpfe.dian.gov.coAutorización de numeración DIAN18760000001, prefijo KA del 1 al 50000,vigente del 2026-01-01 al 2027-12-31Software: Caja Ejemplo · Fabricante:Software de Ejemplo S.A.S., NIT900000002-7En 32 columnas es igual, con más saltos de línea. Parte el CUFE en varias líneas: son 96 caracteres.
El código QR
Sección titulada «El código QR»- Codifica
print.qr_texttal cual, con sus saltos de línea. No lo armes tú ni codifiques solo la URL. Es el mismo texto del QR del PDF: número, fecha y hora, NIT del emisor, documento del adquirente, valores, el CUFE y, al final, la URL de consulta. print.qr_urles la última línea de ese texto: la página de consulta de la DIAN para ese CUFE. Úsala para un enlace o para imprimir el dominio junto al QR. La cámara de muchos teléfonos lee un QR de varias líneas pero no lo abre como enlace; por eso conviene la línea «Consulte en catalogo-vpfe.dian.gov.co» y el CUFE impreso.- Tamaño.
qr_textes largo: elige un tamaño de módulo que tu impresora resuelva bien y prueba la lectura con un teléfono. - En el sandbox
qr_textsolo trae el aviso de documento simulado y el código, yqr_urlapunta al catálogo de habilitación, donde ese documento no existe.
Consumidor final y correo
Sección titulada «Consumidor final y correo»- Omite
customery la factura se emite al consumidor final de la DIAN (222222222222). No pidas datos al comprador para esto. - Sin correo no se envía nada. La entrega queda
delivery.status: not_applicabley la emisión no falla. El comprador recibe la tirilla impresa. - El correo es opcional. La emisión no lo exige.
- Si el comprador deja un correo, cuando la factura quede
acceptedo encontingencyenvíala conPOST .../documents/{document_id}/delivery{"email": "..."}(reenviar). No es idempotente: cada llamada es un correo más. - Si pide la factura a su nombre, envía
customercon suidentification(yemailssi lo da) al emitir (emitir una factura).
Contingencia
Sección titulada «Contingencia»Si la DIAN no responde y se agotan los reintentos dentro de tu espera, la respuesta es 201 con status: contingency. Es una factura expedida sin validación previa (tipo 04), no un error (contingencia).
- Imprime la tirilla completa.
print.validated_atesnullyprint.status_labeldice «Expedida en contingencia DIAN, sin validación previa». Imprime esa leyenda tal cual; no escribas «validado por la DIAN». - El CUFE y el QR ya son los definitivos. foliios transmite después ese mismo documento firmado, con el mismo CUFE, hasta que la DIAN lo acepte.
- Tú no haces nada más. No reenvíes ni emitas de nuevo. Cuando pase a
accepted,printtraerávalidated_aty la leyenda de validación; el comprador no necesita otra tirilla. - foliios no adelanta la contingencia para cumplir tu espera. Si los reintentos duran más que
wait, recibes202y la contingencia llega por elGETo el webhook.
Si lo que falla es tu conexión o tu sistema y no puedes llegar a foliios, es otro caso: la contingencia del facturador (factura de papel). Cómo opera ahí un punto de venta sin operador es una decisión de tu negocio.
Límites
Sección titulada «Límites»- Cupo de esperas. Cada empresa tiene 5 emisiones síncronas abiertas a la vez por ambiente (2 en el sandbox). Cada solicitud que espera ocupa una mientras espera (límites).
- Con el cupo lleno, la siguiente responde
429 concurrency_limitedconlimit: sync_openyRetry-After(hasta 25 segundos), sin crear nada. No esperes ese tiempo frente al comprador: repite con?wait=0. - Una repetición que espera también ocupa cupo. Por eso las repeticiones van con
?wait=0. - Si tienes más de 5 puntos de venta de una misma empresa que pueden vender a la vez, pídele a foliios que ajuste el cupo para tu empresa. Con 5 exactos no hay margen.
- Las consultas cuentan como lecturas (300 por minuto por empresa). Respeta
Retry-Afterentre consultas.
Reimpresión
Sección titulada «Reimpresión»GET /v1/companies/{company_id}/documents/{document_id} devuelve el mismo print cada vez: mismo CUFE, mismo QR, mismo software y fabricante, aunque tu empresa cambie después su configuración. Guarda el id del documento con la venta y reimprime desde ahí.
Solo cambia una cosa: un documento que estaba en contingencia y ya fue validado trae validated_at y la leyenda de validación en lugar de la de contingencia.
Lista de comprobación
Sección titulada «Lista de comprobación»- La
Idempotency-Keysale de la venta y se guarda antes del primerPOST. - El
POSTlleva?wait=Nexplícito y el cliente HTTP espera más queN. - Las repeticiones usan la misma clave, el mismo cuerpo y
?wait=0. -
202y429terminan en una consulta, no en un error de venta ni en otra clave. -
dian_outcome_uncertainnunca genera una clave nueva. -
200y4xxno imprimen nada que parezca una factura y avisan a una persona. - Hay un comprobante provisional, con la leyenda «no es la factura», y una cola que sigue la venta hasta un estado final.
- La tirilla toma de
printel CUFE, el QR (qr_texttal cual), la leyenda, la autorización y el software, y toleramanufacturer_id: null. - La tirilla lleva los datos del emisor, las líneas, los impuestos y el pago que pone tu sistema.
- La contingencia imprime su leyenda y no dice «validado».
- Un
print: nullen un documento aceptado se vuelve a leer y, si persiste, se trata como provisional. - El QR impreso se lee con un teléfono.
- Probaste en el sandbox los escenarios
dian_unavailabley un rechazo (escenarios). - El contenido de la tirilla lo revisó tu asesor.