Entrega por correo
Una factura no queda expedida hasta que llega al comprador. Cuando el documento queda accepted (o se declara la contingencia de la DIAN, que se entrega sin validación previa), foliios arma el paquete y lo envía por correo a los correos del comprador que están en el documento. Las normas están en el marco normativo, con revisión pendiente de Armando.
Qué recibe el comprador
Sección titulada «Qué recibe el comprador»Un correo con un ZIP que contiene:
- el contenedor firmado (AttachedDocument): el XML del documento y la respuesta de la DIAN, y
- la representación gráfica en PDF.
La entrega no depende de la validación de la DIAN para la contingencia: en ese caso se envía el tipo 04 y, cuando la DIAN lo valida, se entrega otra vez el contenedor validado. En el sandbox no sale ningún correo: va al buzón de pruebas del portal (HTML, XML, PDF y ZIP), y el PDF lleva la marca de agua «SANDBOX · SIN VALIDEZ FISCAL».
El estado de la entrega
Sección titulada «El estado de la entrega»delivery en el documento es un estado aparte del de la DIAN (null mientras no empieza):
"delivery": { "status": "sent", "trigger": "accepted", "recipients": ["facturas@andina.example"], "failure_code": null, "reason": null, "next_attempt_at": null, "attempts": [{"trigger": "accepted", "number": 1, "outcome": "sent"}]}delivery.status |
Significa |
|---|---|
pending |
Espera su envío o el siguiente reintento (next_attempt_at). |
sent |
El servicio de correo aceptó el mensaje. No garantiza que el comprador lo haya leído. |
failed |
No se enviará sin intervención; failure_code dice por qué. |
not_applicable |
El documento no tiene correo del comprador (por ejemplo, consumidor final). Se entrega por otro medio: el PDF impreso. La emisión no falla por esto. |
Principales failure_code: mailer_rejected, retries_exhausted (seis envíos con fallo temporal), outcome_unknown (el envío se interrumpió y no se reenvía solo), recipient_bounced, recipient_suppressed, invalid_recipient_address, artifacts_unavailable, certificate_unavailable, issuer_not_configured, rendering_failed y package_too_large. Los fallos temporales se reintentan solos a 1 min, 5 min, 15 min, 1 h y 3 h.
El reason es un mensaje fijo en español por clase de fallo, sin detalles internos.
Reenviar
Sección titulada «Reenviar»curl -s -X POST "https://api.foliios.com/v1/companies/$FOLIIOS_COMPANY_ID/documents/$DOCUMENT_ID/deliver" \ -H "Authorization: Bearer $FOLIIOS_API_KEY" -H "Content-Type: application/json" \ -d '{"email": "contabilidad@cliente.example"}'El cuerpo es opcional: sin él, va a los correos del comprador. Requiere documents:write. Responde 202 con delivery.status en pending; el envío es asíncrono.
| Respuesta | Por qué |
|---|---|
409 document_not_deliverable |
El documento no está accepted ni emitido en contingencia. |
422 delivery_recipient_required |
No hay correo del comprador y no enviaste email. |
409 recipient_suppressed |
La dirección (o todas las del comprador) está suprimida. No se encola nada. |
409 concurrent_modification |
Se está enviando en ese momento. |
No es idempotente: cada llamada es un correo más.
from foliios_inicio import EMPRESA, llamar
estado, documento, _ = llamar( "POST", f"/v1/companies/{EMPRESA}/documents/{documento_id}/deliver", {"email": "contabilidad@cliente.example"},)print(estado, documento["delivery"]["status"]) # 202 pendingDescargar lo que recibió el comprador
Sección titulada «Descargar lo que recibió el comprador»# PDF (inline)curl -s -H "Authorization: Bearer $FOLIIOS_API_KEY" -o factura.pdf \ "https://api.foliios.com/v1/companies/$FOLIIOS_COMPANY_ID/documents/$DOCUMENT_ID/pdf"
# El ZIP entregado; con ?format=xml, el contenedor firmado solocurl -s -H "Authorization: Bearer $FOLIIOS_API_KEY" -o entrega.zip \ "https://api.foliios.com/v1/companies/$FOLIIOS_COMPANY_ID/documents/$DOCUMENT_ID/attached-document"Los dos se generan con la entrega: antes responden 409 pdf_not_available o 409 attached_document_not_available. Un documento sin correo del comprador también los tiene: sirve para imprimir.
Rebotes y quejas
Sección titulada «Rebotes y quejas»Un rebote permanente falla la entrega con recipient_bounced y suprime la dirección para esa empresa; una queja solo la registra. Con varios destinatarios, la entrega solo falla si todos tienen un fallo definitivo; si solo algunos, sigue sent y el intento lleva una nota en attempts[].feedback.
GET /v1/companies/{company_id}/suppressions (permiso documents:read) lista las direcciones suprimidas de la empresa, con email, reason (bounce_permanent o complaint), suppressed_at y document_id. Es un registro por empresa: no reemplaza la lista de supresión del servicio de correo, así que una dirección puede seguir bloqueada aunque tu lista esté vacía. Quitar una dirección bloqueada lo hace soporte, no la API.
Formato de los correos
Sección titulada «Formato de los correos»Cada correo debe tener una forma válida (parte local sin comas, punto y coma, paréntesis ni comillas; dominio de dos o más partes, sin direcciones IP). Un dominio con tildes o ñ va en punycode (ventas@xn--espaa-rta.co). Si no, la API responde 422 invalid_email. Para el comprador facturador electrónico, el correo debe ser el que registró en la DIAN o el medio que él señaló.
Webhooks de entrega
Sección titulada «Webhooks de entrega»document.delivered, document.delivery_failed y document.delivery_not_applicable, con data.delivery. Su forma está en eventos de webhook. Para probarlos sin esperar, dispara un evento de prueba (ver webhooks) o provoca el fallo con los escenarios delivery_rejected y delivery_transient (escenarios).