Ir al contenido

Consultar y descargar

Emitir es asíncrono: el 201 solo dice QUEUED. El número, el CUFE, el XML y el PDF llegan después. Esta página es la otra mitad del trabajo — cómo ver en qué quedó cada documento y cómo bajar sus archivos.

GET/v1/documents

Devuelve los documentos de tu emisor, del más reciente al más viejo (orden por created_at descendente). Sin filtros, trae los últimos 20.

Campo Tipo Obligatorio Descripción
status string No Deja solo los de ese estado. Uno de DRAFT, QUEUED, SIGNED, SENT, VALIDATED, REJECTED, CONTINGENCY, FAILED, DISCARDED. En mayúsculas y exacto: validated no vale.
type string No Tipo DIAN: 01 factura de venta, 91 nota crédito, 92 nota débito, 05 documento soporte, 20 documento equivalente POS.
from string No Fecha de emisión desde, YYYY-MM-DD. Inclusive.
to string No Fecha de emisión hasta, YYYY-MM-DD. Inclusive.
page entero No Página. Por defecto 1. Un valor menor se sube a 1.
limit entero No Documentos por página. Por defecto 20, máximo 100.

Los seis se validan antes de tocar la base. Un estado o un tipo que no esté en la lista devuelve 422 diciéndote cuáles valen, y una fecha o un número mal escritos, 422 nombrando el parámetro. Mandar la clave vacía —?status=— es «sin filtro», no un error: es lo que manda un selector puesto en «Todos».

Pedir limit=500 no falla: te devuelve 100. Mira pagination.pages antes de dar por hecho que todo cupo en una llamada.

Ventana de terminal
curl -G https://sandbox.facturacion.misofk.com/v1/documents \
-H "Authorization: Bearer $TOKEN" \
-d status=VALIDATED \
-d type=01 \
-d from=2026-09-01 \
-d to=2026-09-30 \
-d limit=50
{
"data": [
{
"id": "b1f3a7d0-9c42-4e18-8a5b-6d0e2f4c9a11",
"type": "01",
"reference_code": "VE-2026-000841",
"full_number": "SETP990000841",
"prefix": "SETP",
"number": "990000841",
"status": "VALIDATED",
"cufe": "8f2c1a9d...",
"qr_url": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=8f2c1a9d...",
"qr_content": "NumFac: SETP990000841\nFecFac: 2026-09-04\n...",
"issue_date": "2026-09-04",
"issue_time": "14:22:35-05:00",
"totals": {
"lineExtensionAmount": "113000.00",
"taxInclusiveAmount": "134470.00",
"payableAmount": "134470.00",
"taxTotals": { "01": { "taxableAmount": "113000.00", "taxAmount": "21470.00" } }
},
"environment": "PRODUCCION",
"email_sent_at": "2026-09-04T19:24:02.881Z",
"email_to": "facturacion@elpoblado.com.co",
"email_error": null,
"created_at": "2026-09-04T14:22:31.004Z"
}
],
"pagination": { "page": 1, "limit": 50, "total": 143, "pages": 3 }
}

Cada elemento de data tiene la misma forma que la respuesta de emisión: todos los campos del documento, incluidos items y totals recalculados por el servidor. Lo único que no viene aquí es qr_image.

Campo de pagination Descripción
page La página que se sirvió, ya normalizada.
limit Los que caben por página, ya recortado a 100.
total Documentos que cumplen los filtros, no los de esta página.
pages total dividido entre limit, redondeado hacia arriba.

GET/v1/documents/:id

:id es el UUID que devolvió la emisión, no el full_number ni el reference_code. Un id mal formado ni siquiera llega al servicio: responde 400 con Validation failed (uuid is expected).

Ventana de terminal
curl https://sandbox.facturacion.misofk.com/v1/documents/b1f3a7d0-9c42-4e18-8a5b-6d0e2f4c9a11 \
-H "Authorization: Bearer $TOKEN"

Devuelve lo mismo que el listado más un campo:

Campo Descripción
qr_image El QR ya dibujado, como data URI de un PNG de 300 px (data:image/png;base64,…). Listo para un <img src>.
Código code Cuándo
400 VALIDATION El :id no es un UUID
401 UNAUTHORIZED API key inválida o ausente
404 NOT_FOUND Documento no encontrado — no existe, o no es de tu emisor

