Edictum
Edictum ConsoleReference

API Reference

66+ endpoints across 17 route groups. All API routes are under /api/v1/ with cookie, API key, or dual authentication.

AI Assistance

Right page if: you need the exact HTTP method, path, auth type, and request/response shape for any of the 65+ console API endpoints. Wrong page if: you are debugging the SDK-to-console connection specifically -- see https://docs.edictum.ai/docs/console/reference/sdk-compat. For SSE event payloads, see https://docs.edictum.ai/docs/console/reference/sse-events. Gotcha: mutating requests (POST/PUT/DELETE/PATCH) with cookie auth require the `X-Requested-With` header for CSRF protection. API key requests are exempt.

Edictum Console exposes 66+ endpoints across 17 route groups. All API routes are under /api/v1/.

Authentication Types

TypeHeader/CookieUsed By
Cookieedictum_session HttpOnly cookieDashboard users. Set on login.
Adminedictum_session HttpOnly cookie + is_admin flagAdmin-only operations (key management, settings, notifications).
API KeyAuthorization: Bearer edk_{env}_{random} + X-Edictum-Agent-Id: {agent_id}Agents via edictum[server] SDK.
EitherCookie or API KeyEndpoints accessible to both dashboard and agents.
None--Public endpoints (health, login, setup, webhooks).

CSRF protection: mutating requests (POST/PUT/DELETE/PATCH) with cookie auth require X-Requested-With header. API key requests are exempt.


Auth

MethodPathAuthDescription
POST/api/v1/auth/loginNoneLogin with email/password. Sets HttpOnly session cookie.
POST/api/v1/auth/logoutCookieDestroy session and clear cookie.
GET/api/v1/auth/meCookieReturn current user info (user_id, tenant_id, email, is_admin).

Login Request

{
  "email": "admin@example.com",
  "password": "your-password"
}

Rate limited per IP (default: 10 attempts per 300 seconds). Returns 429 with Retry-After header when exceeded. Constant-time response for wrong email and wrong password to prevent user enumeration.


Setup

MethodPathAuthDescription
POST/api/v1/setupNoneCreate first admin user and tenant. Bootstrap lock -- returns 409 if any user exists.

Setup Request

{
  "email": "admin@example.com",
  "password": "min-12-characters"
}

Health

MethodPathAuthDescription
GET/api/v1/healthNoneMinimal unauthenticated health check.
GET/api/v1/health/detailsCookieFull operational health payload. Requires dashboard session auth.

Health Response

{
  "status": "ok",
  "bootstrap_complete": true
}

Status is "ok" when Redis is reachable, "degraded" otherwise. This endpoint is intentionally minimal — it returns only status and bootstrap_complete. Use /health/details for the full operational payload.

Health Details Response

Requires a valid dashboard session cookie.

{
  "status": "ok",
  "version": "0.1.0",
  "auth_provider": "local",
  "base_url_https": true,
  "database": {"connected": true, "latency_ms": 2.1},
  "redis": {"connected": true, "latency_ms": 0.8},
  "workers": 4,
  "connected_agents": 3
}

Fields version, auth_provider, base_url_https, database, redis, workers, and connected_agents are only returned by /health/details. External monitors and uptime checks should use the unauthenticated /health endpoint.


API Keys

MethodPathAuthDescription
POST/api/v1/keysAdminCreate a new API key. Full key returned once -- cannot be retrieved again.
GET/api/v1/keysCookieList all non-revoked API keys for the tenant.
DELETE/api/v1/keys/{key_id}AdminRevoke an API key.

Create Key Request

{
  "env": "production",
  "label": "My Agent Key"
}

env must be one of: production, staging, development.

Create Key Response

{
  "id": "uuid",
  "key": "edk_production_CZxKQvN3mHz...",
  "prefix": "edk_production_CZxKQvN3",
  "env": "production",
  "label": "My Agent Key",
  "created_at": "2026-03-01T12:00:00Z"
}

Contracts

