> ## Documentation Index
> Fetch the complete documentation index at: https://docs.telemax.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> JWT Bearer tokens via API key — form-encoded token endpoint and claims.

The External API uses **JWT Bearer tokens** (HS256 symmetric signing). All business routes expect:

```http theme={null}
Authorization: Bearer <access_token>
```

There is **no** API-key-in-header pattern for data routes: you exchange the API key for a JWT using the token endpoint, then call `/v2/api/*` with the Bearer token.

## How to obtain credentials

| Method      | When to use                                                          |
| ----------- | -------------------------------------------------------------------- |
| **API key** | Your company-issued 43-character API key from the Telemax dashboard. |

Credentials are **not** passed on every data request—only the JWT.

## Token endpoint

### API key login

[`POST /v2/api/authentication/token/api-key`](/v2/api-reference/post-authentication-token-api-key)

* **Content-Type**: `application/x-www-form-urlencoded`
* **Body field**: `apiKey` (string)

## Successful token response

JSON fields (see `JwtTokenResponse`):

| Field          | Type   | Description                     |
| -------------- | ------ | ------------------------------- |
| `access_token` | string | JWT for `Authorization: Bearer` |
| `token_type`   | string | Always `bearer`                 |
| `expires_in`   | number | Lifetime in **seconds**         |

## Token expiry and refresh

* Default token lifetime: **\~24 hours** (`expires_in: 86399` seconds).
* The actual lifetime may vary if the server's `JWT:TokenExpiryTime` setting is configured (minimum 5 minutes).
* There is **no refresh endpoint** — when a token expires, re-authenticate using [`POST /v2/api/authentication/token/api-key`](/v2/api-reference/post-authentication-token-api-key).
* **Recommendation:** Re-authenticate **5 minutes before** the token expires rather than waiting for a 401 response. See [Token caching strategy](#token-caching-strategy) below.

## Token caching strategy

<Warning>
  Do not request a new token on every API call. Each token is valid for \~24 hours. Requesting tokens unnecessarily adds latency and risks hitting future rate limits.
</Warning>

Recommended approach:

1. On startup, request a token and store it in memory with its expiry time (`Date.now() + expires_in * 1000`).
2. Before each API call, check if the token expires within the next **5 minutes**.
3. If yes, re-authenticate and replace the cached token.
4. If no, use the cached token.

**Example (JavaScript):**

```javascript theme={null}
let cachedToken = null;
let tokenExpiresAt = 0;

async function getToken() {
  if (cachedToken && Date.now() < tokenExpiresAt - 5 * 60 * 1000) {
    return cachedToken;
  }
  const res = await fetch('https://api.telemax.com.au/v2/api/authentication/token/api-key', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({ apiKey: process.env.TELEMAX_API_KEY }),
  });
  const { access_token, expires_in } = await res.json();
  cachedToken = access_token;
  tokenExpiresAt = Date.now() + expires_in * 1000;
  return cachedToken;
}
```

**Example (Python):**

```python theme={null}
import time
import requests

_token = None
_token_expires_at = 0

def get_token():
    global _token, _token_expires_at
    if _token and time.time() < _token_expires_at - 300:
        return _token
    r = requests.post(
        'https://api.telemax.com.au/v2/api/authentication/token/api-key',
        data={'apiKey': os.environ['TELEMAX_API_KEY']},
    )
    r.raise_for_status()
    data = r.json()
    _token = data['access_token']
    _token_expires_at = time.time() + data['expires_in']
    return _token
```

***

## Token scoping

Every token is bound to a **single company**. The `CompanyId` claim in the JWT determines which resources the token can access.

To check which companies and vehicles your token can access, call [`GET /v2/api/companies`](/v2/api-reference/get-companies) and [`POST /v2/api/vehicles/list`](/v2/api-reference/post-vehicles-list) after authenticating.

***

## API key rotation

To rotate an API key without downtime:

1. **Create the new key** in the Telemax dashboard (API Keys V2 section). Both keys are active simultaneously.
2. **Update your integration** to use the new key and confirm tokens are being obtained successfully.
3. **Delete the old key** in the dashboard. Existing tokens issued with the old key remain valid until they expire (up to 24 hours).

<Warning>
  Deleting a key immediately invalidates future token requests with that key. Tokens already issued remain valid until their `expires_in` elapses.
</Warning>

***

## Code examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -s -X POST "https://api.telemax.com.au/v2/api/authentication/token/api-key" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "apiKey=a3f1c2b4-5d6e-7890-abcd-ef1234567890"
  ```

  ```javascript JavaScript theme={null}
  const tokenRes = await fetch('https://api.telemax.com.au/v2/api/authentication/token/api-key', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({ apiKey: 'a3f1c2b4-5d6e-7890-abcd-ef1234567890' }),
  });
  const { access_token, expires_in } = await tokenRes.json();
  ```

  ```python Python theme={null}
  import requests
  r = requests.post(
      'https://api.telemax.com.au/v2/api/authentication/token/api-key',
      data={'apiKey': 'a3f1c2b4-5d6e-7890-abcd-ef1234567890'},
  )
  r.raise_for_status()
  token = r.json()['access_token']
  ```
</CodeGroup>
