Skip to main content

Agent Keys

Agent Keys are user-owned, scope-restricted API keys designed for AI agents and automated workflows. Each key is scoped to specific services and namespaces, supports optional TTL expiry, and can carry a fine-grained RBAC permission manifest that controls per-tool, per-namespace, and per-route access.

Key properties:

  • Format: ak_ followed by a token_urlsafe(32) string (e.g., ak_dGhpcyBpcyBhIHRlc3Qga2V5...)
  • Storage: Only the SHA-256 hash is persisted. The raw key is returned exactly once at creation and cannot be recovered.
  • Expiry: Keys with an expires_at timestamp past the current time are rejected with 401.
  • Limit: Maximum 100 active keys per user.

Authentication

All endpoints require a valid session (JWT bearer token or existing API key) via the unified auth middleware.

Base URL

/api/v1/auth

Scope Format

Scopes follow the pattern <service>:<permission>[:<namespace>]:

zerodb:read:project/my-project
zerodb:write:project/my-project
inference:read
memory:write:session:abc123

Valid services: zerodb, inference, memory, file, agent, mcp

Namespace is optional. When present, it restricts the key to a specific data partition.


Permission Manifest (RBAC)

A permission manifest provides fine-grained access control beyond scopes. All fields are optional; omitting a field means unrestricted access for that dimension.

{
"allowed_tools": ["zerodb_store_memory", "zerodb_recall"],
"allowed_namespaces": ["project/my-project"],
"denied_routes": ["/api/v1/billing/**", "/api/v1/admin/**"],
"max_memory_bytes": 1048576
}
FieldTypeDescription
allowed_toolsstring[]Whitelist of MCP tool names this key may invoke. Omit to allow all.
allowed_namespacesstring[]Whitelist of namespaces. Valid formats: global, project:<name>, project/<name>, session:<name>. Omit to allow all.
denied_routesstring[]Glob patterns for routes this key is denied. Supports ** wildcard (e.g., /api/v1/billing/**).
max_memory_bytesintegerMaximum memory the key may store, in bytes. Maximum: 104857600 (100 MB).

Permission evaluation order:

  1. Key must exist and be active (not revoked, not expired).
  2. If allowed_tools is set and the requested tool is not in the list, the request is denied.
  3. If allowed_namespaces is set and the requested namespace is not in the list, the request is denied.
  4. If denied_routes contains a pattern matching the request path, the request is denied.
  5. Otherwise, the request is allowed.

An empty manifest {} grants unrestricted access.


Endpoints

POST /api/v1/auth/keys

Create a new agent-scoped API key.

Request body:

{
"name": "ci-agent-key",
"scopes": ["zerodb:read:project/my-project", "zerodb:write:project/my-project"],
"ttl_seconds": 86400,
"permissions": {
"allowed_tools": ["zerodb_store_memory", "zerodb_recall"],
"allowed_namespaces": ["project/my-project"],
"denied_routes": ["/api/v1/billing/**"],
"max_memory_bytes": 1048576
}
}
FieldTypeRequiredDescription
namestringYesHuman-readable label (1-128 characters)
scopesstring[]YesAt least one scope in service:permission[:namespace] format
ttl_secondsintegerNoSeconds until expiry. Omit for a non-expiring key.
permissionsobjectNoRBAC permission manifest. Omit for unrestricted access.

Response (201 Created):

{
"id": "a1b2c3d4-...",
"user_id": "u-5678-...",
"name": "ci-agent-key",
"key": "ak_dGhpcyBpcyBhIHRlc3Qga2V5...",
"scopes": ["zerodb:read:project/my-project", "zerodb:write:project/my-project"],
"permissions": {
"allowed_tools": ["zerodb_store_memory", "zerodb_recall"],
"allowed_namespaces": ["project/my-project"],
"denied_routes": ["/api/v1/billing/**"],
"max_memory_bytes": 1048576
},
"expires_at": "2026-06-02T12:00:00+00:00",
"last_used_at": null,
"is_active": true,
"created_at": "2026-06-01T12:00:00+00:00"
}

The key field is only returned at creation time. Store it immediately.


GET /api/v1/auth/keys

List API keys for the authenticated user.

Query parameters:

ParameterTypeDefaultDescription
include_inactivebooleanfalseInclude revoked/expired keys
limitinteger50Max results (1-200)
offsetinteger0Pagination offset

Response (200 OK):

[
{
"id": "a1b2c3d4-...",
"user_id": "u-5678-...",
"name": "ci-agent-key",
"scopes": ["zerodb:read:project/my-project"],
"permissions": {},
"expires_at": "2026-06-02T12:00:00+00:00",
"last_used_at": "2026-06-01T14:30:00+00:00",
"is_active": true,
"created_at": "2026-06-01T12:00:00+00:00"
}
]

The raw key is never included in list responses.


DELETE /api/v1/auth/keys/{key_id}

Permanently revoke a key. This cannot be undone.

Response: 204 No Content

Errors:

StatusCondition
404Key not found or already revoked

GET /api/v1/auth/keys/{key_id}/permissions

Return the RBAC permission manifest for a key that belongs to the authenticated user.

Response (200 OK):

{
"allowed_tools": ["zerodb_store_memory"],
"allowed_namespaces": ["project/my-project"],
"denied_routes": ["/api/v1/billing/**"],
"max_memory_bytes": 1048576
}

An empty object {} means the key has unrestricted access.


POST /api/v1/auth/keys/{key_id}/check-permission

Evaluate a key's RBAC manifest against a specific tool, namespace, or route.

Request body:

{
"tool": "zerodb_store_memory",
"namespace": "project/my-project",
"route": "/api/v1/memory/v2/remember"
}

All fields are optional. Only the supplied fields are checked.

Response (200 OK):

{
"allowed": true,
"reason": "all checks passed"
}

When denied:

{
"allowed": false,
"reason": "tool 'zerodb_delete' not in allowed_tools"
}

Key Validation at Request Time

When an agent presents a key in the Authorization header, the validation logic:

  1. Confirms the key starts with ak_.
  2. Computes SHA-256(raw_key) and looks up the hash in agent_api_keys_v2.
  3. Checks is_active = true.
  4. Checks expires_at is null or in the future.
  5. Updates last_used_at on successful validation.
  6. Returns the key's metadata (user_id, scopes, permissions) to the caller.

Error Responses

StatusMeaning
401Missing or invalid authentication
404Key not found or does not belong to the user
422Validation error (invalid scopes, permissions, or name)