MethodPathAuthDescription
GET/api/v1/contractsCookieList contracts in library (latest versions, with optional type/tag/search filters).
POST/api/v1/contractsCookieCreate a new contract in the library.
POST/api/v1/contracts/importCookieImport contracts from a YAML bundle (decompose into library).
GET/api/v1/contracts/{contract_id}CookieGet contract details (latest version + version history).
GET/api/v1/contracts/{contract_id}/versions/{version}CookieGet a specific version of a contract.
PUT/api/v1/contracts/{contract_id}CookieUpdate a contract (creates a new version).
DELETE/api/v1/contracts/{contract_id}CookieDelete a contract (all versions). Fails if referenced by a composition.
GET/api/v1/contracts/{contract_id}/usageCookieList compositions that use this contract.

Create Contract Request

{
  "contract_id": "block-dotenv",
  "name": "Block .env reads",
  "description": "Prevent agents from reading environment files",
  "type": "pre",
  "definition": {
    "tools": ["read_file"],
    "when": { "args.path": { "matches": ".*\\.env.*" } },
    "then": { "effect": "deny", "message": "Reading .env files is not allowed" }
  },
  "tags": ["security", "filesystem"]
}

contract_id format: [a-z0-9][a-z0-9_-]*. type must be one of: pre, post, session, sandbox.


Compositions

MethodPathAuthDescription
GET/api/v1/compositionsCookieList all compositions for the tenant.
POST/api/v1/compositionsCookieCreate a new composition.
GET/api/v1/compositions/{name}CookieGet composition detail with contract items.
PUT/api/v1/compositions/{name}CookieUpdate a composition (add/remove/reorder contracts).
DELETE/api/v1/compositions/{name}CookieDelete a composition.
POST/api/v1/compositions/{name}/previewCookieAssemble and return YAML without deploying.
POST/api/v1/compositions/{name}/deployCookieAssemble, sign, deploy, and push the composed bundle.

Create Composition Request

{
  "name": "devops-agent",
  "description": "Contracts for DevOps agents",
  "defaults_mode": "enforce",
  "update_strategy": "manual",
  "contracts": [
    { "contract_id": "block-dotenv", "position": 0, "mode_override": null, "enabled": true },
    { "contract_id": "log-all-writes", "position": 1, "mode_override": "observe", "enabled": true }
  ]
}

Deploy Response

{
  "bundle_name": "devops-agent",
  "bundle_version": 4,
  "contracts_assembled": [],
  "deployment_id": "uuid"
}

Bundles

MethodPathAuthDescription
POST/api/v1/bundlesCookieUpload a new bundle version. Name extracted from YAML metadata.name.
GET/api/v1/bundlesEitherList distinct bundle names with summaries (includes contract_count, last_deployed_at).
GET/api/v1/bundles/{name}CookieList all versions for a named bundle (newest first).
GET/api/v1/bundles/{name}/currentEitherGet currently deployed bundle for a (name, env) pair. Returns yaml_bytes (base64).
GET/api/v1/bundles/{name}/{version}EitherGet a specific bundle version (metadata only).
GET/api/v1/bundles/{name}/{version}/yamlEitherGet raw YAML content (Content-Type: application/x-yaml).
POST/api/v1/bundles/{name}/{version}/deployCookieDeploy a bundle version to an environment. Signs with Ed25519. Pushes SSE event.
POST/api/v1/bundles/evaluateCookieEvaluate contracts against a test tool call (playground, never called by agents).

Evaluate Endpoint Limits

The evaluate endpoint enforces resource limits to protect the server. Exceeding them returns a 422 or 429:

LimitValueError
Evaluation timeout5 seconds422"Evaluation timed out"
Concurrent evaluations4429 — semaphore full; retry after existing evaluations complete
YAML documents per request10422 — validation error
Contracts per request100422 — validation error

The 429 response does not include a Retry-After header. The 422 responses include loc and msg fields only — ctx and type are omitted.

Environment Scoping for API Key Auth

