API Keys
Admin-only CRUD for API keys. API keys provide an alternative to JWT cookie authentication for programmatic access.
Create API Key
POST /api/v1/api-keys
Request body:
{
"name": "CI Pipeline",
"role": "operator",
"read_only": true,
"expires_at": "2027-01-01T00:00:00Z"
}
Validation:
name is required
role must be "admin", "engineer" or "operator" (required)
read_only is an optional boolean, default false for API compatibility; see Read-only API Keys for the exact allowlist and version caveat. It is returned in creation and list responses.
expires_at is optional (ISO 8601 timestamp); if omitted, the key does not expire
Response: 201 Created
{
"key": "osprey_<one-time-secret>",
"api_key": {
"id": "uuid",
"user_id": "uuid",
"name": "CI Pipeline",
"role": "operator",
"read_only": true,
"key_prefix": "a1b2c3d4",
"is_active": true,
"created_at": "2026-02-17T12:00:00Z",
"expires_at": "2027-01-01T00:00:00Z"
}
}
Important: The top-level key field is returned only in this response. It cannot be retrieved afterward. Clients must store it securely at creation time.
Error responses:
400 Bad Request — Missing name or invalid role
403 Forbidden — Non-admin user
List API Keys
GET /api/v1/api-keys
List all API keys. The raw key is never included in list responses.
Response: 200 OK
[
{
"id": "uuid",
"name": "CI Pipeline",
"role": "operator",
"read_only": true,
"key_prefix": "a1b2c3d4",
"is_active": true,
"created_at": "2026-02-17T12:00:00Z",
"last_used_at": "2026-02-17T14:30:00Z",
"expires_at": "2027-01-01T00:00:00Z"
}
]
Note: last_used_at is null if the key has never been used. expires_at is null if the key does not expire.
Delete API Key
DELETE /api/v1/api-keys/{keyID}
Delete an API key. The key is immediately invalidated.
Response: 200 OK
{"status":"deleted"}
Error responses:
403 Forbidden — Non-admin user
404 Not Found — API key does not exist