# Banking API authentication

> Login, token exchange and Bearer JWT usage in Tilopay's Banking API.

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

The Banking API uses a two-step flow: first you authenticate the customer with email and
password, then you exchange the resulting token for a JWT access token that signs every
other call.

The three endpoints in the `Auth` group are the only ones that carry **no**
`Authorization` header. Every other endpoint requires
`Authorization: Bearer <access_token>`.

## Step 1 — Login [#login]

```http
POST /api/public/v1/auth/login
```

Required body: `email` (email format) and `password`.

```json
{
  "email": "operations@merchant.com",
  "password": "••••••••"
}
```

The `200` response returns in `data`:

| Field | Type | Description |
|---|---|---|
| `gidp_id_token` | string | Identity token for step 2, valid for 1 hour and only usable for the exchange. |
| `assignments` | array | Available customer contexts. |

Each `assignments` item carries `assignment_id`, `owner_type`, `owner_id`, `tenant_id`,
`tenant_code`, `country_code`, `role`, `roles` and `status`. Pick the `assignment_id` of
the context you will operate with.

## Step 2 — Token exchange [#exchange]

```http
POST /api/public/v1/auth/token/exchange
```

Required body: `gidp_id_token` (from step 1) and `assignment_id` (the chosen context).

```json
{
  "gidp_id_token": "eyJhbGciOi...",
  "assignment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

The `200` response returns in `data`:

| Field | Type | Description |
|---|---|---|
| `token` | string | JWT access token. |
| `expires_in` | integer | Access-token lifetime in seconds; read `expires_in`, do not assume a fixed value. |
| `claims` | object | Resolved token context. |

`claims` includes `sub`, `subject_kind`, `user_type`, `tenant_id`, `owner_type`,
`owner_id`, `roles`, `scopes`, `country_code`, `locale`, `channel`, `idp`, `idp_sub` and
`idempotency_key`.

`claims.idempotency_key` is reserved and always empty: ignore it. Idempotency uses the `Idempotency-Key` header.

## Step 3 — Use the Bearer token [#bearer]

The declared security scheme is `BearerAuth`: HTTP bearer with JWT format.

```http
Authorization: Bearer <access_token>
```

Context travels **inside** the token: business operations do not take `tenant_id`,
`owner_id` or `owner_type` as parameters. The token alone scopes which accounts and
payments you can reach.

When the token is absent, expired or invalid, the response is `401` with
`response_code: UNAUTHORIZED`. If the token is valid but the context does not authorize
the resource, it is `403` with `FORBIDDEN`. There is no refresh token: repeat login and exchange (steps 1 and 2) before expiration, recommended at **80% of `expires_in`**, or after receiving a `401`.

## Passwords [#password]

```http
POST /api/public/v1/auth/request-set-password
```

Starts the set/reset password process for the given email. It requires no prior
authentication and always responds the same way whether or not the account exists, so it
never reveals if an email is registered.

```json
{
  "email": "operations@merchant.com"
}
```

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

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

## Sandbox access [#sandbox]

Tilopay issues sandbox credentials on request; coordinate access with your merchant contact at Tilopay.
