---
title: "Exchange code for tokens"
description: "Exchange an authorization code for an access token and a refresh token."
source: https://developers.qashio.com/v2/reference/post-oauth2-token/
---

# Exchange code for tokens

`POST /oauth2/token`

Does not require a Bearer access token.

**Purpose.** Exchange an authorization code for an access token and a refresh token.

**Description.** The token endpoint, called with `grant_type=authorization_code`. Send the code
returned by the Qashio login flow, together with the `redirect_uri` it was issued against, and
Qashio returns an access token and a refresh token. To rotate an expiring token, call the same URL
with `grant_type=refresh_token`: see [Refresh access token](#post-oauth2tokenrefreshtoken).

Your `client_id` and `client_secret` are required. These are confidential client credentials and
must never be used from a browser or mobile app.

Authorization codes are single use and expire after ten minutes. Exchange one as soon as it
arrives.

This endpoint does not use the standard response envelope.

**Input (body, `application/json`).**

| Field | Type | Description |
| --- | --- | --- |
| `grant_type` | string | Always `authorization_code`. Required |
| `client_id` | string | Your client identifier. Required |
| `client_secret` | string | Your client secret. Required |
| `code` | string | The authorization code. Required |
| `redirect_uri` | string | The redirect URI used to obtain the code; must match exactly. Required |

```json
{
  "grant_type": "authorization_code",
  "code": "AUTHORIZATION_CODE",
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "redirect_uri": "https://app.example.com/callback"
}
```

**Output.** `200` with the token set.

| Field | Type | Description |
| --- | --- | --- |
| `access_token` | string | Bearer token to send on API requests |
| `token_type` | string | Always `Bearer` |
| `refresh_token` | string | Send this to [Refresh access token](#post-oauth2tokenrefreshtoken) before the access token expires |
| `scope` | string | Space-separated scopes granted, e.g. `cards:read cards:write transactions:read` |

**Errors.**

| Status | Cause |
| --- | --- |
| `400` | Missing or unsupported parameters, or `redirect_uri` does not match the one used at authorization |
| `401` | Authorization code invalid, expired or already used; invalid client credentials |

### Request body

```json
{
  "grant_type": "authorization_code",
  "client_id": "qc_xxx",
  "client_secret": "••••",
  "code": "auth-code",
  "redirect_uri": "https://app.acme.com/callback"
}
```

### Example request

```bash
curl -X POST 'https://api.qashio.com/oauth2/token' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "redirect_uri": "https://app.example.com/callback"
  }'
```

### Example response (200)

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJDTzl5eTBtZnpxaHh0eGtrayIsImNvbXBhbnlfaWQiOiJDTzl5eTBtZnpxaHh0eGtrayIsInNjb3BlIjoiZXJwIiwiaWF0IjoxNzU3NDk3OTgwLCJleHAiOjE3NTc0OTg4ODB9...",
  "token_type": "Bearer",
  "refresh_token": "rt_8f3a1c9e2b7d4a6c0e5f9b1d3a7c2e4f8a0b1c2d...",
  "scope": "wallet:read cards:read cards:write transactions:read transactions:write users:read..."
}
```

### Errors

- `400` Invalid grant / missing client credentials
- `401` Invalid client, or authorization code invalid, expired or already used
