Banking API accounts

API 1.0.0

An MCP tool wraps this operation: Banking tools.

The Accounts group covers the account as a resource: validate a destination account before transferring, list accessible accounts, check balances and request statements.

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}

Resource rules#

Scope. The listing returns only the accounts the token authorizes; tenant_id and owner_id are never sent as parameters.

Validate first. Validate the destination account before creating a payment: the operation confirms the account exists and is eligible, and returns the holder data the service exposes.

Asynchronous statements. POST /api/public/v1/accounts/statements accepts Idempotency-Key and always returns HTTP 202 (ACCEPTED) with request_id and status: PENDING; generation is asynchronous. Poll GET /api/public/v1/accounts/statements/{request_id}: it returns HTTP 200 with status PENDING, PROCESSING, DONE or ERROR. DONE includes download_url, valid for 48 hours. See safe retries.

Pagination. GET /api/public/v1/accounts and GET /api/public/v1/accounts/balances use limit and offset, and return pagination with limit, offset and total.

Operations#

Validate external account for a payment method

POST /api/public/v1/accounts/validate

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>.

Validates a counterparty account (IBAN or phone) via the SINPE provider for the given payment method. Does not validate internal platform accounts. When valid, data.holder.id_type uses the same identification catalog keys as identification.type in POST /payments (e.g. cedula, juridica, dimex).

SINPE_MOVIL field availability (expected, stable)

For payment_method_code = SINPE_MOVIL, the SINPE Móvil wallet query does not return identification type or institution name. A successful validation may therefore return:

  • data.holder.id_type = unknown
  • data.financial_institution.entity_name = "" (empty string)

This is expected, stable behavior, not a mapping bug or a transient provider error. PIN (account query in SINPE) does populate both fields.

Integrators must not report these values as defects, and must not assume that holder.id_type or financial_institution.entity_name are always populated when is_valid is true.

SINPE rejection codes (data.rejection)

When is_valid is false, data.rejection explains why (see the rejected example on the 200 response below). rejection.code is one of a fixed set of normalized semantics (see the value table below). Most rows in the table below do NOT get a distinct `code` — only a subset of reason_code values has a dedicated semantic; every other reason_code, even one listed below with a specific message, returns code = SINPE_REJECTED (e.g. reason_code = 21 "fondos insuficientes" still returns SINPE_REJECTED). This same object and catalog is also used by the payment.failed webhook's rejection field. A reason_code not listed here at all still produces a response — message falls back to a generic text and code falls back to SINPE_REJECTED.

Account / profile / limits

