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

# Authentication and API keys

> Key generation, rotation, and storage best practices.

The Kardinal Route Optimization API authenticates every request with a JWT bearer token, sent as `Authorization: Bearer <token>`. Every request needs a **long-term API token**, obtained once via the Console and meant to be stored by your integration — it doesn't depend on repeating an interactive login, which is what makes it the credential your integration actually stores and uses. It's valid for **366 days** and scoped to a single [agency](/reference/glossary) (`sandbox` or `production`).

<Note>
  Access to the API is self-service: sign up on the [Console](https://console.kardinal.ai) with your email, GitHub, or Google Account — a first login creates your builder account automatically, with a `sandbox` and a `production` agency.
</Note>

## Obtain your long-term API token

Log in to the [Console](https://console.kardinal.ai), go to **API Keys**, and generate your token there, once per environment (`sandbox`, `production`). Generating, rotating, and revoking a long-term token are Console-only operations — there is no API endpoint for a script or backend to call directly for this.

<Warning>
  **The Console only ever shows you the token value once, at generation time.** Kardinal never stores it in plain text, only a one-way hash — capture it immediately. Regenerating also **replaces** the previous token for that environment: any integration still using the old value starts getting `401`s as soon as you regenerate, so roll the new value out everywhere before discarding the old one.
</Warning>

Send it on every request:

```
Authorization: Bearer <long_term_token>
```

## Token lifetime

A long-term API token is valid for **366 days** — no refresh flow to manage day to day. Rotate it from the Console before it expires, or immediately if you suspect it leaked.

## Storing your token

Treat your long-term API token like any other production secret:

* Store it in an environment variable or a secrets manager (Vault, AWS/GCP/Azure secret managers, etc.) — never hard-code it in source control.
* Keep your `sandbox` and `production` tokens in separate secrets, scoped to separate deployment environments.
* Log requests without the `Authorization` header value; if you need to debug a `401`, log the response body, not the token.
* If a token is suspected to be compromised, revoke it from the Console immediately and generate a fresh one.

## Common authentication issues

| Symptom | Likely cause | What to do |
| - | - | - |
| Every request fails with `401` | Long-term token expired or revoked | Generate a fresh token from the Console |
| Requests fail with no `Authorization` header sent | Header missing or malformed | Confirm the header is exactly `Authorization: Bearer <token>` |
| Requests succeed, but data doesn't show up where you expect it | The token used belongs to the other agency (`sandbox` vs `production`) — a valid token always authenticates successfully for its own agency, so mixing up the two doesn't fail, it silently operates on the wrong one | Check the `agencyId` field in the response to confirm which agency the token actually hit |

<Info>
  For the full table of business error codes (`NOT_AUTHENTICATED`, `NOT_ALLOWED`, `INVALID_INPUT`, and so on) and when each is returned, see the `Error` schema in the [API reference](/api-reference/plan/create-a-plan).
</Info>

## See also

* [Sandbox to production](/guides/sandbox-to-production) — moving from a `sandbox` token to a `production` one.
* [Glossary](/reference/glossary) — the full list of Kardinal-specific terms, including `agency`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.