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

# API v3 authentication: keys, scopes and caps

> Authenticate Rask API v3 requests with a bearer key. Key format, scopes, monthly spend caps, and what each 401 and 403 means.

Send an API key on every request:

```typescript TypeScript theme={null}
const { data: me } = await rask.account.getMe();
```

```python Python theme={null}
me = client.account.get_me()
```

```go Go theme={null}
me, err := client.Account.GetMe(ctx)
if err != nil {
	return err
}
```

```java Java theme={null}
Me me = rask.account().getMe().data();
```

```php PHP theme={null}
$me = $rask->account->getMe();
```

```bash cURL theme={null}
curl https://api.rask.ai/v3/me \
  -H "Authorization: Bearer $RASK_API_KEY"
```

Keep the key in the environment variable `RASK_API_KEY`. A request with any of the query parameters
`access_token, api_key, token` is refused with 400 [`token_in_query`](https://docs.api.rask.ai/errors/token_in_query), and `parameter` names the one it
found. This happens even when the `Authorization` header holds a valid key. The key in the URL stays valid, so revoke it in
Settings if the URL was logged or shared.
API v3 does not accept web sessions, and API v2 credentials answer 401 [`invalid_token`](https://docs.api.rask.ai/errors/invalid_token).

## Get a key

Keys are created in the web app, under **Settings -> API keys** ([open it](https://app.rask.ai/account/api-keys)). There is no API
for it. You choose:

* **A name and a workspace.** The key works in that workspace only.
* **Access.** One of three presets, or your own set of [scopes](#scopes).
* **Spending.** Whether the key may spend credits, with its [monthly caps](#spend-caps).
* **Expiry.** 30 days, 90 days or 1 year (the default). A key that cannot spend may also never expire. A key that can spend must
  expire.

The key is shown once. Rask stores only its hash and cannot show it again, so a lost key means a new key.

A workspace holds at most 100 active keys, and one person at most 25 per workspace.

## What a key is

Each key is bound to **one workspace** and acts as **one user**, the person who created it. The workspace owner is the **payer**:
all work is charged to the owner and the owner's plan applies. All workspaces of one owner share one set of credit pools.

No request takes a workspace id. An id outside the key's workspace answers 404, as if it did not exist, never 403.

What you can change later: the name (only the key's own user can) and the caps. Scopes, workspace, acting user and expiry are
fixed, so a key that lacks a scope needs a replacement.

Requests that spend credits or delete data always see the key's current state. Other requests can take a minute or two to see a
revocation, or a change to the key, its user, its workspace or the payer's plan.

A key is `raskai_live_key_` and 49 base62 characters. `GET /v3/me` shows it masked, in `auth.display`.

## Scopes

Scopes are `resource:action`. Every operation lists the ones it needs in its reference page, and the
[operation table](https://docs.api.rask.ai/v3/concepts/operation-table.md) has them all.

| Scope | Grants |
| - | - |
| `account:read` | Read me, plan, entitlements, balance and usage |
| `media:read` | Read uploads and media |
| `media:write` | Create, complete and delete uploads, import from a URL, delete media |
| `projects:read` | Read projects, folders, outputs, subtitles, lip-sync and on-screen state |
| `projects:write` | Create, copy, update and delete projects; folders; exports; file restores |
| `transcripts:read` | Read transcripts, segments, versions and translation settings |
| `transcripts:write` | Edit, split, merge and retranslate segments, import subtitles, save and restore versions, change translation settings |
| `voices:read` | Read speakers, the voice catalog and voice clones |
| `voices:write` | Change a speaker's voice; create, update and delete voice clones |
| `glossaries:read` | Read glossaries |
| `glossaries:write` | Create, update and delete glossaries |
| `dubbing:write` | Dub and redub, segment generation, localization runs and their estimates |
| `lipsync:write` | Lip-sync and its estimate |
| `onscreen:write` | On-screen text translation and its estimate |
| `jobs:read` | Get, list and wait for jobs |
| `jobs:write` | Cancel and resume jobs |
| `webhooks:read`, `webhooks:write` | Reserved: webhooks are not served yet |
| `credits:spend` | Additionally required by every operation that can withdraw credits |

Two rules expand what a key holds: `X:write` implies `X:read`, and every `*:write` implies `jobs:read`. Estimates need the action's
scope but not `credits:spend`. [`GET /v3/languages`](https://docs.api.rask.ai/operations/listLanguages) works with any valid key.

`jobs:read` reads every job the key started. A job that another key started also needs the scope that reads what the job works
on: `media:read` for `media_import`, `voices:read` for `voice_clone`, `transcripts:read` for `translation` and
`segment_generation`, and `projects:read` for the rest. Without it, the job answers 404 [`job_not_found`](https://docs.api.rask.ai/errors/job_not_found)
and is left out of lists.

| Preset | Scopes |
| - | - |
| Read-only | Every `*:read` |
| Full access | All of them |
| Full access without spending | All but `credits:spend`: the key can upload, edit and estimate, while a person creates projects and starts other paid work |

A run that orders lip-sync or on-screen adds those scopes for that request, as `x-rask-operation.conditional` says on
[createLocalization](https://docs.api.rask.ai/operations/createLocalization.md), [createProject](https://docs.api.rask.ai/operations/createProject.md) and
[resumeJob](https://docs.api.rask.ai/operations/resumeJob.md).

## Spend caps

A key can carry two monthly caps, counted per UTC month: one on minutes and one on project credits. Free lip-sync minutes
(`lipsync_free_minutes`) count against neither. A key that can spend gets a minutes cap of **120 minutes** unless you set
another; "no limit" is an explicit choice. The project-credit cap is off unless you set one. The workspace owner can change the
caps of any key in the workspace, and a member cannot raise a cap the owner set. Members' spending keys follow the owner's
policy: whether members may create them at all, and a highest minutes cap that starts at 300 minutes. A member's key gets at
most that cap by default, and a member cannot set a minutes cap above it or "no limit".

The cap is checked exactly at every spend. A request above it answers 403
[`token_spend_limit_exceeded`](https://docs.api.rask.ai/errors/token_spend_limit_exceeded) with `credit_type`, `limit_minutes`, `spent_minutes`,
`required_minutes` (or the `_projects` fields) and `resets_at`.

Spending that is already promised counts too: a stored auto-dub, an on-screen auto-start and the remaining stages of a run. A
refunded charge stops counting. To see where a key stands, read `auth` in [`GET /v3/me`](https://docs.api.rask.ai/operations/getMe), or `spend_limit` in
any estimate.

## What each 401 means

A 401 is about the key itself. Do not retry it unchanged.

| Code | What happened | What to do |
| - | - | - |
| [`authentication_required`](https://docs.api.rask.ai/errors/authentication_required) | No `Authorization: Bearer` header | Send the header |
| [`invalid_token`](https://docs.api.rask.ai/errors/invalid_token) | The key is malformed, incomplete or unknown | Check that `RASK_API_KEY` holds the whole key |
| [`token_expired`](https://docs.api.rask.ai/errors/token_expired) | The key passed its expiry (`expired_at`) | Create a new key |
| [`token_revoked`](https://docs.api.rask.ai/errors/token_revoked) | The key was revoked (`revoked_reason`): in Settings, by Rask (for example after a confirmed leak), or because its user left or was removed from the workspace, or the user's account, the workspace or the owner's account was deleted | Create a new key; a revoked key cannot be restored |
| [`token_wrong_environment`](https://docs.api.rask.ai/errors/token_wrong_environment) | A key of another environment (`token_env`, `server_env`) | Use a `raskai_live_` key with `api.rask.ai` and a `raskai_test_` key with a test environment |

Many failed authentications from one address answer 429 [`rate_limited`](https://docs.api.rask.ai/errors/rate_limited) with the policy `auth-fail-ip`,
and until `Retry-After` passes, even a valid key from that address can be refused. Fix the key, then wait `Retry-After` seconds.
503 [`auth_unavailable`](https://docs.api.rask.ai/errors/auth_unavailable) means the check itself failed: wait `Retry-After` seconds and retry.

## What each 403 means

A 403 means the key is fine and this request is refused. Branch on `code`.

| Code | What happened | What to do |
| - | - | - |
| [`insufficient_scope`](https://docs.api.rask.ai/errors/insufficient_scope) | The key lacks a scope (`required_scopes`, `granted_scopes`) | Use a key with those scopes; scopes cannot be added to a key |
| [`token_spend_limit_exceeded`](https://docs.api.rask.ai/errors/token_spend_limit_exceeded) | The request would pass the key's monthly cap | Wait until `resets_at`, or raise the cap in Settings |
| [`feature_not_in_plan`](https://docs.api.rask.ai/errors/feature_not_in_plan) | The payer's plan lacks a feature (`feature`) | Tell the user. [`GET /v3/plan`](https://docs.api.rask.ai/operations/getPlan) lists the features, and the plan changes in the web app |
| [`workspace_access_suspended`](https://docs.api.rask.ai/errors/workspace_access_suspended) | The workspace is paused (`reason`: `subscription_inactive`, `space_limit_exceeded`, `seat_limit_exceeded`) | Restore access in the web app; the key works again by itself |
| [`account_disabled`](https://docs.api.rask.ai/errors/account_disabled) | The user the key acts as is deactivated | Contact support |
| [`demo_project_read_only`](https://docs.api.rask.ai/errors/demo_project_read_only) | The project is a demo | Create your own project |
| [`trial_project_dub_not_allowed`](https://docs.api.rask.ai/errors/trial_project_dub_not_allowed) | A trial project is dubbed only once, automatically | Create a new project on a paid plan |
| [`prepare_mode_not_enabled`](https://docs.api.rask.ai/errors/prepare_mode_not_enabled) | The request sent `auto_dub: false`, and free preparation is not available | Remove `auto_dub: false`; choose voices with `speaker_voices` |
| [`voice_clone_limit_reached`](https://docs.api.rask.ai/errors/voice_clone_limit_reached) | The plan's clone quota is used up (`limit`, `used`) | Delete a clone, or tell the user the limit is reached |
| [`forbidden`](https://docs.api.rask.ai/errors/forbidden) | The request came from this site's playground, which may call only GET and estimate operations | Call the operation from your own code |

`feature_not_in_plan` with `feature: api_access` on every call means the plan has no API access at all.

## Trying requests on this site

The playground on the reference pages calls the API directly, with the key you paste. It may call only GET and estimate operations,
so nothing it does can spend. Use a read-only key. Estimates need the action's write scope, so a read-only key gets 403
[`insufficient_scope`](https://docs.api.rask.ai/errors/insufficient_scope) on them; to try an estimate, use a key without `credits:spend`.


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