> ## 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.

# Error handling

> Standardised error response model, HTTP status codes, example responses, and retry guidance for the Telemax External API.

## Error response shape

Every error response from the Telemax API returns the same JSON structure:

```json theme={null}
{
  "type": "AUTHENTICATION",
  "code": "TOKEN_EXPIRED",
  "description": "The access token has expired. Request a new token.",
  "requestId": "0HNLTALNU4DCO:00000004",
  "docUrl": "https://docs.telemax.com.au/errors#token-expired"
}
```

| Field         | Type   | Description                                                                                                     |
| ------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| `type`        | string | Error category: `AUTHENTICATION`, `AUTHORIZATION`, `RESOURCE`, `VALIDATION_ERROR`, `RATE_LIMIT`, `SERVER_ERROR` |
| `code`        | string | Machine-readable code identifying the specific error                                                            |
| `description` | string | Human-readable explanation and resolution hint                                                                  |
| `requestId`   | string | Unique ID for this request — include it when contacting support                                                 |
| `docUrl`      | string | Link to the specific error documentation                                                                        |

<Note>
  `requestId` is present in all V2 error responses. V1 error responses may omit this field.
  The format is an ASP.NET Kestrel connection/request ID (e.g. `"0HNLTALNU4DCO:00000004"`), not a human-readable string.
</Note>

***

## 401 Unauthorized

**Cause:** JWT is missing, expired, or malformed. The request is rejected by bearer middleware before reaching the controller.

**Common codes:**

| `code`            | Meaning                                        |
| ----------------- | ---------------------------------------------- |
| `TOKEN_EXPIRED`   | Token lifetime has elapsed                     |
| `TOKEN_MALFORMED` | Token cannot be parsed or signature is invalid |
| `TOKEN_MISSING`   | No `Authorization: Bearer ...` header was sent |

**Example response:**

```json theme={null}
{
  "type": "AUTHENTICATION",
  "code": "TOKEN_EXPIRED",
  "description": "The access token has expired. Request a new token.",
  "requestId": "0HNLTALNU4DCO:00000004",
  "docUrl": "https://docs.telemax.com.au/errors#token-expired"
}
```

**Resolution:** Request a new token via [`POST /api/authentication/token/user`](/v1/api-reference/post-authentication-token-user) or [`POST /api/authentication/token/api-key`](/v1/api-reference/post-authentication-token-api-key). Tokens expire after approximately 24 hours (`expires_in: 86399`).

***

## 403 Forbidden

**Cause:** Token is valid but the caller does not have access to the requested company or vehicle. Tokens are scoped to a company hierarchy — a token issued for company A cannot access resources belonging to company B.

**Common codes:**

| `code`                  | Meaning                                                                   |
| ----------------------- | ------------------------------------------------------------------------- |
| `COMPANY_ACCESS_DENIED` | The company ID in the request is not in the caller's accessible hierarchy |
| `VEHICLE_ACCESS_DENIED` | The vehicle does not belong to any company accessible by this token       |

**Example response:**

```json theme={null}
{
  "type": "AUTHORIZATION",
  "code": "COMPANY_ACCESS_DENIED",
  "description": "Your token does not grant access to company 99. Ensure you are using a token issued for this company.",
  "requestId": "0HNLTALNU4DCE:00000002",
  "docUrl": "https://docs.telemax.com.au/errors#company-access-denied"
}
```

**Resolution:** Check your company ID against the list returned by [`POST /api/GetCompanies`](/v1/api-reference/post-get-companies). Use the correct `companyId` or request a token scoped to that company.

***

## 404 Not Found

**Cause:** The vehicle ID, company ID, or IMEI in the request does not exist or is not accessible with the current token.

**Common codes:**

| `code`              | Meaning                                  |
| ------------------- | ---------------------------------------- |
| `VEHICLE_NOT_FOUND` | No vehicle with the given ID exists      |
| `COMPANY_NOT_FOUND` | No company with the given ID exists      |
| `IMEI_NOT_FOUND`    | No device registered with the given IMEI |

**Example response:**

```json theme={null}
{
  "type": "RESOURCE",
  "code": "VEHICLE_NOT_FOUND",
  "description": "Vehicle with ID 9999 was not found.",
  "requestId": "0HNLTALNU4DDM:00000003",
  "docUrl": "https://docs.telemax.com.au/errors#not-found"
}
```

**Resolution:** Verify the ID using [`POST /api/Devices`](/v1/api-reference/post-devices) or [`GET /api/GetDeviceId/{imei}`](/v1/api-reference/get-device-id-by-imei).

***

## 422 Unprocessable Entity

**Cause:** A parameter is present but has an invalid format — for example, a date string that cannot be parsed as ISO 8601, or a negative vehicle ID.

**Common codes:**

| `code`                | Meaning                                         |
| --------------------- | ----------------------------------------------- |
| `INVALID_DATE_FORMAT` | Date/time string is not valid ISO 8601          |
| `INVALID_ID`          | Vehicle or company ID is not a positive integer |
| `INVALID_PARAMETER`   | Other parameter format violation                |

**Example response:**

```json theme={null}
{
  "type": "VALIDATION_ERROR",
  "code": "INVALID_DATE_FORMAT",
  "description": "The 'from' parameter '2025-13-45' is not a valid ISO 8601 date-time string.",
  "requestId": "0HNLTALNU4DDJ:00000004",
  "docUrl": "https://docs.telemax.com.au/errors#invalid-parameter"
}
```

**Resolution:** All date-time parameters must be ISO 8601 strings (e.g. `2025-05-01T00:00:00Z`). All ID parameters must be positive integers.

***

## 429 Too Many Requests

<Note>
  V1 endpoints (`/api/...`) are **not rate-limited**. A `429` response will not occur on V1 routes. Rate limiting applies only to V2 (`/api/v2/...`) endpoints — if you are on V1, you can skip this section.
</Note>

**Cause:** The caller has exceeded the rate limit on a V2 endpoint. The limit is **60 requests per 60-second sliding window** per token.

**Example response:**

```json theme={null}
{
  "type": "RATE_LIMIT",
  "code": "TOO_MANY_REQUESTS",
  "description": "Too many requests. Please try again later.",
  "requestId": "0HNLTALNU4DD8:00000006",
  "docUrl": "https://docs.telemax.com.au/errors#rate-limit"
}
```

**Resolution:** Check the `Retry-After` response header for the number of seconds to wait. Use exponential backoff: after the first 429, wait `Retry-After` seconds; double the interval on each subsequent 429 up to a maximum of 60 seconds.

***

## 500 Internal Server Error

**Cause:** An unexpected server-side error occurred. This is not caused by the request parameters.

**Example response:**

```json theme={null}
{
  "type": "SERVER_ERROR",
  "code": "INTERNAL_ERROR",
  "description": "An unexpected error occurred. Please try again or contact support with the requestId.",
  "requestId": "0HNLTALNU4DE1:00000002",
  "docUrl": "https://docs.telemax.com.au/errors#server-error"
}
```

**Resolution:** Retry after a short delay. If the error persists, contact Telemax support and include the `requestId` value.

***

## Retryable vs non-retryable

| Retry?  | Status codes                                                         |
| ------- | -------------------------------------------------------------------- |
| **Yes** | 429 (after `Retry-After`), 500 (transient), 503 (gateway timeout)    |
| **No**  | 401 (fix token), 403 (fix scope), 404 (fix ID), 422 (fix parameters) |
