Ir al contenido

Estados y archivos

Un comprobante tiene tres estados separados: el interno (status), el fiscal (sunat_status) y el de entrega de avisos (delivery_status). Los ejemplos usan la terminal de Primeros pasos y el DOCUMENT_ID de la boleta emitida ahí.

Ventana de terminal
curl -sS -o estado.json -w '%{http_code}\n' \
-H "Authorization: Bearer $BOLETURA_API_KEY" \
"$BOLETURA_BASE_URL/v1/documents/${DOCUMENT_ID:?}"
python -m json.tool estado.json

Espera 200. Una factura se envía a SUNAT enseguida; la boleta espera su resumen diario. En test entra en la siguiente corrida del planificador, que pasa cada 10 minutos. En live espera el siguiente corte: por defecto 13:00, 19:00 y 23:30 de Lima, y el operador de la cuenta puede configurar otros; el resumen puede salir hasta 10 minutos después del corte, y varias horas en pending antes del siguiente corte no implican un rechazo. No programes contra esos tiempos: una nota de crédito o una baja se rechazan mientras la boleta no esté aceptada, y en live eso puede durar horas aunque en test no lo notes. Espera el estado o el webhook. Tu sistema no construye ni envía resúmenes, ni reintenta el envío a SUNAT.

Campo Qué vigilar
status issued, void_requested, voided, expired: ciclo interno
sunat_status pending o submitted: seguir consultando; accepted: aceptado; accepted_with_observations: revisar sunat.notes; rejected: corregir con un documento nuevo; deadline_missed: intervención de Boletura
delivery_status none, pending, delivered, failed: entrega de los avisos del último evento; no mide la aceptación fiscal ni la impresión del PDF
sunat.reconciliation_required Resultado fiscal desconocido: consultar y conciliar, sin reenviar ni reemitir
sunat.deadline_at Fin del plazo de envío, en UTC; no es el plazo de llegada del CDR
sunat_status Qué significa Qué hacer
pending Emitido con XML firmado y PDF; pendiente de informar y validar Se puede entregar al cliente, aclarando que está pendiente de validación
submitted Enviado o conciliando un resultado desconocido Consultar el estado; no reemitir mientras el resultado sea incierto
accepted Aceptado Guardar links.cdr si se necesita; puede ser nulo en una boleta confirmada con una revisión manual
accepted_with_observations Aceptado con observaciones (sunat.notes) Revisar las observaciones; normalmente, datos del cliente
rejected Rechazado; el número no se reutiliza Leer sunat.description, corregir los datos y emitir un documento nuevo con replaces_document_id
deadline_missed Se confirmó que no hubo un envío válido en plazo Escribir a soporte; no pedir la baja ni emitir otro documento sin resolver el caso

XML firmado, PDF A4 y PDF para rollo de 80 mm:

Ventana de terminal
curl -sS -o comprobante.xml -w '%{http_code}\n' \
-H "Authorization: Bearer $BOLETURA_API_KEY" \
"$BOLETURA_BASE_URL/v1/documents/$DOCUMENT_ID/xml"
curl -sS -o comprobante-a4.pdf -w '%{http_code}\n' \
-H "Authorization: Bearer $BOLETURA_API_KEY" \
"$BOLETURA_BASE_URL/v1/documents/$DOCUMENT_ID/pdf"
curl -sS -o comprobante-80mm.pdf -w '%{http_code}\n' \
-H "Authorization: Bearer $BOLETURA_API_KEY" \
"$BOLETURA_BASE_URL/v1/documents/$DOCUMENT_ID/pdf?format=ticket"

Los tres responden 200. Los PDF de test llevan la marca «PRUEBA – SIN VALOR FISCAL». Comprueba el código HTTP antes de abrir el archivo: con un error contiene JSON, aunque le hayas dado la extensión .pdf. Si falla la descarga, reintenta la del mismo UUID.

Si un documento es válido lo dice sunat_status (accepted o accepted_with_observations), no links.cdr: una boleta que perdió la respuesta de su resumen y se confirmó en SUNAT con una revisión manual queda accepted sin CDR. Cuando links.cdr deje de ser nulo:

Ventana de terminal
curl -sS -o cdr.zip -w '%{http_code}\n' \
-H "Authorization: Bearer $BOLETURA_API_KEY" \
"$BOLETURA_BASE_URL/v1/documents/$DOCUMENT_ID/cdr"

Devuelve 200 con un ZIP, también si SUNAT rechazó el documento. Antes de la respuesta fiscal devuelve 409 cdr_not_available, y también en una boleta accepted que se confirmó en la consulta de validez de SUNAT porque su resumen perdió la respuesta: esa boleta es válida y no tiene CDR. El CDR de una boleta es el del resumen que la informó y puede ser compartido por varias boletas. Los links del documento son rutas relativas a la URL base, requieren la misma clave y no son enlaces públicos para enviar a un cliente. La consulta pública de app.boletura.com/consulta solo muestra documentos live.

Para que tu cliente reciba el PDF A4 y el XML sin que los reenvíes, hay dos caminos:

  • Automático: un owner o admin activa «Enviar los comprobantes por correo al cliente» en Empresas → General de cada empresa, y cada comprobante con customer.email sale solo: la boleta al emitirse y la factura cuando SUNAT la acepta. Una factura rechazada no sale. No lo actives si tu sistema ya envía el comprobante: el cliente lo recibiría dos veces.
  • A pedido: POST /v1/documents/{id}/email, con el scope documents:write. Sin cuerpo va a customer.email; con { "email": "…" }, a otra dirección.
Ventana de terminal
curl -sS -w '%{http_code}\n' -X POST \
-H "Authorization: Bearer $BOLETURA_API_KEY" -H 'Content-Type: application/json' \
-d '{"email":"compras@cliente.example"}' \
"$BOLETURA_BASE_URL/v1/documents/$DOCUMENT_ID/email"

Responde 202 con el envío en pending; sale en segundos, a nombre de la empresa («Empresa S.A.C. vía Boletura») y con su correo como respuesta, si lo tiene. Sigue la regla del automático: una factura se envía cuando SUNAT la acepta, y antes responde 409 document_email_document_not_accepted; uno rechazado, anulado o fuera de plazo no se envía (409 document_email_document_invalid). Hasta 5 envíos a pedido por documento y día (429 document_email_limit_reached). No lleva Idempotency-Key, así que un reintento puede enviarlo otra vez. En test el asunto empieza con [PRUEBA] y cada envío cuenta para el tope de 20 correos diarios de la cuenta. Los envíos de cada comprobante se ven en su detalle del back office.