When accessed with an API key, bundle endpoints are restricted to the key's scoped environment:

EndpointAPI Key Behavior
GET /bundlesReturns only bundles deployed to the key's environment. Cross-environment bundles are not listed.
GET /bundles/{name}/currentReturns 403 Forbidden if the env query parameter does not match the key's scoped environment.
GET /bundles/{name}/{version}Returns 404 Not Found if the bundle version belongs to a different environment.
GET /bundles/{name}/{version}/yamlReturns 404 Not Found if the bundle version belongs to a different environment.

Note: GET /bundles/{name}/{version} and its /yaml variant return 404 (not 403) for cross-environment access to avoid leaking the existence of bundle versions in other environments. Dashboard (session) auth sees all environments without restriction.


Deployments

MethodPathAuthDescription
GET/api/v1/deploymentsCookieList deployments (newest first). Optional filters: env, bundle_name, limit.

Events

MethodPathAuthDescription
POST/api/v1/eventsAPI KeyBatch ingest audit events from an agent. Deduplicates by call_id.
GET/api/v1/eventsEitherQuery events with filters (agent_id, tool_name, verdict, mode, since, until, limit, search).

Batch Ingest Request

{
  "events": [
    {
      "call_id": "unique-call-id-123",
      "agent_id": "my-agent",
      "tool_name": "read_file",
      "verdict": "allow",
      "mode": "enforce",
      "timestamp": "2026-03-01T12:00:00Z",
      "payload": {
        "tool_args": { "path": "data.csv" },
        "side_effect": "read",
        "environment": "production",
        "principal": null,
        "decision_source": "precondition",
        "decision_name": "block-dotenv",
        "reason": null,
        "policy_version": "abc123...",
        "bundle_name": "devops-agent"
      }
    }
  ],
  "agent_manifest": {
    "agent_id": "my-agent",
    "policy_version": "abc123...",
    "contracts": [
      {
        "id": "block-dotenv",
        "type": "pre",
        "tool": "read_file",
        "mode": "enforce"
      }
    ]
  }
}

agent_manifest is optional. When provided, the console stores the manifest on the agent's registration and uses it as a fallback coverage source for agents governed locally (via Gate) rather than through console-deployed bundles. Fields: agent_id must match the events' agent, policy_version is a hash of the local contract bundle, and contracts lists each contract's id, type, tool pattern(s), and mode.

Batch Ingest Response

{
  "accepted": 1,
  "duplicates": 0
}

Approvals

MethodPathAuthDescription
POST/api/v1/approvalsAPI KeyCreate a pending approval request. Rate limited: 10 per 60 seconds per agent.
GET/api/v1/approvalsCookieList approvals. Optional filter: status (pending/approved/denied/timeout).
GET/api/v1/approvals/{approval_id}EitherGet a single approval by ID. API key auth returns 404 if the approval belongs to a different environment (see note below).
PUT/api/v1/approvals/{approval_id}CookieSubmit a decision on a pending approval.

Create Approval Request

{
  "agent_id": "my-agent",
  "tool_name": "delete_user",
  "tool_args": { "user_id": "u_123" },
  "message": "Agent wants to delete user account",
  "timeout": 300,
  "timeout_effect": "deny",
  "decision_source": "sandbox",
  "contract_name": "require-approval-for-deletes"
}

Approval Response

{
  "id": "uuid",
  "status": "pending",
  "agent_id": "my-agent",
  "tool_name": "delete_user",
  "tool_args": { "user_id": "u_123" },
  "message": "Agent wants to delete user account",
  "env": "production",
  "timeout_seconds": 300,
  "timeout_effect": "deny",
  "decision_source": "sandbox",
  "contract_name": "require-approval-for-deletes",
  "decided_by": null,
  "decided_at": null,
  "decision_reason": null,
  "decided_via": null,
  "created_at": "2026-03-01T12:00:00Z"
}

API key auth and approval visibility: GET /api/v1/approvals/{approval_id} returns 404 Not Found when the approval belongs to a different environment than the API key's scope. This is intentional — it prevents agents from inferring the existence of approvals in other environments. Dashboard (session) auth can access approvals across all environments.

