Manual de integración
API de extracción de documentos electrónicos DIAN
Cómo consultar de forma masiva las facturas de compra y de venta registradas en el catálogo de la DIAN, y descargar sus XML desde su propio sistema.
Qué hace este servicio
El servicio consulta el catálogo de la DIAN y devuelve los documentos electrónicos de un rango de fechas, con toda su información estructurada y, si se solicita, el XML original firmado de cada documento.
Se resuelve en dos etapas, que la API encadena automáticamente:
- Listado. Obtiene del catálogo los CUFE de todos los documentos del rango, con su emisor, folio, fecha, estado y valor.
- Consulta. Por cada CUFE pregunta a la DIAN, firmando con el certificado digital, y devuelve el XML original del documento.
La información proviene directamente de la DIAN en cada consulta. El servicio no mantiene una copia de los documentos: actúa como pasarela, no como repositorio. Vea la sección Almacenamiento.
Antes de empezar
Para consumir la API necesita tener a mano lo siguiente:
| Elemento | Para qué sirve | Quién lo entrega |
|---|---|---|
| URL base | Dirección del servicio | Ágil Factura |
API KeyX-Api-Key | Autenticar los endpoints de listado y de XML por CUFE | Ágil Factura |
Token de empresaAuthorization: Bearer | Autenticar el flujo completo usando el certificado ya configurado | Ágil Factura |
| Enlace AuthToken de la DIAN | Autorizar la consulta del catálogo. Cambia en cada extracción | La DIAN, por correo |
Certificado .p12 y su contraseña | Solo si usará el endpoint de XML por CUFE enviando el certificado | Su entidad certificadora |
La API Key y el token de empresa son credenciales: consúmalas desde su servidor, nunca desde el navegador ni desde una aplicación móvil, y no las publique en repositorios. Si sospecha que se expusieron, solicite su rotación.
El token de la DIAN
Es el punto que más dudas genera, así que conviene entenderlo bien. La DIAN envía por correo un enlace de autorización con esta forma:
https://catalogo-vpfe.dian.gov.co/User/AuthToken?pk=10910094|53031455&rk=901234567&token=6b84e2c2-9530-4e02-8bc0-647da438d804
Ese enlace completo es lo que se envía en el campo url de cada petición.
Tres reglas que debe respetar
| Regla | Detalle |
|---|---|
| Caduca | Tiene vigencia limitada. Genere uno nuevo justo antes de cada extracción; no lo guarde para reutilizarlo al día siguiente. |
| Debe ser del mismo ambiente | Un token de habilitación no sirve para consultar documentos de producción, y viceversa. |
| Va completo | Cópielo íntegro, incluidos pk, rk y token. Si recorta algún parámetro, la consulta falla. |
El enlace de la DIAN contiene una barra vertical en el parámetro pk, que no es
un carácter válido en una URL. El servicio la codifica automáticamente, así que puede pegar
el enlace tal como lo recibió. Si su cliente HTTP valida URLs por su cuenta, envíela
como %7C.
Autenticación
Hay dos formas, según el endpoint que use.
A · API Key para volumen
X-Api-Key: <api_key>
Es la que usan los dos endpoints del flujo principal. Una sola clave sirve para todas las empresas que usted maneje: el certificado de cada una viaja dentro de la petición, así que no hay nada que registrar previamente.
Como el certificado va en el cuerpo, use siempre HTTPS y consuma la API desde su servidor, nunca desde el navegador.
B · Token de empresa
Authorization: Bearer <token_de_empresa>
Alternativa para los endpoints de extracción completa. El servicio firma con el certificado que la empresa ya tiene configurado, de modo que usted no lo envía — pero requiere dar de alta cada empresa con su certificado, lo que no resulta práctico cuando son muchas.
Compras y ventas
El campo tipo determina qué documentos se extraen:
| Valor | Qué trae | Consideraciones |
|---|---|---|
Received |
Compras — documentos que le emitieron a su empresa | Se valida que su empresa sea el adquiriente. Son los únicos sobre los que pueden registrarse eventos RADIAN. |
Sent |
Ventas — documentos que su empresa emitió | Solo para consulta y reportes. No aplican eventos RADIAN. |
Para obtener ambos debe hacer dos extracciones separadas, una por cada valor. El resto de los parámetros es idéntico.
El listado incluye todo lo que la DIAN registre en el rango: facturas electrónicas, notas
crédito y débito, documentos equivalentes POS y títulos valor. Filtre por el campo
tipoDoc si solo le interesan algunos.
Endpoints
Para extraer XML de forma masiva bastan los dos primeros. Ambos usan la misma API Key y no requieren registrar ninguna empresa en el servicio. Los demás son alternativas para casos puntuales.
Devuelve únicamente el listado del catálogo, sin consultar cada documento. Es mucho más rápido y sirve para saber qué hay antes de decidir qué extraer.
{
"success": true,
"total": 6,
"data": [{
"cufe": "1ac814c2df59984f...",
"tipoDoc": "01",
"folio": "DPOS73771",
"fechaEmision": "26-07-2026",
"nitEmisor": "901772356",
"nombreEmisor": "GRUPO RC S.A.S.",
"estado": "Aprobado",
"EstadoRadian": "No Aplica",
"valor": "$ 246.850"
}]
}
Entrega el XML original firmado de una lista de CUFE, en base64. Hasta 500 documentos por llamada. No requiere que su empresa esté registrada en el servicio: el certificado viaja en la petición.
{
"certificate": "<contenido del .p12 en base64>",
"password": "<contraseña del certificado>",
"ambiente": 1, // 1 producción · 2 habilitación
"cufes": [ "1669c097...", "18a20b3d..." ]
}
{
"success": true, "total": 2, "ok": 2,
"data": [{
"cufe": "1669c097...",
"success": true,
"xmlBase64": "PD94bWwgdmVyc2lvbj0iMS4wIi..."
}]
}
Alternativas
Estas tres usan token de empresa, lo que exige que cada empresa esté registrada en el servicio con su certificado. Sirven cuando se opera una sola empresa, no cuando son muchas.
Inicia una extracción completa. Responde de inmediato con un identificador de trabajo, sin esperar a que termine el proceso. Es el endpoint principal.
{
"tipo": "Received",
"fechaDesde": "2026-07-01",
"fechaHasta": "2026-07-31",
"url": "https://catalogo-vpfe.dian.gov.co/User/AuthToken?..."
}
{
"success": true,
"jobId": "19e1f865-8d68-4b93-8f1a-b162eb27ca08",
"statusUrl": "https://.../api/extractor/company/jobs/19e1f865-..."
}
Consulta el avance y, al finalizar, entrega el resultado. Repita la llamada cada 15–20
segundos hasta que status sea done.
{
"status": "running", // running · done · error
"stage": "enriching",
"total": 6,
"processed": 5,
"log": [ "..." ],
"data": [ /* documentos, al terminar */ ]
}
Hace todo el proceso en una sola llamada y responde al terminar. no recomendado
Mantiene la conexión abierta durante todo el proceso, por lo que el servidor web la corta
con un error 504 en cuanto hay unos pocos documentos. Úselo solo para pruebas
rápidas con rangos mínimos; para todo lo demás use el flujo asíncrono.
El XML que recibe
El campo xmlBase64 contiene el documento UBL 2.1 firmado, tal como lo tiene
la DIAN. No es un extracto ni una conversión: es el archivo original, con validez legal, que
usted procesa y conserva.
Qué trae
- La firma digital XAdES del emisor y la validación de la DIAN.
- Las extensiones DIAN (
sts:DianExtensions) con el CUFE, la resolución de numeración y el rango autorizado. - Emisor y adquiriente completos, con identificación, régimen y ubicación.
- Totales, desglose de impuestos, retenciones y el detalle de todos los renglones.
- Notas, medios de pago, descuentos y cargos.
Cómo obtenerlo
Decodifique el base64 y guarde el resultado como archivo .xml:
# PHP
file_put_contents("$cufe.xml", base64_decode($doc['xmlBase64']));
# Python
open(f"{cufe}.xml", "wb").write(base64.b64decode(doc["xmlBase64"]))
El contenido decodificado empieza siempre por
<?xml version="1.0"...><Invoice ...> (o CreditNote /
DebitNote según el tipo de documento).
Junto al XML, la respuesta incluye algunos campos ya extraídos (CUFE, emisor, totales) que sirven para identificar el documento sin abrirlo. Si su sistema procesa el XML directamente, puede ignorarlos.
Flujo recomendado
Dos llamadas por cada empresa y período. Sin trabajos asíncronos ni consultas de avance.
- Obtener un enlace AuthToken nuevo de la DIAN para esa empresa.
POST /api/cufescon el rango de fechas → devuelve los CUFEs del período.POST /api/ubl2.1/xml/by-cufescon esos CUFEs y el certificado → devuelve los XML.- Decodificar cada
xmlBase64, guardarlo y causarlo en su sistema. - Repetir con
tipo: "Sent"si también necesita las ventas.
# 1 · listar
curl -X POST https://<url-base>/api/cufes \
-H "X-Api-Key: <api_key>" -H "Content-Type: application/json" \
-d '{"tipo":"Received","fechaDesde":"2026-07-01","fechaHasta":"2026-07-31","url":"<authtoken>"}'
# 2 · traer los XML (en lotes)
curl -X POST https://<url-base>/api/ubl2.1/xml/by-cufes \
-H "X-Api-Key: <api_key>" -H "Content-Type: application/json" \
-d '{"certificate":"<p12_base64>","password":"<clave>","ambiente":1,"cufes":["..."]}'
Cuando son muchas empresas
El esquema escala sin configuración adicional, y esa es su principal ventaja:
- Una sola API Key para toda la operación, sin importar cuántas empresas maneje.
- Los certificados se quedan de su lado. No hay que cargarlos ni registrarlos en el servicio: viajan en cada petición.
- Lo único que cambia por empresa son sus credenciales DIAN: su enlace AuthToken y su
.p12.
El enlace AuthToken es uno por empresa y caduca. Con muchas empresas, conseguir los enlaces vigentes es la parte más pesada del proceso — conviene planificarla antes de automatizar el resto.
Límites y rendimiento
| Aspecto | Límite | Qué significa |
|---|---|---|
| CUFEs por llamada | 500 | Tope de /api/ubl2.1/xml/by-cufes. Es el máximo que acepta, no el recomendado — vea abajo. |
| Llamadas totales | sin tope | Puede paginar tantos lotes como necesite. |
| Rango de fechas | sin tope | Un rango amplio simplemente tarda más en listar. |
El límite real es el tiempo, no la cantidad
El servicio consulta la DIAN una vez por cada documento, de forma secuencial. Un lote de 500 CUFEs son 500 consultas encadenadas, y puede tardar más de lo que el servidor web permite mantener abierta una petición.
Use lotes de 100 a 150 CUFEs. Para afinarlo a su servidor, envíe un lote de 10 y mida
cuánto tarda: divida ese tiempo entre 10 y aplique
lote = 300 s ÷ segundos_por_documento. Lotes más pequeños además son más fáciles
de reintentar cuando algo falla.
Tiempos de referencia
| Operación | Tiempo | Por qué |
|---|---|---|
| Listar un período | 1–2 min | Abre un navegador contra el portal, autentica y recorre las páginas. |
| Un XML por CUFE | ~2 s | Consulta directa al servicio web, sin navegador. |
El listado suele tardar más de un minuto, así que el servidor web debe permitirlo. Con los
valores por defecto (60 s) la petición se corta con un error 504. Solicite a su
proveedor que los tiempos de espera estén en 600 segundos.
Recomendaciones
- Extraiga por períodos mensuales y por empresa. Es más fácil de reintentar que un rango de un año.
- Programe el proceso en tareas de fondo o nocturnas, nunca dentro de una petición de usuario.
- No vuelva a pedir lo que ya tiene. Guarde por CUFE y consulte solo lo nuevo.
- Compare
okcontratotalen cada respuesta y reintente solo los CUFEs que fallaron. - Procese los lotes en serie, no en paralelo, para no saturar el servicio ni la DIAN.
Almacenamiento de los XML
El servicio no archiva los documentos. Los consulta a la DIAN, se los entrega en la respuesta y no conserva copia. Si necesita los XML para efectos contables o de auditoría, guardarlos es responsabilidad de su sistema.
Al recibir un xmlBase64, decodifíquelo y persístalo. Una convención simple:
almacenamiento/xml/<NIT>/<AAAA-MM>/<CUFE>.xml
Guarde también el CUFE en su base de datos como identificador único del documento: le sirve para no volver a descargarlo y para cualquier consulta posterior.
Que el servicio no almacene nada significa que su información no queda duplicada en un tercero, y que siempre recibe el documento tal como lo tiene la DIAN en ese momento.
Errores
| Código | Significado | Qué hacer |
|---|---|---|
401 | Credencial ausente o incorrecta | Revise el encabezado Authorization o X-Api-Key. |
422 | Datos inválidos, o empresa sin certificado configurado | Verifique el formato de fechas (AAAA-MM-DD) y que el enlace de la DIAN esté completo. |
404 | Trabajo inexistente o vencido | Pasaron más de 2 horas. Inicie la extracción de nuevo. |
502 | No hay comunicación con el componente de extracción | Reintente en unos minutos; si persiste, avise a Ágil Factura. |
504 | La petición excedió el tiempo permitido | Ocurre al usar /stream. Cambie al flujo asíncrono. |
Errores por documento
Una extracción puede terminar correctamente y aun así tener documentos individuales con error. Revise siempre los contadores del resultado:
- Procesados — cuántos se intentaron.
- OK — cuántos se obtuvieron completos.
- No coincide — el adquiriente del documento no corresponde a su NIT.
- Error — la DIAN no devolvió el documento. Reintente esos CUFE por separado.
Checklist de integración
Antes de dar por terminada la integración, verifique que su sistema:
- Solicita un enlace AuthToken nuevo por empresa en cada extracción, sin reutilizar el anterior.
- Usa
/api/cufesy/api/ubl2.1/xml/by-cufescomo flujo principal. - Divide los CUFEs en lotes de 100 a 150, ajustados a la medición de su servidor.
- Procesa los lotes en serie, no en paralelo.
- Almacena los XML por su cuenta, indexados por CUFE, y no vuelve a pedir lo ya descargado.
- Compara
okcontratotaly reintenta solo los CUFEs fallidos. - Extrae compras y ventas por separado (
ReceivedySent). - Corre en un proceso de fondo o tarea programada, no dentro de una petición de usuario.
- Guarda las credenciales y los certificados fuera del código, y los consume solo desde el servidor.
- Reintenta con espera progresiva cuando la DIAN no responde.
- Confirmó con su proveedor que los tiempos de espera del servidor están en 600 segundos.