> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.meshapi.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.meshapi.ai/_mcp/server.

# API Keys

> Create and manage inference keys programmatically — labels, limits, spend caps, model allow-lists, and org/team assignment.

An API key (`rsk_...`) is how your applications authenticate to MeshAPI. It is also the unit that carries **limits, spend caps, model access, and usage attribution** — so managing keys is how you control what each application is allowed to do.

This page covers the key-management API. For *using* a key to authenticate a request, see [Authentication](/docs/guides/authentication).

Key management uses a **user JWT** — your dashboard session token — not an `rsk_` key. An inference key cannot create or modify keys, by design: a leaked key must not be able to mint more.

***

## Creating a key

```bash
curl https://api.meshapi.ai/v1/keys \
  -H "Authorization: Bearer <YOUR_USER_JWT>" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "production-web",
    "rpm": 300,
    "spend_cap_usd": "50.00",
    "allowed_models": ["openai/gpt-4o-mini", "anthropic/claude-sonnet-4-5"]
  }'
```

The plaintext key is returned **once**, in the `key` field of the create response, and is never retrievable again — only a hash is stored. Capture it at creation or you will have to issue a new one.

### Fields

| Field                                           | Purpose                                                                           |
| ----------------------------------------------- | --------------------------------------------------------------------------------- |
| `label`                                         | Human name shown in the dashboard and usage breakdowns                            |
| `default_model`                                 | Model used when a request omits `model`                                           |
| `rpm` / `rpd` / `tpm`                           | Rate limits — see [Rate Limits & Spend Caps](/docs/guides/rate-limits-spend-caps) |
| `spend_cap_usd`                                 | Cumulative USD ceiling for this key                                               |
| `allowed_models`                                | Allow-list of models this key may call                                            |
| `model_limits`                                  | Per-model overrides                                                               |
| `org_id` / `team_id`                            | Attach the key to an org or team for pooled billing and limits                    |
| `routing_policy` / `routing_policy_template_id` | Retry and fallback behaviour (mutually exclusive — sending both is a `422`)       |

`rpm` above 1,000 or `rpd` above 1,000,000 are rejected with `422`.

***

## Managing keys

| Operation                   | Endpoint                      |
| --------------------------- | ----------------------------- |
| List keys                   | `GET /v1/keys`                |
| Filter options for the list | `GET /v1/keys/filter-options` |
| Update a key                | `PATCH /v1/keys/{id}`         |
| Suspend a key               | `DELETE /v1/keys/{id}`        |
| Resolved effective limits   | `GET /v1/keys/{id}/limits`    |

`DELETE` is a **soft delete**: it sets the key's status to `suspended`. The key stops working at the inference layer immediately, but the record and its usage history are preserved. There is no hard-delete endpoint — this keeps historical usage attributable.

***

## Model allow-lists

`allowed_models` restricts a key to a named set of models. It is the cleanest way to stop a cheap application reaching an expensive model.

An allow-list silently breaks features that route to models you didn't list:

* **`model: "auto"`** — the Auto Router picks from your allow-list. If none of its candidates are listed, routing fails.
* **Web search** — `/v1/web/search` checks against its own model pin. An allow-list that omits it disables web search for that key.

Neither failure is obvious from the error. If a feature stops working right after you set an allow-list, this is why. Include the models those features depend on, or leave the key unrestricted.

***

## Org and team keys

Assigning `org_id` or `team_id` makes a key part of a shared structure: it draws on the **org's shared balance** and inherits the org's and team's limits, resolved minimum-wins alongside the key's own.

Attaching a `routing_policy_template_id` requires the key to belong to an org — templates are org-scoped, and a key with no org gets a `422`.

See [Organizations & Teams](/docs/guides/organizations-teams) for the surrounding model.

***

## Related

* [Authentication](/docs/guides/authentication) — using a key to make requests
* [Rate Limits & Spend Caps](/docs/guides/rate-limits-spend-caps) — how limits resolve across tiers
* [Organizations & Teams](/docs/guides/organizations-teams) — shared billing and pooled limits
* [Account Configuration Checklist](/docs/guides/account-configuration-checklist) — recommended setup pass