---
title: Managing keys
description: How to create and revoke an API key in the Developer Console, what a new key comes with, where to find its webhook secret, and how many keys you can hold.
icon: KeySquare
---

You create and revoke API keys in the [Developer Console](/en/developer), on the **API keys** tab. The full key and the webhook signing secret are shown **once**, at creation — save them right away. How to send the key with requests is covered in [Authentication](/en/docs/getting-started/authentication).

## Creating a key

<Steps>
<Step>
### Open the console

Go to the [Developer Console](/en/developer), open the **API keys** tab and click **Create key**. A key is issued only after a recent sign-in: if you signed in a while ago, the console asks you to confirm it again (your password, or a code when two-factor protection is on).
</Step>

<Step>
### Set a name and environment

The name can be up to 100 characters; it helps you tell keys apart in the list and in logs. The environment is either live (`clipia_live_…`) or test (`clipia_test_…`, see [Sandbox](/en/docs/getting-started/sandbox)).
</Step>

<Step>
### Set the expiry and the budget

Expiry is **never** by default, or 30, 90, 180 or 365 days. The budget is an optional spending cap for the key in credits: over the last day, 7 or 30 days, or over the key's whole lifetime. See [Expiry and budget](#expiry-and-budget).
</Step>

<Step>
### Save the key and the secret

Copy the full key and the **webhook signing secret**. Each key has its own secret, used to sign webhooks for jobs submitted with that key. Neither is shown again.
</Step>
</Steps>

Creating and rotating a key requires a recent sign-in: with an old session the console asks you to confirm your sign-in and then retries the action itself. The account owner gets an email about every key created and every key revoked in the console — see [Owner emails](#owner-emails).

<Callout type="warn" title="Lost a key or secret">
They can't be recovered. Click **Rotate** next to the key: you get a new key and secret, and the old key keeps working for 24 more hours — see [Rotating a key](#rotating-a-key).
</Callout>

## What a key comes with

| Property | Value |
|----------|-------|
| Permissions | `generate` and `read`; you can't choose them — see [Key permissions](/en/docs/getting-started/authentication#scopes) |
| Request limit | 120 per minute per key, see [Rate limits](/en/docs/api-reference/rate-limits) |
| Concurrency | unlimited by default |
| Expiry | never by default; 30, 90, 180 or 365 days to choose from |
| Budget | no cap by default; credits over the last day, 7 or 30 days, or lifetime |
| Balance | shared by all keys on the account |

An account can hold up to 20 active keys; expired keys and keys expiring within a day, such as those replaced by a rotation, don't count. Beyond that, creating a key returns `400` with the message `api_key_limit_reached`.

## Expiry and budget

**Expiry** is set at creation and can't be extended: after the date, requests with the key get `401 invalid_api_key`, and the key list marks it **expired**. To avoid downtime, rotate the key ahead of time, at least a day before it expires — the new key gets the same term, counted from the rotation.

**Budget** is a cap on the credits the key may spend: over the last day, 7 or 30 days (a sliding window) or over the key's whole lifetime. The owner sets it in the console when creating the key. Spending is counted from the charge ledger and this key's unfinished jobs — generations, LLM chat and MCP; refunded credits don't count.

A generation submit is rejected with `402` and the code `insufficient_quota` if it would take spending over the budget; a chat request, once spending has reached the budget. Simultaneous requests can go slightly over it. Reading a result, a status or the catalog is never blocked by the budget. A rejected submit looks like this:

```json
{
  "error": {
    "type": "billing_error",
    "code": "insufficient_quota",
    "message": "This request does not fit the remaining API key budget for the current period."
  }
}
```

In [chat](/en/docs/llm-gateway/chat-completions) the same code comes in the OpenAI envelope with `type: insufficient_quota`. Spending that leaves the window makes room in the budget; a lifetime budget doesn't regain room on its own. A budget limits one key and doesn't change the account balance: it doesn't protect against spending through other keys. After a rotation, the new key's count starts from zero.

## Rotating a key

Click **Rotate** next to an active key. The console creates a new key with the same name, environment, permissions, limits and budget and shows its full key and webhook signing secret — once, as at creation. The old key keeps working for **24 more hours**, then expires on its own — no need to revoke it. A key that expires within a day, including one already rotated, can't be rotated: the request returns `409` with the code `api_key_rotation_unavailable`, so create a new key instead.

Zero-downtime order: rotate → update the key and the secret in your integration and webhook handler → confirm requests are coming from the new key. Each key has its own secret, and webhooks for jobs submitted with the old key are signed with the old one. Keep both secrets in your handler until those deliveries end: retries run for about 24 hours after the job finishes.

## Owner emails

The account email receives service notifications about access events: **API key created** (with the name and the last four characters; for a rotation, which key was replaced), **key revoked** (a password reset sends no separate revocation email) and **app connected** (a new OAuth connection, for example Claude or ChatGPT). Secrets never appear in emails. If an event isn't yours, revoke the key or disconnect the app in the console and change your password.

## Revoking a key

Click **Revoke** next to the key in the list. Revocation takes effect immediately, or within a minute at most. After that, requests with the key get `401 invalid_api_key`.

<Callout type="warn" title="The key is a server-side secret">
Never put the key in a browser, mobile app or public repository. If a key leaks, revoke it right away and create a new one.
</Callout>

## Key usage

The console's **Logs** tab shows requests by key; for a rejected request the log stores the error code (`invalid_request`, `not_found`), not its text. [`GET /v1/account`](/en/docs/api-reference/account) returns a 30-day summary for the current key, and LLM clients can use [`GET /v1/key`](/en/docs/llm-gateway/account).
