Appearance
Exportar consultas (bulk reports export)
Esta pagina describe el feature de exportacion masiva de consultas a buros (type=reports) desde la seccion de Analisis. El endpoint canonico es POST /exports con body {type: "reports"}. Las rutas legacy /reports/export/* siguen funcionando con headers de deprecacion hasta el sunset (ver guia de migracion).
Flujo del usuario
- Navega a
/analysesdesde el menu lateral. - Click en Exportar consultas (visible solo con permiso
ExportReports). - Se abre el modal Exportar consultas.
- Completa el formulario y revisa la estimacion.
- Click en Exportar para encolar el job.
- La pagina navega a
/analyses/exportsdonde aparece el job con estado en vivo via SSE. - Cuando el job esta
done, descarga el ZIP desde la lista.
Formulario del modal
Rango de fechas
- Desde (
after): fecha inclusiva inicial. No puede ser futura. - Hasta (
before): fecha inclusiva final. Debe ser >=after. - Maximo: 365 dias entre
afterybefore. Excederlo retornaDATE_RANGE_TOO_LARGE.
Sources (sourceKeys)
Lista de identificadores de buros a incluir. Ejemplos: datacredito-acierta, datacredito-cifin, transunion-cdv, midas.
- Por defecto: todas las sources marcadas (al abrir el modal sin seleccion previa).
- Persistencia: la ultima seleccion se guarda en
sessionStorage(reports-export-last-sources). - UX en listas largas (>10 sources):
- Botones Seleccionar todos / Deseleccionar todos en la cabecera.
- Barra de busqueda (
ion-searchbar) que filtra por nombre/key sin perder la seleccion.
- Dejar todas deshabilitadas deshabilita el boton Exportar con mensaje "Selecciona al menos una source".
- Si
sourceKeysviene vacio en la API se interpreta como "todas las sources" (sin filtro).
Statuses (statuses)
Estados de los reports a incluir (whitelist):
donefailedrunningretryinitialunverifiable
Vacio significa "todos los estados".
Formato (format)
| Valor | Salida |
|---|---|
consolidated | Un solo reports.csv con todas las columnas seleccionadas en cada fila |
separated | Un manifest.csv con metadata + carpetas payloads-crudos/ y/o payloads-parseados/ con los payloads individuales por archivo |
Columnas (columns)
Whitelist cerrada de columnas. Al menos una debe estar seleccionada (EMPTY_COLUMNS si no):
| Key | Descripcion | Origen |
|---|---|---|
date | Fecha de creacion del report | report.created_at |
name | Source key | parametro del job |
idType | Tipo de documento del consultado | parseado de report.input |
idNumber | Numero de documento | parseado de report.input |
firstName | Nombres | parseado de report.input |
lastName | Apellidos | parseado de report.input |
status | Estado del report | enum |
error | Mensaje de error si fallo | report.error |
retries | Reintentos | report.retries |
durationMs | Duracion en ms | report.finished_in_ms |
id | ID del report | report.id |
rawPayload | Payload crudo del buro (XML/JSON) | report.Response |
parsedPayload | Payload parseado (JSON) | report.Output |
rawPayload y parsedPayload se exportan como celdas escapadas si format=consolidated, o como archivos individuales en payloads-* si format=separated.
Estimacion previa (dry-run)
Antes de encolar el job, el modal hace una llamada de estimacion para mostrar:
itemCount: cantidad estimada de reports que entran en los filtros.overflowed:truesi el conteo excede el hard-cap del tenant — en ese caso el boton Exportar se deshabilita.softWarn:truesi el conteo supera el soft-warn (tipicamente 100k). El modal muestra una advertencia pero permite continuar.
Endpoint: POST /exports?dryRun=true body {type: "reports", ...}. No crea estado.
Permisos requeridos
ExportReportspara todas las operaciones (abrir modal, crear, estimar, listar sources, descargar).- El boton Exportar consultas esta oculto si el usuario no tiene el permiso.
- Las descargas validan ownership cross-tenant: el archivo de un tenant T1 no es accesible por T2 (
404 Not Found).
Formato del ZIP descargado
format=consolidated
reports-export-2026-05-12.zip
+- reports.csvreports.csv contiene una fila por report con las columnas seleccionadas. Encoding UTF-8 sin BOM.
format=separated
reports-export-2026-05-12.zip
+- manifest.csv
+- payloads-crudos/
| +- datacredito-acierta/
| | +- 01H8XYZ.xml
| | +- 01H8ABC.xml
| +- transunion-cdv/
| +- 01H8DEF.json
+- payloads-parseados/
+- datacredito-acierta/
| +- 01H8XYZ.json
+- transunion-cdv/
+- 01H8DEF.jsonmanifest.csv actua como indice e incluye las columnas de metadata seleccionadas (sin rawPayload/parsedPayload). Las carpetas payloads-crudos/ y payloads-parseados/ aparecen solo si las columnas correspondientes estan marcadas.
Nombres de archivos por payload
- Crudos:
<source>/<reportID>.<ext>donde<ext>esxmlojsonsegun el formato nativo del buro. - Parseados:
<source>/<reportID>.json.
Compliance y PII
- Los payloads contienen PII: nombres, documentos, scores, deudas.
- Acceso restringido por permiso
ExportReports(noReadAnalysis). - Retencion: 30 dias desde el
finishedAtdel job. - Tras la expiracion,
GET /exports/{id}/file(y el alias legacy/reports/export/download/:fileid) retornan410 Goneconcode: "EXPORT_FILE_EXPIRED". - Cada descarga se loguea (entity_id, user_id, order_id, file_id, ip, user_agent).
Codigos de error
| Status | Code | Causa |
|---|---|---|
400 | EMPTY_COLUMNS | El array columns esta vacio |
400 | INVALID_COLUMN | Una columna no esta en la whitelist |
400 | INVALID_STATUS | Un status no esta en la whitelist |
400 | INVALID_DATE_RANGE | after o before vacio, o before < after |
400 | DATE_RANGE_TOO_LARGE | before - after > 365 dias |
400 | INVALID_FORMAT | format no es consolidated ni separated |
403 | — | Usuario sin permiso ExportReports |
404 | — | Order no existe o pertenece a otro tenant |
410 | EXPORT_FILE_EXPIRED | Archivo expirado (>30 dias) |
429 | — | Rate limit del tenant excedido |
Ejemplos curl
bash
# Estimacion previa
curl -X POST "https://api.kuenta.co/v1/exports?dryRun=true" \
-H "Authorization: Bearer $TOKEN" \
-H "Organization-ID: $ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "reports",
"after": "2026-01-01T00:00:00Z",
"before": "2026-04-30T23:59:59Z",
"format": "consolidated",
"columns": ["date", "name", "idNumber", "status"]
}'
# Crear export
curl -X POST "https://api.kuenta.co/v1/exports" \
-H "Authorization: Bearer $TOKEN" \
-H "Organization-ID: $ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "reports",
"after": "2026-01-01T00:00:00Z",
"before": "2026-04-30T23:59:59Z",
"sourceKeys": ["datacredito-acierta"],
"statuses": ["done"],
"format": "separated",
"columns": ["date", "name", "idNumber", "status", "rawPayload", "parsedPayload"]
}'
# Sources disponibles
curl -H "Authorization: Bearer $TOKEN" \
-H "Organization-ID: $ORG_ID" \
"https://api.kuenta.co/v1/exports/sources?type=reports"
# Descarga
curl -OJ \
-H "Authorization: Bearer $TOKEN" \
-H "Organization-ID: $ORG_ID" \
"https://api.kuenta.co/v1/exports/01H8XYZ/file"Notas operativas
- El job corre en un worker async; tiempos tipicos: 30s-2min para <50k reports.
- El estado se actualiza via SSE en
GET /exports/sse; el frontend escucha y actualiza la lista sin polling. - Si el job falla,
status="failed"yerrordescribe la causa. Se puede reintentar creando un nuevo export.