---
title: Keys
description: The whole life of a key: what is chosen at creation and never again, the one showing of the secret, the switch, the trash, and erasing for good.
keywords: keys, api key, secret, expiry, whitelist, trash, revoke, disable
group: account
---

## Issue a key in a minute {#quick keywords="create a key, copy, environment variable"}

:::steps
- **Create the key** — On the keys screen in the console. A name and, if you want one, an expiry; the rest can stay as it is.
- **Copy the secret at once** — It is shown once, on the very panel that created it.
- **Put it in the environment** — Not in the source, and not in a config that will travel to a repository.
:::

```bash title=Shell
export KUMO_API_KEY="kumo_sk_..."
```

> [Open the console →](https://console.kumorouter.com/) [Check the key is alive →](/en/key-check)

## What is chosen at creation {#create keywords="name, expiry, spends from, whitelist, package, balance"}

The creation form asks two things — a **name** and an **expiry**. The key carries more than that, but it is not chosen here.

:::deflist
| Property | Rule |
| --- | --- |
| Name | 1 to 50 characters after trimming spaces. Counted in characters, so a 50-character non-Latin name goes through whole. **Fixed at creation.** |
| Expiry | No expiration, or one of the ready terms: 1 hour, 1 day, 7, 30, 90, 180 days, 1 year. **Changed later.** |
| Spends from | The account package or the organization balance. **Changed later** — in the "Choose how it is charged" window. |
| Whitelists | Modalities, models, providers. **Fixed at creation.** |
:::

What is chosen at creation is a term rather than an instant: the form carries exactly that ladder, and there is nothing in it to mistype. An exact date and time live in the settings of a key that already exists.

A key is not renamed — there is no rename operation at all, and the settings say so in words. The whitelists are not editable for the same reason: the cure is not an edit but a new key with the whitelist you want and a revocation of the old one.

:::note
Today the console creates a key **open on all three axes**: the creation form offers no whitelist fields, even though the key itself carries them. While that is so, a key created in the console reaches everything published. A new key spends from the account package when there is one, and from the balance otherwise.
:::

### The whitelists

A key has an optional scope on three axes, and an empty axis means "every one": a key with no axis at all is unrestricted. A call that names something outside the list is refused rather than routed — this is a whitelist, not a preference.

- **Modalities** — kinds of work: text generation, embeddings, image generation.
- **Models** — specific identifiers, one per line.
- **Providers** — the suppliers behind those models.

### The ceilings

Kumo sets the rate ceilings, and they stand on the key from the moment it exists. Neither this form nor any other console screen sets them — the console shows them.

> [Which ceilings, and what to do on a 429 →](/en/limits) [How the scope reads back →](/en/authentication)

## The secret is shown once {#secret keywords="secret, reveal, hash, lost key"}

The full secret is shown by **only the operation that created the key**, and only at that moment. After it, the platform holds its hash together with the two fragments used for display, and nothing can read the secret back: not a screen, not an operation, not a request to support.

:::warning
A replay of the same creation with the same attempt identifier answers with the key's metadata and **no secret**: it is never revealed a second time and never reissued. The cure for a lost key is a new key.
:::

## How a key reads in the list {#list keywords="prefix, tail, version, status, usage"}

The list answers metadata and nothing else: no secret, no hash. A key is recognized by the **first eight characters of its random part and the last four**, plus the name you gave it — and that is how it is printed, the two fragments with an ellipsis between them.

| Column | What it shows |
| --- | --- |
| `Name` | What you set at creation. |
| `Key` | The prefix and the tail — the fragments that are safe to show. |
| `Billing` | The account package, or the organization balance. |
| `Usage` | What this key has been charged since the start of the current UTC month. |
| `Limit` | The key's effective ceilings. |
| `Project` | The label the key sits under, or the absence of one. |

A key also carries a **version** — not a column of the list but a property of the row. It is the number an edit checks itself against: two concurrent changes cannot both win, and the loser is refused rather than quietly overwritten. The version rises when the key's metadata changes and deliberately does not rise from the key being used.

There is a **last-used instant** too. It is approximate by construction: the value is written with a delay and is not a request counter.

## What changes after creation {#edit keywords="expiry, project, disable, enable, package, balance"}

Four things, all four reversible.

- **The expiry** — set, moved and cleared. A past instant is refused: a key cannot be edited into having been dead already.
- **The project** — a key moves into a project and out of it. A project is a label and never a funding container, so the move does not touch what the key spends from.
- **What it spends from** — the account package or the balance, and for a key on the package, also what happens when the limit runs out: stop, or carry on from the balance. The key's own package limits are set there too. All of it lives in the "Choose how it is charged" window, which opens when you press the key's cell in the "Billing" column.
- **The switch** — Disable and Enable. A switched-off key authenticates nothing while it is off, and loses nothing else.

The switch is independent of revocation and is not a second spelling of it: enabling clears only the switch, while a revoked or expired key stays exactly as dead as it was.

## The end of a key's life {#end-of-life keywords="disable, trash, restore, erase, expired, revoke"}

Four states in which a key does not work. Two of them are reversible and two are not, and confusing them is expensive.

:::matrix
| What happened | Key works | Reversible |
| --- | --- | --- |
| Disabled | no | yes, Enable |
| In the trash | no | yes, Restore |
| Expired | no | no |
| Erased for good | no | no |
:::

**The trash** is a state and not a deletion: the key stays in the list with its deletion stamped, keeps everything else, and comes back from a restore exactly as it went in — switched off if it was off. The trash has no deadline: deleted keys stay there until they are restored or erased for good.

**Erasing for good** is available only for a key already in the trash; a key that is not is refused. After it, no list of this surface returns the key.

:::warning
Neither deleting into the trash nor erasing for good asks twice: both act on a single press. Only the first of them is reversible.
:::

The organization's history outlives an erasure: the calls and the money movements stay, because they are records about money and not about a key. Such a call keeps its row in the log with an empty key name — the call is there, there is simply nothing left to name it with.

**Expiry** is final: an expired key cannot be extended and cannot have its expiry lifted — a new one is issued.

There is a fifth state, and it is terminal: **revocation**. It ends the key's life and records the act in the log together with the reason, if you gave one; there is no reactivation, and two concurrent revocations cannot both succeed. The console carries no separate revoke button — it has the switch and the trash. In the list a revoked key and a switched-off key read as one word, because for a reader they are one state: not working, but its row still there.

## What a dead key answers {#refusals keywords="401, refusal, revoked, expired, oracle"}

The same `401` and the same sentence — for a missing header, a malformed key, an unknown one, a revoked one, a switched-off one and an expired one. The gateway never says which of the six it was: telling them apart would make it an oracle on key material.

Which of your keys is alive is a question for the console and for the identity echo, not for the gateway.

> [Check a key →](/en/key-check) [Every gateway status →](/en/errors)
