Cuentas del API Bancario
API 1.0.0Una herramienta del MCP envuelve esta operación: Herramientas bancarias.
El grupo Accounts cubre la cuenta como recurso: validar una cuenta destino antes de
transferir, listar las cuentas accesibles, consultar saldos y pedir estados de cuenta.
POST /api/public/v1/accounts/validate
GET /api/public/v1/accounts
POST /api/public/v1/accounts/balances
GET /api/public/v1/accounts/balance
POST /api/public/v1/accounts/statements
GET /api/public/v1/accounts/statements/{request_id}Reglas del recurso#
Alcance. El listado devuelve sólo las cuentas que autoriza el token; no se envía
tenant_id ni owner_id como parámetro.
Validación previa. Validá la cuenta destino antes de crear un pago: la operación confirma que la cuenta existe y es apta, y devuelve los datos del titular que el servicio expone.
Estados de cuenta asincrónicos. POST /api/public/v1/accounts/statements acepta Idempotency-Key y responde siempre HTTP 202 (ACCEPTED) con request_id y status: PENDING; la generación es asíncrona. Consultá GET /api/public/v1/accounts/statements/{request_id}: responde HTTP 200 con status PENDING, PROCESSING, DONE o ERROR. En DONE incluye download_url, válida por 48 horas. Ver
reintentos seguros.
Paginación. GET /api/public/v1/accounts y GET /api/public/v1/accounts/balances
usan limit y offset, y devuelven pagination con limit, offset y total.
Operaciones#
Validar cuenta externa para un método de pago
POST /api/public/v1/accounts/validate
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Valida una cuenta de beneficiario (IBAN o teléfono) a través del proveedor SINPE para el método de pago indicado. No valida cuentas internas de la plataforma. Cuando es válida, data.holder.id_type usa las mismas claves del catálogo de identificación que identification.type en POST /payments (ej. cedula, juridica, dimex).
Disponibilidad de campos en SINPE_MOVIL (esperado, estable)
Para payment_method_code = SINPE_MOVIL, la consulta del monedero SINPE Móvil no devuelve el tipo de identificación ni el nombre de la entidad. Una validación exitosa puede entonces devolver:
data.holder.id_type=unknowndata.financial_institution.entity_name=""(cadena vacía)
Este comportamiento es esperado y estable, no un error de mapeo ni un error transitorio del proveedor. PIN (la consulta de la cuenta en SINPE) sí completa ambos campos.
No reportés estos valores como defectos ni asumás que holder.id_type o financial_institution.entity_name siempre vienen completos cuando is_valid es true.
Códigos de rechazo SINPE (data.rejection)
Cuando is_valid es false, data.rejection explica por qué (ver el ejemplo rejected en la respuesta 200 más abajo). rejection.code es uno de un conjunto fijo de semánticas normalizadas (ver la tabla de valores más abajo). La mayoría de filas de la tabla NO tienen un `code` propio: solo un subconjunto de valores de reason_code tiene una semántica dedicada; cualquier otro reason_code, incluso uno listado abajo con un message específico, devuelve code = SINPE_REJECTED (ej. reason_code = 21 "fondos insuficientes" igual devuelve SINPE_REJECTED). Este mismo objeto y catálogo los usa también el campo rejection del webhook payment.failed. Un reason_code que no aparece aquí igual produce respuesta: message cae a un texto genérico y code a SINPE_REJECTED.
Cuenta / perfil / límites
| Code | Message |
|---|---|
| 21 | Cuenta Cliente con fondos insuficientes |
| 22 | Cuenta Cliente no admite créditos |
| 23 | Cuenta Cliente cerrada |
| 24 | Cuenta Cliente inactiva |
| 25 | Cuenta Cliente no admite débitos |
| 26 | Cuenta Cliente no es de fondos |
| 27 | Moneda de la Cuenta Cliente no corresponde |
| 28 | Cuenta cliente no existe |
| 29 | Cuenta Cliente no registrada en el SINPE |
| 30 | Cuenta Cliente no habilitada para el servicio |
| 31 | Cuenta Cliente bloqueada |
| 32 | Id cliente destino no coincide con registrado en la entidad |
| 33 | Nombre del cliente destino no coincide con el registrado en la entidad |
| 34 | Cuenta Cliente en proceso de cierre |
| 35 | Cuenta Cliente embargada |
| 36 | Cuenta Cliente con retención judicial |
| 37 | Cuenta de expediente simplificado no permite el monto indicado |
| 38 | Límite transaccional de la Cuenta Cliente excedido |
| 39 | Cuenta Cliente incorrecta |
| 40 | IBAN de la cuenta destino inválido |
| 41 | IBAN de la cuenta origen inválido |
| 42 | Tipo de cuenta no permite la transacción |
| 43 | Cuenta Cliente no pertenece a la entidad indicada |
| 44 | Producto de la cuenta no admite el servicio |
| 45 | Cuenta Cliente en estado de cancelación |
| 46 | Cuenta Cliente restringida por política de la entidad |
| 47 | Cuenta Cliente no permite pagos inmediatos |
| 48 | Cuenta Cliente no permite SINPE Móvil |
| 49 | Titular de la cuenta destino fallecido |
| 50 | Cuenta Cliente consolidada o migrada |
| 51 | Identificación del cliente origen no coincide |
| 52 | Identificación del cliente destino inválida |
| 53 | Cliente destino no autorizado para recibir el pago |
| 54 | Cliente origen no autorizado para enviar el pago |
| 55 | Perfil del cliente origen no permite la transacción |
| 56 | Monto inferior al mínimo permitido |
| 57 | Monto superior al máximo permitido |
| 58 | Cantidad de transacciones diarias excedida |
| 59 | Cantidad de transacciones mensuales excedida |
| 60 | Límite acumulado diario excedido |
| 61 | Límite acumulado mensual excedido |
| 62 | Comisión no pudo ser aplicada |
| 63 | Tipo de cambio no disponible |
| 64 | Transacción rechazada por control de lavado de dinero |
| 65 | Transacción rechazada por listas de control |
| 66 | Transacción en revisión de cumplimiento |
| 67 | Documento de respaldo requerido no presente |
| 68 | Firma o autenticación inválida |
| 69 | Token o segundo factor inválido |
| 70 | Sesión de usuario expirada |
| 71 | Usuario no autorizado para el canal |
| 72 | Dispositivo no registrado |
| 73 | Geolocalización no permitida |
| 74 | Operación no soportada en la moneda indicada |
| 75 | Operación no soportada para el tipo de cliente |
| 76 | Problemas de comunicación |
| 77 | Tiempo de espera agotado en la entidad origen |
| 78 | Tiempo de espera agotado en el SINPE |
| 79 | Error interno de la entidad origen |
| 80 | Error interno de la entidad destino |
| 81 | Entidad origen no disponible |
| 82 | Entidad destino no encontrada |
| 83 | Problemas en la respuesta del destino |
| 84 | Respuesta de la entidad origen incorrecta |
| 85 | Mensaje con formato electrónico inválido |
| 86 | Versión del estándar electrónico no soportada |
| 87 | Campo obligatorio no informado |
| 88 | Campo con valor fuera de catálogo |
| 89 | Checksum o integridad del mensaje inválida |
| 90 | Referencia SINPE duplicada |
| 91 | Moneda no corresponde |
| 92 | Transacción no autorizada por entidad destino |
| 93 | Transacción no autorizada por cliente destino |
| 94 | Transacción no autorizada por entidad origen |
| 95 | Transacción no autorizada por cliente origen |
| 96 | Reverso no permitido para el estado de la transacción |
| 97 | Reverso ya aplicado |
| 98 | Confirmación no permitida para el estado de la transacción |
| 99 | Liquidación no permitida para el estado de la transacción |
| 100 | Entidad Destino no disponible para procesar en tiempo real |
| 101 | Entidad origen no disponible para procesar en tiempo real |
| 102 | Servicio PIN no habilitado para la entidad destino |
| 103 | Servicio PIN no habilitado para la entidad origen |
| 104 | Código de entidad destino inválido |
| 105 | Código de entidad origen inválido |
| 106 | Código de país de la entidad destino inválido |
| 107 | Código de país de la entidad origen inválido |
| 108 | Número de referencia interna inválido |
| 109 | Número de referencia SINPE inválido |
| 110 | Transacción no se encuentra en un estado que permita la consulta |
Compensación con entidad destino
| Code | Message |
|---|---|
| 201 | Tiempo respuesta excedido por la entidad destino |
| 202 | Respuesta de la entidad destino incorrecta según el estándar electrónico |
| 203 | Se recibió una excepción de la entidad destino |
| 204 | Error de comunicación con la entidad destino |
| 205 | Falló procesamiento en el SINPE |
| 206 | Transacción no autorizada por cliente destino |
| 207 | Perfil transaccional del cliente destino no permite recibir el pago |
| 208 | Operación no autorizada entre las entidades participantes |
| 209 | Pendientes de Cumplimiento |
| 210 | Conciliación de la transacción no fue posible |
Identificación
| Code | Message |
|---|---|
| 801 | Identificación inválida |
| 802 | Identificación del cliente origen no encontrada |
| 803 | Identificación del cliente destino no encontrada |
| 804 | Identificación no vigente |
| 805 | Identificación vencida |
| 806 | Identificación no corresponde al tipo indicado |
| 807 | Tipo de identificación inválido |
| 808 | País de la identificación no soportado |
| 809 | Identificación de menor de edad no permitida |
| 810 | Identificación de persona jurídica no permitida para el servicio |
Validación de formato / Core Bancario
| Code | Message |
|---|---|
| 1002 | El Id de cliente destino no cumple con el formato esperado por el SINPE |
| 1003 | El Id de cliente origen no fue informado |
| 1004 | El Id de cliente origen no cumple con el formato esperado por el SINPE |
| 1005 | Monto con formato inválido |
| 1006 | Moneda con formato inválido |
| 1007 | Problemas de comunicación con el Core Bancario |
| 1008 | Core Bancario no disponible |
| 1009 | El valor para el campo no puede ser nulo o infringir su longitud mínima o máxima |
| 1010 | El valor para el campo no corresponde al tipo de dato esperado |
| 1011 | El valor para el campo no corresponde al catálogo permitido |
| 1012 | Fecha con formato inválido |
| 1013 | Hora con formato inválido |
| 1014 | Número de referencia con formato inválido |
| 1015 | IBAN con formato inválido |
Canal / tipo de identificación
| Code | Message |
|---|---|
| 1040 | Canal no informado |
| 1041 | Canal inválido |
| 1042 | Canal no corresponde |
| 1043 | Canal no habilitado para la entidad |
| 1044 | Canal no habilitado para el servicio |
| 1045 | El formato de la identificación es inválido |
| 1046 | Tipo de identificación no informado |
| 1080 | Tipo de identificación no corresponde al cliente origen |
| 1081 | Tipo de identificación no corresponde al cliente destino |
| 1082 | Tipo de identificación no vigente |
| 1083 | Tipo de identificación no soportado por el servicio |
| 1084 | Tipo de identificación inválido |
| 1085 | Tipo de identificación no soportado por la entidad |
SINPE Móvil (monedero)
| Code | Message |
|---|---|
| 15300 | El número de teléfono origen indicado es inválido |
| 15301 | El número de teléfono origen no tiene activo el Servicio Monedero |
| 15302 | El número de teléfono destino indicado es inválido |
| 15303 | El número de teléfono destino no está registrado en el padrón móvil del BCCR |
| 15304 | No es posible inactivar el monedero indicado pues no existe |
| 15305 | El número de teléfono indicado ya se encuentra activo como monedero en el padrón local |
Valores de `rejection.code`
| Valor | Significado |
|---|---|
ACCOUNT_CLOSED | Cuenta cerrada |
ACCOUNT_NOT_FOUND | Cuenta no encontrada |
ACCOUNT_BLOCKED | Cuenta bloqueada |
INVALID_ACCOUNT | Cuenta inválida |
IDENT_MISMATCH | La identificación no coincide |
IDENT_TYPE_INVALID | Tipo de identificación inválido |
INVALID_ID_FORMAT | Formato de identificación inválido |
VALIDATION_ERROR | Error de validación |
CURRENCY_MISMATCH | La moneda no corresponde |
NOT_AUTHORIZED_BY_RECIPIENT | No autorizado por el destinatario |
PROFILE_NOT_ALLOWED | Perfil no permitido |
CHANNEL_NOT_RECOGNIZED | Canal no reconocido |
COMMUNICATION_ERROR | Error de comunicación |
RETRY_LATER | Reintentar más tarde |
WALLET_PHONE_ORIGIN_INVALID | Teléfono origen inválido (SINPE Móvil) |
WALLET_PHONE_ORIGIN_NOT_ENABLED | Teléfono origen sin servicio de monedero |
WALLET_PHONE_DEST_INVALID | Teléfono destino inválido (SINPE Móvil) |
WALLET_PHONE_NOT_REGISTERED_BCCR | Teléfono no registrado en el padrón móvil del BCCR |
WALLET_NOT_FOUND | Monedero no encontrado |
WALLET_PHONE_ALREADY_ACTIVE | El teléfono ya tiene un monedero activo |
PHONE_NOT_REGISTERED | Teléfono no registrado |
SINPE_REJECTED | Rechazado por SINPE (valor genérico de respaldo) |
Actualmente hay límites de tasa en autenticación y validación de cuentas. Superarlos devuelve HTTP 429 (TOO_MANY_REQUESTS). Reintentá con espera exponencial.
El código SINPE 1001 indica que la cuenta existe y está activa; es un resultado válido, no un motivo de rechazo.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
Cuerpo del request
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
payment_method_code | string | sí | Método de pago usado para enrutar la validación (PIN para IBAN externo, SINPE_MOVIL para monedero telefónico).Valores: PIN, SINPE_MOVIL |
account | object | sí | — |
account.type | string | sí | —Valores: IBAN, PHONE |
account.value | string | sí | — |
Ejemplo de request
pin
{
"payment_method_code": "PIN",
"account": {
"type": "IBAN",
"value": "CR16010400000000000031"
}
}sinpe_movil
{
"payment_method_code": "SINPE_MOVIL",
"account": {
"type": "PHONE",
"value": "88887777"
}
}Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
is_valid | boolean | no | — |
account | object | no | — |
account.type | string | no | — |
account.value | string | no | — |
account.currency | string | no | — |
account.product_name | string | no | — |
holder | object | no | Titular de la cuenta cuando la validación tiene éxito.
id_type coincide con PaymentIdentification.type (mismo catálogo que POST /payments).
Para SINPE_MOVIL, id_type puede ser unknown porque la consulta del monedero
no devuelve el tipo de identificación. Es esperado
y estable; no lo tratés como un error.Puede ser null. |
holder.name | string | no | — |
holder.id_type | string | no | Clave del catálogo de identificación (minúsculas), ej. cedula, juridica, dimex.
Mismo vocabulario que identification.type al crear un pago.
PIN: se obtiene de la consulta de cuenta del proveedor (confirmado por el proveedor).
SINPE_MOVIL: la consulta del monedero no devuelve el tipo de identificación,
así que este campo puede ser `unknown`. Es un comportamiento esperado y
estable por los datos disponibles del proveedor, no un error de mapeo ni
transitorio. No asumás que siempre hay un tipo confirmado.Valores: cedula, dimex, gobierno, juridica, institucion_autonoma, didi, pasaporte, unknown |
holder.id_number | string | no | — |
financial_institution | object | no | Entidad del beneficiario cuando la validación tiene éxito.
PIN completa entity_name desde la consulta de cuenta en SINPE.
SINPE_MOVIL solo recibe el código de entidad desde la consulta del monedero;
no devuelve el nombre de la entidad, así que entity_name
puede ser `""`. Es un comportamiento esperado y estable, no un error
transitorio. No asumás que entity_name siempre viene completo.Puede ser null. |
financial_institution.country_code | string | no | — |
financial_institution.entity_code | string | no | — |
financial_institution.entity_name | string | no | Nombre legible de la entidad.
PIN: se completa desde la consulta de cuenta del proveedor.
SINPE_MOVIL: puede ser "" porque la consulta del monedero no
expone el nombre. Limitación esperada, no un error. |
rejection | object | no | Presente cuando is_valid es false y el proveedor rechazó la cuenta. null cuando is_valid es true.Puede ser null. |
rejection.code | string | sí | Semántica normalizada de la plataforma derivada de reason_code. Solo un subconjunto
de valores de reason_code (ver el catálogo en la descripción de POST /accounts/validate
y del endpoint de contrato del webhook payment.failed) tiene entrada propia aquí;
para cualquier otro reason_code numérico, code es SINPE_REJECTED aunque message
sea específico (ej. reason_code = 21 "fondos insuficientes" igual devuelve
code = SINPE_REJECTED, no tiene semántica propia). PHONE_NOT_REGISTERED es
el valor de respaldo cuando reason_code no es numérico (flujo del monedero SINPE_MOVIL).Valores: ACCOUNT_CLOSED, ACCOUNT_NOT_FOUND, ACCOUNT_BLOCKED, INVALID_ACCOUNT, IDENT_MISMATCH, IDENT_TYPE_INVALID, INVALID_ID_FORMAT, VALIDATION_ERROR, CURRENCY_MISMATCH, NOT_AUTHORIZED_BY_RECIPIENT, PROFILE_NOT_ALLOWED, CHANNEL_NOT_RECOGNIZED, COMMUNICATION_ERROR, RETRY_LATER, WALLET_PHONE_ORIGIN_INVALID, WALLET_PHONE_ORIGIN_NOT_ENABLED, WALLET_PHONE_DEST_INVALID, WALLET_PHONE_NOT_REGISTERED_BCCR, WALLET_NOT_FOUND, WALLET_PHONE_ALREADY_ACTIVE, PHONE_NOT_REGISTERED, SINPE_REJECTED |
rejection.reason_code | string | sí | Motivo/código crudo devuelto por SINPE. El catálogo completo está en la descripción
de POST /accounts/validate (lo comparte este objeto dondequiera que aparezca,
incluido el webhook payment.failed). Un código no listado igual produce respuesta:
message cae a un texto genérico y code a SINPE_REJECTED. |
rejection.message | string | sí | Texto descriptivo del Motivo; prefiere el Detalle del proveedor cuando existe. |
provider | object | no | — |
provider.operation | string | no | — |
provider.correlation_id | string | no | —Puede ser null. |
provider.occurred_at | string (date-time) | no | —Puede ser null. |
Ejemplo de respuesta — valid
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"is_valid": true,
"account": {
"type": "IBAN",
"value": "CR16010400000000000031",
"currency": "CRC",
"product_name": "Cuenta corriente"
},
"holder": {
"name": "Juan Perez",
"id_type": "cedula"
},
"financial_institution": {
"entity_code": "104",
"entity_name": "Banco Ejemplo"
},
"provider": {
"reason_code": "0",
"message": "Cuenta válida",
"code": null
},
"rejection": null
}
}Ejemplo de respuesta — rejected
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"is_valid": false,
"account": {
"type": "IBAN",
"value": "CR16010400000000000099",
"currency": "CRC",
"product_name": ""
},
"holder": null,
"financial_institution": {
"entity_code": "104",
"entity_name": "Banco Ejemplo"
},
"provider": {
"reason_code": "28",
"message": "Cuenta cliente no existe",
"code": "ACCOUNT_NOT_FOUND"
},
"rejection": {
"code": "ACCOUNT_NOT_FOUND",
"reason_code": "28",
"message": "Cuenta cliente no existe"
}
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 400 | INVALID_ACCOUNT_TYPE | Unsupported or invalid account type. |
| 400 | INVALID_ACCOUNT_FORMAT | Invalid account format. |
| 400 | INVALID_PAYMENT_METHOD | Invalid or unsupported payment method. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 422 | UNPROCESSABLE_ENTITY | The request is well-formed but cannot be processed due to business rules. |
| 429 | TOO_MANY_REQUESTS | Too many requests. Please retry after a short delay. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
Listar saldos de las cuentas accesibles
GET /api/public/v1/accounts/balances
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Devuelve los saldos paginados de las cuentas (account, amounts, as_of). Este endpoint consulta el saldo actual en tiempo real y puede responder más lento que GET /accounts. Para los atributos de la cuenta sin montos, usá GET /accounts.
Los filtros opcionales usan el estándar público de identificación de cuentas: type + value (esquema de identificación + valor). type no es la clasificación interna de la cuenta.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
limit | query | integer | no | — |
offset | query | integer | no | — |
type | query | string | no | Filtro opcional por esquema de identificación de la cuenta (ej. IBAN).
No es la clasificación interna de la cuenta. |
value | query | string | no | Filtro opcional por valor del identificador de la cuenta (los listados admiten coincidencia parcial). |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
items | array<object> | no | — |
items[].account | object | sí | — |
items[].account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
items[].account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
items[].account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
items[].amounts | object | sí | Saldos del ledger como textos decimales con 2 decimales (misma escala que los montos públicos de pago). Preferí texto sobre número JSON para montos financieros. |
items[].amounts.available | string | no | — |
items[].amounts.posted | string | no | — |
items[].amounts.inbound_in_transit | string | no | — |
items[].amounts.outbound_in_transit | string | no | — |
items[].as_of | string (date-time) | sí | Marca de tiempo del ledger cuando se conoce (RFC 3339 UTC, precisión de segundos, Z); null cuando no está disponible.Puede ser null. |
pagination | object | no | — |
pagination.limit | integer | no | — |
pagination.offset | integer | no | — |
pagination.total | integer | no | — |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"items": [
{
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
},
"amounts": {
"available": "991900.00",
"posted": "991900.00",
"inbound_in_transit": "0.00",
"outbound_in_transit": "0.00"
},
"as_of": "2026-01-15T12:00:00Z"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 1
}
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | NOT_FOUND | The requested resource was not found. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | — | Error de dependencia |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Listar cuentas accesibles sin saldos
GET /api/public/v1/accounts
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Devuelve las cuentas accesibles paginadas sin consultar saldos actuales. Cada ítem trae solo atributos de la cuenta (account.type, account.value, account.currency). No incluye amounts ni as_of; usá GET /accounts/balances o POST /accounts/balance.
Los filtros opcionales usan el estándar público de identificación de cuentas: type + value (esquema de identificación + valor). type no es la clasificación interna de la cuenta.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
limit | query | integer | no | — |
offset | query | integer | no | — |
type | query | string | no | Filtro opcional por esquema de identificación de la cuenta (ej. IBAN).
No es la clasificación interna de la cuenta. |
value | query | string | no | Filtro opcional por valor del identificador de la cuenta (los listados admiten coincidencia parcial). |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
items | array<object> | no | — |
items[].account | object | sí | — |
items[].account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
items[].account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
items[].account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
pagination | object | no | — |
pagination.limit | integer | no | — |
pagination.offset | integer | no | — |
pagination.total | integer | no | — |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"items": [
{
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
}
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 1
}
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 404 | NOT_FOUND | The requested resource was not found. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | — | Error de dependencia |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Obtener saldo de una cuenta
POST /api/public/v1/accounts/balance
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Devuelve la foto actual de una cuenta con amounts y as_of. Para los atributos de la cuenta sin saldos, usá GET /accounts.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
Cuerpo del request
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account | object | sí | — |
account.type | string | sí | Esquema de identificación de la cuenta. Aquí solo se admite IBAN.
No es la clasificación interna de la cuenta
(ej. operativa).Valores: IBAN |
account.value | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account | object | sí | — |
account.type | string | sí | Esquema de identificación de la cuenta (ej. IBAN, PHONE).
No es la clasificación interna de la cuenta (ej. operativa).Valores: IBAN, PHONE |
account.value | string | sí | Cuando type es PHONE (SINPE Móvil): 8 dígitos locales, sin prefijo de país (ej. "88887777"). |
account.currency | string | no | Moneda opcional de la cuenta en las respuestas. |
amounts | object | sí | Saldos del ledger como textos decimales con 2 decimales (misma escala que los montos públicos de pago). Preferí texto sobre número JSON para montos financieros. |
amounts.available | string | no | — |
amounts.posted | string | no | — |
amounts.inbound_in_transit | string | no | — |
amounts.outbound_in_transit | string | no | — |
as_of | string (date-time) | sí | Marca de tiempo del ledger cuando se conoce (RFC 3339 UTC, precisión de segundos, Z); null cuando no está disponible.Puede ser null. |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"account": {
"type": "IBAN",
"value": "CR26036900101010588061",
"currency": "CRC"
},
"amounts": {
"available": "991900.00",
"posted": "991900.00",
"inbound_in_transit": "0.00",
"outbound_in_transit": "0.00"
},
"as_of": "2026-01-15T12:00:00Z"
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | ACCOUNT_NOT_FOUND | Account not found. |
| 422 | ACCOUNT_NOT_CONFIGURED | This account is not mapped in the system. Please contact support to configure it correctly. |
| 422 | UNPROCESSABLE_ENTITY | The request is well-formed but cannot be processed due to business rules. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | PROVIDER_ERROR | Unable to complete the request with the payment provider. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Solicitar generación de estado de cuenta
POST /api/public/v1/accounts/statements
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>. Acepta Idempotency-Key.
Crea una solicitud asíncrona de estado de cuenta para un rango de fechas (máximo 60 días). Identificá la cuenta con account.type + account.value (esquema de identificación + valor, ej. IBAN). Sigue el estándar público de identificación de cuentas. account.type no es la clasificación interna de la cuenta. Devuelve {request_id, status: PENDING} de inmediato. Consultá GET /accounts/statements/{request_id} para el estado; cuando es DONE, la respuesta incluye una download_url firmada.
Siempre devuelve HTTP 202 (ACCEPTED) con request_id y status PENDING. La generación es asíncrona. Consultá GET /api/public/v1/accounts/statements/{request_id}: HTTP 200 con PENDING, PROCESSING, DONE o ERROR. DONE incluye download_url, válida por 48 horas.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
Idempotency-Key | header | string | no | — |
Cuerpo del request
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account | object | sí | — |
account.type | string | sí | Esquema de identificación de la cuenta. Aquí solo se admite IBAN.
No es la clasificación interna de la cuenta
(ej. operativa).Valores: IBAN |
account.value | string | sí | IBAN (se permiten espacios; se normaliza en el servidor) |
date_from | string (date-time) | sí | Marca de tiempo RFC 3339 aceptada en solicitudes. Se permite UTC Z u offset numérico.
Las fracciones de segundo opcionales se aceptan y se truncan a segundos. |
date_to | string (date-time) | sí | RFC 3339 (máximo 60 días después de date_from) |
notify_email | boolean | no | — |
Respuesta 202
Solicitud de estado de cuenta aceptada para generación asíncrona.
response_code: ACCEPTED
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
request_id | string (uuid) | sí | — |
status | string | sí | —Valores: PENDING |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 202,
"response_code": "ACCEPTED",
"message": "Statement request accepted.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"request_id": "5f3b2c1d-9e8a-4b7c-8d6e-5f4a3b2c1d0e",
"status": "PENDING"
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request. Check the required fields and try again. |
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 403 | ACCOUNT_ACCESS_DENIED | The actor does not have access to the requested account. |
| 404 | NOT_FOUND | The requested resource was not found. |
| 409 | IDEMPOTENCY_CONFLICT | Idempotency conflict: the same Idempotency-Key was reused with a different request body, or a previous request is still in progress. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 502 | — | Error de dependencia |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Consultar estado de la solicitud de estado de cuenta
GET /api/public/v1/accounts/statements/{request_id}
Host: https://api-baas-sandbox.tilopay.com — requiere Authorization: Bearer <access_token>.
Devuelve el estado de la solicitud. Cuando es DONE, incluye una download_url firmada y temporal (48 h desde su generación) y expires_at. Cuando es ERROR, incluye un message genérico sin detalles internos. Un request_id desconocido o no autorizado devuelve 404.
Devuelve HTTP 200 con status PENDING, PROCESSING, DONE o ERROR. DONE incluye download_url, válida por 48 horas.
Parámetros
| Parámetro | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
X-Correlation-Id | header | string | no | Id de correlación opcional que enviás para trazar la solicitud de punta a punta.
Se devuelve como correlation_id en el sobre de respuesta. Si lo omitís,
la API genera uno y igual lo devuelve. |
request_id | path | string (uuid) | sí | — |
Respuesta 200
La solicitud se procesó correctamente.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
request_id | string (uuid) | sí | — |
status | string | sí | —Valores: PENDING, PROCESSING, DONE, ERROR |
download_url | string (uri) | no | URL de descarga firmada, presente con status DONE; válida por 48 horas desde su generación. |
expires_at | string (date-time) | no | Vencimiento de download_url (48 h desde su generación) |
message | string | no | Mensaje genérico de error cuando el estado es ERROR |
Ejemplo de respuesta
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {
"request_id": "5f3b2c1d-9e8a-4b7c-8d6e-5f4a3b2c1d0e",
"status": "DONE",
"download_url": "https://storage.example.com/statements/5f3b2c1d.pdf?signature=example",
"expires_at": "2026-01-17T12:00:00Z",
"message": null
}
}Respuestas de error
| HTTP | response_code | Descripción |
|---|---|---|
| 401 | UNAUTHORIZED | Unauthorized. Verify your session or credentials. |
| 403 | FORBIDDEN | You do not have permission to perform this action. |
| 404 | NOT_FOUND | The requested resource was not found. |
| 500 | INTERNAL_ERROR | An unexpected error occurred. Please try again later. |
| 503 | SERVICE_UNAVAILABLE | A required service is temporarily unavailable. Please try again later. |
Validación y códigos SINPE#
El código 1001 indica que la cuenta existe y está activa: no es un rechazo. 208 significa «Operación no autorizada entre las entidades participantes» y 209, «Pendientes de Cumplimiento».
La validación de cuentas tiene límites de tasa: al superarlos responde 429 (TOO_MANY_REQUESTS). Reintentá con espera exponencial.
Última verificación: 2026-10-22