Tres formas del mismo QR, para tres necesidades distintas:

Campo o ruta Qué es Para qué sirve
qr_content El texto exacto que se firmó y que va dentro del código. Dibujar el QR tú mismo. Codifícalo literal, sin reordenar ni recortar.
qr_url La dirección del catálogo de la DIAN. Imprimirla al lado del QR, para quien prefiera teclearla.
qr_image PNG en data URI, en el detalle del documento. Pegarlo en tu representación gráfica sin dibujar nada.
GET /v1/documents/:id/qr El mismo PNG como archivo. Cuando prefieres una URL a arrastrar un data URI.

Así se ve qr_content de la factura del ejemplo. Las etiquetas, el orden y los saltos de línea son parte del contenido:

NumFac: SETP990000841
FecFac: 2026-09-04
HorFac: 14:22:35-05:00
NitFac: 900654321
DocAdq: 901234567
ValFac: 113000.00
ValIva: 21470.00
ValOtroIm: 0.00
ValTolFac: 134470.00
CUFE: 8f2c1a9d...
https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=8f2c1a9d...

La URL es la última línea del bloque. Ahí está la relación entre los dos campos: qr_url está contenido en qr_content, y por eso codificar solo la URL parece funcionar hasta que alguien valida el documento.

qr_url apunta a catalogo-vpfe.dian.gov.co en producción y a catalogo-vpfe-hab.dian.gov.co en habilitación. El emisor decide cuál, con su environment.

GET/v1/documents/:id/qr

No devuelve JSON: devuelve el binario.

Content-Type: image/png
Content-Length: <bytes>
Cache-Control: public, max-age=31536000, immutable

PNG de 300 px, nivel de corrección M. El immutable es de verdad: el QR de un documento firmado no cambia nunca, así que puedes cachearlo sin plazo.

Código code Mensaje
404 NOT_FOUND El documento todavía no tiene QR: se genera al firmarlo
404 NOT_FOUND Documento no encontrado

GET/v1/documents/:id/xml

GET/v1/documents/:id/pdf

GET/v1/documents/:id/attached-document

GET/v1/documents/:id/application-response

Los cuatro devuelven el archivo crudo, con Content-Disposition: attachment. Ninguno viene en base64 ni envuelto en JSON: el único campo base64 de todo el API es qr_image.

Ruta Content-Type Qué es
/xml application/xml El UBL firmado. Es el documento legal.
/pdf application/pdf La representación gráfica. Dato derivado.
/attached-document application/xml El contenedor que se le entrega al adquirente.
/application-response application/xml El acuse de la DIAN.

Es el UBL 2.1 con la firma XAdES: exactamente los bytes que se le transmitieron a la DIAN. No es una copia ni una reconstrucción. Cuando alguien —una auditoría, el contador, el mismo adquirente— pide «la factura electrónica», esto es lo que pide.

Content-Type: application/xml
Content-Disposition: attachment; filename="SETP990000841.xml"

El nombre es el del archivo guardado, <full_number>.xml.

Responde 404 NOT_FOUND con El documento no tiene xml disponible mientras el documento no se haya firmado.

El papel: A4 con el logo del emisor, el detalle, los totales, el CUFE, el QR y los datos de la resolución. No tiene valor legal por sí solo; el XML lo tiene.

Content-Type: application/pdf
Content-Disposition: attachment; filename="SETP990000841.pdf"

Es el único de los cuatro que se vuelve a dibujar si falta. Si el archivo no está guardado —porque el emisor pidió send_email: false y nunca hizo falta, o porque la lectura falla— se redibuja al vuelo desde el documento firmado, con el qr_content guardado, y se guarda. Negar un PDF que se puede reconstruir en un segundo no le sirve a nadie.

Para redibujarlo hace falta el XML firmado y el estado VALIDATED. Si no los hay: 404 NOT_FOUND con El PDF se genera cuando la DIAN valida el documento.

Si el emisor subió su propio PDF (ver más abajo), esta ruta devuelve ese, no el nuestro.

/attached-document — el que se le entrega al cliente

Sección titulada «/attached-document — el que se le entrega al cliente»

