Get a token
/oauth/tokenExchanges an authorization code for an access token and a refresh token, or a refresh token for a new pair. The access token works as a bearer token on Call the MCP server and on every other API endpoint, like an API key.
Scope | Heavy call | Long poll | CLI |
|---|---|---|---|
None, no key | No | No | None |
Guidance
It lives at the root of
https://api.chartnaut.com, not under/v1. The body is form-encoded, not JSON.An access token (
cn_oat_) lasts 1 hour. Before it runs out, or on a401from the API, swap the refresh token (cn_ort_) for a new pair. Each swap starts the refresh token's 30 days again.Every refresh returns a new refresh token and ends the old one. Store the new one straight away. Presenting an old refresh token again more than 30 seconds after the swap ends the whole connection, and the person has to approve your app again. Within those 30 seconds, a repeat gets another pair, so two requests racing each other are safe. A refresh does not end access tokens already issued; each works until its own hour is up.
An access token acts as the person, with the scopes they approved, and passes the same plan, request-budget and scope checks as an API key. On Free every call with it gets
403 plan_limit.Errors use OAuth's shape,
{"error": "...", "error_description": "..."}. Every answer carriesCache-Control: no-store.Limited to 60 a minute from one IP address, shared with Revoke a token.
Request body
application/x-www-form-urlencoded, up to 64 KB. client_id can also come as the user name in HTTP Basic auth.
authorization_code
Field | Type | Required | Description |
|---|---|---|---|
| string | Yes |
|
| string | Yes | From the redirect, within 60 seconds |
| string | Yes | The exact |
| string | Yes | The PKCE verifier behind the |
| string | Yes | The client the code was issued to |
| string | No |
|
refresh_token
Field | Type | Required | Description |
|---|---|---|---|
| string | Yes |
|
| string | Yes | The latest refresh token |
| string | No | Checked against the connection when sent |
| string | No | Space-separated. Only scopes already granted |
| string | No |
|
Response
200 with:
Field | Type | Description |
|---|---|---|
| string |
|
| string |
|
| integer | Seconds: 3600 |
| string |
|
| string | The granted scopes, space-separated |
Status codes
Status | Code | Meaning |
|---|---|---|
| - | A new access token and refresh token |
|
| A required field is missing, or the body is not form-encoded |
|
| The code or refresh token is wrong, expired, already used, or issued to another client; the |
|
|
|
|
|
|
|
| Not |
|
| Unknown |
|
| More than 60 in a minute from your IP address |
|
| Retry |