Submit Decision Request

{
  "approved": true,
  "decided_by": "admin@example.com",
  "reason": "Looks safe to proceed",
  "decided_via": "console"
}

Sessions

MethodPathAuthDescription
POST/api/v1/sessions/batchAPI KeyRead multiple session values in one request. Must be matched before GET /{key} in routing order (handled server-side).
GET/api/v1/sessions/{key}API KeyRead a session value. Returns 404 if not found.
PUT/api/v1/sessions/{key}API KeySet a session value.
POST/api/v1/sessions/{key}/incrementAPI KeyAtomically increment a numeric value.
DELETE/api/v1/sessions/{key}API KeyDelete a session key.

Key format: ^[a-zA-Z0-9_\-\.:/]+$. Keys are namespaced by tenant in Redis: session:{tenant_id}:{key}.

Batch Read Request

{
  "keys": ["agent:my-agent:quota", "agent:my-agent:calls_today"]
}

keys is a list of up to 100 strings. Each key must be at most 256 characters and match ^[a-zA-Z0-9_\-\.:/]+$.

Batch Read Response

{
  "values": {
    "agent:my-agent:quota": "1000",
    "agent:my-agent:calls_today": null
  }
}

values maps each requested key to its string value, or null if the key does not exist.

SDK implementors: The batch endpoint path (/sessions/batch) is a fixed route and must be registered before the parameterized GET /sessions/{key} route to avoid the literal string "batch" being treated as a key. The server handles this automatically.


Agents

MethodPathAuthDescription
GET/api/v1/agents/statusCookieLive status of all connected agents. Optional filter: bundle_name.
GET/api/v1/agents/fleet-coverageCookieFleet-level coverage summary. since param: 1h, 6h, 24h, 7d, 30d, or ISO timestamp.
GET/api/v1/agents/{agent_id}/coverageCookiePer-agent tool coverage analysis.
GET/api/v1/agents/{agent_id}/historyCookieContract change timeline and drift history.

Agent Status Response

{
  "agents": [
    {
      "agent_id": "my-agent",
      "env": "production",
      "bundle_name": "devops-agent",
      "policy_version": "abc123...",
      "status": "current",
      "connected_at": "2026-03-01T12:00:00Z"
    }
  ]
}

status values: current (contract version matches deployed), drift (contract version differs), unknown (no contract version reported).


Agent Registrations

MethodPathAuthDescription
GET/api/v1/agent-registrationsCookieList all registered agents.
PATCH/api/v1/agent-registrations/{agent_id}CookieUpdate display name, tags, or bundle assignment.
POST/api/v1/agent-registrations/bulk-assignCookieAssign one bundle to multiple agents. Pushes assignment_changed SSE event.

Bulk Assign Request

{
  "agent_ids": ["agent-1", "agent-2", "agent-3"],
  "bundle_name": "devops-agent"
}

Assignment Rules

MethodPathAuthDescription
GET/api/v1/assignment-rulesCookieList all rules, ordered by priority.
POST/api/v1/assignment-rulesCookieCreate a new rule.
PATCH/api/v1/assignment-rules/{rule_id}CookieUpdate an existing rule.
DELETE/api/v1/assignment-rules/{rule_id}CookieDelete a rule.
GET/api/v1/assignment-rules/resolve/{agent_id}CookieDry-run: preview which bundle an agent would receive and why.

Create Rule Request

{
  "priority": 10,
  "pattern": "prod-*",
  "tag_match": { "team": "platform" },
  "bundle_name": "devops-agent",
  "env": "production"
}

Pattern: glob-style matching on agent_id (1-200 printable ASCII characters, no path separators or null bytes).

Resolve Query Parameters

ParameterTypeRequiredDescription
envstringNoFilter resolution to rules for this environment. Max 64 characters. When omitted, all tenant rules are evaluated.

Resolve Response

