API Reference
OpenFlows is a thin orchestration brain on top of a self-hosted Coder deployment. It exposes a small, versioned control-plane API for operator automation, consumes the Coder API for workspace lifecycle, and uses the GitHub REST API and MCP for repository operations. This page documents the full API surface: OpenFlows endpoints, Coder integration points, GitHub calls, authentication, and request/response examples.
The key architectural principle is that Coder is the only runtime. OpenFlows does not run agents locally; it provisions ephemeral Coder workspaces and drives them through the Coder control plane. LLM calls go through the Coder AI Gateway, and GitHub identity is provided by Coder external auth. Worker workspaces contain zero AI software, zero LLM keys, and zero GitHub tokens.
Base URL and Versioning
All OpenFlows control-plane endpoints are prefixed with /api/v1. When running the orchestrator
from Docker Compose, the default base URL is http://localhost:8080. In production, route through
your internal ingress or load balancer.
# Default local base URL OPENFLOWS_BASE_URL=http://localhost:8080/api/v1 # Coder deployment base URL CODER_URL=https://coder.example.com
The API is versioned by URL path. /api/v1 is the current stable version. Breaking changes will
be introduced under a new path (e.g. /api/v2) with a deprecation window for the previous version.
Authentication
OpenFlows uses three distinct credential types, each scoped to a different subsystem. None of them are stored inside worker workspaces.
| Credential | Scope |
|---|---|
Authorization: Bearer <openflows-token> | OpenFlows control-plane API. Set via OPENFLOWS_API_TOKEN or the bootstrap-created admin token. |
CODER_SESSION_TOKEN | Coder API and Chats API. Scoped to provision workspaces, read users, and send chat messages. |
GitHub external auth token | GitHub REST and MCP. Managed by Coder external auth; OpenFlows never stores a PAT. |
The GitHub token is never configured in OpenFlows directly. It is obtained by Coder external auth and injected
into workspaces via the git-config module. OpenFlows GitHub calls use the same token through the
Coder MCP server or a short-lived REST credential provided by Coder.
# Example request to the OpenFlows control plane curl -X GET $OPENFLOWS_BASE_URL/health -H "Authorization: Bearer $OPENFLOWS_API_TOKEN" -H "Content-Type: application/json" # Example request to the Coder API curl -X GET $CODER_URL/api/v2/users/me -H "Authorization: Bearer $CODER_SESSION_TOKEN" -H "Coder-Session-Token: $CODER_SESSION_TOKEN"
OpenFlows Control-Plane Endpoints
These endpoints are served by the openflows binary. They are intended for operators, dashboards, and
external integrations. They are not required for normal autonomous operation; NEXUS drives the flow internally.
| Endpoint | Purpose |
|---|---|
GET /api/v1/health | Health check for the orchestrator, Redis, Coder, and AI Gateway |
GET /api/v1/tenants | List all configured tenants and their repository bindings |
POST /api/v1/tenants | Create or update a tenant repository binding |
GET /api/v1/tenants/:id | Fetch tenant details, active workers, and current state |
DELETE /api/v1/tenants/:id | Remove a tenant and stop its workers |
GET /api/v1/tickets | List all tickets in the SharedStore |
GET /api/v1/tickets/:id | Fetch a ticket status, linked PR, and event history |
POST /api/v1/tickets/:id/reassign | Reassign a stuck ticket to another idle worker |
GET /api/v1/workers | List all worker slots and their current state |
POST /api/v1/workers/:id/pause | Pause a worker without deleting it |
POST /api/v1/workers/:id/resume | Resume a paused worker |
GET /api/v1/events | Read recent events from the event ring |
Request and Response Examples
Health check:
GET /api/v1/health Authorization: Bearer $OPENFLOWS_API_TOKEN
{
"status": "ok",
"version": "1.2.0",
"dependencies": {
"redis": "ok",
"coder": "ok",
"ai_gateway": "ok"
},
"timestamp": "2026-07-20T15:42:00Z"
}Create a tenant:
POST /api/v1/tenants Authorization: Bearer $OPENFLOWS_API_TOKEN Content-Type: application/json
{
"name": "my-team",
"repository": "owner/repo",
"coder_user": "openflows-nexus"
}{
"id": "tenant-2f8c1e",
"name": "my-team",
"repository": "owner/repo",
"namespace": "my-team",
"state": "active",
"created_at": "2026-07-20T15:42:00Z"
}Reassign a ticket:
POST /api/v1/tickets/OF-123/reassign Authorization: Bearer $OPENFLOWS_API_TOKEN Content-Type: application/json
{
"target_worker": "forge-2",
"reason": "Worker forge-1 timed out"
}{
"ticket_id": "OF-123",
"worker_id": "forge-2",
"state": "assigned",
"reassigned_at": "2026-07-20T15:45:00Z"
}Coder API Integration Points
OpenFlows uses the Coder API to provision, monitor, and destroy ephemeral workspaces. The orchestrator holds the Coder session token and acts as a Coder user. All workspace lifecycle calls are made from the OpenFlows control plane, not from inside the workspace.
| Endpoint | Purpose |
|---|---|
GET /api/v2/users/me | Resolve the authenticated Coder user for identity checks |
GET /api/v2/workspaces | List existing workspaces |
POST /api/v2/workspaces | Provision a new ephemeral workspace from a Coder template |
GET /api/v2/workspaces/:id | Fetch workspace status, resources, and agent metadata |
POST /api/v2/workspaces/:id/builds | Start or stop a workspace build |
DELETE /api/v2/workspaces/:id | Tear down a workspace after merge or failure |
POST /api/v2/chats | Coder Chats API - send a control-plane message to a Coder Agent |
GET /api/v2/chats/:id | Retrieve a chat session and its messages |
POST /api/v2/chats/:id/messages | Append a follow-up message to an existing chat |
Coder Chats API vs. AgentAPI
OpenFlows drives Coder AI agents through the Coder Chats API, which is a control-plane API. The Chats API runs agents on Coder's servers and connects them to workspaces over the same secure tunnel used by IDEs. This is fundamentally different from the in-workspace AgentAPI, which runs inside a workspace and exposes local tools.
The Chats API is the correct integration point for OpenFlows because:
- Agent code does not run inside the workspace, so the workspace can remain minimal and unprivileged.
- LLM keys and tool registrations stay in the Coder control plane, never reaching the workspace.
- Agents can be routed through the Coder AI Gateway with central audit, governance, and rate limits.
- Agents can be reused across multiple workspaces without re-installing software.
# Start a control-plane chat with a Coder agent for a specific workspace POST /api/v2/chats Authorization: Bearer $CODER_SESSION_TOKEN Content-Type: application/json
{
"agent_id": "coder-agent-forge-1",
"user_id": "openflows-nexus",
"workspace_id": "workspace-uuid",
"message": {
"role": "user",
"content": "Read the current plan in PLAN.md and implement segment 3."
}
}{
"id": "chat-uuid",
"agent_id": "coder-agent-forge-1",
"workspace_id": "workspace-uuid",
"status": "running",
"messages": [
{ "role": "user", "content": "Read the current plan in PLAN.md and implement segment 3." }
]
}Why not AgentAPI
Workspace Lifecycle Example
When NEXUS assigns a ticket to FORGE, it orchestrates the following Coder API calls. The sequence is fully deterministic and can be observed in the event ring.
- Provision:
POST /api/v2/workspaceswith the template ID and parameter values. - Build:
POST /api/v2/workspaces/:id/buildsto start the workspace. - Chat:
POST /api/v2/chatsto attach a Coder agent to the workspace. - Observe: Poll
GET /api/v2/workspaces/:iduntil the workspace is running. - Destroy:
DELETE /api/v2/workspaces/:idafter merge or failure.
# Provision an ephemeral FORGE workspace POST /api/v2/workspaces Authorization: Bearer $CODER_SESSION_TOKEN Content-Type: application/json
{
"template_id": "openflows-forge",
"name": "forge-42-abc123",
"parameter_values": [
{ "name": "repo", "value": "owner/repo" },
{ "name": "ticket_id", "value": "OF-42" },
{ "name": "coder_module", "value": "claude-code" }
],
"auto_start": true
}{
"id": "workspace-uuid",
"name": "forge-42-abc123",
"template_id": "openflows-forge",
"owner_id": "openflows-nexus",
"status": "pending",
"created_at": "2026-07-20T15:42:00Z"
}GitHub MCP and REST
OpenFlows interacts with GitHub through two mechanisms: the Coder GitHub MCP server, which is the preferred path for high-level operations like opening PRs and posting comments, and the GitHub REST API for polling and read-only queries that do not require tool semantics.
| Endpoint | Purpose |
|---|---|
GET /repos/:owner/:repo/issues | Issue discovery and priority polling |
GET /repos/:owner/:repo/issues/:number | Fetch a single issue body and labels |
POST /repos/:owner/:repo/issues/:number/comments | Post status updates back to the issue |
POST /repos/:owner/:repo/pulls | Open a pull request |
GET /repos/:owner/:repo/pulls/:number | Read PR state and mergeable status |
PUT /repos/:owner/:repo/pulls/:number/merge | Merge a green PR |
GET /repos/:owner/:repo/actions/runs | Poll GitHub Actions CI status |
GET /repos/:owner/:repo/git/ref/:ref | Resolve branch or tag refs for rebase checks |
The MCP server is configured in the Coder dashboard (AI Settings → MCP Servers) and is referenced by name in
registry.json. REST calls are made from the orchestrator with the same token obtained through Coder
external auth.
GitHub REST Example: Open a Pull Request
POST https://api.github.com/repos/owner/repo/pulls Authorization: Bearer $GITHUB_TOKEN Accept: application/vnd.github+json Content-Type: application/json
{
"title": "feat(scope): implement feature described in #42",
"head": "forge-42-abc123",
"base": "main",
"body": "Closes #42.
This PR was generated by OpenFlows FORGE. Review contract in CONTRACT.md.",
"draft": false
}{
"number": 123,
"html_url": "https://github.com/owner/repo/pull/123",
"state": "open",
"head": { "ref": "forge-42-abc123" },
"base": { "ref": "main" }
}GitHub MCP Example: Post a Comment
When using the MCP server, the Coder agent calls the tool with a structured JSON payload. The orchestrator
does not construct HTTP requests directly; it instructs the agent to use the github MCP server.
{
"tool": "github.create_issue_comment",
"params": {
"owner": "owner",
"repo": "repo",
"issue_number": 42,
"body": "FORGE has opened PR #123. SENTINEL review is in progress."
}
}No GitHub PATs in OpenFlows
GITHUB_REPOSITORY environment variable only
tells OpenFlows which repo to monitor; it is not a credential.
Status Codes and Error Envelope
All OpenFlows control-plane responses use a consistent JSON envelope. Errors include a machine-readable
code and a human-readable message.
{
"error": {
"code": "TENANT_NOT_FOUND",
"message": "Tenant 'my-team' does not exist.",
"request_id": "req-uuid"
}
}| Status | Meaning |
|---|---|
200 OK | Request succeeded. |
202 Accepted | Async operation started (tenant creation, workspace build). |
400 Bad Request | Malformed JSON or validation failure. |
401 Unauthorized | Missing or invalid bearer token. |
403 Forbidden | Token lacks required scope. |
404 Not Found | Unknown tenant, ticket, or worker. |
409 Conflict | Resource already exists or state transition illegal. |
500 Internal Server Error | Orchestrator error; check RUST_LOG. |
Rate Limits and Retries
The orchestrator respects the rate limits of the upstream APIs it calls. Coder and GitHub rate limits are
inherited from the Coder deployment and the GitHub token. OpenFlows retries transient failures with exponential
backoff (up to 3 attempts) and surfaces persistent failures as FAILED or AwaitingHuman
states.
Control-plane endpoints are not heavily throttled by default because they are intended for internal tooling. If you expose the OpenFlows API externally, place it behind a reverse proxy or API gateway with its own rate-limit policy.
Observing API calls
RUST_LOG=openflows=debug to see every Coder and GitHub API call in the orchestrator logs, including
request IDs, status codes, and retry attempts. The event ring also captures high-level lifecycle events for the
TUI dashboard.