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

# Get Access Token

> Exchange your business client credentials for a short-lived Bearer access token used to authenticate every other API call.

## Overview

`POST /auth/token` exchanges your business credentials (`client_id` and `client_key`) for a short-lived Bearer access token. Every other Cartevo endpoint requires this token in the `Authorization` header. There is no refresh-token endpoint — when a token expires, call this endpoint again.

## When to use it

* Once at the start of any worker, cron job, or HTTP request that needs to call Cartevo.
* Whenever a previous token is about to expire (recommended: refresh \~5 minutes before `expires_in` runs out).
* After a `401 Unauthorized` response from any other endpoint — refresh and retry once.

## Prerequisites

* An active Cartevo company account.
* A `client_id` / `client_key` pair, available from the dashboard at **Settings → API Keys**.

## Request

### Headers

| Name           | Required | Description                 |
| -------------- | -------- | --------------------------- |
| `Content-Type` | Yes      | Must be `application/json`. |

No `Authorization` header is required for this endpoint.

### Body

| Field        | Type   | Required | Description                                                               |
| ------------ | ------ | -------- | ------------------------------------------------------------------------- |
| `client_id`  | string | Yes      | Your business client identifier (begins with `client_`).                  |
| `client_key` | string | Yes      | Your business client secret. Treat as a password — never commit or share. |

```json theme={null}
{
  "client_id": "client_abcdef123456",
  "client_key": "key_xyz9876543210"
}
```

## Response

### 200 — Success

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

| Field          | Type    | Description                                                                                       |
| -------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `access_token` | string  | The JWT to send in the `Authorization: Bearer <token>` header on every other request.             |
| `token_type`   | string  | Always `"Bearer"`.                                                                                |
| `expires_in`   | integer | Token lifetime in seconds. Treat this value as authoritative — do not hard-code an expiry length. |

> **Note:** This endpoint returns the raw response shown above — it is **not** wrapped in the standard `{ success, statusCode, message, data }` envelope used elsewhere. See [API Conventions → Response envelope](/getting-started/conventions#response-envelope).

### Error responses

| Status | Trigger                                                                        | Recommended action                                                                                 |
| ------ | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `400`  | `client_id` or `client_key` missing or empty.                                  | Fix the request body.                                                                              |
| `401`  | `client_id` does not exist, `client_key` is wrong, or the account is disabled. | Verify credentials in the dashboard. Do not retry without changing credentials.                    |
| `429`  | Rate limit exceeded (default 10 req / 60 s per IP).                            | Back off, then retry. Cache the access token aggressively rather than minting a new one each call. |

```json theme={null}
{
  "message": "Invalid client credentials",
  "error": "Unauthorized",
  "statusCode": 401
}
```

## Token scope and lifetime

* **Scope:** Each token is bound to one company in one mode (preproduction or production). It cannot operate on another company's data, and it cannot cross modes.
* **Lifetime:** Determined by the deployment configuration. Treat `expires_in` as the only authoritative value. The current production default is short-lived (typically 1 hour); preproduction may differ.
* **Revocation:** There is no per-token revocation endpoint. Rotating the underlying `client_key` immediately invalidates all tokens minted from it.

## Code examples

```bash cURL theme={null}
curl -X POST https://api.cartevo.co/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "client_abcdef123456",
    "client_key": "key_xyz9876543210"
  }'
```

```js Node.js (axios) theme={null}
import axios from "axios";

const { data } = await axios.post(
  "https://api.cartevo.co/api/v1/auth/token",
  {
    client_id: process.env.CARTEVO_CLIENT_ID,
    client_key: process.env.CARTEVO_CLIENT_KEY,
  }
);

const accessToken = data.access_token;
const expiresAt = Date.now() + data.expires_in * 1000;
```

```python Python (requests) theme={null}
import os, requests

resp = requests.post(
    "https://api.cartevo.co/api/v1/auth/token",
    json={
        "client_id": os.environ["CARTEVO_CLIENT_ID"],
        "client_key": os.environ["CARTEVO_CLIENT_KEY"],
    },
    timeout=10,
)
resp.raise_for_status()
token = resp.json()["access_token"]
```

```php PHP (Guzzle) theme={null}
$client = new GuzzleHttp\Client();
$response = $client->post("https://api.cartevo.co/api/v1/auth/token", [
    "json" => [
        "client_id" => getenv("CARTEVO_CLIENT_ID"),
        "client_key" => getenv("CARTEVO_CLIENT_KEY"),
    ],
]);
$data = json_decode($response->getBody(), true);
$accessToken = $data["access_token"];
```

## Best practices

* **Cache the token** in your server for `expires_in - 300` seconds and reuse it across requests — do not mint a new token per call.
* **Refresh preemptively.** Schedule a refresh \~5 minutes before expiry so in-flight requests never hit a `401`.
* **Never expose `client_key` or the `access_token` to browsers, mobile apps, or any client-side code.** Always proxy through your server.
* **Rotate `client_key` immediately** if you suspect compromise. Existing tokens minted from it remain valid until expiry — there is no per-token revocation.
* **Use separate credentials per environment** (preproduction vs. production) so a leaked test key cannot touch live money.

## Webhooks fired

None. This endpoint is purely synchronous.

## Related

* [API Conventions → Authentication](/getting-started/conventions#authentication)
* [Environments](/getting-started/environment)


## OpenAPI

````yaml POST /auth/token
openapi: 3.1.0
info:
  title: Cartevo API
  description: Essential endpoints for wallets, transactions, customers and conversion.
  version: 1.0.0
servers:
  - url: https://api.cartevo.co/api/v1
security:
  - bearerAuth: []
paths:
  /auth/token:
    post:
      summary: >-
        To access the platform, you must first have an access token. Through
        this URL, you can obtain one — but be careful! The access token expires
        after 1 hour. After this period, you will need to re-authenticate.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                client_id:
                  type: string
                client_key:
                  type: string
              required:
                - client_key
                - client_id
      responses:
        '200':
          description: Authentication successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                    description: JWT access token for API authentication
                    example: >-
                      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlY2E1ZTk4Mi0wMGI1LTRhYTItYjcwOS03ZDVjZDY3M2U5NWMiLCJjb21wYW55SWQiOiJlY2E1ZTk4Mi0wMGI1LTRhYTItYjcwOS03ZDVjZDY3M2U5NWMiLCJjbGllbnRJZCI6ImNsaWVudF91dGtxNnV5MnB0IiwiaWF0IjoxNzYyMTY4MDIzLCJleHAiOjE3NjIxNzE2MjN9.hloSSSPJ2WFa31s41BL1nqhemuwHCJKC_wcwVupsBlU
                  token_type:
                    type: string
                    description: Type of token
                    example: Bearer
                  expires_in:
                    type: integer
                    description: Token expiration time in seconds
                    example: 3600
                required:
                  - access_token
                  - token_type
                  - expires_in
        '401':
          description: Unauthorized - invalid client_id or client_key
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    example: Invalid client credentials
                    type: string
                  error:
                    example: Unauthorized
                    type: string
                  statusCode:
                    example: 401
                    type: integer
                required:
                  - message
                  - error
                  - statusCode
      security: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````