CodeMessage
21Cuenta Cliente con fondos insuficientes
22Cuenta Cliente no admite créditos
23Cuenta Cliente cerrada
24Cuenta Cliente inactiva
25Cuenta Cliente no admite débitos
26Cuenta Cliente no es de fondos
27Moneda de la Cuenta Cliente no corresponde
28Cuenta cliente no existe
29Cuenta Cliente no registrada en el SINPE
30Cuenta Cliente no habilitada para el servicio
31Cuenta Cliente bloqueada
32Id cliente destino no coincide con registrado en la entidad
33Nombre del cliente destino no coincide con el registrado en la entidad
34Cuenta Cliente en proceso de cierre
35Cuenta Cliente embargada
36Cuenta Cliente con retención judicial
37Cuenta de expediente simplificado no permite el monto indicado
38Límite transaccional de la Cuenta Cliente excedido
39Cuenta Cliente incorrecta
40IBAN de la cuenta destino inválido
41IBAN de la cuenta origen inválido
42Tipo de cuenta no permite la transacción
43Cuenta Cliente no pertenece a la entidad indicada
44Producto de la cuenta no admite el servicio
45Cuenta Cliente en estado de cancelación
46Cuenta Cliente restringida por política de la entidad
47Cuenta Cliente no permite pagos inmediatos
48Cuenta Cliente no permite SINPE Móvil
49Titular de la cuenta destino fallecido
50Cuenta Cliente consolidada o migrada
51Identificación del cliente origen no coincide
52Identificación del cliente destino inválida
53Cliente destino no autorizado para recibir el pago
54Cliente origen no autorizado para enviar el pago
55Perfil del cliente origen no permite la transacción
56Monto inferior al mínimo permitido
57Monto superior al máximo permitido
58Cantidad de transacciones diarias excedida
59Cantidad de transacciones mensuales excedida
60Límite acumulado diario excedido
61Límite acumulado mensual excedido
62Comisión no pudo ser aplicada
63Tipo de cambio no disponible
64Transacción rechazada por control de lavado de dinero
65Transacción rechazada por listas de control
66Transacción en revisión de cumplimiento
67Documento de respaldo requerido no presente
68Firma o autenticación inválida
69Token o segundo factor inválido
70Sesión de usuario expirada
71Usuario no autorizado para el canal
72Dispositivo no registrado
73Geolocalización no permitida
74Operación no soportada en la moneda indicada
75Operación no soportada para el tipo de cliente
76Problemas de comunicación
77Tiempo de espera agotado en la entidad origen
78Tiempo de espera agotado en el SINPE
79Error interno de la entidad origen
80Error interno de la entidad destino
81Entidad origen no disponible
82Entidad destino no encontrada
83Problemas en la respuesta del destino
84Respuesta de la entidad origen incorrecta
85Mensaje con formato electrónico inválido
86Versión del estándar electrónico no soportada
87Campo obligatorio no informado
88Campo con valor fuera de catálogo
89Checksum o integridad del mensaje inválida
90Referencia SINPE duplicada
91Moneda no corresponde
92Transacción no autorizada por entidad destino
93Transacción no autorizada por cliente destino
94Transacción no autorizada por entidad origen
95Transacción no autorizada por cliente origen
96Reverso no permitido para el estado de la transacción
97Reverso ya aplicado
98Confirmación no permitida para el estado de la transacción
99Liquidación no permitida para el estado de la transacción
100Entidad Destino no disponible para procesar en tiempo real
101Entidad origen no disponible para procesar en tiempo real
102Servicio PIN no habilitado para la entidad destino
103Servicio PIN no habilitado para la entidad origen
104Código de entidad destino inválido
105Código de entidad origen inválido
106Código de país de la entidad destino inválido
107Código de país de la entidad origen inválido
108Número de referencia interna inválido
109Número de referencia SINPE inválido
110Transacción no se encuentra en un estado que permita la consulta

Settlement with destination institution

CodeMessage
201Tiempo respuesta excedido por la entidad destino
202Respuesta de la entidad destino incorrecta según el estándar electrónico
203Se recibió una excepción de la entidad destino
204Error de comunicación con la entidad destino
205Falló procesamiento en el SINPE
206Transacción no autorizada por cliente destino
207Perfil transaccional del cliente destino no permite recibir el pago
208Operación no autorizada entre las entidades participantes
209Pendientes de Cumplimiento
210Conciliación de la transacción no fue posible

Identification

CodeMessage
801Identificación inválida
802Identificación del cliente origen no encontrada
803Identificación del cliente destino no encontrada
804Identificación no vigente
805Identificación vencida
806Identificación no corresponde al tipo indicado
807Tipo de identificación inválido
808País de la identificación no soportado
809Identificación de menor de edad no permitida
810Identificación de persona jurídica no permitida para el servicio

Format validation / Core Banking

CodeMessage
1002El Id de cliente destino no cumple con el formato esperado por el SINPE
1003El Id de cliente origen no fue informado
1004El Id de cliente origen no cumple con el formato esperado por el SINPE
1005Monto con formato inválido
1006Moneda con formato inválido
1007Problemas de comunicación con el Core Bancario
1008Core Bancario no disponible
1009El valor para el campo no puede ser nulo o infringir su longitud mínima o máxima
1010El valor para el campo no corresponde al tipo de dato esperado
1011El valor para el campo no corresponde al catálogo permitido
1012Fecha con formato inválido
1013Hora con formato inválido
1014Número de referencia con formato inválido
1015IBAN con formato inválido

Channel / identification type

