API Keys
Dashboard: /overview/api-keys. Internal API: /api/internal/api-keys.
Endpoints (internal)
| Method | Purpose |
|---|---|
GET |
List non-revoked keys for session's org |
POST |
Create key — returns full key once |
DELETE ?id=key_... |
Soft revoke via revoked_at |
Create
POST /api/internal/api-keys
{
"name": "Server",
"environment": "live",
"expiresInDays": 90,
"rateLimitPerMinute": 1200
}
| Field | Notes |
|---|---|
name |
required, user-visible label |
environment |
live or test |
expiresInDays |
optional, 1–3650. If set, expiresAt is stored; validation rejects expired keys. |
rateLimitPerMinute |
optional, 1–100000. Per-key sliding-window limit checked before the org/plan bucket. Omit to inherit the plan default. |
allowedCidrs |
optional array of up to 20 CIDR ranges (IPv4 or IPv6). Requests from outside these ranges fail with 403 IP_NOT_ALLOWED. |
Response (201):
{
"id": "key_...",
"key": "sok_live_...",
"name": "Server",
"environment": "live",
"rate_limit_per_minute": 1200,
"expires_at": "2026-07-20T00:00:00.000Z"
}
IP allowlist
When allowedCidrs is set, withApiAuth compares the request's client IP
(from X-Forwarded-For or X-Real-IP) against each CIDR. Any match allows
the request through; no match returns:
HTTP 403
{ "error": { "type": "authentication_error", "code": "IP_NOT_ALLOWED", "message": "Request IP is not in this key's allowlist" } }
IPv4 and IPv6 are both supported. Bare IPs are treated as /32 (IPv4) or
/128 (IPv6). 0.0.0.0/0 effectively disables the check.
Audit: api_key.created logged.
Storage model
- Full key displayed once to user, never persisted.
key_hash= sha256(full key) — lookup index.last_four= last 4 chars of the nanoid portion — shown in UI.key_prefix=sok_live_orsok_test_.expires_atenforced invalidateApiKey()viaOR (expires_at IS NULL, expires_at > now()).
Revoke
DELETE /api/internal/api-keys?id=key_... — sets revoked_at = now(). Revoked keys fail the isNull(revoked_at) filter and return 401 on use. Audit: api_key.revoked.
Test vs live
See ../api/authentication.md. Test keys bypass AWS calls and usage limits.