Agent DocsDeveloper documentation
Reference

API Reference

Complete REST API reference for all endpoints

API Reference

Enterprise Agentic AI Platform — Hono-based API Gateway

Overview

The API Gateway is the single entry point for all platform operations. It runs on Hono (a lightweight TypeScript-native HTTP framework) and serves the three frontend applications (Portal, Studio, Admin Console) as well as external agent runtimes and programmatic integrations.

Base URL

http://localhost:4000

In production, the gateway is exposed behind an ingress controller at your configured domain (e.g., https://api.your-platform.example.com).

Authentication

All API requests (except /health and SCIM endpoints) require authentication. The gateway supports two methods:

MethodHeaderFormatUse Case
Bearer TokenAuthorizationBearer <JWT>Frontend apps (OIDC/NextAuth.js sessions)
API KeyAuthorizationBearer ak_<hex>Programmatic access, external agents

API keys are created via POST /api/studio/api-keys and can be scoped to specific agents and permissions.

Tenant Scoping

Every request is scoped to a tenant. The tenant ID is extracted from the JWT claims or inferred from the API key. You can also set it explicitly with the X-Tenant-Id header during development.

Common Headers

HeaderRequiredDescription
AuthorizationYesBearer token or API key
Content-TypeYes (POST/PUT)application/json
X-Tenant-IdNoOverride tenant (dev only)
X-User-IdNoOverride user (dev only)
X-User-RoleNoOverride role: consumer, builder, admin
X-User-GroupsNoComma-separated group list
X-Agent-IdNoAgent identity for LLM proxy calls

Standard Response Envelope

Most endpoints return responses in a consistent envelope:

{
  "data": { ... },
  "total": 42
}

Error responses use:

{
  "error": "Human-readable error message"
}

Role-Based Access

Routes under /api/admin/* require the admin role. Routes under /api/studio/* typically require builder or admin. Portal routes are accessible to all authenticated users.


Health & Metrics

GET /health

Returns the operational status of all infrastructure dependencies.

Authentication: None required.

Response Fields:

  • status"ok"
  • database — PostgreSQL connection status
  • redis — Redis availability (used for rate limiting)
  • qdrant — Vector DB availability
  • neo4j — Graph DB availability
  • kafka — Event bus availability
  • temporal — Workflow engine availability
  • n8n — Low-code runtime availability
  • vault — HashiCorp Vault availability
  • otel — OpenTelemetry status
  • mcpGateway — MCP server/tool counts
curl http://localhost:4000/health

GET /api/health

Returns aggregated platform health metrics from the database (used by Admin dashboard).

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/health

GET /api/dashboard/metrics

Returns chart data aggregated from agent executions for the dashboard.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/dashboard/metrics

GET /metrics

Prometheus-compatible metrics endpoint for scraping.

Authentication: None required.

curl http://localhost:4000/metrics

Agents

Core CRUD and configuration for AI agents.

GET /api/agents

List all agents visible to the current user, with optional filters.

Query Parameters:

  • runtime — Filter by runtime: procode or n8n
  • status — Filter by status: draft, active, canary, suspended, deprecated
  • search — Free-text search on agent name/description

Response: { data: Agent[], total: number }

The response is filtered by the user's entitlements (Dimension 1 access control). Users only see agents they are allowed to access based on visibility settings and group membership.

curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/agents?runtime=procode&status=active"

GET /api/agents/:id

Get a single agent's full configuration.

Response: { data: Agent }

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1

POST /api/agents

Create a new agent. Requires builder or admin role.

Request Body:

  • name (string, required) — Agent display name
  • runtime (string, required) — "procode" or "n8n"
  • config (object, required) — Agent configuration (system prompt, model, tools, etc.)
  • description (string) — Human-readable description
  • version (string) — Semantic version (default: "0.1.0")
  • executionMode (string) — "platform-managed", "external-procode", or "external-n8n"
  • status (string) — Initial status (default: "draft")
  • capabilities (string[]) — List of capability tags
  • riskClassification (string) — "assistive", "semi-autonomous", or "autonomous"

Response: { data: Agent } with status 201

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Research Assistant",
    "runtime": "procode",
    "config": {
      "systemPrompt": "You are a helpful research assistant.",
      "model": "claude-sonnet-4-20250514"
    },
    "capabilities": ["research", "summarization"],
    "riskClassification": "assistive"
  }' \
  http://localhost:4000/api/agents

PUT /api/agents/:id

Update an agent (partial update). Requires builder or admin role. Builders can only update their own agents.

Request Body: Any subset of Agent fields.

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status": "active", "description": "Updated description"}' \
  http://localhost:4000/api/agents/agent-research-1

DELETE /api/agents/:id

Soft-delete an agent by setting its status to deprecated. Requires builder or admin role.

curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1

GET /api/agents/:id/metrics

Get performance metrics for an agent.

Response Fields:

  • successRate — Percentage of successful executions
  • latencyP95 — 95th percentile latency in milliseconds
  • costPerDay — Daily cost in USD
  • totalExecutions — Lifetime execution count
  • hitlEscalationRate — Percentage of executions requiring human approval
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1/metrics

Access Control

The platform enforces four dimensions of access control. These endpoints manage the policies for each dimension.

GET /api/agents/:id/access-summary

Get a combined view of all four access control dimensions for an agent.

Response Fields:

  • d1_userAccess — Entitlements (visibility, allowed groups/roles/users)
  • d2_toolGrants — Which tools this agent can use
  • d3_interactions — Which agents this agent can call
  • d4_modelAccess — Which LLM models this agent can use
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1/access-summary

PUT /api/agents/:id/entitlements

Update user-to-agent access (Dimension 1).

Request Body:

  • visibility"public", "restricted", or "private"
  • allowedGroups (string[]) — IdP groups that can access
  • allowedRoles (string[]) — Platform roles that can access
  • allowedUsers (string[]) — Specific user IDs
  • owners (string[]) — Agent owners (always have access)
curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "visibility": "restricted",
    "allowedGroups": ["engineering", "data-science"],
    "owners": ["user-builder-1"]
  }' \
  http://localhost:4000/api/agents/agent-research-1/entitlements

PUT /api/agents/:id/tool-grants

Update agent-to-tool access (Dimension 2). Defines which MCP tools the agent is allowed to invoke, with optional conditions.

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {"toolId": "tool-jira-1", "conditions": {"rateLimit": 10, "requireHitl": false}},
    {"toolId": "tool-github-1", "conditions": {"requireHitl": true}}
  ]' \
  http://localhost:4000/api/agents/agent-research-1/tool-grants

POST /api/access/check

Unified access check across all four dimensions. Use this to test whether a specific access request would be allowed.

Request Body:

  • dimension (number, required) — 1 (User-to-Agent), 2 (Agent-to-Tool), 3 (Agent-to-Agent), 4 (Agent-to-Model)
  • principalId (string, required) — The requesting entity ID
  • resourceId (string, required) — The target resource ID
  • action (string) — The action being checked
  • depth (number) — Delegation depth (Dimension 3 only)

Response: { data: { allowed: boolean, reason: string, dimension: number, matchedPolicy?: string } }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "dimension": 2,
    "principalId": "agent-research-1",
    "resourceId": "tool-jira-1"
  }' \
  http://localhost:4000/api/access/check

Chat & Conversations

The primary interface for interacting with agents. Messages are streamed via Server-Sent Events (SSE).

POST /api/chat/:agentId/message

Send a message to an agent and receive a streaming SSE response.

Path Parameters:

  • agentId — The target agent ID

Request Body:

  • message (string, required) — The user's message text
  • conversationId (string) — Existing conversation ID to continue (omit to start new)
  • attachments (array) — File attachments with id, mimeType, name, uri, sizeBytes

Response: SSE stream with event types:

  • message / token — Assistant text chunks (streamed)
  • tool_call — Tool invocation start (status: running)
  • tool_result — Tool invocation result (status: success/error)
  • tool_status — Tool sub-status updates (e.g., "Starting sandbox...")
  • thinking_complete — LLM reasoning/thinking text (rendered as collapsible block)
  • workflow_step — Workflow progress step updates
  • approval_required — HITL approval request (tool paused, awaiting user decision)
  • approval_resolved — HITL approval decided (workflow resuming)
  • error — Error events
  • done — Stream completion
curl -N -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "Summarize the latest project status", "conversationId": "conv-abc123"}' \
  http://localhost:4000/api/chat/agent-research-1/message

GET /api/chat/:agentId/prerequisites

Check prerequisites before starting a chat (OAuth connections, tool permissions).

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/chat/agent-research-1/prerequisites

GET /api/conversations

List all conversations for the current user.

Response: Array of conversation summaries.

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/conversations

GET /api/conversations/:conversationId

Get a single conversation with its full message history.

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/conversations/conv-abc123

DELETE /api/conversations/:conversationId

Soft-delete a conversation. The conversation is marked as deleted and excluded from listings but not physically removed.

curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/conversations/conv-abc123

GET /api/chat/:agentId/reconnect/:workflowId

Reconnect to an active Temporal workflow's SSE event stream. When a user navigates away from chat and returns while a workflow is still running, this endpoint bridges Redis Pub/Sub events to a new SSE stream.

Response: SSE stream with the same event types as the chat message endpoint.

curl -N -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/chat/agent-research-1/reconnect/wf-abc123

GET /api/conversations/search

Search conversations by keyword.

Query Parameters:

  • q — Search query string
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/conversations/search?q=project+status"

Approvals (Human-in-the-Loop)

Manage HITL approval requests triggered by tool calls that require human authorization.

GET /api/approvals

List approval requests, optionally filtered by status.

Query Parameters:

  • statuspending, approved, or rejected
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/approvals?status=pending"

POST /api/approvals/:id/decide

Approve or reject a pending approval request.

Request Body:

  • decision (string, required) — "approved" or "rejected"
  • reason (string, required) — Explanation for the decision

The approver must be authorized to decide: either an admin, an explicit approver in the tool grant's approval policy, a member of an approver group, or (in legacy mode) the agent owner.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decision": "approved", "reason": "Safe to proceed with Jira update"}' \
  http://localhost:4000/api/approvals/approval-xyz/decide

Note: After deciding, the platform automatically signals the paused Temporal workflow. The workflow re-executes the tool with the verified approval and emits tool_result + workflow_step SSE events.

POST /api/workflows/:id/resume

Signal a paused workflow to resume after an approval decision. This endpoint is called automatically by POST /api/approvals/:id/decide, but can also be called explicitly.

Security: The endpoint verifies that:

  • The approval exists in the database
  • The approval belongs to the target workflow
  • The approval has been decided (not still pending)
  • The decision matches the actual DB status (prevents flipping rejections to approvals)

Request Body:

  • approvalId (string, required) — The approval record ID
  • decision (string, required) — "approved" or "rejected"
  • reason (string) — Decision reason
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"approvalId": "approval-xyz", "decision": "approved", "reason": "Verified safe"}' \
  http://localhost:4000/api/workflows/wf-abc123/resume

Credentials

GET /api/credentials/resolve-preview

Dry-run credential resolution showing which tier a credential would resolve from without exposing the secret value. Used by the Studio credentials page to visualize the 5-tier hierarchy (Vault, User BYOK, Agent override, Tenant default, Environment variable).

Query Parameters:

  • credentialKey — The credential key to resolve (e.g., OPENAI_API_KEY)
  • agentId — Optional agent context for tier 2 (agent override) resolution

Response: { tier, source, masked, resolvedFrom }

curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/credentials/resolve-preview?credentialKey=OPENAI_API_KEY&agentId=agent-1"

Tools & MCP

Manage MCP (Model Context Protocol) tools and servers.

GET /api/tools

List all registered MCP tools.

Response: { data: Tool[], total: number }

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/tools

POST /api/tools

Register a new MCP tool.

Request Body:

  • name (string, required) — Tool name
  • mcpEndpoint (string, required) — MCP server endpoint URL
  • description (string) — Tool description
  • runtime (string) — "procode", "n8n", or "both" (default)
  • riskLevel (string) — "low", "medium", or "high"
  • category (string) — "read-only", "write", "admin"
  • inputSchema (object) — JSON Schema for tool input
  • outputSchema (object) — JSON Schema for tool output
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "jira-create-issue",
    "mcpEndpoint": "http://mcp-jira:3000/sse",
    "description": "Create a Jira issue",
    "riskLevel": "medium",
    "category": "write"
  }' \
  http://localhost:4000/api/tools

POST /api/tools/:id/invoke

Invoke a tool directly (bypasses agent context). Useful for testing.

Request Body:

  • arguments (object) — Tool input arguments
  • agentId (string) — Agent context for access control checks
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"arguments": {"project": "PLAT", "summary": "Test issue"}, "agentId": "agent-research-1"}' \
  http://localhost:4000/api/tools/tool-jira-1/invoke

POST /api/tools/servers/:serverId/refresh

Reconnect to an MCP server and rediscover its tools. Useful after the MCP server has been updated with new tool definitions. Requires builder or admin role.

Response: { server, toolsRegistered, refreshedAt }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/tools/servers/server-jira-1/refresh

GET /api/mcp/servers

List all registered MCP servers.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/mcp/servers

POST /api/mcp/servers

Register a new MCP server. The gateway connects to the server, discovers its tools, and auto-registers them.

Request Body:

  • name (string, required) — Server display name
  • transport (string, required) — "stdio" or "sse"
  • command (string) — Command to run (stdio transport)
  • args (string[]) — Command arguments (stdio transport)
  • endpoint (string) — Server URL (sse transport)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jira MCP Server",
    "transport": "sse",
    "endpoint": "http://mcp-jira:3000/sse"
  }' \
  http://localhost:4000/api/mcp/servers

Memory

Agent memory management: episodic, semantic, and procedural memory with GDPR controls.

GET /api/studio/memories

List memory entries with optional filters. Requires builder or admin role.

Query Parameters:

  • agentId — Filter by agent
  • type — Filter by type: episodic, semantic, procedural
  • namespace — Filter by namespace
  • userId — Filter by user
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/studio/memories?agentId=agent-research-1&type=episodic"

POST /api/studio/memories

Create a memory entry manually.

Request Body:

  • agentId (string, required) — Associated agent
  • key (string, required) — Memory key
  • content (string, required) — Memory content
  • type (string) — "episodic", "semantic", or "procedural" (default: "episodic")
  • namespace (string) — Namespace for organization (default: "agent")
  • userId (string) — Associated user
  • metadata (object) — Additional metadata
  • ttl (number) — Time-to-live in seconds
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent-research-1",
    "key": "user-preference",
    "content": "User prefers concise summaries with bullet points",
    "type": "semantic"
  }' \
  http://localhost:4000/api/studio/memories

POST /api/studio/memories/search

Semantic search across memory entries.

Request Body:

  • query (string) — Search query
  • agentId (string) — Scope to agent
  • type (string) — Scope to memory type
  • limit (number) — Max results
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "user preferences", "agentId": "agent-research-1", "limit": 10}' \
  http://localhost:4000/api/studio/memories/search

DELETE /api/studio/memories/gdpr-forget

GDPR right-to-erasure: permanently delete all memory entries for a specific user across all agents.

Request Body:

  • userId (string, required) — User to forget
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userId": "user-consumer-5"}' \
  http://localhost:4000/api/studio/memories/gdpr-forget

GET /api/memories/consent

Get memory consent preferences for the current user.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/memories/consent

POST /api/memories/consent

Update memory consent preferences.

Request Body:

  • shortTermEnabled (boolean) — Allow short-term (session) memory
  • longTermEnabled (boolean) — Allow long-term (persistent) memory
  • graphEnabled (boolean) — Allow graph-based entity memory
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shortTermEnabled": true, "longTermEnabled": true, "graphEnabled": false}' \
  http://localhost:4000/api/memories/consent

Knowledge Bases

Manage knowledge bases, documents, embeddings, and semantic queries.

GET /api/studio/knowledge

List all knowledge bases accessible to the current user.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/studio/knowledge

POST /api/studio/knowledge

Create a new knowledge base. Requires builder or admin role.

Request Body:

  • name (string, required) — Knowledge base name
  • description (string) — Description
  • visibility (string) — "public", "restricted", or "private" (default: "public")
  • embeddingModel (string) — Model for embeddings
  • chunkStrategy (string) — "fixed", "recursive", or "semantic"
  • chunkSize (number) — Chunk size in tokens
  • chunkOverlap (number) — Overlap between chunks
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Product Documentation",
    "description": "Internal product docs and guides",
    "chunkStrategy": "recursive",
    "chunkSize": 512
  }' \
  http://localhost:4000/api/studio/knowledge

POST /api/studio/knowledge/:kbId/documents

Add a document to a knowledge base. Supports text content or binary file upload (multipart/form-data).

Request Body (JSON):

  • title (string, required) — Document title
  • content (string) — Raw text content
  • format (string) — "markdown", "text", "pdf", "csv", "html", "docx"
  • sourceUrl (string) — Source URL for reference
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Getting Started Guide",
    "content": "# Getting Started\n\nThis guide covers...",
    "format": "markdown"
  }' \
  http://localhost:4000/api/studio/knowledge/kb-docs-1/documents

PATCH /api/studio/knowledge/:kbId/access

Update access control settings for a knowledge base. Requires builder or admin role.

Request Body:

  • visibility (string) — "public", "restricted", or "private"
  • allowedGroups (string[]) — Groups that can access this KB
  • allowedAgents (string[]) — Agents that can query this KB
curl -X PATCH -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"visibility": "restricted", "allowedAgents": ["agent-research-1"]}' \
  http://localhost:4000/api/studio/knowledge/kb-docs-1/access

POST /api/studio/knowledge/:kbId/query

Semantic query against a knowledge base. Supports vector, keyword, and hybrid search.

Request Body:

  • query (string, required) — Natural language query
  • mode (string) — "semantic", "keyword", or "hybrid" (default: "semantic")
  • topK (number) — Number of results (default: 5)

Response: Array of matching chunks with scores and metadata.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "How do I configure authentication?", "mode": "hybrid", "topK": 5}' \
  http://localhost:4000/api/studio/knowledge/kb-docs-1/query

Deployments

Agent deployment pipeline with staged rollouts.

GET /api/agents/:id/deployments

List all deployments for an agent.

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1/deployments

POST /api/agents/:id/deploy

Start a new deployment. Triggers a multi-stage pipeline: Build & Sign, Eval Suite, Safety Gate, Canary, Behavior Check, and Full Rollout.

Request Body:

  • environment (string) — Target environment: "dev", "staging", or "prod" (default: "dev")
  • canaryPercent (number) — Initial canary traffic percentage (default: 5)

Response: { data: Deployment } with status 201

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"environment": "staging", "canaryPercent": 10}' \
  http://localhost:4000/api/agents/agent-research-1/deploy

Eval Suite

Manage evaluation suites, test cases, and evaluation runs for agent quality assessment.

GET /api/studio/evals

List evaluation suites, optionally filtered by agent.

Query Parameters:

  • agentId — Filter by agent ID
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/studio/evals?agentId=agent-research-1"

POST /api/studio/evals

Create an evaluation suite.

Request Body:

  • name (string, required) — Suite name
  • agentId (string, required) — Associated agent
  • description (string) — Description
  • tags (string[]) — Tags for organization
  • judgeConfig (object) — LLM-as-judge configuration
  • testCases (array) — Initial test cases with input, expectedOutput, assertion
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Core QA Suite",
    "agentId": "agent-research-1",
    "testCases": [
      {"input": "What is our refund policy?", "expectedOutput": "30-day money-back guarantee"}
    ]
  }' \
  http://localhost:4000/api/studio/evals

POST /api/studio/evals/:suiteId/run

Execute an evaluation run against the agent.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/studio/evals/eval-abc123/run

Models

Manage LLM model registry, routing rules, and fallback chains.

GET /api/models

List all registered models.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/models

POST /api/models

Register a new model in the model registry.

Request Body:

  • modelName (string, required) — Model identifier (e.g., "claude-sonnet-4-20250514")
  • displayName (string, required) — Human-readable name
  • provider (string, required) — "anthropic", "openai", "google", "meta", etc.
  • hostingType (string, required) — "eu-sovereign", "us-cloud", "self-hosted"
  • costPer1kInput (number, required) — Cost per 1K input tokens
  • costPer1kOutput (number, required) — Cost per 1K output tokens
  • contextWindow (number) — Maximum context length
  • capabilities (string[]) — ["chat", "vision", "function-calling"]
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "modelName": "claude-sonnet-4-20250514",
    "displayName": "Claude Sonnet 4",
    "provider": "anthropic",
    "hostingType": "eu-sovereign",
    "costPer1kInput": 0.003,
    "costPer1kOutput": 0.015
  }' \
  http://localhost:4000/api/models

LLM Proxy

OpenAI-compatible proxy endpoint for external agents. Routes LLM calls through platform guardrails, model access enforcement, cost tracking, and audit logging.

POST /api/llm/chat/completions

OpenAI-compatible chat completions endpoint. Requires agent identity (via SPIFFE, A2A token, or X-Agent-Id header).

Request Body: Standard OpenAI chat completions format:

  • model (string) — Model name
  • messages (array, required) — Chat messages with role and content
  • temperature (number) — Sampling temperature
  • max_tokens (number) — Maximum output tokens
  • stream (boolean) — Enable SSE streaming

Response: Standard OpenAI chat completions response with added cost metadata.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Agent-Id: agent-research-1" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "messages": [{"role": "user", "content": "Summarize this document"}],
    "max_tokens": 1024
  }' \
  http://localhost:4000/api/llm/chat/completions

Traces & Observability

View execution traces with span-level detail.

GET /api/traces

List traces with optional filters. Returns summaries without spans for performance.

Query Parameters:

  • agentId — Filter by agent
  • status — Filter by trace status
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/traces?agentId=agent-research-1"

GET /api/traces/:id

Get a single trace with all spans (LLM calls, tool invocations, guardrail checks).

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/traces/trace-xyz

Admin — Tenant Management

All admin routes require the admin role and are prefixed with /api/admin/.

GET /api/tenants

List all tenants.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/tenants

POST /api/admin/tenants

Create a new tenant.

Request Body:

  • name (string, required) — Tenant name
  • plan (string) — "free", "pro", "enterprise"
  • quotas (object) — Resource quotas
  • modelPolicy (object) — Default model access policy
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "plan": "enterprise"}' \
  http://localhost:4000/api/admin/tenants

GET /api/admin/audit

Query the immutable audit log.

Query Parameters:

  • agentId — Filter by agent
  • userId — Filter by user
  • action — Filter by action type
  • from / to — Date range (ISO 8601)
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/admin/audit?action=tool_call&from=2026-02-01"

GET /api/admin/finops

Get FinOps cost data: per-agent cost breakdown, budget utilization, and cost trends.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/admin/finops

GET /api/admin/policies

List all governance policies (Cedar/OPA).

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/admin/policies

POST /api/admin/policies

Create a governance policy.

Request Body:

  • name (string, required) — Policy name
  • type (string, required) — "cedar" or "opa"
  • description (string) — Description
  • policyBody (string, required) — Policy source code
  • scope (string) — Scope: "global", "tenant", "agent"
  • enabled (boolean) — Whether the policy is active
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Block PII in responses",
    "type": "cedar",
    "policyBody": "forbid(principal, action == Action::\"respond\", resource) when { resource.containsPII == true };",
    "scope": "global",
    "enabled": true
  }' \
  http://localhost:4000/api/admin/policies

POST /api/admin/policies/simulate

Dry-run a policy against a simulated request to test behavior before deployment.

Request Body:

  • policyId (string) — Policy to simulate
  • request (object) — Simulated request context
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "policyId": "policy-pii-block",
    "request": {"principal": "user-1", "action": "respond", "resource": {"containsPII": true}}
  }' \
  http://localhost:4000/api/admin/policies/simulate

Identity & Users

User management, service accounts, and SPIFFE agent identity.

GET /api/me

Get the current authenticated user's profile.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/me

GET /api/users/search

Search the tenant user directory for the picker when configuring access grants (name/email typeahead). Consumer-safe; returns id, displayName, email, role, groups.

curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/users/search?q=zoe&limit=20"

POST /api/users/resolve

Batch-resolve stored grant ids to display names. Matches each id by platform id or externalId (Keycloak sub), so a grant saved as either id form renders a readable name (see ACCESS_CONTROL.md → User identity resolution). Consumer-safe, tenant-scoped.

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"ids":["user-3f2a1c","sub-62155b42"]}' \
  http://localhost:4000/api/users/resolve
# -> [{ "id": "user-3f2a1c", "externalId": "sub-...", "displayName": "Zoe Zed", "email": "zoe@acme.com" }]

GET /api/admin/users

List all platform users (admin only).

Query Parameters:

  • search — Search by name or email
curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/admin/users?search=jane"

PUT /api/admin/users/:id/role

Change a user's platform role.

Request Body:

  • role (string, required) — "consumer", "builder", or "admin"
curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"role": "builder"}' \
  http://localhost:4000/api/admin/users/user-jane-1/role

POST /api/admin/users/invite

Invite a new user to the platform.

Request Body:

  • email (string, required) — Invitee email
  • role (string) — Initial role (default: "consumer")
  • groups (string[]) — Groups to assign
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "jane@example.com", "role": "builder", "groups": ["engineering"]}' \
  http://localhost:4000/api/admin/users/invite

GET /api/agents/:id/identity

Get the SPIFFE identity (SVID) for an agent.

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/agents/agent-research-1/identity

API Keys

Programmatic access management for external integrations.

GET /api/studio/api-keys

List API keys for the current tenant.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/studio/api-keys

POST /api/studio/api-keys

Create a new API key. The raw key is returned only once in the response.

Request Body:

  • name (string, required) — Key name/description
  • agentScopes (string[]) — Restrict to specific agent IDs
  • permissions (string[]) — ["chat"], ["chat", "manage"], etc.
  • rateLimitPerMinute (number) — Rate limit (default: 60)
  • dailyCostCap (number) — Daily cost cap in USD
  • expiresAt (string) — Expiration date (ISO 8601)

Response: { data: ApiKey, rawKey: "ak_..." }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI/CD Integration Key",
    "agentScopes": ["agent-research-1"],
    "permissions": ["chat"],
    "rateLimitPerMinute": 30
  }' \
  http://localhost:4000/api/studio/api-keys

File Upload

Upload files for multimodal chat attachments.

POST /api/upload

Upload a file (multipart/form-data). Maximum file size: 10 MB.

Allowed MIME types: image/jpeg, image/png, image/gif, image/webp, audio/mpeg, audio/wav, audio/ogg, application/pdf, text/csv, text/plain, application/json

Response: Attachment metadata with id, uri, mimeType, name, sizeBytes.

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -F "file=@document.pdf" \
  http://localhost:4000/api/upload

Feedback

User feedback on agent responses (thumbs up/down).

POST /api/portal/feedback

Submit feedback on an agent response.

Request Body:

  • agentId (string, required) — Agent that produced the response
  • thumbsUp (boolean, required) — Positive or negative feedback
  • conversationId (string) — Associated conversation
  • messageId (string) — Specific message
  • correction (string) — User-provided correction text
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent-research-1",
    "thumbsUp": false,
    "conversationId": "conv-abc123",
    "correction": "The refund policy is 30 days, not 60"
  }' \
  http://localhost:4000/api/portal/feedback

GET /api/portal/feedback/stats

Get satisfaction statistics and 14-day trend data.

curl -H "Authorization: Bearer $TOKEN" http://localhost:4000/api/portal/feedback/stats

Marketplace

POST /api/marketplace/:listingId/install

Clone an agent from a marketplace listing into the current user's tenant as a draft agent with a new ID. Increments the listing's install count.

Response: { data: Agent } with status 201

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/marketplace/listing-abc123/install

n8n Workflows

POST /api/n8n/workflows/deduplicate

Remove duplicate n8n workflows within the current tenant. Groups workflows by name and keeps the most recently updated one, deleting the rest. Requires builder or admin role.

Response: { deduplicatedCount, keptWorkflows }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/n8n/workflows/deduplicate

Admin — Guardrails Configuration

GET /api/admin/guardrails/config

Get the current guardrail sensitivity thresholds for the tenant. Returns inputSensitivity and outputSensitivity values (0-100 scale). Defaults to 75/60 if not configured.

Response: { data: { inputSensitivity: number, outputSensitivity: number } }

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/guardrails/config

PUT /api/admin/guardrails/config

Update guardrail sensitivity thresholds. Values are clamped to the 0-100 range. Requires admin role.

Request Body:

  • inputSensitivity (number) -- Input guardrail sensitivity (0-100, default: 75)
  • outputSensitivity (number) -- Output guardrail sensitivity (0-100, default: 60)
curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputSensitivity": 80, "outputSensitivity": 70}' \
  http://localhost:4000/api/admin/guardrails/config

Admin — DSAR (Data Subject Access Requests)

GDPR-compliant Data Subject Access Request workflow.

GET /api/admin/dsar

List all DSAR requests for the tenant. Requires admin role.

Response: { data: DSARRequest[] }

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/dsar

POST /api/admin/dsar

Create a new DSAR request. Requires admin role.

Request Body:

  • userEmail (string, required) -- Email of the data subject
  • type (string, required) -- "export" or "forget"
  • userId (string) -- User ID (defaults to userEmail)
  • agentId (string) -- Scope to a specific agent

Response: { data: { id: string, status: "pending" } } with status 201

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userEmail": "jane@example.com", "type": "export"}' \
  http://localhost:4000/api/admin/dsar

POST /api/admin/dsar/:id/execute

Execute a pending DSAR request. Exports conversations, messages, and approvals for the specified user. Status transitions from pending to in-progress to completed. Requires admin role.

Response: { data: { exportedAt, userId, userEmail, conversations, messages, approvals } }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/dsar/dsar-12345/execute

Admin — Announcements

Broadcast and manage system announcements with optional scheduling.

POST /api/admin/announcements

Broadcast an immediate system announcement to all connected users via the alerts channel.

Request Body:

  • title (string, required) -- Announcement title
  • message (string, required) -- Announcement body
  • severity (string) -- "info", "warning", or "critical" (default: "info")
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Scheduled Maintenance", "message": "The platform will be down for maintenance tonight.", "severity": "warning"}' \
  http://localhost:4000/api/admin/announcements

GET /api/admin/announcements/list

List all persisted announcements for the tenant, ordered by creation date.

Response: { data: Announcement[] }

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/announcements/list

POST /api/admin/announcements/schedule

Create a new announcement, either immediate or scheduled. Requires admin role.

Request Body:

  • title (string, required) -- Announcement title
  • message (string, required) -- Announcement body
  • severity (string) -- "info", "warning", or "critical"
  • scheduledAt (string) -- ISO 8601 timestamp for future delivery (omit for immediate)
  • expiresAt (string) -- ISO 8601 expiry timestamp
  • targetRoles (string[]) -- Restrict to specific roles (e.g., ["admin", "builder"])

Response: { data: { id, status: "sent" | "scheduled" } } with status 201

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "New Feature", "message": "Agent memory is now GA.", "scheduledAt": "2026-03-20T09:00:00Z"}' \
  http://localhost:4000/api/admin/announcements/schedule

DELETE /api/admin/announcements/:id

Delete a specific announcement. Requires admin role.

curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/announcements/ann-12345

Admin — User Stats

GET /api/admin/users/:userId/stats

Get activity statistics for a specific user. Requires admin role.

Response Fields:

  • conversationCount -- Total conversations
  • approvalCount -- Total approval requests
  • lastActive -- Timestamp of most recent conversation
  • totalCost -- Cumulative cost (USD)
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/users/user-jane-1/stats

Admin — Agent Cost Cap

PUT /api/admin/agents/:id/cost-cap

Set or update the daily cost cap for an agent. Updates config.modelAccess.maxCostPerDay. Requires admin role.

Request Body:

  • maxCostPerDay (number, required) -- Maximum daily cost in USD (0 = unlimited)

Response: { data: { agentId, maxCostPerDay } }

curl -X PUT -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"maxCostPerDay": 50}' \
  http://localhost:4000/api/admin/agents/agent-finance-1/cost-cap

Admin — OBO Token Management

Monitor and manage On Behalf Of (OBO) delegated tokens. See docs/OBO_TOKEN_EXCHANGE.md for the full OBO guide.

GET /api/admin/obo/tokens

List active OBO tokens with optional filters.

Query Parameters:

  • agentId -- Filter by agent
  • audience -- Filter by target audience

Response: { data: OBOToken[], total: number }

curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:4000/api/admin/obo/tokens?agentId=agent-finance-1"

GET /api/admin/obo/stats

Get OBO token exchange statistics.

Response: { data: { totalActive, totalExpired, totalRevoked, byAgent: [{ agentId, count }] } }

curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/admin/obo/stats

POST /api/admin/obo/revoke

Revoke OBO tokens for a specific agent, optionally scoped to a user.

Request Body:

  • agentId (string, required) -- Agent whose tokens to revoke
  • userId (string) -- Optional user scope

Response: { data: { revokedCount }, message }

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"agentId": "agent-finance-1"}' \
  http://localhost:4000/api/admin/obo/revoke

Execution Management

Cancel a conversation

POST /api/chat/conversations/:conversationId/cancel

Cancels the active workflow for a conversation. Returns the workflow ID that was cancelled.

Response:

{ "success": true, "workflowId": "wf-abc123" }

Cancel a workflow by ID

POST /api/workflows/:workflowId/cancel

Sends cancelWorkflow signal to a Temporal workflow. Only works for workflows in running or paused state.

Admin: List running executions

GET /api/admin/executions/running?agentId=&tenantId=&minDurationMinutes=

Returns all workflows in running/paused state with agent name, user, tenant, duration, and token usage.

Admin: Force-cancel an execution

POST /api/admin/executions/:workflowId/cancel
Body: { "reason": "Admin-provided reason" }

No tenant restriction (admin override). Creates high-severity audit event.

Admin: Emergency stop all

POST /api/admin/executions/cancel-all
Body: { "agentId": "optional-filter", "tenantId": "optional-filter", "reason": "Emergency" }

Response:

{ "cancelled": 12, "failed": 0 }

Per-user rate limits

GET  /api/admin/users/:userId/limits
PUT  /api/admin/users/:userId/limits
Body: {
  "maxMessagesPerMinute": 10,
  "maxDailyCost": 5.0,
  "maxDailyTokens": 100000,
  "maxConcurrentConversations": 3
}

Per-agent admin controls

PUT /api/admin/agents/:agentId/admin-controls
Body: {
  "executionLimits": {
    "maxExecutionTimeMinutes": 15,
    "maxTokensPerExecution": 50000,
    "maxCostPerExecution": 2.0
  },
  "costControls": { "dailyCostCap": 50.0 },
  "rateLimits": {
    "maxRequestsPerMinute": 30,
    "maxConcurrentExecutions": 3
  }
}

Error Codes

HTTP StatusMeaning
200Success
201Resource created
400Bad request (missing fields, invalid input)
401Unauthorized (missing or invalid token)
403Forbidden (insufficient role or access denied by policy)
404Resource not found (or not accessible in current tenant)
429Rate limit exceeded
500Internal server error
503Service unavailable (LLM provider not configured)

Rate Limiting

Per-user rate limiting is enforced after authentication. Limits are configured per tenant and can be overridden on API keys. When a rate limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header.

SSE Streaming

Chat and deployment endpoints use Server-Sent Events for real-time streaming. Connect with:

Accept: text/event-stream

Events follow the format:

event: <type>
data: <json>

For chat streaming, keep the connection open until you receive a done event.