CodeMessage
1040Canal no informado
1041Canal inválido
1042Canal no corresponde
1043Canal no habilitado para la entidad
1044Canal no habilitado para el servicio
1045El formato de la identificación es inválido
1046Tipo de identificación no informado
1080Tipo de identificación no corresponde al cliente origen
1081Tipo de identificación no corresponde al cliente destino
1082Tipo de identificación no vigente
1083Tipo de identificación no soportado por el servicio
1084Tipo de identificación inválido
1085Tipo de identificación no soportado por la entidad

SINPE Móvil (wallet)

CodeMessage
15300El número de teléfono origen indicado es inválido
15301El número de teléfono origen no tiene activo el Servicio Monedero
15302El número de teléfono destino indicado es inválido
15303El número de teléfono destino no está registrado en el padrón móvil del BCCR
15304No es posible inactivar el monedero indicado pues no existe
15305El número de teléfono indicado ya se encuentra activo como monedero en el padrón local

`rejection.code` values

ValueMeaning
ACCOUNT_CLOSEDAccount closed
ACCOUNT_NOT_FOUNDAccount not found
ACCOUNT_BLOCKEDAccount blocked
INVALID_ACCOUNTInvalid account
IDENT_MISMATCHIdentification does not match
IDENT_TYPE_INVALIDInvalid identification type
INVALID_ID_FORMATInvalid identification format
VALIDATION_ERRORValidation error
CURRENCY_MISMATCHCurrency mismatch
NOT_AUTHORIZED_BY_RECIPIENTNot authorized by the recipient
PROFILE_NOT_ALLOWEDProfile not allowed
CHANNEL_NOT_RECOGNIZEDChannel not recognized
COMMUNICATION_ERRORCommunication error
RETRY_LATERRetry later
WALLET_PHONE_ORIGIN_INVALIDOrigin phone invalid (SINPE Móvil)
WALLET_PHONE_ORIGIN_NOT_ENABLEDOrigin phone without wallet service
WALLET_PHONE_DEST_INVALIDDestination phone invalid (SINPE Móvil)
WALLET_PHONE_NOT_REGISTERED_BCCRPhone not registered in the BCCR mobile registry
WALLET_NOT_FOUNDWallet not found
WALLET_PHONE_ALREADY_ACTIVEPhone already has an active wallet
PHONE_NOT_REGISTEREDPhone not registered
SINPE_REJECTEDRejected by SINPE (generic fallback)

Rate limits currently apply to authentication and account validation. Exceeding them returns HTTP 429 (TOO_MANY_REQUESTS). Retry with exponential backoff.

SINPE code 1001 means the account exists and is active; it is a valid result, not a rejection reason.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.

Request body

FieldTypeRequiredDescription
payment_method_codestringyesPayment method used to route validation (PIN for external IBAN, SINPE_MOVIL for phone wallet).Values: PIN, SINPE_MOVIL
accountobjectyes—
account.typestringyes—Values: IBAN, PHONE
account.valuestringyes—

Request example

pin

{
  "payment_method_code": "PIN",
  "account": {
    "type": "IBAN",
    "value": "CR16010400000000000031"
  }
}

sinpe_movil

{
  "payment_method_code": "SINPE_MOVIL",
  "account": {
    "type": "PHONE",
    "value": "88887777"
  }
}

Response 200

The request was processed successfully.

