API Reference
Complete reference for all Molecule AI Platform HTTP and WebSocket endpoints.
API Reference
The Molecule AI Platform exposes a REST API (default port 8080) for workspace management, agent registry, communication, and administration. All endpoints return JSON unless otherwise noted.
Breaking changes — PR #701 (2026-04-17)
PATCH /workspaces/:idnow requires authentication. Previously, requests without a bearer token could update cosmetic fields (name, x/y position). AllPATCHcalls now requireAuthorization: Bearer <workspace-token>or receive 401 Unauthorized.GET /templatesandGET /org/templatesnow require AdminAuth. Unauthenticated callers receive 401 Unauthorized.- All
/workspaces/:idendpoints validate the:idpath parameter as a UUID. Non-UUID values return 400 Bad Request before any database interaction.
Migration: add Authorization: Bearer <workspace-token> to all PATCH /workspaces/:id calls. Use an admin bearer token for GET /templates and GET /org/templates. Ensure :id values in automation scripts are valid UUIDs.
Base URL: http://localhost:8080 (self-hosted) or https://api.moleculesai.app (SaaS)
Authentication Model
The platform uses three authentication middleware variants depending on the sensitivity of the route.
AdminAuth
Strict bearer-token authentication. Required for any route where a forged request could leak prompts/memory, create/mutate workspaces, or leak operational data.
Authorization: Bearer <token>Fail-open behavior: When no live tokens exist globally (fresh install), AdminAuth passes all requests through. Once the first token is created, all AdminAuth routes require a valid bearer.
WorkspaceAuth
Per-workspace bearer token binding. Workspace A's token cannot access workspace B's sub-routes. Used for the entire /workspaces/:id/* group (except the A2A proxy, which uses CanCommunicate).
Authorization: Bearer <workspace-token>CanvasOrBearer
Accepts either a valid bearer token OR a request whose Origin header matches CORS_ORIGINS. Used only for cosmetic-only routes where a forged request has zero data/security impact.
Currently applies only to PUT /canvas/viewport. Do not extend to data-sensitive routes.
Health and Monitoring
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health | None | Returns 200 OK if the platform is running. Use for load balancer health checks. |
| GET | /metrics | None | Prometheus text format (v0.0.4) metrics. Scrape-safe, no auth required. |
| GET | /admin/liveness | AdminAuth | Per-subsystem supervised.Snapshot() ages. Check before debugging stuck scheduler/heartbeat goroutines. |
Workspaces
Core workspace CRUD and lifecycle operations.
CRUD
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces | AdminAuth | Create a new workspace. Accepts name, runtime, template, parent_id, tier, workspace_dir, and other fields. Runtime is auto-detected from template config if omitted (defaults to langgraph). |
| GET | /workspaces | AdminAuth | List all workspaces with status, runtime, agent card, position, and hierarchy info. |
| GET | /workspaces/:id | WorkspaceAuth | Get a single workspace by ID. |
| PATCH | /workspaces/:id | WorkspaceAuth | Update workspace fields. A workspace bearer token is always required — unauthenticated calls return 401. Validates field constraints: name ≤ 255 chars, role ≤ 1,000 chars, model and runtime ≤ 100 chars each; name and role must not contain newlines (\\n, \\r) or YAML-special characters (`[] |
| DELETE | /workspaces/:id | AdminAuth | Delete a workspace. Stops the container, revokes all auth tokens, and removes all associated data. |
Lifecycle
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/restart | WorkspaceAuth | Restart the workspace container. Sends a restart_context A2A message after successful re-registration. |
| POST | /workspaces/:id/pause | WorkspaceAuth | Stop the container and set status to paused. Paused workspaces skip health sweep, liveness monitor, and auto-restart. |
| POST | /workspaces/:id/resume | WorkspaceAuth | Re-provision a paused workspace. Status transitions to provisioning. |
Registry
Workspace registration and heartbeat endpoints. Called by workspace runtimes, not by end users.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /registry/register | None | Register a workspace with the platform. Sets status to online. Body includes agent URL, agent card, capabilities. |
| POST | /registry/heartbeat | Bearer (if token exists) | Send a heartbeat. Updates Redis TTL key (60s expiry). Body can include active_tasks, current_task, error_rate. Triggers degraded status if error_rate > 0.5. |
| POST | /registry/update-card | Bearer (if token exists) | Update the workspace's agent card (name, description, skills, etc.). |
Discovery
Peer discovery and access control verification.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /registry/discover/:id | Bearer + X-Workspace-ID | Discover a workspace's agent card and URL. Requires caller identification. Fails open on DB hiccup since hierarchy check is primary. |
| GET | /registry/:id/peers | Bearer + X-Workspace-ID | List all peers (siblings, parent, children) that the caller can communicate with. |
| POST | /registry/check-access | None | Check whether two workspaces can communicate. Body: { "caller_id": "...", "target_id": "..." }. Returns { "allowed": true/false }. |
Communication
A2A Proxy
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/a2a | CanCommunicate | Proxy an A2A JSON-RPC message to the target workspace. Caller identified via X-Workspace-ID header. Canvas requests (no header) bypass access check. On connection error, checks if container is dead and triggers auto-restart. |
Delegation
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/delegate | WorkspaceAuth | Async fire-and-forget delegation. Supports idempotency keys. Body includes target workspace, prompt, and metadata. |
| GET | /workspaces/:id/delegations | WorkspaceAuth | List delegation status for a workspace. Returns delegation rows with status, result, timestamps. |
Configuration
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/config | WorkspaceAuth | Get the workspace's config.yaml contents. |
| PATCH | /workspaces/:id/config | WorkspaceAuth | Update the workspace config. "Save & Restart" writes config and auto-restarts; "Save" writes only and shows a restart banner in the Canvas. |
Secrets
Per-Workspace Secrets
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/secrets | WorkspaceAuth | List secret keys for a workspace (keys only, values masked). |
| POST | /workspaces/:id/secrets | WorkspaceAuth | Set a secret { "key": "...", "value": "..." }. Auto-restarts the workspace. |
| PUT | /workspaces/:id/secrets | WorkspaceAuth | Alias for POST (upsert semantics). Auto-restarts the workspace. |
| DELETE | /workspaces/:id/secrets/:key | WorkspaceAuth | Delete a secret by key. Auto-restarts the workspace. |
| GET | /workspaces/:id/model | WorkspaceAuth | Return the model configuration derived from available API keys (which provider keys are set). |
Global Secrets
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /settings/secrets | AdminAuth | List global secrets (keys only, values masked). |
| PUT | /settings/secrets | AdminAuth | Set a global secret { "key": "...", "value": "..." }. Auto-restarts every non-paused/non-removed workspace that does not shadow the key with a workspace-level override. |
| POST | /settings/secrets | AdminAuth | Alias for PUT. |
| DELETE | /settings/secrets/:key | AdminAuth | Delete a global secret. Same auto-restart fan-out as PUT. |
Legacy aliases GET/POST/DELETE /admin/secrets[/:key] also exist and behave identically.
Memory
Key-Value Memory
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/memory | WorkspaceAuth | List all key-value memory entries for a workspace. |
| POST | /workspaces/:id/memory | WorkspaceAuth | Set a memory entry { "key": "...", "value": "..." }. |
| DELETE | /workspaces/:id/memory/:key | WorkspaceAuth | Delete a memory entry by key. |
Agent Memories (HMA-scoped)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/memories | WorkspaceAuth | List or search agent memories. Supports ?q= for semantic search (see below). |
| POST | /workspaces/:id/memories | WorkspaceAuth | Create an agent memory entry. |
| DELETE | /workspaces/:id/memories/:id | WorkspaceAuth | Delete an agent memory by ID. |
Semantic search (?q=)
When a platform-level embedding function is configured, passing ?q=<text>
on GET /workspaces/:id/memories triggers vector similarity search instead of
the default full-text / ILIKE path:
GET /workspaces/{id}/memories?q=authentication+flow&limit=10
Authorization: Bearer {token}Matching entries are returned ordered by cosine similarity (most similar
first). Each row includes an additional similarity_score field (0–1, higher
is closer):
[
{
"id": "mem_abc123",
"key": "auth-design",
"value": "We use short-lived JWTs issued by the platform and refreshed via /auth/token.",
"similarity_score": 0.91,
"created_at": "2026-04-10T14:22:00Z"
}
]Graceful fallback: if no embedding function is configured, or if the
embedding call fails for a given query, the platform falls back transparently
to the text-search path. The similarity_score field is absent in fallback
responses. You do not need to change client code to handle both modes.
Files
Workspace file management. Files are stored in the workspace's config directory.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/files | WorkspaceAuth | List files in the workspace config directory. |
| GET | /workspaces/:id/files/*path | WorkspaceAuth | Read a specific file. |
| PUT | /workspaces/:id/files/*path | WorkspaceAuth | Write a file. Creates parent directories as needed. |
| DELETE | /workspaces/:id/files/*path | WorkspaceAuth | Delete a file. |
| GET | /workspaces/:id/shared-context | WorkspaceAuth | Get the shared context files for a workspace (aggregated from parent hierarchy). |
Activity
Activity logging and search for A2A communications, task updates, and agent logs.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/activity | WorkspaceAuth | List activity logs for a workspace. Supports ?source=canvas or ?source=agent filter, and ?type=delegation for A2A topology overlay polling. |
| POST | /workspaces/:id/activity | WorkspaceAuth | Log an activity entry (used by workspace runtimes to self-report). |
| POST | /workspaces/:id/notify | WorkspaceAuth | Agent-to-user push message via WebSocket. Delivers a notification to connected Canvas clients. |
Audit Ledger
Tamper-evident audit trail for workspace events. Used by the Canvas Audit Trail panel.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/audit | WorkspaceAuth | List audit entries for a workspace. Supports ?event_type=delegation|decision|gate|hitl, ?cursor=<cursor>, and ?limit=<n> (default 50). |
Audit entry schema
| Field | Type | Description |
|---|---|---|
id | string | Unique entry ID |
event_type | string | delegation, decision, gate, or hitl |
actor | string | Workspace ID that generated the event |
summary | string | Human-readable event description |
chain_valid | bool | false if the entry's hash does not match the prior chain — indicates possible tampering |
created_at | string (ISO 8601) | Event timestamp |
cursor | string | null | Opaque pagination cursor; null when there are no more entries |
Example response:
{
"entries": [
{
"id": "aud_xyz789",
"event_type": "delegation",
"actor": "ws_abc123",
"summary": "Delegated task 'fix CI' to Backend Engineer",
"chain_valid": true,
"created_at": "2026-04-17T14:05:00Z"
}
],
"cursor": "eyJpZCI6ImF1ZF94eXo3ODkifQ"
}Session Search
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/session-search | WorkspaceAuth | Search activity logs with filters for type, date range, and text content. Returns paginated results. |
Workflow Checkpoints
Step-level progress persistence for long-running Temporal workflows. Workspaces with runtime: langgraph (Temporal) automatically save a checkpoint after each of the three workflow stages (task_receive, llm_call, task_complete) and resume from the last completed stage on restart.
Automatic resume behavior (runtime: langgraph only)
When a Temporal workspace restarts mid-workflow, the runtime reads the highest-index checkpoint and sets resume_from_step accordingly. Already-completed stages are skipped — the agent picks up exactly where it left off without re-running earlier steps.
Checkpoint I/O is non-fatal: network errors are silently swallowed. A crashed or unreachable platform never prevents the agent from running.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/checkpoints | WorkspaceAuth | Upsert a step checkpoint. Body: { "workflow_id": "...", "step_name": "task_receive|llm_call|task_complete", "step_index": 0, "payload": {...} }. Uses ON CONFLICT DO UPDATE — safe to call multiple times. |
| GET | /workspaces/:id/checkpoints/:wfid | WorkspaceAuth | Return all checkpoints for a workflow, ordered by step_index DESC. Returns 404 if no checkpoints exist for the workflow. |
| DELETE | /workspaces/:id/checkpoints/:wfid | WorkspaceAuth | Clear all checkpoints for a workflow. Called by the runtime on clean task completion. Returns 404 if none exist. |
Step names and indices:
| Step | step_index | Meaning |
|---|---|---|
task_receive | 0 | Task received from A2A message |
llm_call | 1 | LLM inference completed |
task_complete | 2 | Task result sent back to caller |
Schedules
Cron-based scheduled tasks per workspace.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/schedules | WorkspaceAuth | List all schedules for a workspace. |
| POST | /workspaces/:id/schedules | WorkspaceAuth | Create a schedule. Body: { "expression": "0 */6 * * *", "timezone": "UTC", "prompt": "...", "enabled": true }. |
| PATCH | /workspaces/:id/schedules/:scheduleId | WorkspaceAuth | Update a schedule (expression, timezone, prompt, enabled). |
| DELETE | /workspaces/:id/schedules/:scheduleId | WorkspaceAuth | Delete a schedule. |
| POST | /workspaces/:id/schedules/:scheduleId/run | WorkspaceAuth | Manually trigger a schedule immediately. |
| GET | /workspaces/:id/schedules/:scheduleId/history | WorkspaceAuth | List past runs for a schedule. Includes status (success, error, skipped) and error_detail. |
Schedule source field: template for org/import-seeded schedules, runtime for Canvas/API-created. The last_status includes skipped when the scheduler concurrency-aware-skips a busy workspace.
Channels
Social channel integrations (Telegram, Slack, etc.) for workspace agents.
Per-Workspace Channels
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/channels | WorkspaceAuth | List channels for a workspace. |
| POST | /workspaces/:id/channels | WorkspaceAuth | Create a channel. Body includes platform type, JSONB config, and allowlist. |
| PATCH | /workspaces/:id/channels/:channelId | WorkspaceAuth | Update a channel's config or allowlist. |
| DELETE | /workspaces/:id/channels/:channelId | WorkspaceAuth | Delete a channel. |
| POST | /workspaces/:id/channels/:channelId/send | WorkspaceAuth | Send an outbound message through the channel. |
| POST | /workspaces/:id/channels/:channelId/test | WorkspaceAuth | Test the channel connection (send a test message). |
Global Channel Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /channels/adapters | None | List available social platform adapters (Telegram, Slack, etc.). |
| POST | /channels/discover | AdminAuth | Auto-detect available chats/groups for a bot token. |
| POST | /webhooks/:type | None | Incoming webhook endpoint for social platforms. The :type parameter identifies the platform (e.g., telegram, slack). |
Plugins
Plugin registry and per-workspace plugin management.
Global Plugin Registry
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /plugins | None | List all plugins in the registry. Supports ?runtime= filter to show only compatible plugins. |
| GET | /plugins/sources | None | List registered install-source schemes (e.g., github://, local://). |
Per-Workspace Plugins
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/plugins | WorkspaceAuth | List installed plugins for a workspace. |
| POST | /workspaces/:id/plugins | WorkspaceAuth | Install a plugin. Body: { "source": "github://org/repo" }. Safeguards: 64 KiB body limit, 5 min fetch timeout, 100 MiB max staged-tree. |
| DELETE | /workspaces/:id/plugins/:name | WorkspaceAuth | Uninstall a plugin by name. |
| GET | /workspaces/:id/plugins/available | WorkspaceAuth | List plugins available for this workspace (filtered by workspace runtime). |
| GET | /workspaces/:id/plugins/compatibility | WorkspaceAuth | Preflight runtime-change check. Query: ?runtime=X. Returns which currently-installed plugins would be incompatible with the target runtime. |
Auth Tokens
Bearer token management for workspaces.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/tokens | WorkspaceAuth | List active tokens for a workspace (token values are masked). |
| POST | /workspaces/:id/tokens | WorkspaceAuth | Create a new bearer token for the workspace. |
| DELETE | /workspaces/:id/tokens/:tokenId | WorkspaceAuth | Revoke a specific token. |
Test Token (Development Only)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /admin/workspaces/:id/test-token | None | Mint a fresh bearer token for E2E scripts. Returns 404 unless MOLECULE_ENV != production or MOLECULE_ENABLE_TEST_TOKENS=1. |
Teams
Expand and collapse team views in the Canvas hierarchy.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/expand | WorkspaceAuth | Expand a team workspace to show its children on the canvas. |
| POST | /workspaces/:id/collapse | WorkspaceAuth | Collapse a team workspace to hide its children. |
Templates and Bundles
Templates
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /templates | AdminAuth | List available workspace templates with their runtime, description, and config schema. |
| POST | /templates/import | AdminAuth | Import a workspace template from a github:// source URL. |
Org Templates
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /org/templates | AdminAuth | List available organization templates. |
| POST | /org/import | AdminAuth | Import an org template. Applies resolveInsideRoot path sanitization. Creates the full workspace hierarchy defined in org.yaml. |
Bundles
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /bundles/export/:id | AdminAuth | Export a workspace (or workspace tree) as a portable bundle. Includes config, secrets (keys only), memory, schedules, and hierarchy. |
| POST | /bundles/import | AdminAuth | Import a previously-exported bundle. Recreates the workspace tree with all associated data. |
Approvals
Human-in-the-loop approval system for agent actions.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /workspaces/:id/approvals | WorkspaceAuth | Create an approval request. Body includes the action description, metadata, and options. |
| GET | /workspaces/:id/approvals | WorkspaceAuth | List approval requests for a workspace. |
| POST | /workspaces/:id/approvals/:id/decide | WorkspaceAuth | Approve or reject an approval request. Body: { "decision": "approve" } or { "decision": "reject" }. |
| GET | /approvals/pending | AdminAuth | List all pending approval requests across all workspaces. |
Canvas
Canvas viewport persistence (cosmetic only).
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /canvas/viewport | None | Get the saved canvas viewport (zoom, pan position). Open endpoint for bootstrap-friendliness. |
| PUT | /canvas/viewport | CanvasOrBearer | Save the canvas viewport. Accepts bearer OR matching Origin header. Worst case on forgery: viewport corruption, recovered by page refresh. |
Traces
LLM trace retrieval from Langfuse.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/traces | WorkspaceAuth | List LLM traces for a workspace from Langfuse. |
Audit Ledger
HMAC-SHA256-chained immutable agent event log for compliance record-keeping (EU AI Act Art. 12 / Art. 13). Each event is cryptographically chained to the previous one — tampering with any record breaks all subsequent HMACs.
AUDIT_LEDGER_SALT required. The platform and workspace containers must share the same AUDIT_LEDGER_SALT environment variable to compute and verify event HMACs. Set it in both your platform env and workspace container env. If the variable is absent, chain_valid returns null (not false) — no records are lost, verification is simply unavailable.
Query
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/audit | WorkspaceAuth | Query the audit ledger for a workspace. Returns events in descending chronological order with inline chain verification. |
Query parameters:
| Parameter | Type | Description |
|---|---|---|
agent_id | string | Filter to a specific agent. |
session_id | string | Filter to a specific session. |
from | RFC 3339 | Start of time range (e.g. 2026-04-01T00:00:00Z). |
to | RFC 3339 | End of time range. |
limit | int | Max records to return. Capped at 500. |
offset | int | Pagination offset. |
Response shape:
{
"events": [
{
"id": "uuid",
"workspace_id": "uuid",
"agent_id": "my-researcher",
"session_id": "sess_abc123",
"event_type": "tool_call",
"payload": { "tool": "bash", "input": "ls /workspace" },
"hmac": "sha256hex...",
"prev_hmac": "sha256hex...",
"created_at": "2026-04-17T12:00:00Z"
}
],
"chain_valid": true
}chain_valid values:
true— all HMACs verified; ledger is intact.false— at least one HMAC mismatch; possible tampering.null—AUDIT_LEDGER_SALTis absent from the platform env; verification skipped.
Workspace-side: recording events
In your workspace template, wire LedgerHooks into the agent pipeline:
from molecule_audit.hooks import LedgerHooks
hooks = LedgerHooks(agent_id="my-researcher", session_id=session_id)
async with hooks:
# hooks.on_task_start / on_llm_call / on_tool_call / on_task_end
# fire automatically at each pipeline stage
result = await agent.run(task)LedgerHooks is exception-safe — a failed ledger write never aborts the agent task.
CLI chain verification
# Verify the full chain for an agent; exit 0 = intact
python -m molecule_audit.verify --agent-id my-researcher
# Custom DB URL
python -m molecule_audit.verify --agent-id my-researcher --db postgresql://user:pass@host/dbExit codes: 0 = chain valid · 1 = broken chain · 2 = AUDIT_LEDGER_SALT missing · 3 = DB error.
Events
Append-only event log for structure changes.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /events | AdminAuth | List all structure events across all workspaces. |
| GET | /events/:workspaceId | AdminAuth | List structure events for a specific workspace. |
Terminal
WebSocket-based terminal access to workspace containers.
| Method | Path | Auth | Description |
|---|---|---|---|
| WS | /workspaces/:id/terminal | WorkspaceAuth | Open a WebSocket terminal session to the workspace container. Provides interactive shell access. |
WebSocket
Real-time event streaming for Canvas clients.
| Method | Path | Auth | Description |
|---|---|---|---|
| WS | /ws | None | Connect to the WebSocket hub. Receives all structure events (WORKSPACE_ONLINE, WORKSPACE_OFFLINE, HEARTBEAT, CONFIG_UPDATED, A2A_RESPONSE, AGENT_MESSAGE, etc.). Canvas clients connect here for real-time updates. |
Server-Sent Events (AG-UI)
Per-workspace SSE stream compatible with the AG-UI protocol. Use this endpoint to consume structured agent events from a web client or external tool without a WebSocket library.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workspaces/:id/events/stream | WorkspaceAuth | Open an SSE stream for the workspace. Returns Content-Type: text/event-stream. Sends an initial : ping comment on connect, then delivers every event emitted by the workspace in AG-UI envelope format. Events from other workspaces are filtered out. Returns 404 if the workspace does not exist. |
Event envelope format
Each event is delivered as an SSE data: line containing a JSON object:
{
"type": "AGENT_MESSAGE",
"timestamp": 1713398400000,
"data": { ... }
}type— event type string (e.g.AGENT_MESSAGE,A2A_RESPONSE,TASK_UPDATED)timestamp— Unix milliseconds at time of broadcastdata— event-specific payload (same payload as the WebSocket hub delivers)
Event types streamed
All event types emitted by RecordAndBroadcast and BroadcastOnly reach the SSE stream. The BroadcastOnly path is important: events like AGENT_MESSAGE, A2A_RESPONSE, and TASK_UPDATED skip Redis and would be invisible to a Redis-only subscriber — the in-process SSE layer catches them.
Example: connect with curl
curl -N \
-H "Authorization: Bearer <workspace-token>" \
http://localhost:8080/workspaces/<id>/events/stream: ping
data: {"type":"AGENT_MESSAGE","timestamp":1713398401234,"data":{"text":"Starting task..."}}
data: {"type":"TASK_UPDATED","timestamp":1713398405678,"data":{"status":"running"}}Example: connect from JavaScript
const es = new EventSource(
`/workspaces/${workspaceId}/events/stream`,
{ headers: { Authorization: `Bearer ${token}` } }
);
es.onmessage = (e) => {
const event = JSON.parse(e.data);
console.log(event.type, event.data);
};The SSE endpoint uses WorkspaceAuth — the bearer token must be bound to the :id in the path. A token for workspace A cannot open a stream for workspace B.
Error Responses
All endpoints return standard HTTP status codes:
| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request (malformed body, missing required fields) |
| 401 | Unauthorized (missing or invalid bearer token) |
| 403 | Forbidden (valid token but insufficient access) |
| 404 | Not found (workspace, schedule, channel, etc. does not exist) |
| 409 | Conflict (idempotency key collision on delegation) |
| 429 | Rate limited (exceeds RATE_LIMIT requests/min) |
| 500 | Internal server error |
Error response body format:
{
"error": "human-readable error message"
}Rate Limiting
All endpoints are subject to a global rate limit of RATE_LIMIT requests per minute (default: 600). When exceeded, the platform returns 429 Too Many Requests with a Retry-After header.
CORS
The platform sets CORS headers based on the CORS_ORIGINS environment variable (comma-separated list, default: http://localhost:3000,http://localhost:3001). Preflight (OPTIONS) requests are handled automatically by the Gin CORS middleware.