Create an API key
POST /v1/api-keys · permission api-keys:write · required Idempotency-Key
Creates a management API key for the environment. A secret key reaches the whole management API; a restricted key carries only the listed permissions (<resource>:<action>).
- Raw key. The response carries
keyonce (idp_sk_live_…,idp_sk_test_…,idp_rk_live_…oridp_rk_test_…). It cannot be retrieved again; store it immediately. The response hasCache-Control: no-store. - No escalation. A key cannot create a key whose permissions exceed its own, and a
restrictedkey cannot create asecretkey. The new key cannot expire after the calling key, and a calling key withallowed_cidrscan only create keys limited to networks inside its own; ifallowed_cidrsis omitted, the new key gets the calling key's list (permission_escalation). - Limits. At most 50 active keys per environment, at most 20 CIDR blocks per key, expiry at most 730 days ahead. A key with
allowed_cidrsis accepted only from those networks. - Idempotent replay. Repeating the request with the same
Idempotency-Keyreplays the stored response without the key: the body hassecret_redacted: trueand nokey. Create a new key if the key was lost.
Request
Body:
| Field | Type | Description |
|---|---|---|
name |
string | Required. 1–100 characters. |
type |
string | Required. secret or restricted. |
permissions |
string[] | Required and non-empty for restricted (at most 200); absent or empty for secret. Cannot exceed the caller's own permissions. |
expires_at |
string (date-time) | Required, in the future, at most 730 days ahead. |
allowed_cidrs |
string[] | Optional, at most 20 CIDR blocks. |
Response
201 Created with Cache-Control: no-store. The key object as in the list response, plus key.
{
"id": "key_0000000000000000000000001z",
"name": "ci",
"type": "restricted",
"permissions": ["users:read"],
"allowed_cidrs": [],
"last4": "xxxx",
"created_by": "key_…",
"created_at": "2026-10-01T10:00:00Z",
"expires_at": "2027-10-01T10:00:00Z",
"last_used_at": null,
"last_used_ip": null,
"rotated_from": null,
"revoked_at": null,
"revoke_reason": null,
"key": "<shown once>"
}
Errors
| HTTP | code |
When |
|---|---|---|
| 401 | unauthenticated |
The key is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The key lacks the required permission. |
| 403 | permission_escalation |
The request would give a key more permissions, a wider network range or a later expiry than the calling key has, a restricted key tries to create, rotate or revoke beyond its own permissions, or another key tries to rotate or revoke a key created in the dashboard. |
| 409 | api_key_limit_reached |
The environment already has the maximum of 50 active keys. |
| 422 | validation_failed |
The body is invalid: missing or too long name, unknown type, restricted without permissions, secret with permissions, malformed permission or CIDR, expires_at in the past or more than 730 days ahead. |
Example
curl -X POST https://api.eu.keenauth.com/v1/api-keys \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"ci","type":"restricted","permissions":["users:read"],"expires_at":"2027-10-01T10:00:00Z"}'