API Keys API
API key endpoints require the admin scope. All responses redact the plaintext key (it is only returned at creation time).
Key Endpoints
Section titled “Key Endpoints”| Method | Path | Description |
|---|---|---|
POST |
/api/v1/api-keys |
Create API key |
GET |
/api/v1/api-keys |
List API keys |
DELETE |
/api/v1/api-keys/:id |
Revoke API key |
POST |
/api/v1/api-keys/:id/rotate |
Rotate API key |
GET |
/api/v1/api-keys/dormant |
List dormant keys |
Role Endpoints (RBAC)
Section titled “Role Endpoints (RBAC)”| Method | Path | Description |
|---|---|---|
POST |
/api/v1/roles |
Create role |
GET |
/api/v1/roles |
List roles |
GET |
/api/v1/roles/:id |
Get role |
PATCH |
/api/v1/roles/:id |
Update role |
DELETE |
/api/v1/roles/:id |
Delete role |
POST |
/api/v1/roles/assign/:keyId |
Assign role to API key |
DELETE |
/api/v1/roles/assign/:keyId |
Remove role from API key |
Create API Key
Section titled “Create API Key”POST /api/v1/api-keysBody:
{ "tenant_id": "uuid", "name": "my-service", "rate_limit_max": 100, "rate_limit_window": "1 minute"}| Field | Type | Required | Description |
|---|---|---|---|
tenant_id |
UUID | Yes | Tenant to scope the key to |
name |
string | No | Descriptive name |
rate_limit_max |
integer | No | Max requests per window (1–100,000) |
rate_limit_window |
string | No | Time window (e.g., "30 seconds", "1 minute", "1 hour") |
Response: 201 Created
{ "id": "key-uuid", "tenant_id": "tenant-uuid", "key_prefix": "sk_live_abc", "name": "my-service", "created_at": "2024-01-01T00:00:00.000Z", "plaintext_key": "sk_live_abc123..."}The plaintext_key is only returned in this response and cannot be retrieved again.
List API Keys
Section titled “List API Keys”GET /api/v1/api-keys?tenant_id=<uuid>Query Parameters:
| Param | Type | Description |
|---|---|---|
tenant_id |
UUID | Filter by tenant (optional; scoped keys auto-filter) |
Response: 200 OK – array of API key records (without plaintext keys).
Revoke API Key
Section titled “Revoke API Key”DELETE /api/v1/api-keys/:idResponse: 204 No Content
Returns 404 if the key does not exist or is already revoked.
Rotate API Key
Section titled “Rotate API Key”POST /api/v1/api-keys/:id/rotateRevokes the existing key and creates a new one. Optionally update the name.
Body (optional):
{ "name": "my-service-v2"}Response: 201 Created – returns the new key with plaintext_key.
List Dormant Keys
Section titled “List Dormant Keys”GET /api/v1/api-keys/dormant?days=90Returns keys that have not been used in the specified number of days.
| Param | Type | Default | Description |
|---|---|---|---|
days |
integer | 90 | Minimum days since last use (1–365) |
Response: 200 OK – array of API key records.
Create Role
Section titled “Create Role”POST /api/v1/rolesBody:
{ "name": "Editor", "description": "Can read and write but not manage keys", "scopes": ["read", "write"], "tenant_id": "uuid (optional, null for global)"}| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Role name (1–100 chars) |
description |
string | No | Description (max 500 chars) |
scopes |
string[] | Yes | Array of "read", "write", "admin" |
tenant_id |
UUID | No | Scope role to a tenant (null for global) |
Response: 201 Created – returns the role object.
List Roles
Section titled “List Roles”GET /api/v1/roles?tenant_id=<uuid>Response: 200 OK – array of role objects.
Update Role
Section titled “Update Role”PATCH /api/v1/roles/:idBody (all optional):
{ "name": "Senior Editor", "scopes": ["read", "write", "admin"]}Response: 200 OK – returns the updated role.
Assign Role to API Key
Section titled “Assign Role to API Key”POST /api/v1/roles/assign/:keyIdBody:
{ "role_id": "uuid"}When a role is assigned, the role’s scopes override the key’s default scopes.
Response: 200 OK – {"success": true}
Remove Role from API Key
Section titled “Remove Role from API Key”DELETE /api/v1/roles/assign/:keyIdRemoves the role, reverting the key to its own default scopes.
Response: 200 OK – {"success": true}
Error Responses
Section titled “Error Responses”| Code | Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid API key / JWT |
FORBIDDEN |
403 | Insufficient scope |
NOT_FOUND |
404 | Key or role not found |
VALIDATION_ERROR |
400 | Invalid request body |
