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

# API authentication: bearer tokens, scopes, and 401s

> Create a Kite API key and authenticate every Platform API request as a Bearer token, including key format, scopes, and 401 handling for invalid keys.

The Platform API lives at `https://api.kiteml.com/v1` and authenticates every request with an API key.

## Create a key

Create a key from **Developers → API keys** in the [dashboard](https://kiteml.com/app). Scope it to augmentations if you only need dataset generation.

<Warning>
  Keys start with `kite_` and are shown **only once**, at creation time. Store the value in a secret manager or environment variable — you can't retrieve it later, only revoke it and create a new one.
</Warning>

## Authenticate a request

Send the key in the `Authorization` header as a Bearer token on every request.

```bash theme={"system"}
export KITE_API_KEY=kite_aBcDeFgH...

curl https://api.kiteml.com/v1/keys/me \
  -H "Authorization: Bearer $KITE_API_KEY"
```

A valid key returns the key's identity and scopes:

```json theme={"system"}
{
  "object": "api_key",
  "id": "key_01J8X4...",
  "name": "ci-augmentations",
  "scopes": ["augmentations:read", "augmentations:write"],
  "created_at": "2026-07-21T09:00:00Z"
}
```

An invalid or revoked key returns `401 Unauthorized`.

## Scopes

Scopes are `resource:verb` strings. `write` implies `read` for the same resource, so a key with `augmentations:write` can also read augmentations.

Grant a key the narrowest scopes that its job needs. A CI task that only starts runs needs `augmentations:write` and nothing else, so a leaked key can't read your usage or credit balance.

| Scope                 | Grants                                                |
| --------------------- | ----------------------------------------------------- |
| `augmentations:write` | Create and cancel augmentation runs (implies `:read`) |
| `augmentations:read`  | List and read augmentations, episodes, and downloads  |
| `usage:read`          | Read token usage and credit balance                   |

A call whose key is missing the required scope returns `403` with code `missing_scope`.

## Errors

Every error returns the same envelope. `type` maps to the HTTP status; `code` is a stable, specific reason you can branch on; `request_id` identifies the request — include it in any support message.

```json theme={"system"}
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "episode_count must be between 1 and 50",
    "param": "config.episode_count",
    "request_id": "req_01J8X4..."
  }
}
```

| Status | Common `code`            | Meaning                                            |
| ------ | ------------------------ | -------------------------------------------------- |
| `400`  | `parameter_invalid`      | Malformed or out-of-range field (named in `param`) |
| `401`  | `unauthenticated`        | Missing, invalid, or expired API key               |
| `402`  | `insufficient_tokens`    | Not enough credits                                 |
| `403`  | `missing_scope`          | The key lacks the scope this call requires         |
| `404`  | `resource_not_found`     | No such resource                                   |
| `409`  | `idempotency_key_reused` | `Idempotency-Key` reused with a different payload  |
| `429`  | `rate_limit_exceeded`    | Rate limited — honor the `Retry-After` header      |
| `5xx`  | `api_error`              | Server error — safe to retry idempotent requests   |

<Tip>
  Keep your key server-side. Never ship it in a browser, mobile app, or public repository. If a key leaks, revoke it from the dashboard immediately and create a scoped replacement.
</Tip>
