RoboCo's backend is a single FastAPI application (roboco/api/app.py, one create_app() factory). It mounts every domain router under the /api prefix, the agent-gateway intent verbs under /api/v1, and the live WebSocket streams under /ws. Everything is fronted by nginx on localhost:3000, so the panel and any integrator use relative URLs (/api/..., /ws/...) against one origin with no CORS to configure.

The live OpenAPI docs are the source of truth

The fastest way to see the full, current REST surface — every path, request body, and response schema — is the interactive docs the app serves itself:

This page is a map of where things live; /docs is the authoritative reference for exactly how to call them.

The two prefixes

There are two distinct API surfaces, and the prefix tells you which one you're on:

PrefixAudienceWhat it is
/api/*You / the panel / integratorsThe domain REST surface — tasks, agents, projects, git, usage, settings, and the rest. This is what the control panel calls.
/api/v1/flow/{role}/{verb} and /api/v1/doAI agents onlyThe agent gateway. Agents never call the domain routes above — they POST intent verbs here through their MCP servers, and the server-side Choreographer enforces state, locks, and evidence.

Health and readiness probes sit at the root, not under /api: GET /health and GET /ready.

Domain route groups (/api/*)

Every router is mounted under /api. The groups an operator or integrator hits:

Route groupPrefixPurpose
Tasks/api/tasksThe largest router: full task CRUD and lifecycle transitions (claim, submit, pass/fail, complete, escalate). The CEO god-mode override (PATCH /api/tasks/{id} with X-Agent-Role: ceo) lives here.
Kanban/api/kanbanBoard view of tasks grouped by state.
Agents/api/agentsAgent roster, roles, teams, current state.
Work sessions/api/work-sessionsGit session records — branch, commits, files, PR.
Projects/api/projectsRepository config, CI/quality commands, git-token management.
Products/api/productsProduct entities + CEO approve-and-start / cell-routing.
Sessions/api/sessionsCommunication sessions and their messages.
Channels/api/channelsTeam channels.
Groups/api/groupsAgent/channel grouping.
Messages/api/messagesExtracted messages from agent streams.
Notifications/api/notificationsFormal ack-required notifications.
Stream/api/streamAgent output stream access.
Journals/api/journalsAgent journals and entries.
Optimal/api/optimalRAG queries (in-house pgvector engine).
Git/api/gitGit operations surfaced for the panel.
Providers/api/providersModel-provider routing config.
Orchestrator/api/orchestratorAgent-runtime control (spawn/stop, dispatcher state).
Dashboard/api/dashboardAggregated dashboard data.
Usage/api/usageToken/cost analytics (GET /api/usage/summary?period=24h|7d|30d).
System/api/systemRate-limit introspection (GET /api/system/rate-limits).
Settings/api/settingsApp settings, including feature-flag persistence.
Company goals/api/company-goalsThe company charter.
Cockpit/api/cockpitCEO read-only business summary.
Research/api/researchWeb-research subsystem (flag-gated).
Pitches/api/pitchesPitch provisioning (flag-gated).
Secretary/api/secretarySecretary chief-of-staff + its live-chat bridge.
Prompter/api/prompterIntake interviewer live chat (SSE relay).
Docs/api/docsProject documentation file management.
A2A/api/a2aAgent-to-agent messaging plumbing.
Health vs readiness

GET /health is a liveness probe — it returns 200 once the app is up. GET /ready is a readiness probe — it checks PostgreSQL and Redis and returns a degraded payload if either is down. Wire your uptime monitor to /ready if you want it to react to a backing-store outage, /health if you only care that the process is alive. See Health & metrics.

The agent gateway (/api/v1)

Agents do not touch the domain routes. They go through the gateway, which exposes one POST endpoint per (role, verb) pair plus a shared content-tools endpoint:

EndpointRole
POST /api/v1/flow/developer/{verb}Developer
POST /api/v1/flow/qa/{verb}QA
POST /api/v1/flow/documenter/{verb}Documenter
POST /api/v1/flow/cell_pm/{verb}Cell PM
POST /api/v1/flow/main_pm/{verb}Main PM
POST /api/v1/flow/board/{verb}Board (Product Owner, Head of Marketing, Auditor)
POST /api/v1/flow/auditor/{verb}Auditor
POST /api/v1/flow/pr_reviewer/{verb}PR reviewer
POST /api/v1/doContent tools (commit, note, say, dm, evidence) for every role

The roboco-flow MCP server in each agent container is a thin shim: it reads the agent's spawn manifest, registers only the verbs that role may call, and POSTs each one here. The verb set per role and the structural sandboxing are documented in How agents are sandboxed — you generally won't call these endpoints yourself.

The error envelope

Every gateway verb returns the same standardized envelope (roboco/services/gateway/envelope.py), so agents recover from a rejection instead of looping:

  • Success carries status, task_id, next (the verb to call next), an optional evidence block, a context_briefing, and introspection fields (current_state, valid_next_verbs).
  • Error carries an error flavor, a human message, a concrete remediate hint, and — for input gaps — a missing list and a field_hints answer-key.

The error flavors:

errorMeaning
tracing_gapA required tracing artifact (e.g. a commit, PR, or note) is missing.
incomplete_inputA required input field was not supplied; missing + field_hints tell the agent exactly which.
invalid_stateThe verb isn't valid from the task's current state.
not_authorizedThe role isn't allowed to perform this action.
not_foundThe task or resource doesn't exist.
circuit_openThe agent has hammered one failing verb too many times; the breaker points it at a graceful exit.

The domain routes (/api/*) use FastAPI's standard error model, with the exception-handler stack in roboco/api/middleware.py mapping domain and service errors to clean responses. Notably:

  • A provider rate-limit error becomes HTTP 429 with a Retry-After header.
  • A validation failure is a 422, with a special remediation hint when an agent sends an 8-character short task id instead of a full UUID.
  • Every response echoes back an X-Correlation-ID (and the request's X-Response-Time-Ms), so one id threads through the panel, the API, and the logs.

Quick checks

bash
1curl -s localhost:3000/health2curl -s localhost:3000/ready3curl -s localhost:3000/api/system/rate-limits4curl -s 'localhost:3000/api/usage/summary?period=7d'5open http://localhost:3000/docs

Next