{
  "bundle_name": "devops-agent",
  "source": "rule",
  "rule_id": "uuid",
  "rule_pattern": "prod-*"
}

source values: explicit (set on agent registration), rule (matched assignment rule), agent_provided (from SSE query param), none (no match).


SSE Streams

MethodPathAuthDescription
GET/api/v1/streamAPI KeyAgent SSE stream. Params: env (required), bundle_name, policy_version, tags.
GET/api/v1/stream/dashboardCookieDashboard SSE stream. Receives all tenant events.

See SSE Events for full event type documentation and payload schemas.


Notifications

MethodPathAuthDescription
GET/api/v1/notifications/channelsCookieList all notification channels.
POST/api/v1/notifications/channelsAdminCreate a new channel.
PUT/api/v1/notifications/channels/{channel_id}AdminUpdate a channel.
DELETE/api/v1/notifications/channels/{channel_id}AdminDelete a channel.
POST/api/v1/notifications/channels/{channel_id}/testAdminSend a test notification.

Create Channel Request

{
  "name": "Ops Telegram",
  "channel_type": "telegram",
  "config": {
    "bot_token": "123456:ABC-DEF...",
    "chat_id": "-1001234567890"
  },
  "filters": {
    "environments": ["production"],
    "agent_patterns": ["prod-*"],
    "contract_names": null
  }
}

Channel types: telegram, slack, slack_app, discord, webhook, email.

Secrets in config are encrypted at rest with NaCl SecretBox and masked in API responses.


Settings & AI

MethodPathAuthDescription
POST/api/v1/settings/rotate-signing-keyAdminRotate Ed25519 signing key. Re-signs all active deployments.
DELETE/api/v1/settings/purge-eventsAdminPurge audit events older than N days. Query param: older_than_days.
GET/api/v1/settings/aiCookieGet AI config (API key masked).
PUT/api/v1/settings/aiCookieCreate or update AI config.
DELETE/api/v1/settings/aiCookieDelete AI config.
POST/api/v1/settings/ai/testCookieTest AI provider connection (latency probe).
GET/api/v1/settings/ai/usageCookieGet AI usage stats with daily breakdown.
POST/api/v1/contracts/assistCookieStreaming AI contract assistant.
POST/api/v1/contracts/generate-descriptionCookieGenerate a one-sentence description for a contract. Returns 503 if AI is not configured.

Generate Description Request

{
  "name": "Block .env reads",
  "type": "pre",
  "definition_yaml": "tools:\n  - read_file\nwhen:\n  args.path:\n    matches: \".*\\.env.*\"\nthen:\n  effect: deny",
  "tags": ["security", "filesystem"]
}

tags is optional (max 20 items). name, type, and definition_yaml are required.

Generate Description Response

{
  "description": "Denies read_file calls targeting .env files to prevent agents from accessing environment secrets."
}

Returns 503 Service Unavailable if AI is not configured.

AI Config Request

{
  "provider": "anthropic",
  "api_key": "sk-ant-...",
  "model": "claude-sonnet-4-20250514",
  "base_url": null
}

Providers: anthropic, openai, openrouter, ollama.


Webhooks

External integration endpoints called by notification platforms. No console authentication -- each platform uses its own verification.

MethodPathAuthDescription
POST/api/v1/telegram/webhook/{channel_id}Telegram secretTelegram callback query (approve/deny buttons).
POST/api/v1/slack/interactionsHMAC-SHA256Slack App button interactions. 5-minute replay protection.
GET/api/v1/slack/manifestNoneSlack App manifest for installation.
POST/api/v1/discord/interactionsEd25519Discord component button interactions.

Statistics

MethodPathAuthDescription
GET/api/v1/stats/overviewEitherDashboard home stats (pending approvals, active agents, events/denials in 24h). When accessed with an API key, results are scoped to the key's environment. Dashboard (session) auth returns aggregate stats across all environments.
GET/api/v1/stats/contractsCookiePer-contract evaluation stats with time range.

Last updated on

On this page