<!-- API Keys — https://docs.warmerly.com/keys -->

# API Keys

Manage the API keys used to authenticate requests to the Warmerly API. This page covers
creating, listing, and revoking keys programmatically. If you're looking for how to use
a key you already have, see [Authentication](https://docs.warmerly.com/authentication).

Key management endpoints are not project-scoped: they only need `X-Api-Key`, not
`X-Project-Id`.

**API access is an Agency-plan feature.** Listing and creating keys returns `403
agency_plan_required` on Starter and Growth workspaces; upgrade at
[warmerly.com/pricing](https://warmerly.com/pricing). Revoking a key you already hold is
always allowed, even after a downgrade.

## List keys

```
GET /keys
```

Returns all of your active (non-revoked) keys, newest first. The raw secret is never
returned, only the id, name, prefix, rate limit, and usage metadata.

```bash
curl https://app.warmerly.com/api/v1/keys \
  -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

```json
{
  "keys": [
    {
      "id": "3b1f6e2a-9c4d-4e2a-8b5f-6a2c1d9e0f7b",
      "name": "CI pipeline",
      "prefix": "wmv_7f3a2c",
      "rateLimitPerMin": 60,
      "lastUsedAt": "2026-07-01T09:12:44.000Z",
      "createdAt": "2026-06-20T14:03:11.000Z"
    },
    {
      "id": "9a2d4c11-5e7b-4f10-b2aa-1c8f0d3e6a4b",
      "name": "Zapier",
      "prefix": "wmv_9d1e0b",
      "rateLimitPerMin": 120,
      "lastUsedAt": null,
      "createdAt": "2026-06-18T08:47:02.000Z"
    }
  ]
}
```

| Field | Type | Description |
| --- | --- | --- |
| `id` | string (UUID) | Key ID, use this to revoke the key. |
| `name` | string | The label you gave the key when creating it. |
| `prefix` | string | The first few characters of the key (`wmv_...`), useful for identifying which key is which without exposing the secret. |
| `rateLimitPerMin` | number | Requests per minute allowed for this key. |
| `lastUsedAt` | string \| null | ISO 8601 timestamp of the key's most recent authenticated request, or `null` if it has never been used. |
| `createdAt` | string | ISO 8601 timestamp of when the key was created. |

Revoked keys are excluded from this list entirely.

## Create a key

```
POST /keys
```

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string (1-120 chars) | Yes | A label to help you identify the key later. |
| `rateLimitPerMin` | integer (1-120) | No | Requests per minute allowed for this key. Defaults to `60`, capped at `120` regardless of plan. |

Each user can hold at most **10 active keys**; creating an 11th (without revoking one
first) returns `400 too_many_keys`.

```bash
curl -X POST https://app.warmerly.com/api/v1/keys \
  -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "name": "CI pipeline", "rateLimitPerMin": 100 }'
```

```json
{
  "key": "wmv_7f3a2cdb9e1a4f0c8b6d2e5f7a1c3b9d",
  "id": "3b1f6e2a-9c4d-4e2a-8b5f-6a2c1d9e0f7b",
  "prefix": "wmv_7f3a2c",
  "name": "CI pipeline"
}
```

**The `key` field is the only time the raw secret is ever returned.** Warmerly stores
only a hash of the key, copy it and store it securely immediately. If you lose it,
there is no way to recover it; revoke the key and create a new one instead.

A response with HTTP status `201` confirms the key was created.

### Validation errors

An invalid body (missing `name`, `name` over 120 characters, or `rateLimitPerMin`
outside `1` to `120`) returns `400`:

```json
{ "error": { "code": "bad_request", "message": "invalid_body", "details": { /* field errors */ } } }
```

## Revoke a key

```
DELETE /keys/{id}
```

Revokes (soft-deletes) the key. Revoked keys fail authentication immediately on their
next request, there is no grace period, and revocation cannot be undone.

```bash
curl -X DELETE https://app.warmerly.com/api/v1/keys/3b1f6e2a-9c4d-4e2a-8b5f-6a2c1d9e0f7b \
  -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

```json
{ "revoked": true }
```

If the key doesn't exist, doesn't belong to you, or has already been revoked, this
returns `404`:

```json
{ "error": { "code": "not_found", "message": "not_found", "details": null } }
```

You can revoke the key you're currently authenticating with. The revocation takes
effect immediately, so any subsequent request with that key (including further calls
in the same script) will fail with `401 unauthorized`.
