> ## Documentation Index
> Fetch the complete documentation index at: https://learn.biq.li/llms.txt
> Use this file to discover all available pages before exploring further.

# Exchange or refresh a token

> Issue workspace-scoped OAuth access tokens and rotate refresh tokens.

```http theme={null}
POST https://biq.li/api/v1/oauth/token
Content-Type: application/x-www-form-urlencoded
```

The token endpoint accepts authorization-code and refresh-token grants. Token
responses include `Cache-Control: no-store` and `Pragma: no-cache`.

## Exchange an authorization code

| Field | Required | Description |
| :- | :- | :- |
| `grant_type` | Yes | `authorization_code` |
| `client_id` | Yes | OAuth client ID |
| `client_secret` | Confidential clients | Current client secret |
| `code` | Yes | Unused authorization code returned to the callback |
| `redirect_uri` | Yes | Exact callback URL used during authorization |
| `code_verifier` | Public PKCE clients | Original verifier that produced the S256 challenge |

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/oauth/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=YOUR_CLIENT_ID' \
  --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
  --data-urlencode 'redirect_uri=https://app.example.com/oauth/callback' \
  --data-urlencode 'code=AUTHORIZATION_CODE'
```

## Refresh an access token

| Field | Required | Description |
| :- | :- | :- |
| `grant_type` | Yes | `refresh_token` |
| `client_id` | Yes | OAuth client ID |
| `client_secret` | Confidential clients | Current client secret |
| `refresh_token` | Yes | Current unused refresh token |

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/oauth/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'client_id=YOUR_CLIENT_ID' \
  --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
  --data-urlencode 'refresh_token=YOUR_REFRESH_TOKEN'
```

## Response

```json theme={null}
{
  "token_type": "Bearer",
  "access_token": "...",
  "expires_in": 3600,
  "refresh_expires_in": 31536000,
  "refresh_token": "...",
  "scope": "workspace.read links.view"
}
```

Every successful refresh rotates both tokens. Persist the new values atomically
before another worker can refresh the same installation. Reusing the previous
refresh token revokes the entire token family and its active access token.

Authorization codes and rotated refresh tokens are not retryable credentials.
Start a new authorization after `invalid_grant` unless you can prove another
worker completed the request and stored its response.