FieldTypeRequiredDescription
is_validbooleanno—
accountobjectno—
account.typestringno—
account.valuestringno—
account.currencystringno—
account.product_namestringno—
holderobjectnoAccount holder when validation succeeds. id_type matches PaymentIdentification.type (same catalog as POST /payments). For SINPE_MOVIL, id_type may be unknown because the wallet operation does not return an identification type. That is expected and stable; do not treat it as a bug.Can be null.
holder.namestringno—
holder.id_typestringnoIdentification catalog key (lowercase), e.g. cedula, juridica, dimex. Same vocabulary as identification.type on payment create. PIN: mapped from the provider account query (confirmed by the provider). SINPE_MOVIL: the wallet query does not return an identification type, so this field may be `unknown`. That is expected, stable behavior due to available provider data — not a mapping bug or a transient error. Do not assume a confirmed type is always present.Values: cedula, dimex, gobierno, juridica, institucion_autonoma, didi, pasaporte, unknown
holder.id_numberstringno—
financial_institutionobjectnoCounterparty institution when validation succeeds. PIN fills entity_name from the SINPE account query. SINPE_MOVIL only receives an entity code from the wallet query; it does not return the institution name, so entity_name may be `""`. That is expected, stable behavior — not a transient error. Do not assume entity_name is always populated.Can be null.
financial_institution.country_codestringno—
financial_institution.entity_codestringno—
financial_institution.entity_namestringnoHuman-readable institution name. PIN: populated from the provider account-info operation. SINPE_MOVIL: may be "" because the wallet query does not expose the name. Expected limitation, not an error.
rejectionobjectnoPresent when is_valid is false and the provider rejected the account. null when is_valid is true.Can be null.
rejection.codestringyesNormalized platform semantic derived from reason_code. Only a subset of reason_code values (see the catalog in the description of POST /accounts/validate and of the payment.failed webhook contract endpoint) has a distinct entry here — for any other numeric reason_code, code is SINPE_REJECTED even when message is specific (e.g. reason_code = 21 "fondos insuficientes" still returns code = SINPE_REJECTED, it has no dedicated semantic). PHONE_NOT_REGISTERED is the fallback when reason_code is non-numeric (SINPE_MOVIL wallet flow).Values: 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_codestringyesRaw Motivo/code returned by SINPE. See the endpoint description of POST /accounts/validate for the full code catalog (shared by this object wherever it appears, including the payment.failed webhook). A code not listed there still produces a response — message falls back to a generic text and code falls back to SINPE_REJECTED.
rejection.messagestringyesDescriptive Motivo text; prefers provider Detalle when present.
providerobjectno—
provider.operationstringno—
provider.correlation_idstringno—Can be null.
provider.occurred_atstring (date-time)no—Can be null.

Response example — 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
  }
}

Response example — 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"
    }
  }
}

Error responses

HTTPresponse_codeDescription
400INVALID_REQUESTInvalid request. Check the required fields and try again.
400INVALID_ACCOUNT_TYPEUnsupported or invalid account type.
400INVALID_ACCOUNT_FORMATInvalid account format.
400INVALID_PAYMENT_METHODInvalid or unsupported payment method.
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
403ACCOUNT_ACCESS_DENIEDThe actor does not have access to the requested account.
422UNPROCESSABLE_ENTITYThe request is well-formed but cannot be processed due to business rules.
429TOO_MANY_REQUESTSToo many requests. Please retry after a short delay.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
502PROVIDER_ERRORUnable to complete the request with the payment provider. Please try again later.

List balances for accessible accounts

GET /api/public/v1/accounts/balances

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>.

Returns paginated account balances (account, amounts, as_of). This endpoint checks the current balance in real time and may respond more slowly than GET /accounts. For account attributes without amounts, use GET /accounts.

Optional filters use the public account identification standard: type + value (identifier scheme + value). type is not the internal account classification.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.
limitqueryintegerno—
offsetqueryintegerno—
typequerystringnoOptional filter by account identifier scheme (e.g. IBAN). Not the internal account classification.
valuequerystringnoOptional filter by account identifier value (partial match supported for list endpoints).

Response 200

The request was processed successfully.

FieldTypeRequiredDescription
itemsarray<object>no—
items[].accountobjectyes—
items[].account.typestringyesAccount identifier scheme (e.g. IBAN, PHONE). Not the internal account classification (e.g. operational).Values: IBAN, PHONE
items[].account.valuestringyesWhen type is PHONE (SINPE Móvil): 8 local digits, no country prefix (e.g. "88887777").
items[].account.currencystringnoOptional account currency in response payloads.
items[].amountsobjectyesLedger balances as decimal strings with 2 fraction digits (same display scale as public payment amounts). Prefer string over JSON number for financial amounts.
items[].amounts.availablestringno—
items[].amounts.postedstringno—
items[].amounts.inbound_in_transitstringno—
items[].amounts.outbound_in_transitstringno—
items[].as_ofstring (date-time)yesLedger timestamp when known (RFC 3339 UTC, second precision, Z); null when not available.Can be null.
paginationobjectno—
pagination.limitintegerno—
pagination.offsetintegerno—
pagination.totalintegerno—