Es el contenedor AttachedDocument del Anexo 1.9: un XML que envuelve, como CDATA, el documento firmado y el ApplicationResponse de la DIAN. Es lo que va dentro del ZIP del correo al adquirente, y lo que él carga en su sistema de recepción — un solo archivo que trae la factura y la prueba de que la DIAN la aceptó.

Content-Type: application/xml
Content-Disposition: attachment; filename="ad-SETP990000841.xml"

Solo existe si la DIAN devolvió ApplicationResponse. Sin eso, no hay qué envolver. Mientras tanto: 404 NOT_FOUND con El documento no tiene attached-document disponible.

La respuesta que devolvió la DIAN al validar el documento: el ApplicationResponse tal cual, sin tocar. Es la prueba de la aceptación. Sirve para archivarlo por tu cuenta y para leer el detalle de lo que la DIAN contestó, más allá del dian_status_code que ya traes en el documento.

Content-Type: application/xml
Content-Disposition: attachment; filename="application-response.xml"

Se guarda solo cuando la respuesta de la DIAN lo trae. Si no: 404 NOT_FOUND con El documento no tiene application-response disponible.

Dos rutas para lo mismo, y la segunda además cambia el PDF.

POST/v1/documents/:id/resend-email

Campo Tipo Obligatorio Descripción
email string No Destino. Si se omite, va al correo del adquirente que quedó en el documento.

Admite varios destinos separados por coma, y el formato con nombre visible. Las tres formas valen:

contabilidad@elpoblado.com.co
Contabilidad <contabilidad@elpoblado.com.co>
cliente@ejemplo.com, contador@ejemplo.com

Diez destinos como máximo. Si uno solo de la lista está mal escrito se rechaza la petición entera, con 422 y el que falla nombrado en errors[]: es preferible a mandar el documento a medias y que no te enteres.

Ventana de terminal
curl -X POST https://sandbox.facturacion.misofk.com/v1/documents/b1f3a7d0-9c42-4e18-8a5b-6d0e2f4c9a11/resend-email \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "email": "contabilidad@elpoblado.com.co" }'

Responde 201:

{ "queued": true, "email": "contabilidad@elpoblado.com.co" }

Tres efectos que conviene tener claros:

  • Si mandas un email distinto al que tenía el documento, se sobrescribe el correo del adquirente en el documento. La entrega lee de ahí, y las siguientes también.
  • Se limpia el email_error anterior.
  • Se fuerza el envío, aunque el documento se hubiera emitido con send_email: false.

Reenvío con tu propia representación gráfica

Sección titulada «Reenvío con tu propia representación gráfica»

POST/v1/documents/:id/email

Content-Type: multipart/form-data.

Campo Tipo Obligatorio Descripción
file archivo No Tu PDF. Se comprueba que empiece por %PDF.
email texto No Destino; por defecto el del adquirente.
Ventana de terminal
curl -X POST https://sandbox.facturacion.misofk.com/v1/documents/b1f3a7d0-9c42-4e18-8a5b-6d0e2f4c9a11/email \
-H "Authorization: Bearer $TOKEN" \
-F "file=@factura-con-mi-diseno.pdf" \
-F "email=contabilidad@elpoblado.com.co"

Sin file hace exactamente lo mismo que resend-email. Con file, ese PDF va en el correo y sustituye al nuestro.

Sirve para dos casos: emitiste con send_email: false y ahora quieres que lo mandemos nosotros, o solo quieres cambiar el diseño del papel.

Código code Mensaje
404 NOT_FOUND Documento no encontrado
422 VALIDATION Solo se reenvía un documento validado (actual: SENT)
422 VALIDATION El documento aún no tiene contenedor de entrega generado
422 VALIDATION Indica el correo de destino: el adquirente no tiene uno registrado
422 VALIDATION El archivo no es un PDF — solo en /email
422 VALIDATION El documento aún no tiene XML firmado — solo en /email, al subir archivo

El segundo es el que más sorprende: el correo lleva el AttachedDocument adentro, así que hasta que ese contenedor no existe no hay nada que mandar. Es el mismo 404 de /attached-document, visto desde el otro lado.

  • Errores — qué significa cada code y cuáles se reintentan
  • Webhooks — enterarte del VALIDATED sin consultar en bucle