# Banking API conventions

> Response envelope, correlation, safe retries, pagination and date format in the Banking API.

- kind: concept
- status: stable
- api_version: 1.0.0
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api-bancario/convenciones

Every Banking API operation shares the same response shape, the same pagination rules
and the same date format. Here we explain those shared rules.

## Response envelope [#envelope]

Every response, successful or not, travels in the same envelope:

```json
{
  "success": true,
  "http_status_code": 200,
  "response_code": "OK",
  "message": "The request was processed successfully.",
  "correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "data": {}
}
```

| Field | Type | Description |
|---|---|---|
| `success` | boolean | `true` on successful responses; `false` on errors. |
| `http_status_code` | integer | Repeats the HTTP status inside the body. |
| `response_code` | string | Code from the [`response_code` catalog](/en/developers/api-bancario/errores). |
| `message` | string | Human-readable response message. |
| `correlation_id` | string | Call identifier. |
| `data` | object | Operation payload. |

Error responses also carry `errors`, a detail object that may include arbitrary fields
such as `code`, `message` or `detail`.

Branch your logic on `response_code`, never on the `message` text.

## Correlation [#correlacion]

Send `X-Correlation-Id` on the request to propagate your own identifier; the value comes
back as `correlation_id` in the envelope. Keep it in your logs: it is what support uses
to trace a specific call.

## Safe retries [#reintentos]

Two operations accept the `Idempotency-Key` header:

```http
POST /api/public/v1/transactions/payments
POST /api/public/v1/accounts/statements
```

Resending the same key with the same body returns the original result instead of
creating a second record, so a network timeout can be retried without duplicating. If
you reuse a key with a different body, the response is `409` with
`response_code: IDEMPOTENCY_CONFLICT`.

Generate one key per business intent (for example a UUID per order), not one per retry.
Every other operation is a read and can be repeated with no additional effects.

## Pagination [#paginacion]

The API uses two schemes depending on the resource.

**Cursor, on the payment list.** `GET /api/public/v1/transactions/payments` accepts
`limit` (default 20, maximum 100) and `cursor`. The response carries
`pagination.next_cursor`: pass it as `cursor` on the next request. When it is empty or
omitted, there are no more pages.

**Offset, on accounts.** `GET /api/public/v1/accounts` and
`GET /api/public/v1/accounts/balances` accept `limit` (1 to 100) and `offset` (from 0),
and return `pagination` with `limit`, `offset` and `total`.

## Dates and amounts [#formatos]

Date parameters and fields use RFC 3339, for example `2026-09-02T15:04:05Z`. The
`date_from` and `date_to` filters on the payment list follow that same format.

## Host health and documentation [#host]

The host itself exposes three service routes:

```http
GET /api/public/v1/healthz
GET /openapi.yaml
GET /docs
```

`healthz` is for availability checks, `openapi.yaml` returns the OpenAPI definition and `/docs` the
interactive documentation. We also publish it in this portal at
[openapi.json](/developers/api-bancario/openapi.json) and
[openapi.yaml](/developers/api-bancario/openapi.yaml).

## Public identifier [#public-id]

`public_id` is a number in webhooks and text in REST; it is the same identifier. **Always treat it as text.**

## Rate limits [#limites-de-tasa]

They currently apply to authentication and account validation. Exceeding them returns `429` (`TOO_MANY_REQUESTS`); retry with exponential backoff.