Response example

{
  "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
    }
  }
}

Error responses

HTTPresponse_codeDescription
400INVALID_REQUESTInvalid request. Check the required fields and try again.
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
403ACCOUNT_ACCESS_DENIEDThe actor does not have access to the requested account.
404NOT_FOUNDThe requested resource was not found.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
502—Dependency error
503SERVICE_UNAVAILABLEA required service is temporarily unavailable. Please try again later.

List accessible accounts without balances

GET /api/public/v1/accounts

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>.

Returns paginated accessible accounts without querying current balances. Each item is account attributes only (account.type, account.value, account.currency). amounts and as_of are not included; use GET /accounts/balances or POST /accounts/balance.

Optional filters use the public account identification standard: type + value (identifier scheme + value). type is not the internal account classification.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.
limitqueryintegerno—
offsetqueryintegerno—
typequerystringnoOptional filter by account identifier scheme (e.g. IBAN). Not the internal account classification.
valuequerystringnoOptional filter by account identifier value (partial match supported for list endpoints).

Response 200

The request was processed successfully.

FieldTypeRequiredDescription
itemsarray<object>no—
items[].accountobjectyes—
items[].account.typestringyesAccount identifier scheme (e.g. IBAN, PHONE). Not the internal account classification (e.g. operational).Values: IBAN, PHONE
items[].account.valuestringyesWhen type is PHONE (SINPE Móvil): 8 local digits, no country prefix (e.g. "88887777").
items[].account.currencystringnoOptional account currency in response payloads.
paginationobjectno—
pagination.limitintegerno—
pagination.offsetintegerno—
pagination.totalintegerno—

Response example

{
  "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
    }
  }
}

Error responses

HTTPresponse_codeDescription
400INVALID_REQUESTInvalid request. Check the required fields and try again.
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
404NOT_FOUNDThe requested resource was not found.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
502—Dependency error
503SERVICE_UNAVAILABLEA required service is temporarily unavailable. Please try again later.

Get account balance

POST /api/public/v1/accounts/balance

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>.

Returns a single account snapshot with amounts and as_of. For account attributes without balances, use GET /accounts.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.

Request body

FieldTypeRequiredDescription
accountobjectyes—
account.typestringyesAccount identifier scheme. Only IBAN is supported here. This is not the internal account classification (e.g. operational).Values: IBAN
account.valuestringyesIBAN (spaces allowed; normalized server-side)

Response 200

The request was processed successfully.

FieldTypeRequiredDescription
accountobjectyes—
account.typestringyesAccount identifier scheme (e.g. IBAN, PHONE). Not the internal account classification (e.g. operational).Values: IBAN, PHONE
account.valuestringyesWhen type is PHONE (SINPE Móvil): 8 local digits, no country prefix (e.g. "88887777").
account.currencystringnoOptional account currency in response payloads.
amountsobjectyesLedger balances as decimal strings with 2 fraction digits (same display scale as public payment amounts). Prefer string over JSON number for financial amounts.
amounts.availablestringno—
amounts.postedstringno—
amounts.inbound_in_transitstringno—
amounts.outbound_in_transitstringno—
as_ofstring (date-time)yesLedger timestamp when known (RFC 3339 UTC, second precision, Z); null when not available.Can be null.

Response example

{
  "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"
  }
}

Error responses

HTTPresponse_codeDescription
400INVALID_REQUESTInvalid request. Check the required fields and try again.
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
403ACCOUNT_ACCESS_DENIEDThe actor does not have access to the requested account.
404ACCOUNT_NOT_FOUNDAccount not found.
422ACCOUNT_NOT_CONFIGUREDThis account is not mapped in the system. Please contact support to configure it correctly.
422UNPROCESSABLE_ENTITYThe request is well-formed but cannot be processed due to business rules.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
502PROVIDER_ERRORUnable to complete the request with the payment provider. Please try again later.
503SERVICE_UNAVAILABLEA required service is temporarily unavailable. Please try again later.

