Entrega por correo
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.
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». En habilitación (sk_test_), por defecto, tampoco sale ningún correo: cada uno se guarda en el buzón de habilitación de la empresa, la entrega queda sent y el intento dice destination: inbox (el correo al comprador en habilitación). La excepción es el tope diario de correos reales que foliios habilita a pedido para una empresa: esos correos sí se envían, con [PRUEBA] en el asunto y destination: email. En producción (sk_live_) el correo llega siempre al comprador, con destination: email.
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 (el destinatario marcó el correo como spam) registra la dirección y emite el evento document.delivery_complained; la entrega no cambia de estado. 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.
Límites conocidos
Sección titulada «Límites conocidos»- No hay reintento tras un rebote temporal. Los reintentos automáticos son para cuando el servicio de correo no acepta el mensaje. Si lo aceptó y después el buzón del comprador lo rebota de forma temporal (buzón lleno, servidor caído), la entrega sigue
senty el intento lleva la nota enattempts[].feedback(bounce_transient); foliios no programa otro envío, porque el servicio de correo ya reintentó antes de reportarlo. Un rebote temporal no suprime la dirección ni cuenta para el aviso de rebotes. Si el comprador no recibió el documento, reenvíalo. - No hay seguimiento de apertura.
sentdice que el servicio de correo aceptó el mensaje, no que el comprador lo abrió. El correo no lleva píxeles ni enlaces de seguimiento, y no hay evento de apertura ni de clic. - El historial guarda 50 intentos.
attemptstrae los últimos 50 envíos del documento; los más viejos se descartan. - Un fallo del contador de reenvíos deja pasar el reenvío. En producción y en habilitación los reenvíos tienen tope: 10 por minuto por empresa y 5 por documento en 24 horas; al superarlo,
429 rate_limitedconRetry-After. Si el contador por minuto falla de nuestro lado, el reenvío se acepta en vez de rechazarse. El tope por documento no depende de ese contador.
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. document.delivery_complained trae data.complaint.complained_at (cuándo se reportó la queja) y no trae data.delivery ni la dirección: consúltala en la lista de direcciones suprimidas. Llega una vez por queja y documento. 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).