Calseta uses API key authentication. Both the REST API and MCP server accept the same keys.
All keys use the cai_ prefix followed by a 32-character URL-safe random string:
cai_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Keys are stored as bcrypt hashes. The full key is shown once on creation and cannot be retrieved again.
Creating an API Key
Via CLI (recommended for first key)
python -m app.cli.create_api_key \
--name "My Agent" \
--scopes "alerts:read,alerts:write,enrichments:read,workflows:read,workflows:execute"
Via API
curl -X POST http://localhost:8000/v1/api-keys \
-H "Authorization: Bearer cai_your_admin_key" \
-H "Content-Type: application/json" \
-d '{
"name": "My Agent Key",
"scopes": ["alerts:read", "alerts:write", "enrichments:read", "workflows:read"],
"key_type": "agent",
"expires_at": "2026-01-01T00:00:00Z"
}'
Save the returned API key immediately. It cannot be retrieved after creation.
Key Types
Every API key has a key_type — either "human" (default) or "agent":
| Type | Purpose | Workflow behavior |
|---|
human | Human operators, dashboards, scripts | Workflows triggered as trigger_source: human. Bypasses agent_only approval gates. |
agent | AI agents, automated systems | Workflows triggered as trigger_source: agent. Must provide reason and confidence when executing workflows. Subject to agent_only and always approval gates. |
The trigger_source for workflow execution is derived server-side from the API key’s key_type — it is not a request body field. This ensures agents cannot bypass approval gates by claiming to be human.
Create separate keys for human operators and AI agents. This gives you audit clarity and lets approval gates distinguish between human and agent triggers automatically.
Using API Keys
Include the key in the Authorization header with the Bearer prefix:
curl -X GET http://localhost:8000/v1/alerts \
-H "Authorization: Bearer cai_your_api_key"
The MCP server uses the same header format.
Scopes
Each API key has one or more scopes that control access:
| Scope | Grants access to |
|---|
alerts:read | Read alerts, indicators, activity, context |
alerts:write | Update alert status, post findings |
enrichments:read | Read and trigger enrichment, read field extractions |
workflows:read | Read workflows and workflow runs |
workflows:execute | Execute workflows |
approvals:write | Approve or reject workflow approval requests |
agents:read | Read agent registrations |
agents:write | Register, update, delete agents |
admin | Full access (API keys, source integrations, enrichment providers, field extractions) |
Follow the principle of least privilege. An agent that only reads alerts and posts findings needs alerts:read and alerts:write — not admin.
Key Prefix Display
For display and audit purposes, only the key prefix (first 8 characters, e.g., cai_a1b2) is stored. This identifies which key was used in logs without exposing the full secret.
Rate Limiting
All endpoints are rate-limited. Authenticated requests are limited by API key prefix. Unauthenticated requests are limited by IP address. When rate-limited, the response includes a Retry-After header.
Allowed Sources
API keys can optionally restrict which alert sources they can ingest from:
{
"name": "Sentinel-only key",
"scopes": ["alerts:write"],
"allowed_sources": ["sentinel"]
}
When allowed_sources is null (default), the key can ingest from any source.