---
title: Authentication
description: How to authorize Clipia API requests — API keys, three header schemes, live vs test keys, scopes, and secure storage.
---

Every request to `/v1/*` is authorized with an API key passed in a header. The recommended scheme is `Authorization: Bearer clipia_live_…`; `Authorization: Key …` and `X-Api-Key: …` are also supported. A key is created in your dashboard, shown once, tied to your account, and charges credits from its balance.

## Header schemes

Three equivalent forms are supported — pick one.

<Tabs items={['Bearer', 'Key', 'X-Api-Key']}>
<Tab value="Bearer">

```bash
curl https://api.clipia.ai/v1/account \
  -H "Authorization: Bearer $CLIPIA_KEY"
```

</Tab>
<Tab value="Key">

```bash
curl https://api.clipia.ai/v1/account \
  -H "Authorization: Key $CLIPIA_KEY"
```

</Tab>
<Tab value="X-Api-Key">

```bash
curl https://api.clipia.ai/v1/account \
  -H "X-Api-Key: $CLIPIA_KEY"
```

</Tab>
</Tabs>

| Scheme | Header | Note |
|--------|--------|------|
| Bearer | `Authorization: Bearer …` | recommended, OAuth-style standard |
| Key | `Authorization: Key …` | compatible with fal.ai-style queues |
| X-Api-Key | `X-Api-Key: …` | if a dedicated header suits you better |

## Live vs test keys

The key prefix selects the environment.

| Prefix | Environment | Behaviour |
|--------|-------------|-----------|
| `clipia_live_…` | live | real generation, credits are charged |
| `clipia_test_…` | sandbox | instant mock result, no credits charged |

Live and test keys are independent. To move from sandbox to live, just swap the key — no code changes needed. See the "Sandbox" page for details.

## Getting and storing a key

Create a key in your dashboard: **Developer Console** (`/developer`) → **API Keys** tab. The full key is shown **once**.

<Callout type="warn" title="The key is a server-side secret">
Never put the key in a browser, mobile app, frontend bundle, or public repository. Keep it in a secrets manager or server environment variables. If a key is compromised, revoke it in the dashboard (revocation is instant) and create a new one.
</Callout>

## Scopes

Each key carries scope restrictions. The allowed values are `generate`, `read` and `chat`; by default a key gets `["generate", "read"]`.

| Scope | Grants |
|-------|--------|
| `generate` | creating an image/video generation (`POST /v1/models/{model}`) |
| `chat` | LLM chat — AI Gateway (`POST /v1/chat/completions`) |
| `read` | reserved for future read-only keys |

<Callout type="info" title="One key — both generation and LLM">
You don't need a separate key for the [AI Gateway](/docs/llm-gateway). The `generate` scope automatically satisfies `chat`, so **any of your generation keys (the default `["generate", "read"]`) works right away both for LLM chat `POST /v1/chat/completions` and for image/video generation — from the same credit balance**. A standalone `chat` scope is only needed when you deliberately mint a key for LLM **only** (with no generation rights).
</Callout>

- **Creating generations** requires the `generate` scope.
- **LLM chat** (`POST /v1/chat/completions`) requires the `chat` scope — which `generate` also satisfies (see above), so existing keys work with no re-issuance.
- **Reading status/result** of your own generation works with any valid key — no scope required.
- The model catalog (`GET /v1/models`) and balance (`GET /v1/account`) need no scope.
- A request missing the required scope → `403 insufficient_scope`.

<Callout type="error" title="Invalid key">
A missing, wrong, or revoked key → `401 invalid_api_key`. Check the environment prefix and that the key is sent in one of the three supported headers.
</Callout>
