Boufin API v2
Referencia de la API v2 de Boufin: autenticación, inicio de tareas con composición de acciones y notificación vía webhook. Para detalles operativos (límites, catálogo de entidades, schemas completos), consulta la referencia OpenAPI.
Autenticación
El endpoint de autenticación se mantiene en /api/v1/auth/login y es el único endpoint de auth oficial, compatible tanto con clientes v1 como con clientes v2. Con tu API Key obtienes un token de sesión:
curl -X POST "https://${URL}/api/v1/auth/login" \
-H "X-API-Key: ${API_KEY}" \
-H "Content-Type: application/json" \
--data '{"expire": 60}'
| Campo | Descripción |
|---|---|
X-API-Key | Tu API Key entregada por Boufin |
expire | (Opcional) Minutos de validez del token. Por defecto 60. Ver límites y validaciones en la referencia de la API |
Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Usa el token en el header Authorization: Bearer ${TOKEN} para todas las siguientes peticiones.
Iniciar proceso de extracción
Endpoint: POST /api/v2/tasks
La v2 mantiene el mismo concepto de tarea e incorpora cuatro mejoras principales respecto a v1:
- Entidad como campo independiente: en v1, entidad y acción iban combinadas en un único string (
banco-xx:movement). En v2 la entidad se especifica en el campo top-levelentityy las acciones quedan limpias ({ "id": "movement" }). - Nuevo formato de credenciales: se pasan como objeto con modo
encrypted,persistedoraw, en lugar de campos sueltos. - Composición de acciones: una sola tarea puede ejecutar múltiples acciones (
movement,product-balance,tef) sobre la misma entidad. - Webhook configurable: en lugar de un booleano, el webhook es un objeto que permite habilitarlo y ajustar el número de reintentos.
curl --request POST \
'https://${URL}/api/v2/tasks' \
-H 'Authorization: Bearer ${TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"entity": "banco-chile",
"credentials": {
"mode": "encrypted",
"value": "czuqliRO1DKMj4bbPIzMEIYyj4+GqFLBXXc/TM7d3x0==-Qlih4F8+I6kZv8xCuSAc2A=="
},
"actions": [
{ "id": "movement", "params": { "dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" } } }
]
}'
Response:
{ "taskId": "5cbae0b5e1b5d035d99469f42c653ff4bb8aecdf9dbdb8e10f45a31677683369" }
Referencia de campos
Request
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
entity | string | Sí | Slug de la entidad bancaria (ej. banco-chile). Ver listado en la referencia OpenAPI |
credentials | object | Sí | Credenciales del usuario. Ver tabla de modos |
actions | array | Sí | Lista de acciones a ejecutar. Mínimo una |
webhook | object | No | Notificación al finalizar |
Modos de credentials
mode | Campos | Descripción |
|---|---|---|
encrypted | value: string — formato ${CIPHER_TEXT}-${IV} | Cifrado temporal con el token de sesión como llave (máx. 60 min) |
persisted | value: string — ciphertext obtenido del servicio de cifrado persistente | Cifrado persistente, reutilizable entre requests |
raw | value: object — credenciales según la entidad (ej. username, password) | Texto plano, protegido por TLS |
Campos de actions[]
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | Acción a ejecutar: movement, product-balance, tef |
params | object | Condicional | Obligatorio para movement y debe incluir dateRange; tef y product-balance no lo aceptan |
Campos de webhook
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
enable | boolean | Sí | Activa la notificación al finalizar el proceso. Si es false, no se envía aunque el objeto webhook esté presente |
retries | integer | No | Cantidad total de intentos de entrega (incluye el intento inicial). Rango 1–5. Default 3 |
Credenciales
El campo credentials define cómo se envían las credenciales del usuario. Soporta tres modos:
- Opción 1 — Cifrado temporal (
encrypted): Las credenciales se cifran en cada request usando tu token de sesión como llave (AES-256-CBC; la llave se deriva aplicando SHA-256 sobre el token antes de usarla). El cifrado tiene una duración máxima de 60 minutos, por lo que es ideal para integraciones en tiempo real. Consulta la guía de cifrado temporal. - Opción 2 — Cifrado persistente (
persisted): Las credenciales se cifran una sola vez a través del servicio de cifrado de Boufin y el resultado se reutiliza en múltiples requests. Ideal para extracciones periódicas sin requerir la interacción del usuario. Consulta la guía de cifrado persistente. - Opción 3 — Texto plano (
raw): Las credenciales se envían en "texto plano", protegidas en todo momento por TLS, tanto en la conexión externa como en la comunicación interna.
Opción 1 — Cifrado temporal
{
"entity": "banco-chile",
"credentials": {
"mode": "encrypted",
"value": "czuqliRO1DKMj4bbPIzMEIYyj4+GqFLBXXc/TM7d3x0==-Qlih4F8+I6kZv8xCuSAc2A=="
},
"actions": [
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
]
}
Opción 2 — Cifrado persistente
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
]
}
Opción 3 — Texto plano
{
"entity": "banco-chile",
"credentials": {
"mode": "raw",
"value": {
"username": "11.111.111-1",
"password": "123456789"
}
},
"actions": [
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
]
}
Acciones
Una tarea puede ejecutar múltiples acciones en secuencia sobre la misma entidad. Algunas acciones requieren parámetros (movement requiere dateRange) y otras no aceptan ninguno (tef, product-balance).
Acción simple
Las acciones tef y product-balance no llevan params:
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [{ "id": "product-balance" }]
}
Con filtros
La acción movement requiere params con un dateRange que acota la extracción:
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
]
}
El historial disponible varía según la entidad. Si startDate es anterior al registro más antiguo disponible o endDate es posterior a la fecha más reciente, la fecha fuera de rango se ajusta internamente al límite disponible — la solicitud no falla por estar fuera de rango. El formato YYYY-MM-DD sí es obligatorio.
Composición
Se pueden combinar múltiples acciones. Se ejecutan en orden sobre la misma sesión bancaria:
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [
{ "id": "product-balance" },
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
]
}
| Acción | Descripción | Parámetros |
|---|---|---|
movement | Movimientos de cuenta | dateRange (obligatorio) |
product-balance | Saldo de productos | — |
tef | Destinatarios TEF (Transferencia Electrónica de Fondos) | — |
Configuración del webhook
Para utilizar el webhook debes solicitar la activación con el equipo de soporte. La URL de destino y la llave compartida para verificar la firma del payload se configuran en esa misma instancia.
Si se omite el objeto webhook, la API no enviará notificaciones — el cliente debe consultar el estado vía GET /api/v2/tasks/{taskId}.
Habilitado
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
],
"webhook": { "enable": true }
}
Con reintentos configurados
{
"entity": "banco-chile",
"credentials": {
"mode": "persisted",
"value": "sdfAgNUFdLoF7eDGAcB3BB17gEhWG+3Q6Q5Z6Q=="
},
"actions": [
{ "id": "product-balance" },
{
"id": "movement",
"params": {
"dateRange": { "startDate": "2025-01-01", "endDate": "2025-01-31" }
}
}
],
"webhook": { "enable": true, "retries": 3 }
}
Recepción de la notificación
Cuando el proceso finaliza, Boufin enviará una notificación HTTP POST a la URL configurada con el equipo de soporte.
Payload
El cuerpo de la notificación es un JSON con los campos del resultado:
{
"taskId": "5cbae0b5e1b5d035d99469f42c653ff4bb8aecdf9dbdb8e10f45a31677683369",
"taskStatus": "COMPLETED"
}
| Campo | Descripción |
|---|---|
taskId | ID de la tarea que finalizó |
taskStatus | Estado final del proceso (ver tabla de estados) |
El webhook solo se dispara cuando el proceso termina definitivamente. Los posibles valores son:
taskStatus | Descripción |
|---|---|
COMPLETED | Todas las acciones completadas exitosamente |
PARTIAL | Al menos una acción completó, otra(s) fallaron |
CREDENTIALS_WRONG | Credenciales incorrectas |
CREDENTIALS_LOCKED | La cuenta del usuario está bloqueada en la entidad |
FAILED | Error general — ninguna acción pudo ejecutarse |
CREDENTIALS_WRONG y CREDENTIALS_LOCKED aplican a las credenciales de la entidad bancaria, no al Bearer token. Una falla del Bearer se devuelve como HTTP 401 en la respuesta de la propia llamada, sin envolver en taskStatus.
La v2 define su propio conjunto público de estados (taskStatus). Puedes ver la referencia completa en la documentación del endpoint de estado de tarea.
Verificación de la firma
Cada notificación incluye el header X-Boufin-Signature con una firma HMAC-SHA256 calculada sobre el body crudo de la request:
X-Boufin-Signature: sha256=<hmac-hex>
La firma se calcula como HMAC-SHA256(rawBody, sharedKey), donde sharedKey es la llave compartida acordada con el equipo de soporte.
Para verificar el origen:
- Leer el body crudo (antes de parsearlo como JSON).
- Calcular
HMAC-SHA256(rawBody, sharedKey). - Comparar el resultado con el valor del header usando una comparación en tiempo constante para evitar timing attacks.
Siempre usar el body crudo para calcular el HMAC. Si se parsea y re-serializa el JSON primero, el resultado puede diferir y la verificación fallará.
Una firma válida bajo tu llave compartida es prueba de origen: una petición que no provenga de Boufin no podrá producir una firma correcta bajo esa llave.
Ejemplo de request entrante
Así se verá la solicitud POST que llegará a tu servidor:
POST /tu-endpoint HTTP/1.1
Content-Type: application/json
X-Boufin-Signature: sha256=b94d27b9934d3e08a52e52d7da7dabfac484efe04b6f9d0a08805f2cde4b2218
{
"taskId": "5cbae0b5e1b5d035d99469f42c653ff4bb8aecdf9dbdb8e10f45a31677683369",
"taskStatus": "COMPLETED"
}
Reintentos
Si tu servidor no responde con 200 o 204, Boufin reintentará la entrega. La cantidad total de intentos se controla con webhook.retries (default 3, rango 1–5). Intervalo de 30 segundos entre intentos. Cada intento espera un máximo de 5 segundos antes de marcarlo como fallido.
| Intento | Momento |
|---|---|
| 1° | Al finalizar el proceso |
| 2° | +30 segundos |
| 3° | +60 segundos |
| … | (continúa hasta retries) |
Si todos los intentos fallan, el evento queda registrado internamente. Puedes consultar el estado final de la tarea directamente usando GET /api/v2/tasks/{taskId}.
Respuestas
Esta es la estructura base de la API v2 y todavía está en proceso de trabajo. Puede evolucionar — especialmente por la variabilidad en las respuestas de las entidades financieras durante extracciones compuestas.
Revisa los casos de prueba en sandbox: requests listos para copiar/pegar con resultados deterministas por cada escenario (COMPLETED, PARTIAL, CREDENTIALS_WRONG, FAILED).
Una vez finalizado el proceso, consulta los datos extraídos usando el taskId obtenido al crear la tarea:
curl "https://${URL}/api/v2/tasks/${TASK_ID}" \
-H "Authorization: Bearer ${TOKEN}"
No basta con tener un token válido — debe ser el mismo cliente que inició el proceso de extracción, como indica la documentación oficial. Esto aplica tanto al polling como a la consulta del resultado final.
Estados de la tarea
El taskStatus refleja el resultado consolidado de todas las acciones ejecutadas:
taskStatus | Descripción |
|---|---|
PENDING | Extracción encolada, aún no comenzó |
RUNNING | Extracción en ejecución |
COMPLETED | Todas las acciones completadas exitosamente |
PARTIAL | Al menos una acción completó, otra(s) fallaron |
FAILED | Error general — ninguna acción pudo ejecutarse |
CREDENTIALS_WRONG | Credenciales incorrectas |
CREDENTIALS_LOCKED | La cuenta del usuario está bloqueada en la entidad |
CREDENTIALS_WRONG y CREDENTIALS_LOCKED aplican a las credenciales de la entidad bancaria, no al Bearer token. Una falla del Bearer se devuelve como HTTP 401 en la respuesta de la propia llamada, sin envolver en taskStatus.
La tabla del webhook (Recepción de la notificación) es un subconjunto: solo lista los estados terminales.
Escenarios de respuesta
Cada acción retorna su propia respuesta dentro de results.actions, con su propio status, output y, en caso de fallo, un objeto error.
Éxito completo
Todas las acciones completaron sin problemas:
{
"taskStatus": "COMPLETED",
"results": {
"username": "11111111-1",
"businessId": "76111111-6",
"entityId": "banco-estado",
"actions": [
{
"id": "product-balance",
"status": "COMPLETED",
"output": {
/* productos */
}
},
{
"id": "movement",
"status": "COMPLETED",
"output": [
/* movimientos */
]
}
]
}
}
Resultado parcial
Al menos una acción completó y otra falló. Cada acción indica su propio estado:
{
"taskStatus": "PARTIAL",
"results": {
"username": "11111111-1",
"businessId": "76111111-6",
"entityId": "banco-estado",
"actions": [
{
"id": "product-balance",
"status": "COMPLETED",
"output": {
/* productos */
}
},
{
"id": "movement",
"status": "FAILED",
"output": null,
"error": {
"code": "TIMEOUT_ERROR",
"message": "Entity did not respond during extraction"
}
}
]
}
}
Credenciales incorrectas
{
"taskStatus": "CREDENTIALS_WRONG",
"results": null
}
Credenciales bloqueadas
La cuenta del usuario está bloqueada en la entidad bancaria (típicamente tras múltiples intentos fallidos). Las credenciales podrían ser correctas, pero la entidad rechaza el acceso:
{
"taskStatus": "CREDENTIALS_LOCKED",
"results": null
}
Error general
Ninguna acción se completó. A diferencia de las fallas de credenciales, results sí se incluye con la misma estructura que en COMPLETED/PARTIAL: cada acción reporta su propio status y un objeto error, de modo que el cliente puede ver qué se intentó y por qué falló:
{
"taskStatus": "FAILED",
"results": {
"username": "11111111-1",
"businessId": "76111111-6",
"entityId": "banco-estado",
"actions": [
{
"id": "product-balance",
"status": "FAILED",
"output": null,
"error": {
"code": "ACTION_ERROR",
"message": "The service is currently unavailable"
}
},
{
"id": "movement",
"status": "FAILED",
"output": null,
"error": {
"code": "ENTITY_API_ERROR",
"message": "user has no permission for transfers"
}
}
]
}
}
Referencia de campos
Campos de results
| Campo | Tipo | Descripción |
|---|---|---|
username | string | Identificador del usuario consultado (formato según la entidad) |
businessId | string | Identificador de la empresa. Se devuelve solo si las credenciales del request lo incluían (banca empresa) |
entityId | string | Slug de la entidad bancaria. Ver listado en la referencia de la API |
actions | array | Resultados por acción. Ver tabla siguiente |
Campos de results.actions[]
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador de la acción ejecutada |
status | string | Estado de esta acción en particular. Ver tabla de estados de acción |
output | object | array | null | Datos extraídos; su forma depende de la acción (objeto para product-balance, arreglo para movement). null cuando la acción no entregó datos (p. ej. FAILED) |
error | object | Detalle del fallo. Presente si status = FAILED |
error.code | string | Código del catálogo en UPPER_SNAKE_CASE. Es el identificador estándar para manejo programático. Ver tabla de códigos |
error.message | string | Descripción legible del problema en inglés. Es texto variable y puede cambiar; no lo uses para lógica programática |
Estados de results.actions[].status
status | Descripción |
|---|---|
COMPLETED | La acción se completó exitosamente y retornó datos |
FAILED | La acción falló durante la ejecución (ver objeto error) |
CREDENTIALS_WRONG | Credenciales incorrectas para la entidad |
CREDENTIALS_LOCKED | La cuenta del usuario está bloqueada en la entidad |
Códigos de error (error.code)
El error.code detalla qué pasó en la acción. Es un catálogo independiente del status (aunque algunos nombres puedan coincidir). Códigos públicos disponibles hoy:
error.code | Descripción |
|---|---|
UNKNOWN_ERROR | Error no clasificado o inesperado |
ACTION_ERROR | La acción no pudo completarse durante su ejecución |
REQUEST_BLOCK_ERROR | La solicitud fue bloqueada (p. ej. por la entidad) |
TIMEOUT_ERROR | Se excedió el tiempo máximo de la operación |
ENTITY_API_ERROR | Error reportado por la API / entidad bancaria |
El catálogo de códigos se irá ampliando con el tiempo. El error.message que acompaña a cada código es un texto descriptivo variable (puede cambiar entre versiones o casos); para manejo programático usa siempre error.code, no el message.