> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.teekrr.com/llms.txt.
> For full documentation content, see https://docs.teekrr.com/llms-full.txt.

# Authentication

The Teekrr public API uses **Bearer API keys**. Send your key in the `Authorization` header on every request:

```
Authorization: Bearer <your-api-key>
```

## Issuing keys

API keys are issued from the in-app `/api-management` page (logged-in dashboard). Each key has:

* A **name** (your choice)
* A list of **permission scopes** (see below)
* An optional **IP whitelist** — when non-empty, requests from any other IP are rejected with `403 Forbidden`
* An optional **expiry** date
* A **revoke** action (immediate, no grace period)

<Warning>
  The plaintext key value is shown **only once** at creation. Teekrr stores only the SHA-256 hash. Lost keys cannot be recovered — revoke and reissue.
</Warning>

## Permission scopes

Each endpoint requires a specific scope on the calling key:

| Endpoint                             | Required scope  |
| ------------------------------------ | --------------- |
| `POST /sms`                          | `send_sms`      |
| `POST /whatsapp`                     | `send_whatsapp` |
| `POST /whatsapp/test`                | `send_whatsapp` |
| `POST /whatsapp/upload-header-image` | `send_whatsapp` |
| `POST /email`                        | `send_email`    |

A key without the required scope receives `403 Forbidden`.

## IP whitelisting

Set an IP whitelist on a key to lock it down to specific source IPs (e.g. your production servers). When the whitelist is non-empty, requests from any other IP are rejected with `403 Forbidden — Request IP is not in the API key whitelist`.

For server-to-server integrations on fixed-IP infrastructure, **always set a whitelist**.

## Auth errors

| Status | Reason                                    | `message`                                    |
| ------ | ----------------------------------------- | -------------------------------------------- |
| `401`  | No / malformed `Authorization` header     | `Missing or invalid Authorization header`    |
| `401`  | Bearer token doesn't match any active key | `Invalid API key`                            |
| `401`  | Key was revoked from the dashboard        | `API key has been revoked`                   |
| `401`  | Key has expired                           | `API key has expired`                        |
| `403`  | Caller IP not in the API key's whitelist  | `Request IP is not in the API key whitelist` |

## Best practices

* **Treat keys as secrets.** Store in 1Password / AWS Secrets Manager / Vault. Never commit to source control.
* **Use separate keys per environment** — staging keys for staging, production keys for production.
* **Use IP whitelisting** when keys are deployed on fixed-IP servers.
* **Rotate keys every 90 days.** Issue the new key, deploy it, then revoke the old one.
* **Review usage** at `/api-management → Usage`. Every API call is logged with method, path, status, and latency.
* **Use minimal scopes.** Don't issue a `send_sms + send_whatsapp + send_email` key for a service that only sends SMS.

## API key vs. JWT

Teekrr supports two authentication methods on the same endpoints:

* **JWT** — used by the in-app web dashboard (cookie-based, short-lived)
* **API key** — used by external integrations (Bearer header, long-lived, scoped)

The middleware detects which one you're using by inspecting the token shape. As an external integrator you should always use API keys — JWT is reserved for the web UI.