Request account statement generation

POST /api/public/v1/accounts/statements

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>. Accepts Idempotency-Key.

Creates an asynchronous account statement request for a date range (max 60 days). Identify the account with account.type + account.value (identifier scheme + value, e.g. IBAN). This follows the public account identification standard. account.type is not the internal account classification. Returns {request_id, status: PENDING} immediately. Poll GET /accounts/statements/{request_id} for status; when DONE, the response includes a signed download_url.

Always returns HTTP 202 (ACCEPTED) with request_id and status PENDING. Generation is asynchronous. Poll GET /api/public/v1/accounts/statements/{request_id}: HTTP 200 with PENDING, PROCESSING, DONE or ERROR. DONE includes download_url, valid for 48 hours.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.
Idempotency-Keyheaderstringno—

Request body

FieldTypeRequiredDescription
accountobjectyes—
account.typestringyesAccount identifier scheme. Only IBAN is supported here. This is not the internal account classification (e.g. operational).Values: IBAN
account.valuestringyesIBAN (spaces allowed; normalized server-side)
date_fromstring (date-time)yesRFC 3339 timestamp accepted on requests. UTC Z or a numeric offset is allowed. Optional fractional seconds are accepted and truncated to seconds.
date_tostring (date-time)yesRFC 3339 (max 60 days after date_from)
notify_emailbooleanno—

Response 202

Statement request accepted for asynchronous generation.

response_code: ACCEPTED

FieldTypeRequiredDescription
request_idstring (uuid)yes—
statusstringyes—Values: PENDING

Response example

{
  "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"
  }
}

Error responses

HTTPresponse_codeDescription
400INVALID_REQUESTInvalid request. Check the required fields and try again.
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
403ACCOUNT_ACCESS_DENIEDThe actor does not have access to the requested account.
404NOT_FOUNDThe requested resource was not found.
409IDEMPOTENCY_CONFLICTIdempotency conflict: the same Idempotency-Key was reused with a different request body, or a previous request is still in progress.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
502—Dependency error
503SERVICE_UNAVAILABLEA required service is temporarily unavailable. Please try again later.

Get account statement request status

GET /api/public/v1/accounts/statements/{request_id}

Host: https://api-baas-sandbox.tilopay.com — requires Authorization: Bearer <access_token>.

Returns request status. When DONE, includes a signed, time-limited download_url (48h from generation) and expires_at. When ERROR, includes a generic message without internal details. Unknown or unauthorized request_id returns 404.

Returns HTTP 200 with status PENDING, PROCESSING, DONE or ERROR. DONE includes download_url, valid for 48 hours.

Parameters

ParameterInTypeRequiredDescription
X-Correlation-IdheaderstringnoOptional client-supplied correlation id for end-to-end tracing. Echoed back as correlation_id in the response envelope. If omitted, the API generates one and still returns it.
request_idpathstring (uuid)yes—

Response 200

The request was processed successfully.

FieldTypeRequiredDescription
request_idstring (uuid)yes—
statusstringyes—Values: PENDING, PROCESSING, DONE, ERROR
download_urlstring (uri)noSigned download URL, present when status is DONE; valid for 48 hours from generation.
expires_atstring (date-time)noExpiration of download_url (48h from generation)
messagestringnoGeneric error message when status is ERROR

Response example

{
  "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
  }
}

Error responses

HTTPresponse_codeDescription
401UNAUTHORIZEDUnauthorized. Verify your session or credentials.
403FORBIDDENYou do not have permission to perform this action.
404NOT_FOUNDThe requested resource was not found.
500INTERNAL_ERRORAn unexpected error occurred. Please try again later.
503SERVICE_UNAVAILABLEA required service is temporarily unavailable. Please try again later.

Validation and SINPE codes#

Code 1001 means the account exists and is active: it is not a rejection. 208 means “Operation not authorized between the participating institutions” and 209, “Pending compliance”.

Account validation is rate-limited: exceeding the limit returns 429 (TOO_MANY_REQUESTS). Retry with exponential backoff.

Last verified: 2026-10-22

View as raw Markdown