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:
| Method | Header | Format | Use Case |
|---|---|---|---|
| Bearer Token | Authorization | Bearer <JWT> | Frontend apps (OIDC/NextAuth.js sessions) |
| API Key | Authorization | Bearer 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
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token or API key |
Content-Type | Yes (POST/PUT) | application/json |
X-Tenant-Id | No | Override tenant (dev only) |
X-User-Id | No | Override user (dev only) |
X-User-Role | No | Override role: consumer, builder, admin |
X-User-Groups | No | Comma-separated group list |
X-Agent-Id | No | Agent 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 statusredis— Redis availability (used for rate limiting)qdrant— Vector DB availabilityneo4j— Graph DB availabilitykafka— Event bus availabilitytemporal— Workflow engine availabilityn8n— Low-code runtime availabilityvault— HashiCorp Vault availabilityotel— OpenTelemetry statusmcpGateway— 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:procodeorn8nstatus— Filter by status:draft,active,canary,suspended,deprecatedsearch— 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 nameruntime(string, required) —"procode"or"n8n"config(object, required) — Agent configuration (system prompt, model, tools, etc.)description(string) — Human-readable descriptionversion(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 tagsriskClassification(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 executionslatencyP95— 95th percentile latency in millisecondscostPerDay— Daily cost in USDtotalExecutions— Lifetime execution counthitlEscalationRate— 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 used3_interactions— Which agents this agent can calld4_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 accessallowedRoles(string[]) — Platform roles that can accessallowedUsers(string[]) — Specific user IDsowners(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 IDresourceId(string, required) — The target resource IDaction(string) — The action being checkeddepth(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 textconversationId(string) — Existing conversation ID to continue (omit to start new)attachments(array) — File attachments withid,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 updatesapproval_required— HITL approval request (tool paused, awaiting user decision)approval_resolved— HITL approval decided (workflow resuming)error— Error eventsdone— 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:
status—pending,approved, orrejected
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_stepSSE 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 IDdecision(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 namemcpEndpoint(string, required) — MCP server endpoint URLdescription(string) — Tool descriptionruntime(string) —"procode","n8n", or"both"(default)riskLevel(string) —"low","medium", or"high"category(string) —"read-only","write","admin"inputSchema(object) — JSON Schema for tool inputoutputSchema(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 argumentsagentId(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 nametransport(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 agenttype— Filter by type:episodic,semantic,proceduralnamespace— Filter by namespaceuserId— 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 agentkey(string, required) — Memory keycontent(string, required) — Memory contenttype(string) —"episodic","semantic", or"procedural"(default:"episodic")namespace(string) — Namespace for organization (default:"agent")userId(string) — Associated usermetadata(object) — Additional metadatattl(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 queryagentId(string) — Scope to agenttype(string) — Scope to memory typelimit(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) memorylongTermEnabled(boolean) — Allow long-term (persistent) memorygraphEnabled(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 namedescription(string) — Descriptionvisibility(string) —"public","restricted", or"private"(default:"public")embeddingModel(string) — Model for embeddingschunkStrategy(string) —"fixed","recursive", or"semantic"chunkSize(number) — Chunk size in tokenschunkOverlap(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 titlecontent(string) — Raw text contentformat(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 KBallowedAgents(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 querymode(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 nameagentId(string, required) — Associated agentdescription(string) — Descriptiontags(string[]) — Tags for organizationjudgeConfig(object) — LLM-as-judge configurationtestCases(array) — Initial test cases withinput,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 nameprovider(string, required) —"anthropic","openai","google","meta", etc.hostingType(string, required) —"eu-sovereign","us-cloud","self-hosted"costPer1kInput(number, required) — Cost per 1K input tokenscostPer1kOutput(number, required) — Cost per 1K output tokenscontextWindow(number) — Maximum context lengthcapabilities(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 namemessages(array, required) — Chat messages withroleandcontenttemperature(number) — Sampling temperaturemax_tokens(number) — Maximum output tokensstream(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 agentstatus— 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 nameplan(string) —"free","pro","enterprise"quotas(object) — Resource quotasmodelPolicy(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 agentuserId— Filter by useraction— Filter by action typefrom/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 nametype(string, required) —"cedar"or"opa"description(string) — DescriptionpolicyBody(string, required) — Policy source codescope(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 simulaterequest(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 emailrole(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/descriptionagentScopes(string[]) — Restrict to specific agent IDspermissions(string[]) —["chat"],["chat", "manage"], etc.rateLimitPerMinute(number) — Rate limit (default: 60)dailyCostCap(number) — Daily cost cap in USDexpiresAt(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 responsethumbsUp(boolean, required) — Positive or negative feedbackconversationId(string) — Associated conversationmessageId(string) — Specific messagecorrection(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 subjecttype(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 titlemessage(string, required) -- Announcement bodyseverity(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 titlemessage(string, required) -- Announcement bodyseverity(string) --"info","warning", or"critical"scheduledAt(string) -- ISO 8601 timestamp for future delivery (omit for immediate)expiresAt(string) -- ISO 8601 expiry timestamptargetRoles(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 conversationsapprovalCount-- Total approval requestslastActive-- Timestamp of most recent conversationtotalCost-- 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 agentaudience-- 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 revokeuserId(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 Status | Meaning |
|---|---|
200 | Success |
201 | Resource created |
400 | Bad request (missing fields, invalid input) |
401 | Unauthorized (missing or invalid token) |
403 | Forbidden (insufficient role or access denied by policy) |
404 | Resource not found (or not accessible in current tenant) |
429 | Rate limit exceeded |
500 | Internal server error |
503 | Service 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.