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.
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 any workspace that is not on Agency; upgrade at warmerly.com/pricing. Revoking a key is not plan-gated, so you can still revoke from the dashboard after a downgrade. A request authenticated with an API key, including a revoke, is plan-checked like any other and gets 403 agency_plan_required until the workspace is back on Agency.
#List keys
GET /keysReturns 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.
curl https://app.warmerly.com/api/v1/keys \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{
"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 with error.code bad_request, error.message too_many_keys and error.details { "max": 10 }.
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 }'{
"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:
{ "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.
curl -X DELETE https://app.warmerly.com/api/v1/keys/3b1f6e2a-9c4d-4e2a-8b5f-6a2c1d9e0f7b \
-H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"{ "revoked": true }If the key doesn't exist, doesn't belong to you, or has already been revoked, this returns 404:
{ "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.