> ## Documentation Index
> Fetch the complete documentation index at: https://spillway.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Virtual keys & provider keys

> The two key types: what callers use, and what Spillway uses to reach providers.

Spillway has two distinct kinds of API key, and they're not interchangeable.

> **Provider key**
>
> **Yours.** The real `sk-…` from OpenAI, Anthropic, etc. Spillway stores it encrypted
> (AES-256-GCM) and uses it to call the provider on your behalf. Never returned to
> clients.

> **Virtual key**
>
> **Spillway's.** An `mk-live-…` key you hand to whatever calls the gateway. Scoped to a
> team, model allow-list, and rate limits — never touches a real provider credential.

## Provider keys

Add a provider key once per provider your org uses. All governed traffic to that provider
routes through it.

```jsonc theme={null}
// POST /api/provider-keys   (session auth)
{
  "provider": "openai",
  "label": "prod-openai",
  "apiKey": "sk-..."
}
```

`apiKey` is write-only — it's encrypted on write and never echoed back by `GET
/api/provider-keys`. A custom `baseUrl` isn't accepted yet; custom upstreams go through the
OpenAI-compatible adapter instead.

## Virtual keys

A virtual key is what you actually distribute — to a service, a team, a script. It's the
credential the data plane (`/v1/*`) authenticates.

```jsonc theme={null}
// POST /api/virtual-keys
{
  "name": "checkout-service",
  "teamId": "<team-uuid>",
  "allowedModels": ["gpt-4.1-mini", "gpt-4.1"],
  "rpmLimit": 500,
  "tpmLimit": 200000,
  "maxInputTokens": 32000,
  "maxOutputTokens": 4096,
  "expiresAt": "2027-01-01T00:00:00Z",
  "metadata": { "team": "checkout" }
}
```

| Field | Type | What it does |
| - | - | - |
| `name` | string, required | Label shown in the dashboard and reports. |
| `teamId` | uuid | Attributes spend to a team (drives budgets scoped to `team` and chargeback reports). |
| `allowedProviders` | array | Restricts which providers this key may route to. |
| `allowedModels` | array | Restricts which models this key may request. |
| `rpmLimit` / `tpmLimit` | integer | Per-key requests-per-minute / tokens-per-minute cap. |
| `maxInputTokens` / `maxOutputTokens` | integer | Hard ceiling on a single request's token counts. |
| `expiresAt` | datetime | Key stops authenticating after this time. |
| `metadata` | object (string values) | Arbitrary tags — also settable per request via the `x-spillway-tags` header, merged into the request's logged metadata. |

The plaintext key (`mk-live-…`) is returned **once**, at creation. Only its hash is stored —
there's no "reveal" later, only revoke-and-reissue.

> [!TIP]
>
> A virtual key authenticates with `Authorization: Bearer mk-live-…` or `x-api-key:
>     mk-live-…` — both are accepted, so either SDK convention works unmodified.

## Where next

> **[Budgets](https://spillway.mintlify.site/configuration/budgets.md)**
>
> Cap spend on a virtual key, team, org, or provider.

> **[Teams & orgs](https://spillway.mintlify.site/configuration/teams-and-orgs.md)**
>
> Organize keys under teams for attribution and chargeback.


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