---
title: "Keys, scopes and headers"
url: https://lumean.app/tr/developers/docs/guide/authentication
locale: tr
description: "X-API-KEY as a separate surface, eleven domain scopes plus a wildcard, three presets — and why “automation” doesn't cover the basic scenario end to end."
updated: 2026-10-17
source_locale: en
sources: [get-user, post-templates, post-storage-url, get-templates-template, post-voices-cartesia-clones, post-reseller-codes, get-ai-models]
errors: ["401", "403", template-access-denied]
spec_version: 0.0.1
---

# Keys, scopes and headers

The public API authenticates with a single header and nothing else. It has no anonymous endpoints:
every operation in the spec requires a key, and almost every one names a specific scope in its own
description. The exception is the AI model catalog: any active key works for it. There is one fewer
reference page than there are operations: `PUT` and `PATCH /templates/{template}` are collapsed
into one (it's a single operation under two methods), and `POST /broadcasting/auth` is explained
in the Realtime section.

```
X-API-KEY: <your key>
```

## A separate surface, not a second way to sign in

The public surface (`/api/public/*`) and the dashboard API are different surfaces with different
authentication. The dashboard Bearer token doesn't work here; conversely, a key doesn't open
dashboard endpoints. The header is called exactly `X-API-KEY` — neither `Authorization` nor `Api-Key`
is recognized, and both get the same response as a missing key.

### 401 — 401 — key rejected

| Что произошло | Что делать |
| --- | --- |
| The request was rejected before any business logic ran: no action was performed and nothing was charged. The body is the same on every endpoint: `{"success": false, "message": "API key is missing. Provide it in the X-API-KEY header.", "data": null}`. The public API does not accept anonymous requests anywhere. | Make sure the header is named exactly `X-API-KEY` (not `Authorization`, not `Api-Key`) and the value is sent in full. If the key is correct, open the developer section and check that the key is active and has not expired. Retrying is pointless: a 401 is deterministic, and a retry with the same key gets the same response. |

`Retry-After`: нет. Разбор: https://lumean.app/tr/developers/docs/errors/401

The key is hashed (sha256) and resolved with a cache of about an hour. The practical consequence: editing
a key's scopes or deactivating it in the dashboard doesn't take effect instantly — requests may keep
going through on the old state for a while.

## Eleven scopes and a wildcard

The scope is checked before any business logic: a key without the required scope gets `403` and nothing
is executed. The “Operations” column shows how many public API endpoints the scope opens
(reference pages plus `POST /broadcasting/auth`).

| Scope | What it opens | Operations |
| --- | --- | --- |
| `orders.read` | Reading orders and chunks, the text chunking preview, WebSocket subscription to orders | 9 |
| `orders.write` | Creating, canceling and retrying orders; retrying and regenerating chunks | 6 |
| `orders.download` | `POST /storage/url` — exchanging a file path for a temporary link | 1 |
| `templates.read` | Reading templates, `browse`, `config-options` | 4 |
| `templates.write` | Creating, updating and deleting templates | 3 |
| `voices.read` | All voice catalogs: LumVoice, ElevenLabs, HeyGen, Cartesia, Fish Audio; your own clones and their quota | 14 |
| `voices.write` | Creating, retrying and archiving Cartesia and Fish Audio voice clones | 6 |
| `billing.read` | `usage`, `subscriptions` | 3 |
| `profile.read` | `GET /user` | 1 |
| `reseller.read` | Reseller dashboard: profile and balance, settings, statistics, codes with their full value | 5 |
| `reseller.write` | Issuing gift codes from the reseller balance and canceling them | 2 |
| `*` | Passes any scope check, including scopes that don't exist yet — **except** `reseller.read` and `reseller.write` | all except reseller |

The two AI model catalog operations (`GET /ai/models` and `GET /ai/models/{key}`) require
no scope at all — they're not in the table.

> [!WARNING]
> `*` **does not cover** the reseller scopes, and they aren't part of any preset: a gift code is
> bearer money, so a key gets `reseller.read` and `reseller.write` only when they are
> listed explicitly. A wildcard key will get `403` on `GET /reseller`.

> [!WARNING]
> `orders.download` **is not covered** by `orders.read`. A key that reads orders perfectly well
> and sees the paths in `result.files[]` will get 403 when exchanging a path for a link. This is the most common
> cause of an unexpected rejection at the end of a scenario — when the file has already been generated and paid for.

### POST /storage/url

Get File URL

Справочник: https://lumean.app/tr/developers/docs/api/post-storage-url

## Three presets

When you create a key, its scopes are usually picked with a preset.

| Preset | Scopes | Doesn't open |
| --- | --- | --- |
| `read_only` | `orders.read`, `orders.download`, `templates.read`, `voices.read`, `billing.read`, `profile.read` | anything that writes orders, templates and voice clones, and the reseller dashboard |
| `automation` | the same plus `orders.write` | `POST`, `PUT`/`PATCH` and `DELETE /templates/{template}`, creating, retrying and archiving clones, the reseller dashboard |
| `full` | all scopes except the reseller ones (including `templates.write` and `voices.write`) | the reseller dashboard |

The wildcard `*` is a separate value, not a synonym for the `full` preset: it also passes checks
that didn't exist when the key was issued (but not the reseller scopes). Which of the two
ways to “grant everything” the dashboard applies when you pick `full` isn't specified by the sources — if it
matters, check the scope list of the already created key in the dashboard.

### The automation trap

The preset named “for automation” **doesn't include `templates.write`** — only
`templates.read`. This isn't a documentation typo or a bug: that's how it's designed. By the same
logic it also lacks `voices.write`: for a key that clones voices, this scope is added
manually, or you take `full`.

The consequence is concrete. For TTS, the voice is set not by an order field but by the template's `config.tts_settings.voice_id`
— so the canonical scenario starts with `POST /templates`. With an `automation` key
it stops at the very first step: 403, and the order is never created.

**Правильно**

For the “create a template → order TTS” scenario, take the `full` preset — or `automation`
with `templates.write` added manually when you create the key.

**Неправильно**

Take `automation` because the task is called automation, and then look for the cause of the
403 in the order itself — even though it was the template creation step that was rejected.

If the template was created in advance (on the web or with another key), `automation` is enough: the template's
owner is the account, not a specific key. Someone else's template, however, won't open with any key.

### 403 · `template_access_denied` — template_access_denied — no access to the template

| Что произошло | Что делать |
| --- | --- |
| A domain refusal of order creation: HTTP 403, body `{"success": false, "message": "…", "reason": "template_access_denied"}`. The order was not created. | Check that the template is visible to the key. A template is owned by the account, not by a specific key: a template created on the web works for the API and vice versa, but a template that belongs to another account will not open with any key. If the template is yours, the problem is scopes: `automation` does not include `templates.write`, but it does include `templates.read`. |

`Retry-After`: нет. Разбор: https://lumean.app/tr/developers/docs/errors/template-access-denied

## Language and timezone headers

Both headers are optional, and neither is declared as a parameter in the OpenAPI —
a client generated from the spec won't know about them, so you'll have to send them manually.

- `X-Locale` — the language of human-readable strings: `message` in responses and names in reference lists
  such as `GET /voices/tags`. It has no effect whatsoever on machine fields (`reason`, statuses, codes),
  and that's exactly why you must not branch on `message`. The sources disagree: the OpenAPI names
  this header in 79 descriptions and never mentions `Accept-Language`, while the LLM reference
  does the opposite; if the response language is critical, check the actual behavior with your own key
  and send both headers.
- `X-Timezone` — an IANA zone name (`Europe/Moscow`). Points in time in responses arrive
  in ISO-8601 with an explicit offset, UTC by default. A bare offset (`+03:00`) is rejected:
  it doesn't know about daylight saving time. The server returns the zone it actually applied
  in the same header — send garbage and you'll see `X-Timezone: UTC` in the response.

## What a key can't do

The public surface doesn't process payments and doesn't manage itself. With a key you **cannot**: top up
the balance, make transfers, buy subscriptions, change the profile, or manage the API keys themselves.
All of that stays in the dashboard. Separately: orders have no `update`/`delete` — only `cancel`
and `retry`, and `PUT`/`PATCH`/`DELETE /orders/{order}` will answer 405/404.

## Key smoke test

The cheapest check is the profile: one operation, one scope, no side effects.

```bash
curl -s -o /dev/null -w '%{http_code}\n' \
  'https://api.lumean.app/api/public/user' \
  -H 'X-API-KEY: <your key>'
```

| Code | What it means |
| --- | --- |
| `200` | The key is active and has the `profile.read` scope |
| `403` | The key **works** — authentication passed, only `profile.read` is missing |
| `401` | The key wasn't accepted: not sent, truncated, unknown, deactivated or expired |

The key nuance is the second row: `403` confirms that the key is alive. If your key lacks `profile.read`
by design, check `GET /orders?per_page=1` instead — it needs only
`orders.read`.

### GET /user

Get profile of API key owner

Справочник: https://lumean.app/tr/developers/docs/api/get-user

Keys are created in the [Developers](/developers) section, which also shows the active scopes
and limits of each key. Don't have a key yet? [Sign up](/register) first — keys
are issued only to the account owner.

---

- Bu sayfa tarayıcıda: https://lumean.app/tr/developers/docs/guide/authentication
- Makine tarafından okunabilir tam başvuru: https://api.lumean.app/docs/llm.md
