API Endpoint Reference
Every operation the public API (/api/v1) serves, with its scope, parameters and payload shapes. Generated from the OpenAPI document in the code repository, which is itself generated from the contracts the server routes are built from, so this page cannot drift from the running surface.
Surface version 1.49.0. 115 operations across 22 groups.
Start on the guide, not here
This page is the field level. Public API is the page to read first: how to mint a key, which scope to pick, the worked board workload, how to answer a run that parks, and how the error envelope and paging work. Reach for an official SDK before hand-rolling HTTP, or point a generator at the spec linked above.
Authenticating
A public-API key of the form cf_live_<keyId>.<secret>.
Every call carries the key as a bearer token and is scoped to that key's workspace. Each key holds one scope on an inclusive ladder, so a higher scope grants everything below it:
read → write → decide → admin
Each operation below states the LOWEST scope that admits it. A key below that line is refused with 403 insufficient_scope; an absent or unknown key is refused with 401.
Operations
Debug · Decisions · Environments · Evidence · Identity · Jobs · Keys · Merge records · Model presets · Models · Notifications · Pipelines · Repos · Risk policies · Services · Spec · Task types · Tasks · Tracker · Usage · VCS · Webhook
Debug
A run’s recorded telemetry, for diagnosing one that went wrong: the model calls it made, the context each agent was provided, the searches it ran, the tools it invoked and how its infrastructure came up. Read-only (read scope), and every response’s size is bounded before the request is made.
Get one agent-context snapshot
GET /api/v1/debug/agent-context/{snapshotId}
Minimum scope: read.
The complete context one dispatch was PROVIDED: system and user prompts, the folded standards fragments, and the injected .cat-context/* files an agent reads through tools (which therefore appear in no proxy telemetry). Windowed by bodyOffset/bodyChars.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
snapshotId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
bodyChars | integer | no | 0 to 200000, pattern ^\d+$ |
bodyOffset | integer | no | 0 to 2000000, pattern ^\d+$ |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get one LLM call
GET /api/v1/debug/llm-calls/{callId}
Minimum scope: read.
One recorded model call with its budgeted prompt delta, response and reasoning. bodyOffset/bodyChars window the bodies, so an arbitrarily long transcript is readable in bounded pages.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
callId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
bodyChars | integer | no | 0 to 200000, pattern ^\d+$ |
bodyOffset | integer | no | 0 to 2000000, pattern ^\d+$ |
view | "raw" | "messages" | no |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List the workspace's runs
GET /api/v1/debug/runs
Minimum scope: read.
The triage entry point: the workspace’s runs, newest first and keyset-paginated, with an optional status and since filter.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
status | "running" | "blocked" | "done" | "paused" | "failed" | no | |
since | integer | no | min 0, pattern ^\d+$ |
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a run's diagnostic map
GET /api/v1/debug/runs/{runId}
Minimum scope: read.
One run’s diagnostic overview: its steps, which telemetry sinks this deployment retains (and how much each holds), the LLM cost/latency rollups, and the derived signals worth looking at first.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a run's agent-context dispatches
GET /api/v1/debug/runs/{runId}/agent-context
Minimum scope: read.
Every dispatch whose provided context was captured, with SIZES only (no bodies) so the list stays bounded. Read one in full through the snapshot endpoint.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
stepIndex | integer | no | min 0, pattern ^\d+$ |
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a run's LLM calls
GET /api/v1/debug/runs/{runId}/llm-calls
Minimum scope: read.
The model calls a run made, keyset-paginated and filterable by agent kind, phase, outcome or a substring of the bodies. Bodies are returned only when bodyChars asks for them.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
agentKind | string | no | 1 to 120 characters |
phase | string | no | max 120 characters |
outcome | "ok" | "warning" | "error" | no | |
contains | string | no | 1 to 256 characters |
order | "newest" | "oldest" | no | |
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
bodyChars | integer | no | 0 to 4000, pattern ^\d+$ |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Export a run's model activity as one bundle
GET /api/v1/debug/runs/{runId}/llm-export
Minimum scope: read.
The whole of a run’s model activity as one self-describing document, for handing straight to a model asked why the run truncated, spent or stalled: the SQL rollups (run totals, per agent kind, per phase, with the carry cost that says which slice burdened everything after it) plus a bounded window of the individual calls behind them. The rollups cover EVERY recorded call and do not move with limit, so a windowed bundle still reports what the run actually cost; truncated says the calls are a window and order says which end was kept. Bodies are omitted unless bodyChars asks, and the resumable call list is the way to walk a long run whole.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
order | "oldest" | "newest" | no | |
bodyChars | integer | no | 0 to 4000, pattern ^\d+$ |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a run's infrastructure log
GET /api/v1/debug/runs/{runId}/logs
Minimum scope: read.
The run’s provisioning event log — how its environment, runner pool and containers came up, or why they did not.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a run's web searches
GET /api/v1/debug/runs/{runId}/search-queries
Minimum scope: read.
The web searches the run’s agents actually performed, keyset-paginated. Retained only when the deployment records agent context.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a run's tool calls
GET /api/v1/debug/runs/{runId}/tool-calls
Minimum scope: read.
The tool calls the run’s agents made, in the order they made them — which command, against what, and what came back. The half of “how did this diff come about” that neither the diff nor a prompt body answers. Arguments and results are retained only when the deployment records agent context AND the workspace has not opted out; bodies says which, so an empty args is never mistaken for a call that took none.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
jobId | string | no | |
order | "recent" | "trajectory" | no | |
outcome | "ok" | "error" | no |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Decisions
A run’s human decisions, from requirement-review and clarity findings through approval gates, judge verdicts, interviews and follow-ups, so a headless caller can drive the clarification loop instead of the run hanging. Answering requires a decide-scope key.
List a run's parked decisions
GET /api/v1/runs/{runId}/decisions
Minimum scope: read.
Read what a run is currently asking a human. Each entry names its kind, and every kind this surface can answer is listed: requirements-review, clarity-review, brainstorm, interview, input-gate, approval-gate, judge, fork, agent-decision, pr-review, human-test, visual-confirmation, follow-ups. Each carries the stable ids (item, approval, decision, finding) that its answering route addresses. parked reports only whether the run has STOPPED (status is blocked); it is not a precondition for decisions being non-empty, since a follow-ups entry is answerable while the run is still working, so poll this regardless of parked. An empty decisions beside a non-empty unanswerable means a wait no route here can settle (a person reviewing the pull request, a deployment-registered gate), each named with its reason and step.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Approve a parked step
POST /api/v1/runs/{runId}/decisions/approvals/{approvalId}/approve
Minimum scope: decide.
Approve the proposal a gated step is holding up, optionally replacing it with an edited one (the edit is what flows to every downstream step), and advance the run. The approvalId comes from the run's decision list; passing it back is what makes a racing app user and a racing integration resolve the same gate. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
approvalId | string | yes |
Request body (required): PublicApproveStep (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Reject a parked step
POST /api/v1/runs/{runId}/decisions/approvals/{approvalId}/reject
Minimum scope: decide.
Reject the gated proposal: the run stops entirely, recording a terminal rejected failure the board can retry. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
approvalId | string | yes |
Request body (required): PublicRejectStep (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Request changes on a parked step
POST /api/v1/runs/{runId}/decisions/approvals/{approvalId}/request-changes
Minimum scope: decide.
Send the gated step back to re-run with your guidance folded in. Unlike the in-app twin this takes freeform feedback only: anchored per-block comments address source line ranges of a rendered proposal, which a headless caller never rendered. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
approvalId | string | yes |
Request body (required): PublicRequestStepChanges (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a companion gate at its rework cap
POST /api/v1/runs/{runId}/decisions/approvals/{approvalId}/resolve-exceeded
Minimum scope: decide.
Pick how a quality companion that spent its automatic rework budget proceeds: one more round, proceed with the output as it stands, or stop and reset the task. A gate in this state reports exceeded: true and refuses the plain approve. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
approvalId | string | yes |
Request body (required): PublicResolveExceeded (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Incorporate brainstorm picks
POST /api/v1/runs/{runId}/decisions/brainstorm/{stage}/incorporate
Minimum scope: decide.
Fold the picks into one converged direction. ASYNCHRONOUS: the response shows the session incorporating while the durable driver folds and re-runs in the background. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes |
Request body (required): PublicIncorporate (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss or reopen a brainstorm option
PATCH /api/v1/runs/{runId}/decisions/brainstorm/{stage}/options/{itemId}
Minimum scope: decide.
Dismiss a proposed option, or reopen one dismissed by mistake. Only open options block incorporation. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes | |
itemId | string | yes |
Request body (required): PublicSetFindingStatus (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Respond to a brainstorm option
POST /api/v1/runs/{runId}/decisions/brainstorm/{stage}/options/{itemId}/reply
Minimum scope: decide.
Pick or steer one of the options the brainstorm agent proposed, for the named stage (requirements or architecture). A task may hold one live session per stage at once. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes | |
itemId | string | yes |
Request body (required): PublicReplyFinding (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Proceed past a brainstorm
POST /api/v1/runs/{runId}/decisions/brainstorm/{stage}/proceed
Minimum scope: decide.
Settle the brainstorm with the last converged direction and advance the parked run. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Re-run a brainstorm pass
POST /api/v1/runs/{runId}/decisions/brainstorm/{stage}/re-review
Minimum scope: decide.
Run one more brainstorm pass against the converged direction. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a brainstorm at its iteration cap
POST /api/v1/runs/{runId}/decisions/brainstorm/{stage}/resolve-exceeded
Minimum scope: decide.
Pick how a brainstorm that exhausted its pass budget proceeds: one more round, proceed with the last converged direction, or stop and reset the task. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
stage | string | yes |
Request body (required): PublicResolveExceeded (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss or reopen a clarity finding
PATCH /api/v1/runs/{runId}/decisions/clarity/findings/{itemId}
Minimum scope: decide.
Dismiss a clarity finding as not applicable, or reopen one dismissed by mistake. Only open findings block incorporation. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Request body (required): PublicSetFindingStatus (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Answer a clarity (bug-triage) finding
POST /api/v1/runs/{runId}/decisions/clarity/findings/{itemId}/reply
Minimum scope: decide.
Record an answer to one clarity-review finding — the bug-report twin of the requirements loop. Returns the run's updated decision list. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Request body (required): PublicReplyFinding (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Incorporate clarity answers
POST /api/v1/runs/{runId}/decisions/clarity/incorporate
Minimum scope: decide.
Fold the recorded answers into one standardized bug report. ASYNCHRONOUS: the response shows the review incorporating while the durable driver folds and re-reviews in the background. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicIncorporate (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Proceed past the clarity review
POST /api/v1/runs/{runId}/decisions/clarity/proceed
Minimum scope: decide.
Settle the clarity phase with the last clarified report and advance the parked run. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Re-triage the clarified report
POST /api/v1/runs/{runId}/decisions/clarity/re-review
Minimum scope: decide.
Run one more triage pass over the incorporated bug report. On convergence the parked run advances. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a clarity review at its iteration cap
POST /api/v1/runs/{runId}/decisions/clarity/resolve-exceeded
Minimum scope: decide.
Pick how a clarity review that exhausted its pass budget proceeds: one more round, proceed with the last clarified report, or stop and reset the task. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicResolveExceeded (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Answer a follow-up question
POST /api/v1/runs/{runId}/decisions/follow-ups/items/{itemId}/answer
Minimum scope: decide.
Answer one question item the Coder raised mid-run; the answer steers its next pass. Refused for a follow_up item, which is filed, sent back or dismissed instead. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Request body (required): PublicAnswerFollowUp (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss a follow-up item
POST /api/v1/runs/{runId}/decisions/follow-ups/items/{itemId}/dismiss
Minimum scope: decide.
Wave one item off without acting on it. Valid for either item kind, and (like every other verb here) releases the park once it is the last undecided item. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
File a follow-up item as an issue
POST /api/v1/runs/{runId}/decisions/follow-ups/items/{itemId}/file
Minimum scope: decide.
File one follow_up item on the workspace's issue tracker, recording the ticket ref on the item. Refused for a question item, and for a workspace with no tracker connected. Creating the issue is not idempotent, so a retry after a partial failure files a second one. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Send a follow-up item back to the Coder
POST /api/v1/runs/{runId}/decisions/follow-ups/items/{itemId}/send-back
Minimum scope: decide.
Fold one follow_up item into another Coder pass (the item records as queued). Once every item is decided the run loops the Coder for the ones sent back, within the maxLoops budget the decision reports. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Choose an implementation approach
POST /api/v1/runs/{runId}/decisions/fork/choose
Minimum scope: decide.
Pick one of the proposed implementation forks (by id) or submit your own approach. The Coder then runs with the choice folded in as a binding directive. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicChooseFork (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Confirm a human-test gate
POST /api/v1/runs/{runId}/decisions/human-test/confirm
Minimum scope: decide.
Confirm the change works in the ephemeral environment: it is torn down and the run advances. The decision carries the environment URL to exercise; confirming without exercising it approves untested work. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Request a fix from a human-test gate
POST /api/v1/runs/{runId}/decisions/human-test/request-fix
Minimum scope: decide.
Submit findings against the tested environment and dispatch a fixer, which commits onto the PR branch before the environment is rebuilt. The findings ARE the fixer prompt, so they cannot be blank. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicRequestGateFix (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a run parked on the task's input check
POST /api/v1/runs/{runId}/decisions/input-gate/resolve
Minimum scope: decide.
Settle a run the pre-dispatch input gate parked before its first agent step because the task states nothing an agent could act on. recheck re-evaluates the task as it now stands (edit it over PATCH /api/v1/tasks/{taskId} first: the fix is verified, not taken on trust) and releases the run only if the blocking findings are gone; a still-blocked verdict comes back as an ordinary 200 with refreshed findings. proceed waives the findings, which stay on the run as an overridden record. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicResolveInputGate (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Answer an interview question
POST /api/v1/runs/{runId}/decisions/interview/answer
Minimum scope: decide.
Record an answer to one question the parked interviewer asked. Does NOT resume the run: answer the batch, then continue or proceed. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicAnswerInterview (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Continue a parked interview
POST /api/v1/runs/{runId}/decisions/interview/continue
Minimum scope: decide.
Submit the recorded answers and resume: the interviewer runs again and may ask follow-up questions. ASYNCHRONOUS: the pass runs in the durable driver, so the next round arrives on a later read of the decision list. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Proceed past a parked interview
POST /api/v1/runs/{runId}/decisions/interview/proceed
Minimum scope: decide.
Stop the questions: the interviewer converges on the answers so far and the run advances. Also asynchronous, since converging is itself an interviewer pass. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a parked judge verdict
POST /api/v1/runs/{runId}/decisions/judge/resolve
Minimum scope: decide.
Settle a run parked on a judge verdict: proceed anyway, bounce the producing step for rework, or stop the run. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Challenge a PR review finding
POST /api/v1/runs/{runId}/decisions/pr-review/findings/{findingId}/challenge
Minimum scope: decide.
Dispatch a read-only investigator to re-examine one finding against the full source, optionally with a specific concern. It upholds, strengthens or retracts the finding, and the review re-parks carrying the verdict. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
findingId | string | yes |
Request body (required): PublicChallengePrReviewFinding (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss a PR review finding
POST /api/v1/runs/{runId}/decisions/pr-review/findings/{findingId}/dismiss
Minimum scope: decide.
Drop one finding from the parked review entirely. Curation rather than a resolution: the run stays parked. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
findingId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a parked PR deep review
POST /api/v1/runs/{runId}/decisions/pr-review/resolve
Minimum scope: decide.
Record the curated finding selection and say what to do with it: finish completes the read-only review, fix hands the selected findings to a fixer that commits onto the reviewed PR branch, post publishes them as inline PR review comments. fix and post need at least one selected finding and act on the real pull request. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicResolvePrReview (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Answer an agent-raised decision
POST /api/v1/runs/{runId}/decisions/questions/{decisionId}/answer
Minimum scope: decide.
Answer a question an agent raised mid-work. Resolving RE-RUNS the asking step with the choice folded in, rather than advancing past it. The choice is taken verbatim, so it may be one of the offered options or a steer of your own. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
decisionId | string | yes |
Request body (required): PublicResolveAgentDecision (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss or reopen a finding
PATCH /api/v1/runs/{runId}/decisions/requirements/findings/{itemId}
Minimum scope: decide.
Dismiss a finding as not applicable, or reopen one dismissed by mistake. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Request body (required): PublicSetFindingStatus (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Answer a review finding
POST /api/v1/runs/{runId}/decisions/requirements/findings/{itemId}/reply
Minimum scope: decide.
Record an answer to one reviewer finding. Returns the run's updated decision list. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes | |
itemId | string | yes |
Request body (required): PublicReplyFinding (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Incorporate the answers
POST /api/v1/runs/{runId}/decisions/requirements/incorporate
Minimum scope: decide.
Fold the recorded answers into one standardized requirements document. Asynchronous — the run re-reviews in the background, so the response shows the review incorporating. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicIncorporate (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Proceed with the current requirements
POST /api/v1/runs/{runId}/decisions/requirements/proceed
Minimum scope: decide.
Settle the requirements phase and advance the parked run (used when nothing is outstanding). Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Re-review the incorporated document
POST /api/v1/runs/{runId}/decisions/requirements/re-review
Minimum scope: decide.
Run one more reviewer pass over the incorporated document. On convergence the parked run advances. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Resolve a review at its iteration cap
POST /api/v1/runs/{runId}/decisions/requirements/resolve-exceeded
Minimum scope: decide.
Pick how a review that exhausted its reviewer-pass budget proceeds: one more round, proceed with the last incorporated document, or stop and reset the task. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicResolveExceeded (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Approve a visual-confirmation gate
POST /api/v1/runs/{runId}/decisions/visual-confirmation/approve
Minimum scope: decide.
Approve the captured screenshots against the reference designs and advance the run. The images themselves are not readable over this API — the decision carries only artifact ids — so approving on the projection alone approves screenshots you have not seen. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Request a fix from a visual-confirmation gate
POST /api/v1/runs/{runId}/decisions/visual-confirmation/request-fix
Minimum scope: decide.
Submit findings against the captured screenshots and dispatch a fixer. The findings ARE the fixer prompt, so they cannot be blank. Requires a decide-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Request body (required): PublicRequestGateFix (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicDecisionList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Environments
Connect the workspace to the cluster its environments deploy onto
POST /api/v1/environments/connections
Minimum scope: admin.
Bind environment provisioning to a Kubernetes cluster: the apiserver, how its TLS is verified, the namespace template, and how an environment URL is derived once manifests are applied. The secret bundle authenticating the connection is write-only; the response reports which secret KEYS were stored and never their values. Idempotent, so re-connecting replaces rather than accumulating.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | object (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Probe a candidate cluster connection without saving it
POST /api/v1/environments/connections/test
Minimum scope: admin.
Reach the apiserver with the supplied credentials and report what came back, persisting nothing. Worth a call of its own because the alternative is discovering an unreachable cluster or an expired token on the deploy step of a run that has already paid for a design pass and an implementation. A cluster that refuses the credential is an ANSWER, so it is a 200 carrying ok: false rather than an error.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Evidence
What a run PROVED: the engine’s own verification report (the same bundle it writes onto the pull request) and the binary artifacts the run captured, bytes included. The surface for a consumer that has to judge a run (accept the change, score the fleet) rather than debug one. Read-only (read scope).
Download an artifact's bytes
GET /api/v1/artifacts/{artifactId}/blob
Minimum scope: read.
The stored bytes of one artifact listed by the run-artifacts endpoint, served with the recorded image content type (nosniff, never inline active content). Authenticated like every other call: the bytes are workspace-scoped, so a report that links here on a public repository leaks nothing to a reader without a key. 404 when the id is unknown to the key’s workspace, and separately when the metadata row survives but its bytes are gone from the blob backend.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
artifactId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | binary (application/octet-stream), binary (image/gif), binary (image/jpeg), binary (image/png), binary (image/webp) | The artifact bytes |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
List a run's captured artifacts
GET /api/v1/runs/{runId}/artifacts
Minimum scope: read.
The binary artifacts the run captured (UI screenshots) plus the reference images they were reviewed against: id, kind, view, content type, exact byte size and content hash. Unpaged: the capture path caps how many one run may store, so the response size is bounded before the request. Fetch the bytes with the blob endpoint.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicRunArtifactList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a run's outcome summary
GET /api/v1/runs/{runId}/outcome
Minimum scope: read.
What the run changed and what backs that up, in product language, for a reader who will not open the diff: the run’s disposition, the pull requests it opened, requirement coverage joined to the service’s spec/, the tester’s verdict and concerns, the views it captured, the throwaway environments it stood up (state: "live" is the only one worth opening, and only while its expiresAt is still ahead; every other row still carries its URL), and the machine checks that ran. The same reduction the app’s outcome card renders, over the same evidence the verification report is built from, so the two cannot state different totals for one run. Nothing here is asserted by a model: every count is derived from recorded verdicts. Prefer the verification report when you need a reviewer’s full bundle; prefer this when you need to say what shipped. Sections state reported or absent with a machine-readable gap code, and truncations names any list the response had to bound.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a run's verification report
GET /api/v1/runs/{runId}/report
Minimum scope: read.
The engine’s bundle of CAPTURED FACTS about a run: the CI gate’s verdict and failing checks, the platform’s own run of the service’s lint/test/build commands (with the failing output), the red-then-green reproduction proof for a bugfix, the tester’s structured report, requirement coverage, the throwaway-environment lifecycle, judge verdicts and the merge decision. Byte-for-byte the JSON block the pull-request body carries, composed on read, so it also answers for a run that never opened a pull request. Each section states reported or absent with a note, so a step that did not run never looks like a step that found nothing.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PrVerificationReport (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Identity
What the calling key is and what it may do — the self-check an integration runs at startup, so “can I do this?” does not have to be answered by attempting it and reading the 403. read scope.
Describe the calling key
GET /api/v1/me
Minimum scope: read.
Report what the key on this request is and what it may do: its id, its account, the ONE workspace every call under it acts within, its scope, and the label it was minted with. read scope, the floor of the ladder, because an integration’s startup self-check has to work whatever rung it holds. The scope ladder is INCLUSIVE (read ⊂ write ⊂ decide ⊂ admin), so compare against the rung an action needs rather than for equality.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicIdentity (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Jobs
Headless runs of a public, inline pipeline (start, poll, stream).
List the workspace's jobs
GET /api/v1/jobs
Minimum scope: read.
List the headless runs THIS surface created, newest first and keyset-paginated. Scoped to internal-anchored runs exactly like the single-job read, so an external key can never enumerate the workspace’s ordinary board runs.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
status | "running" | "succeeded" | "failed" | no | |
since | integer | no | min 0, pattern ^\d+$ |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Start a headless job
POST /api/v1/jobs
Minimum scope: write.
Start a public, inline pipeline headlessly against a supplied brief. Returns a job id to poll or stream. Nothing is pushed to GitHub.
Request body (required): CreatePublicJob (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
202 | PublicJobAccepted (application/json) | Accepted — the run has started |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a job
GET /api/v1/jobs/{id}
Minimum scope: read.
Poll a headless job started through this surface: its status and, once finished, its result.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
id | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicJob (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Cancel a job
POST /api/v1/jobs/{id}/cancel
Minimum scope: write.
Stop a headless job run, freeing its concurrency slot. Idempotent — an already-finished job is returned as-is. Use this to abandon a run parked on a decision you do not intend to answer.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
id | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicJob (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Stream a job (SSE)
GET /api/v1/jobs/{id}/events
Minimum scope: read.
Server-sent events for a headless job run: progress frames until a terminal done/error/stopped/timeout event. Authenticated by the API key header.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
id | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | string (text/event-stream) | An event stream of job updates |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
Keys
The workspace’s public-API keys, provisioned headlessly. Requires an admin-scope key; a key minted here can never reach admin itself, and revoking a key revokes everything it minted.
List the workspace's API keys
GET /api/v1/keys
Minimum scope: admin.
The live (non-revoked) keys for the calling key’s workspace, metadata only; a secret is never readable back. createdByKeyId names the key that provisioned a key headlessly; createdByUserId names the person who minted one in the app.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicApiKeyList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Provision an API key
POST /api/v1/keys
Minimum scope: admin.
Mint a key for the calling key’s own workspace and return its raw secret EXACTLY ONCE, so store it now: it is not recoverable. Omitting scope mints a write key. admin cannot be minted here: a key provisioned over the API can never itself provision, which keeps the chain one link long. Requires an admin-scope key.
Request body (required): CreateHeadlessPublicApiKey (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | CreatedPublicApiKey (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Revoke an API key
DELETE /api/v1/keys/{keyId}
Minimum scope: admin.
Revoke a key AND every key it minted, so a leaked provisioning key cannot outlive its own revocation through the credentials it left behind. Idempotent, and it may name the calling key. Requires an admin-scope key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
keyId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
204 | empty | No content |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Merge records
List the per-change-class merge rollups
GET /api/v1/merge-records/rollups
Minimum scope: read.
Every change class’s accumulated track record for the workspace, as one aggregate: how many records it holds, how many landed and by which route (auto-merged, merged through the app, merged directly on the provider), how many were rejected or are still awaiting review, and the distribution of reviewer-effort tags. This is the evidence that justifies widening a per-class auto-merge rule; nothing widens one automatically. A class with no records is present as zeros rather than absent, so "nothing has landed here yet" never reads as a class the response left out. unknown is a real class (no changed-file list was available) and never matches a per-class rule.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get one merge record
GET /api/v1/merge-records/{recordId}
Minimum scope: read.
The same record addressed by its own id, for a caller that holds one without the run: the id a merge_tag_request notification carries on its payload, for instance. Scoped to the calling key’s workspace.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
recordId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Tag the reviewer effort a merge took
POST /api/v1/merge-records/{recordId}/effort
Minimum scope: write.
Record how much review a landed pull request actually needed (none for zero blocking comments, minor for a nit pass, major for real rework), or null to clear the tag. This is the ground truth the auto-merge score thresholds are trying to approximate, and it is never mandatory: an untagged merge records a null tag and nothing downstream breaks. A write key, not an admin one: the pull request already landed, so tagging it merges nothing. Idempotent, and orthogonal to the decision, so a record can be tagged whenever the effort becomes known, before or after the act that merged it.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
recordId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get the merge decision a run left behind
GET /api/v1/runs/{runId}/merge-record
Minimum scope: read.
What kind of change the run’s pull request made (a change class derived on the backend from the changed-file list, never from an agent’s opinion), what the merger scored it, which merge-threshold preset the decision was compared against, what ultimately happened to the pull request, and how much review a human spent if anybody has tagged it. The entry point of the merge-evidence loop for a caller holding a run id: it also hands back the recordId the effort-tag route takes. A run whose pipeline had no merger step made no merge decision and answers 404 with details.reason: "no_merge_record", distinct from the "run_not_found" a run this key cannot read gets.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Model presets
List the workspace’s model presets
GET /api/v1/model-presets
Minimum scope: admin.
The preset library, including which row is the workspace default that a task pinning none resolves. baseModelId is the model every agent step runs on under the preset, and overrides names the agent kinds that run on something else, which is usually the one that matters: two presets often differ only in what the CODER gets. Whether a preset can actually be dispatched to is NOT repeated here, because the models endpoint already answers it while keeping unconfigured apart from refused-by-policy; join on baseModelId.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Models
List the models a run in this workspace could dispatch to
GET /api/v1/models
Minimum scope: admin.
The workspace’s model catalog with the flags that decide whether an agent step can run at all, and which of four unrelated fixes an unrunnable one needs. available says a run can dispatch to it now. policyBlocked says it is configured and refused by the account’s model-family policy, so adding another provider key changes nothing. personalSubscription says it runs on a credential belonging to a PERSON (an individual-usage subscription vendor), which a key resolving no user can never see. subscriptionConfigured then says whether that person actually holds one: true means the model is wired and only the key’s identity is in the way, false means the owner is known and holds none, and null means there was nobody to ask about, so it must not be read as false. userScoped is SUPERSEDED by personalSubscription and still answers its original narrower question (whether a subscription is the route in force); prefer the newer field.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Notifications
The workspace’s human-actionable notifications (list, act on, or dismiss the run tails).
List the workspace's open notifications
GET /api/v1/notifications
Minimum scope: read.
List the open, human-actionable notifications in the key’s workspace (merge reviews, pipeline-complete confirmations, CI/test failures, and informational cards).
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicNotificationList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Act on a notification
POST /api/v1/notifications/{id}/act
Minimum scope: admin.
Run a notification’s typed side-effect and resolve it: merge the PR (merge_review / pipeline_complete) or retry the run (ci_failed / test_failed). Performs a real GitHub merge, so it requires an admin-scoped key. Only these automated-action types are actionable through the API — a notification that parks a run on an interactive human decision cannot be acted on headlessly (dismiss it instead). A card that would retry a run on an individual-usage model likewise cannot be acted on through the API. To record how much review a merged pull request needed, call POST /api/v1/merge-records/{recordId}/effort (a write key) before or after this; a merge_tag_request card carries its record id on the payload and is resolved by tagging that record and dismissing the card.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
id | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | Notification (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Dismiss a notification
POST /api/v1/notifications/{id}/dismiss
Minimum scope: write.
Dismiss a notification without acting on it.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
id | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | Notification (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Pipelines
The workspace’s pipelines (discover a pipelineId to start a task with).
List the workspace's pipelines
GET /api/v1/pipelines
Minimum scope: read.
List the pipelines in the key’s workspace — id/name/steps plus whether each is public and safe to run headlessly — so a caller can pick a pipelineId to start a task with.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicPipelineList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Repos
List the repositories a service can be created against
GET /api/v1/repos
Minimum scope: read.
List the repositories the key’s workspace has LINKED, each with the service that already backs it (null when nothing does, and always null for a monorepo, which can back several). The discovery half of service creation: the create takes a repoId, and this is where one comes from. A repository the connection can reach but nobody has adopted yet is NOT here; list those with the available-repos endpoint and adopt one with the link endpoint.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List the repositories this workspace could adopt
GET /api/v1/repos/available
Minimum scope: admin.
The repositories the workspace’s source-control connection can REACH, whether or not this workspace links them, with linked as the join onto the repos list. It exists because those two populations differ and the difference is invisible otherwise: linking is explicit per workspace, so a repository that exists and is perfectly reachable is absent from the repos list in exactly the way one that was never created is, and those need opposite fixes. Pass q as an exact owner/name for an authoritative point-read, as a substring to search, or omit it to browse what is accessible. Each call reaches the provider, so it is a setup-time read rather than one to poll.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
q | string | no |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Create a repository and adapt it with the bootstrapper agent
POST /api/v1/repos/bootstrap
Minimum scope: admin.
Create a brand-new repository under the account the workspace is connected to, then run the bootstrapper agent in a container to write it against the supplied brief (or to adapt a reference architecture). Answers 201 with a job to poll rather than blocking for the minutes a container takes. The job names the board service frame it materialises, so work can be filed against the service before the repository has finished being written. This is the one act of board setup with no other public counterpart: creating a service takes a repoId, and nothing else here makes one.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | object (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Poll one repository bootstrap
GET /api/v1/repos/bootstrap/{jobId}
Minimum scope: admin.
Read a bootstrap run’s current state. failureKind says whether a retry could plausibly help: a preflight refusal (the target repository already has content, nothing is connected) cannot be retried into success, where an evicted container can.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
jobId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Adopt an existing repository into this workspace
POST /api/v1/repos/link
Minimum scope: admin.
Link a repository the connection can reach, by owner and name, so a service can be created against it. The act that had no headless counterpart: nothing links a repository for you (the provider webhook for an added repository does not project one, and a resync refreshes what is already linked), so a repository created by any means stayed invisible to the repos list and unusable by service creation until a person opened the app. Takes a NAME rather than the numeric repoId its sibling reads report, because a caller setting a workspace up from configuration knows the name and cannot know a provider id for a repository no public read lists; the response carries the repoId for the service-creation call that follows. Idempotent: a repository this workspace already links returns its row rather than refusing, so a setup script re-running itself needs no special case. A repository the connection cannot reach is a 404 with details.reason: repo_not_reachable, which covers both "it does not exist" and "your credential is not granted it": a provider answers those identically, and inventing a split would be a guess.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Risk policies
List the workspace’s risk policies
GET /api/v1/risk-policies
Minimum scope: admin.
The policy library, including which row is the workspace default that a task pinning none resolves. autoMergeEnabled is the master switch that decides whether a run can land its pull request without a person; dryRunRoles names the roles whose runs the policy forces into dry-run mode, which is the difference between “this policy merges” and “this policy merges for everyone except one role”. A policy also caps CI-fixer attempts, requirement and tester iteration rounds and the release-health watch, which is why it is not called a merge preset; the id is what a task pins as riskPolicyId.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Services
The workspace’s board services.
List the workspace's services
GET /api/v1/services
Minimum scope: read.
List the board service frames in the key’s workspace, so a caller can discover the serviceId to create/list tasks under.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicServiceList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Create a service
POST /api/v1/services
Minimum scope: admin.
Create a board service, optionally backed by a repository from GET /api/v1/repos. The repository link is what makes the service runnable: execution resolves a task’s repository by walking up to its enclosing service frame, so a service with none holds tasks and can start none of them. A whole-repo repository that already backs a service in this account is MOUNTED rather than duplicated; a monorepo service must name its subdirectory. The board lays the service out itself: this surface publishes no coordinates. Requires an admin key.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | PublicService (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Patch a service, including where its per-run manifests live
PATCH /api/v1/services/{serviceId}
Minimum scope: admin.
Change a service’s authored fields, and declare its provisioning: where the manifests for a per-run environment are read from. That second half is what a connected cluster alone cannot supply, because the platform keeps “which cluster” (one per workspace) apart from “which manifests” (one set per service). An omitted provisioning leaves the stored one alone rather than clearing it. Board coordinates are deliberately absent, as they are on service creation.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
serviceId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicService (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Spec
The in-repo prescriptive specification: what a service must be true of, as opposed to what any one run did. Two reads, at the two refs that answer different questions: the SERVICE read is the repository’s default branch (the agreed truth), the RUN read is the branch one run pushed its work to (what that run was judged against, including the requirements it added and has not merged). The requirement ids are the join key onto requirements on a run’s report and outcome. Read-only (read scope): the spec’s write path is a reviewed commit.
Get the specification one run was judged against
GET /api/v1/runs/{runId}/spec
Minimum scope: read.
The same in-repo specification the service read serves, read at the branch THIS RUN pushed its work to rather than at the repository default. That is the tree a run’s verdicts were made against: while its pull request is open, every requirement the run itself ADDED is absent from the default branch, so joining requirements rows from GET /api/v1/runs/{runId}/report or …/outcome against the service read leaves exactly those rows without a criterion. provenance names the branch and the commit, so a caller can see which tree it got. anchor carries one value the service read cannot answer, not_read: nothing was read, because the run’s spec read is gated on a tester having reported so that the tree served is the one the verdicts were made against, and provenance is null there and only there. The refusals are the service read’s: a 503 with reason: "spec_read_failed" for a repository that could not be read, "spec_ref_unresolved" for a branch that would not resolve, "vcs_not_configured" for a deployment or workspace that wired no version control. An outage never reaches a 200.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
runId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicRunSpec (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a service's in-repo specification
GET /api/v1/services/{serviceId}/spec
Minimum scope: read.
The prescriptive specification stored in the service’s own repository under spec/: modules → feature groups → requirement items, each with its MoSCoW priority, its aspirational/established implementation state and its Given/When/Then acceptance criteria, plus the domain rules scoped to each group and the Gherkin .feature files rendered from the same tree. provenance names the branch and commit the read describes, because the default branch is not what a run with an open pull request is working against. The requirement ids here are the join key onto requirements on a run’s report and outcome, so criterion → evidence is a map lookup. Four outcomes are kept apart rather than folded: present: false means the default branch holds no spec, a 503 with reason: "spec_read_failed" means the repository could not be read, a 503 with reason: "vcs_not_configured" means the deployment or workspace wired no version control, and a partially readable spec is SERVED with issues naming each file that did not survive. Read-only: the spec’s write path is a reviewed commit.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
serviceId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicServiceSpec (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Task types
List the task types this workspace may create
GET /api/v1/task-types
Minimum scope: read.
List the task types a task can be created as in the key’s workspace (the built-in ones plus any the deployment registered), each with the fields it accepts. Fill those fields through fields on task creation; the descriptors here are what that call validates against, so a caller reads the form rather than guessing it. A type a workspace admin has hidden is absent.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Tasks
Board tasks under a service (create, list, read, edit, start, stop, retry, stream).
List a service's tasks
GET /api/v1/services/{serviceId}/tasks
Minimum scope: read.
List every task under a service (the whole subtree — tasks directly under the frame and under its modules).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
serviceId | string | yes |
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
limit | integer | no | 1 to 100, pattern ^\d+$ |
cursor | string | no | 1 to 200 characters |
status | "planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done" | no |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTaskList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Create a task under a service
POST /api/v1/services/{serviceId}/tasks
Minimum scope: write.
Create a task inside a service frame the key’s workspace owns. The task starts in the planned state; start it with the start endpoint. Optionally file it FROM a tracker ticket, and/or attach the requirements documents it is to be built against (named in a connected document source, or uploaded inline): the only way to get spec-sized input onto a repository-touching run.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
serviceId | string | yes |
Request body (required): CreatePublicTask (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | PublicTask (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a task's status
GET /api/v1/tasks/{taskId}
Minimum scope: read.
Read a task’s current lifecycle status, run progress, run id, and PR URL (once one exists).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTask (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Edit a task's inputs
PATCH /api/v1/tasks/{taskId}
Minimum scope: write.
Edit a task’s human-authored inputs before it runs: its title, its description, and fields, the per-case values for its own task type (checked against the descriptors GET /api/v1/task-types serves). All are optional. fields is MERGED over what the task already carries — a key you send is written, a key you omit keeps its stored value — because this API does not serve the bag back. This is what makes an input the pre-dispatch gate refused repairable: supply the value it named, then recheck the parked run.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): UpdatePublicTask (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTask (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Delete a task
DELETE /api/v1/tasks/{taskId}
Minimum scope: admin.
Delete a task and its run history. Destructive, so it sits at the top of the scope ladder: requires an admin-scoped key.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
204 | empty | No content |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Declare that a task waits for another
POST /api/v1/tasks/{taskId}/dependencies
Minimum scope: write.
Record that this task cannot start until dependsOnTaskId is done. Both ends must be tasks in this workspace, and an edge that would close a cycle is refused. Idempotent: an edge that already exists is returned as-is rather than toggled off, so a provisioning integration re-running its own setup converges. Pair it with autoStartDependents on the BLOCKER (the task patch) to have the chain run itself.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTask (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Drop a dependency edge
POST /api/v1/tasks/{taskId}/dependencies/remove
Minimum scope: write.
Remove the ordering between this task and dependsOnTaskId. Idempotent: an edge that is not there is a no-op.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTask (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List a task's attached documents
GET /api/v1/tasks/{taskId}/documents
Minimum scope: read.
The requirements documents attached to the task, in the order the agents read them. Each is identified by the (source, externalId) pair the attach and detach calls take.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Attach a document to a task
POST /api/v1/tasks/{taskId}/documents
Minimum scope: write.
Attach a requirements document to a task that already exists, in either of the two forms creation takes: NAME a page in a connected document source, or CARRY the text inline. A task’s spec routinely arrives after the task does, and before this the only way to attach one was to delete the task and file it again, losing the id every stored reference points at, its ticket claim and the documents it already carried. A document a different live task already holds is refused rather than moved.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
201 | object (application/json) | Created |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Detach a document from a task
POST /api/v1/tasks/{taskId}/documents/detach
Minimum scope: write.
Detach a document, naming it by the (source, externalId) pair the list serves. The document itself survives in the workspace, so re-attaching it later costs no re-import. Idempotent: detaching one the task does not hold is a no-op.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
204 | empty | No content |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Stream a task run (SSE)
GET /api/v1/tasks/{taskId}/events
Minimum scope: read.
Server-sent events for a board task run: progress frames (the rich run projection) until a terminal done/error event, or a timeout when the connection cap is reached. Authenticated by the API key header.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | string (text/event-stream) | An event stream of run updates |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
Retry a task's failed run
POST /api/v1/tasks/{taskId}/retry
Minimum scope: write.
Retry a task’s failed run. A task on an individual-usage model cannot be retried through the API (no headless personal-credential unlock).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
202 | PublicTask (application/json) | Accepted — the run has started |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Get a task's run (rich projection)
GET /api/v1/tasks/{taskId}/run
Minimum scope: read.
Read a task’s run in detail: per-step status/progress/subtasks, the failure kind and message, and the PR (url + branch).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicRun (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Start (run) a task
POST /api/v1/tasks/{taskId}/start
Minimum scope: write.
Start a task’s pipeline. Uses the request’s pipelineId, else the task’s pinned pipeline. A pipeline that can park on a human decision requires a decide-scope key. A task on an individual-usage model cannot be started through the API (no headless personal-credential unlock).
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Request body (required): StartPublicTask (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
202 | PublicTask (application/json) | Accepted — the run has started |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Stop a task's run
POST /api/v1/tasks/{taskId}/stop
Minimum scope: write.
Stop a task’s in-flight run. Records a cancelled terminal state, leaving the run retryable.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
taskId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicTask (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Tracker
Read the workspace’s tracker writeback disposition
GET /api/v1/tracker/writeback
Minimum scope: admin.
What this workspace does to a task’s LINKED tracker issue as its pull request progresses: comment when the pull request opens, comment and close the issue when it merges, and post a headless run’s parked requirements-review findings so the reporter can answer where they filed. Worth reading before filing a ticket-linked task, since it decides whether the issue the work came from ever hears the outcome. updatedAt is null when nobody has chosen a disposition, in which case the values are this deployment’s defaults (all three ON). Requires an admin key.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Change the workspace’s tracker writeback disposition
PATCH /api/v1/tracker/writeback
Minimum scope: admin.
Turn one or more writeback actions on or off. A MERGE: an action you omit keeps its stored value, so a caller acting on one decision cannot silently move the other two. This is workspace-wide configuration, so it changes what happens to every task’s ticket on the board; the read beside it reports updatedAt so a caller can see whether it is about to overwrite somebody’s choice. An empty patch is a no-op and does not stamp updatedAt. Requires an admin key.
Request body (required): object (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Usage
Read the workspace's usage for the current period
GET /api/v1/usage
Minimum scope: read.
Read this billing period’s METERED spend against the workspace budget (including whether it is exceeded, which pauses runs) plus the per-(billing, vendor, provider, model) token breakdown behind it. Costs on subscription rows are illustrative — a flat-rate plan bills nothing per token — so branch on billing before summing. Workspace-scoped: the account- and user-tier budgets are not reachable through this surface.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicUsage (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Break the workspace's spend down by repository, ticket, run or step kind
GET /api/v1/usage/spend
Minimum scope: read.
Group the board’s spend over a window (24h, 7d, 30d, 90d) by ONE dimension: repo, ticket and run are the cost-attribution axes an organisation budgets against, and model / agentKind / service / taskType slice the same money the other ways. meteredCost is real money and subscriptionCost is the illustrative equivalent-API cost of flat-rate quota usage, so never sum them. The EMPTY key is the unattributed bucket, a real slice rather than a dropped row, never dropped from the breakdown. rows is the heaviest limit slices (default 100, max 500) and truncated says when there was a tail, while totals aggregates the WHOLE window either way, so a capped answer still reports what the board spent. source says which store answered: the short windows scan the live ledger, which resolves a repository or a ticket through today’s links, while the long ones read the durable daily rollup, which froze that attribution while the money was spent and is never pruned. Read rolledUpThrough before reporting a quiet quarter, since a rollup that has never run and a board that spent nothing look identical. Workspace-scoped: the account-wide view is not reachable through this surface.
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
dimension | "model" | "agentKind" | "service" | "repo" | "taskType" | "ticket" | "run" | yes | |
window | "24h" | "7d" | "30d" | "90d" | no | |
limit | integer | no | 1 to 500, pattern ^\d+$ |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicSpend (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
VCS
Read the workspace’s source-control connection and what it may do
GET /api/v1/vcs/connection
Minimum scope: admin.
The connected account, how the workspace authenticates to it, and the two permissions that decide whether an automated flow can complete: whether the platform may create repositories, and whether it may write workflow files. Both are enforced by the provider at push time, so a caller that cannot read them discovers a missing workflow permission as a repository that bootstrapped and then failed to gain its CI workflow. Provider-neutral: a GitLab-connected workspace answers here too. connection is null when nothing is connected, which is a state rather than an error.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | object (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Webhook
The workspace’s one outbound endpoint: register it to receive notifications, run-lifecycle events and platform-health alerts by push instead of polling. Requires an admin-scope key; the signing secret is write-only.
Read the workspace's outbound webhook
GET /api/v1/notification-webhook
Minimum scope: admin.
The endpoint this workspace delivers notifications, run-lifecycle events and platform-health alerts to, or { "webhook": null } when none is registered. The signing secret is never returned; hasSecret reports only whether one is set.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicNotificationWebhook (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Register or update the outbound webhook
PUT /api/v1/notification-webhook
Minimum scope: admin.
Register the HTTPS endpoint deliveries are POSTed to, or update the one already registered. Every omitted field keeps its stored value, so subscribing to run events is a one-field call that re-sends neither the URL nor the secret. url is required only on the first call, when there is nothing registered to keep; omitting it otherwise leaves the endpoint alone. Supplying secret rotates the signing secret; omitting it keeps the current one. The endpoint must be https: and publicly routable unless the deployment widened its allow-list.
Request body (required): PutNotificationWebhook (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | NotificationWebhook (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Remove the outbound webhook
DELETE /api/v1/notification-webhook
Minimum scope: admin.
Deregister the endpoint; deliveries stop. Idempotent.
Responses
| Status | Body | Meaning |
|---|---|---|
204 | empty | No content |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
List the workspace's outbound webhooks
GET /api/v1/notification-webhooks
Minimum scope: admin.
Every endpoint this workspace delivers to, ordered by id. The endpoint the unnamed routes address appears here under the id default. Not paginated: the number of endpoints a workspace may register is capped, so the whole set fits in one response. No signing secret is returned for any of them.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicNotificationWebhookList (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Read one named outbound webhook
GET /api/v1/notification-webhooks/{webhookId}
Minimum scope: admin.
The endpoint registered under this id, or { "webhook": null } when there is none — the same shape the unnamed read answers, so an integration's startup self-check does not branch on a status code. The signing secret is never returned.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
webhookId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
200 | PublicNotificationWebhook (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Register or update one named outbound webhook
PUT /api/v1/notification-webhooks/{webhookId}
Minimum scope: admin.
Register an endpoint under an id YOU choose (1-63 characters of lowercase letters, digits, - or _), or update the one already there. Idempotent by id, so an integration can enroll its own receiver on every cold start without tracking whether it has enrolled before, and without displacing anything else the workspace registered. Every field follows the same keep-on-omit rule as the unnamed route, url being required only when there is nothing under this id to keep, and a supplied secret rotating this endpoint's own signing secret. Refused with reason: "invalid_webhook_id" for an id that is not a slug, and reason: "webhook_limit_reached" (409) when registering a NEW id would exceed the per-workspace cap; editing an existing one is admitted either way.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
webhookId | string | yes |
Request body (required): PutNotificationWebhook (application/json)
Responses
| Status | Body | Meaning |
|---|---|---|
200 | NotificationWebhook (application/json) | Success |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Remove one named outbound webhook
DELETE /api/v1/notification-webhooks/{webhookId}
Minimum scope: admin.
Deregister this endpoint; its deliveries stop and the workspace's other endpoints are untouched. Idempotent.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
webhookId | string | yes |
Responses
| Status | Body | Meaning |
|---|---|---|
204 | empty | No content |
4XX | ErrorResponse (application/json) | Client error (validation, unauthorized, not found, conflict, rate limit) |
5XX | ErrorResponse (application/json) | Server error |
Schemas
The payload shapes the operations above reference. Field names, types and constraints are the contract; the narrative for what each one means lives on the page that owns the feature.
AcceptanceCriterion · CreateHeadlessPublicApiKey · CreatePublicJob · CreatePublicTask · CreatedPublicApiKey · DocumentFreshness · DomainRule · ErrorResponse · Notification · NotificationWebhook · PrReportCheck · PrReportCi · PrReportContext · PrReportContextDocument · PrReportEnvironments · PrReportIssue · PrReportJudge · PrReportJudges · PrReportMerge · PrReportObservability · PrReportReproduction · PrReportRequirements · PrReportRun · PrReportStep · PrReportTestConcern · PrReportTestOutcome · PrReportTests · PrReportValidation · PrReportValidationCommand · PrVerificationReport · PublicAgentDecision · PublicAnswerFollowUp · PublicAnswerInterview · PublicApiKey · PublicApiKeyList · PublicApprovalGateDecision · PublicApproveStep · PublicBrainstormDecision · PublicChallengePrReviewFinding · PublicChooseFork · PublicClarityDecision · PublicDecision · PublicDecisionList · PublicFollowUpItem · PublicFollowUpsDecision · PublicForkDecision · PublicHumanTestDecision · PublicHumanTestEnvironment · PublicIdentity · PublicIncorporate · PublicInputGateDecision · PublicInterviewDecision · PublicInterviewQuestion · PublicJob · PublicJobAccepted · PublicNotificationList · PublicNotificationWebhook · PublicNotificationWebhookList · PublicPipeline · PublicPipelineList · PublicPrReviewDecision · PublicRejectStep · PublicReplyFinding · PublicRequestGateFix · PublicRequestStepChanges · PublicRequirementsDecision · PublicResolveAgentDecision · PublicResolveExceeded · PublicResolveInputGate · PublicResolvePrReview · PublicReviewFinding · PublicRun · PublicRunArtifact · PublicRunArtifactList · PublicRunSpec · PublicService · PublicServiceList · PublicServiceSpec · PublicSetFindingStatus · PublicSpecFeatureFile · PublicSpecProvenance · PublicSpecTruncation · PublicSpend · PublicSpendRow · PublicSpendTotals · PublicTask · PublicTaskDocument · PublicTaskList · PublicTaskSourceDocument · PublicTaskTicket · PublicTaskUploadedDocument · PublicUnanswerableWait · PublicUsage · PublicUsageBudget · PublicUsageRow · PublicVisualConfirmDecision · PutNotificationWebhook · RequirementGroup · RequirementItem · SpecDoc · SpecModule · SpecReadIssue · StartPublicTask · UpdatePublicTask
AcceptanceCriterion
| Field | Type | Required | Notes |
|---|---|---|---|
given | string | yes | max 2000 characters |
id | string | yes | 1 to 200 characters |
outcome | string | yes | max 2000 characters |
when | string | yes | max 2000 characters |
CreateHeadlessPublicApiKey
| Field | Type | Required | Notes |
|---|---|---|---|
externalIdentity | string | no | 1 to 200 characters, pattern ^[^\x00-\x1f\x7f\x80-\x9f]+$ |
label | string | yes | 1 to 120 characters |
scope | "read" | "write" | "decide" | no |
CreatePublicJob
| Field | Type | Required | Notes |
|---|---|---|---|
input | string | yes | 1 to 50000 characters |
pipelineId | string | yes | min 1 character |
title | string | no | max 200 characters |
CreatePublicTask
| Field | Type | Required | Notes |
|---|---|---|---|
description | string | no | max 2000 characters |
documents | array of PublicTaskDocument | no | |
fields | map of string | array of string | boolean | number | no | |
modelPresetId | string | no | 1 to 120 characters |
riskPolicyId | string | no | 1 to 120 characters |
taskType | "feature" | "bug" | "document" | "spike" | "review" | "ralph" | string | no | |
ticket | PublicTaskTicket | no | |
title | string | yes | 1 to 200 characters |
CreatedPublicApiKey
| Field | Type | Required | Notes |
|---|---|---|---|
key | PublicApiKey | yes | |
secret | string | yes |
DocumentFreshness
One of 3 shapes.
status: "confirmed"
| Field | Type | Required | Notes |
|---|---|---|---|
change | "unchanged" | "reimported" | "revision_only" | yes | |
status | "confirmed" | yes | |
version | string | yes |
status: "not-applicable"
| Field | Type | Required | Notes |
|---|---|---|---|
status | "not-applicable" | yes |
status: "unconfirmed"
| Field | Type | Required | Notes |
|---|---|---|---|
reason | "not_connected" | "credentials_unreadable" | "unversioned" | "source_unreachable" | yes | |
status | "unconfirmed" | yes |
DomainRule
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | 1 to 200 characters |
rationale | string | no | max 2000 characters |
rule | string | yes | 1 to 4000 characters |
sourceBlockIds | array of string | no |
ErrorResponse
| Field | Type | Required | Notes |
|---|---|---|---|
error | object | yes | |
error.code | string | yes | |
error.details | ? | no | |
error.issues | array of object | no | |
error.message | string | yes |
Notification
| Field | Type | Required | Notes |
|---|---|---|---|
blockId | string | null | yes | |
body | string | yes | |
createdAt | number | yes | |
executionId | string | null | yes | |
id | string | yes | |
payload | object | null | no | |
resolvedAt | number | null | yes | |
severity | "normal" | "urgent" | no | |
status | "open" | "acted" | "dismissed" | yes | |
title | string | yes | |
type | "merge_review" | "pipeline_complete" | "ci_failed" | "test_failed" | "requirement_review" | "clarity_review" | "release_regression" | "decision_required" | "human_test_ready" | "visual_confirmation_ready" | "human_review" | "followup_pending" | "fork_decision_pending" | "judge_review" | "pr_review_ready" | "initiative" | "platform_health" | "infra_unreachable" | "budget_paused" | "budget_threshold" | "key_drift" | "merge_tag_request" | yes |
NotificationWebhook
| Field | Type | Required | Notes |
|---|---|---|---|
alertEvents | array of "platform_health.firing" | "platform_health.resolved" | yes | |
enabled | boolean | yes | |
hasSecret | boolean | yes | |
id | string | yes | |
name | string | yes | |
runEvents | array of "run.started" | "run.completed" | "run.failed" | yes | |
types | array of "merge_review" | "pipeline_complete" | "ci_failed" | "test_failed" | "requirement_review" | "clarity_review" | "release_regression" | "decision_required" | "human_test_ready" | "visual_confirmation_ready" | "human_review" | "followup_pending" | "fork_decision_pending" | "judge_review" | "pr_review_ready" | "initiative" | "platform_health" | "infra_unreachable" | "budget_paused" | "budget_threshold" | "key_drift" | "merge_tag_request" | yes | |
updatedAt | number | yes | |
url | string | yes |
PrReportCheck
| Field | Type | Required | Notes |
|---|---|---|---|
conclusion | string | null | yes | |
name | string | yes | |
repo | string | null | no | |
url | string | null | no |
PrReportCi
| Field | Type | Required | Notes |
|---|---|---|---|
failingChecks | array of PrReportCheck | yes | |
fixerAttempts | number | yes | |
headSha | string | null | no | |
maxFixerAttempts | number | null | no | |
note | string | null | no | |
status | "reported" | "absent" | yes | |
verdict | "pass" | "pending" | "fail" | null | no |
PrReportContext
| Field | Type | Required | Notes |
|---|---|---|---|
documents | array of PrReportContextDocument | yes | |
note | string | null | no | |
status | "reported" | "absent" | yes |
PrReportContextDocument
| Field | Type | Required | Notes |
|---|---|---|---|
freshness | DocumentFreshness | no | |
movedDuringRun | boolean | yes | |
origin | "confluence" | "notion" | "github" | "figma" | "zeplin" | "linear" | "upload" | yes | |
title | string | yes | |
url | string | null | yes |
PrReportEnvironments
| Field | Type | Required | Notes |
|---|---|---|---|
entries | array of object | yes | |
evidence | object | yes | |
evidence.capturedAt | number | null | yes | |
evidence.note | string | null | no | |
evidence.outcomes | number | yes | |
evidence.ranAgainst | "local" | "ephemeral" | null | yes | |
evidence.requirementVerdicts | number | yes | |
evidence.screenshots | array of object | yes | |
evidence.status | "captured" | "local" | "undeclared" | "absent" | yes | |
evidence.url | string | null | yes | |
gaps | array of string | yes | |
note | string | null | no | |
proof | "complete" | "incomplete" | "not_applicable" | yes | |
status | "reported" | "absent" | yes | |
teardown | "confirmed" | "unconfirmed" | "pending" | "retained" | "failed" | "not_applicable" | yes | |
timeline | object | yes | |
timeline.gap | "unwired" | "unreadable" | "truncated" | "not_provisioned" | null | yes | |
timeline.note | string | null | no | |
timeline.provisionFailures | number | yes | |
timeline.provisionedAt | number | null | yes | |
timeline.teardownFailures | number | yes | |
timeline.teardownsUnconfirmed | number | yes | |
timeline.tornDownAt | number | null | yes |
PrReportIssue
| Field | Type | Required | Notes |
|---|---|---|---|
externalId | string | yes | |
source | string | yes | |
title | string | yes | |
url | string | yes |
PrReportJudge
| Field | Type | Required | Notes |
|---|---|---|---|
bounces | number | yes | |
disposition | "pass" | "park" | "bounce" | "fail" | null | yes | |
findings | array of object | yes | |
maxBounces | number | yes | |
model | string | null | yes | |
modelPin | object | null | no | |
rubricName | string | null | yes | |
rubricOverridden | boolean | yes | |
score | number | null | yes | |
stepKind | string | yes | |
summary | string | null | yes | |
threshold | number | null | yes |
PrReportJudges
| Field | Type | Required | Notes |
|---|---|---|---|
note | string | null | no | |
status | "reported" | "absent" | yes | |
verdicts | array of PrReportJudge | yes |
PrReportMerge
| Field | Type | Required | Notes |
|---|---|---|---|
assessment | object | null | no | |
note | string | null | no | |
outcome | string | null | no | |
presetName | string | null | no | |
reason | string | null | no | |
status | "reported" | "absent" | yes |
PrReportObservability
| Field | Type | Required | Notes |
|---|---|---|---|
reportUrl | string | null | yes | |
runUrl | string | null | yes | |
trajectoryUrl | string | null | yes |
PrReportReproduction
| Field | Type | Required | Notes |
|---|---|---|---|
alternativeVerification | string | null | no | |
at | number | null | no | |
attempts | number | yes | |
base | object | null | no | |
command | string | null | no | |
final | object | null | no | |
maxAttempts | number | null | no | |
note | string | null | no | |
observation | string | null | no | |
omittedTestPaths | number | null | no | |
reason | string | null | no | |
status | "reported" | "absent" | yes | |
testPaths | array of string | yes | |
verdict | "reproduced" | "inconclusive" | "declared_infeasible" | null | no |
PrReportRequirements
| Field | Type | Required | Notes |
|---|---|---|---|
entries | array of object | yes | |
met | number | yes | |
notCovered | number | yes | |
notMet | number | yes | |
note | string | null | no | |
regressions | number | yes | |
status | "reported" | "absent" | yes | |
total | number | yes | |
unmatchedVerdicts | number | no |
PrReportRun
| Field | Type | Required | Notes |
|---|---|---|---|
blockId | string | yes | |
blockTitle | string | yes | |
executionId | string | yes | |
issues | array of PrReportIssue | yes | |
pipelineId | string | yes | |
pipelineName | string | yes | |
provider | "github" | "gitlab" | null | no | |
repo | string | null | no | |
startedAt | number | null | no | |
steps | array of PrReportStep | yes |
PrReportStep
| Field | Type | Required | Notes |
|---|---|---|---|
agentKind | string | yes | |
index | number | yes | |
model | string | null | no | |
state | string | yes |
PrReportTestConcern
| Field | Type | Required | Notes |
|---|---|---|---|
severity | string | yes | |
title | string | yes |
PrReportTestOutcome
| Field | Type | Required | Notes |
|---|---|---|---|
detail | string | null | no | |
name | string | yes | |
status | string | yes |
PrReportTests
| Field | Type | Required | Notes |
|---|---|---|---|
concerns | array of PrReportTestConcern | yes | |
environment | string | null | no | |
fixerAttempts | number | yes | |
greenlight | boolean | null | no | |
maxFixerAttempts | number | null | no | |
note | string | null | no | |
outcomes | array of PrReportTestOutcome | yes | |
status | "reported" | "absent" | yes | |
summary | string | null | no | |
tested | array of string | yes |
PrReportValidation
| Field | Type | Required | Notes |
|---|---|---|---|
at | number | null | no | |
attempts | number | yes | |
commands | array of PrReportValidationCommand | yes | |
configUnreadable | boolean | null | no | |
maxAttempts | number | null | no | |
note | string | null | no | |
passed | boolean | null | no | |
status | "reported" | "absent" | yes | |
stepKind | string | null | no |
PrReportValidationCommand
| Field | Type | Required | Notes |
|---|---|---|---|
command | string | yes | |
durationMs | number | null | no | |
exitCode | number | yes | |
label | string | yes | |
outputTail | string | null | no | |
passed | boolean | yes | |
timedOut | boolean | null | no |
PrVerificationReport
| Field | Type | Required | Notes |
|---|---|---|---|
ci | PrReportCi | yes | |
context | PrReportContext | yes | |
environments | PrReportEnvironments | yes | |
generatedAt | number | yes | |
judges | PrReportJudges | yes | |
merge | PrReportMerge | yes | |
observability | PrReportObservability | yes | |
reproduction | PrReportReproduction | yes | |
requirements | PrReportRequirements | yes | |
run | PrReportRun | yes | |
scope | object | no | |
scope.frameId | string | null | no | |
scope.frameIds | array of string | no | |
scope.ownPullRequest | object | null | no | |
scope.role | "own" | "peer" | yes | |
tests | PrReportTests | yes | |
truncations | array of string | yes | |
validation | PrReportValidation | yes | |
version | number | yes |
PublicAgentDecision
| Field | Type | Required | Notes |
|---|---|---|---|
decisionId | string | yes | |
kind | "agent-decision" | yes | |
options | array of string | yes | |
question | string | yes | |
stepKind | string | yes |
PublicAnswerFollowUp
| Field | Type | Required | Notes |
|---|---|---|---|
answer | string | yes | 1 to 4000 characters |
PublicAnswerInterview
| Field | Type | Required | Notes |
|---|---|---|---|
answer | string | yes | max 2000 characters |
questionId | string | yes | 1 to 80 characters |
PublicApiKey
| Field | Type | Required | Notes |
|---|---|---|---|
accountId | string | yes | |
actsAsUserId | string | null | yes | |
createdAt | number | yes | |
createdByKeyId | string | null | yes | |
createdByUserId | string | null | yes | |
externalIdentity | string | null | yes | |
id | string | yes | |
label | string | yes | |
lastUsedAt | number | null | yes | |
revokedAt | number | null | yes | |
scope | "read" | "write" | "decide" | "admin" | yes | |
workspaceId | string | yes |
PublicApiKeyList
| Field | Type | Required | Notes |
|---|---|---|---|
keys | array of PublicApiKey | yes |
PublicApprovalGateDecision
| Field | Type | Required | Notes |
|---|---|---|---|
approvalId | string | yes | |
exceeded | boolean | yes | |
feedback | string | null | yes | |
kind | "approval-gate" | yes | |
proposal | string | yes | |
recordedApprovals | number | yes | |
requiredApprovals | number | yes | |
status | "pending" | "approved" | "changes_requested" | "rejected" | yes | |
stepIndex | number | yes | |
stepKind | string | yes |
PublicApproveStep
| Field | Type | Required | Notes |
|---|---|---|---|
proposal | string | no | max 50000 characters |
PublicBrainstormDecision
| Field | Type | Required | Notes |
|---|---|---|---|
convergedDirection | string | null | yes | |
iteration | number | yes | |
kind | "brainstorm" | yes | |
maxIterations | number | yes | |
options | array of PublicReviewFinding | yes | |
sessionId | string | yes | |
stage | "requirements" | "architecture" | yes | |
status | "ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated" | yes | |
taskId | string | yes |
PublicChallengePrReviewFinding
| Field | Type | Required | Notes |
|---|---|---|---|
question | string | no | max 4000 characters |
PublicChooseFork
| Field | Type | Required | Notes |
|---|---|---|---|
custom | string | null | no | |
forkId | string | null | no | |
note | string | null | no |
PublicClarityDecision
| Field | Type | Required | Notes |
|---|---|---|---|
clarifiedReport | string | null | yes | |
findings | array of PublicReviewFinding | yes | |
iteration | number | yes | |
kind | "clarity-review" | yes | |
maxIterations | number | yes | |
reviewId | string | yes | |
status | "ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated" | yes | |
taskId | string | yes |
PublicDecision
One of 13 shapes.
Shape 1
Shape 2
kind: "judge"
| Field | Type | Required | Notes |
|---|---|---|---|
bounces | number | yes | |
kind | "judge" | yes | |
maxBounces | number | yes | |
rubricId | string | null | yes | |
rubricName | string | null | yes | |
status | "evaluating" | "awaiting_decision" | "bouncing" | "passed" | "failed" | "skipped" | yes | |
stepKind | string | yes | |
threshold | number | null | yes | |
verdict | object | null | yes |
Shape 4
Shape 5
Shape 6
Shape 7
Shape 8
Shape 9
Shape 10
Shape 11
Shape 12
Shape 13
PublicDecisionList
| Field | Type | Required | Notes |
|---|---|---|---|
decisions | array of PublicDecision | yes | |
parked | boolean | yes | |
runId | string | yes | |
status | "running" | "blocked" | "paused" | "done" | "failed" | yes | |
taskId | string | yes | |
unanswerable | array of PublicUnanswerableWait | yes |
PublicFollowUpItem
| Field | Type | Required | Notes |
|---|---|---|---|
answer | string | null | yes | |
detail | string | yes | |
itemId | string | yes | |
kind | "follow_up" | "question" | yes | |
status | "pending" | "filed" | "queued" | "answered" | "dismissed" | yes | |
suggestedAction | string | null | yes | |
ticketExternalId | string | null | yes | |
ticketUrl | string | null | yes | |
title | string | yes |
PublicFollowUpsDecision
| Field | Type | Required | Notes |
|---|---|---|---|
items | array of PublicFollowUpItem | yes | |
kind | "follow-ups" | yes | |
loops | number | yes | |
maxLoops | number | yes | |
stepIndex | number | yes | |
stepKind | string | yes |
PublicForkDecision
| Field | Type | Required | Notes |
|---|---|---|---|
forks | array of object | yes | |
kind | "fork" | yes | |
seamSummary | string | null | yes | |
status | "proposing" | "awaiting_choice" | "answering" | "chosen" | "single_path" | "skipped" | yes |
PublicHumanTestDecision
| Field | Type | Required | Notes |
|---|---|---|---|
attempts | number | yes | |
degradedReason | string | null | yes | |
environment | PublicHumanTestEnvironment | null | yes | |
kind | "human-test" | yes | |
maxAttempts | number | yes | |
phase | "provisioning" | "awaiting_human" | "fixing" | "resolving_conflicts" | "passed" | yes |
PublicHumanTestEnvironment
| Field | Type | Required | Notes |
|---|---|---|---|
expiresAt | number | null | yes | |
status | "provisioning" | "ready" | "failed" | "expired" | "tearing_down" | "torn_down" | yes | |
url | string | null | yes |
PublicIdentity
| Field | Type | Required | Notes |
|---|---|---|---|
accountId | string | yes | |
createdAt | number | yes | |
externalIdentity | string | null | yes | |
keyId | string | yes | |
label | string | yes | |
scope | "read" | "write" | "decide" | "admin" | yes | |
workspaceId | string | yes |
PublicIncorporate
| Field | Type | Required | Notes |
|---|---|---|---|
feedback | string | no | max 4000 characters |
PublicInputGateDecision
| Field | Type | Required | Notes |
|---|---|---|---|
checkedAt | number | yes | |
issues | array of object | yes | |
kind | "input-gate" | yes | |
mode | "standard" | "advisory" | "off" | yes | |
status | "off" | "not_applicable" | "passed" | "blocked" | "overridden" | yes |
PublicInterviewDecision
| Field | Type | Required | Notes |
|---|---|---|---|
kind | "interview" | yes | |
maxRounds | number | yes | |
questions | array of PublicInterviewQuestion | yes | |
round | number | yes | |
stepKind | string | yes | |
taskId | string | yes |
PublicInterviewQuestion
| Field | Type | Required | Notes |
|---|---|---|---|
answer | string | yes | |
question | string | yes | |
questionId | string | null | yes | |
status | "open" | "answered" | "dismissed" | yes |
PublicJob
| Field | Type | Required | Notes |
|---|---|---|---|
createdAt | number | yes | |
error | object | null | yes | |
externalIdentity | string | null | yes | |
externalIdentityWithheld | boolean | yes | |
jobId | string | yes | |
pipelineId | string | yes | |
result | object | null | yes | |
status | "running" | "succeeded" | "failed" | yes |
PublicJobAccepted
| Field | Type | Required | Notes |
|---|---|---|---|
jobId | string | yes | |
links | object | yes | |
links.events | string | yes | |
links.self | string | yes | |
status | "running" | "succeeded" | "failed" | yes |
PublicNotificationList
| Field | Type | Required | Notes |
|---|---|---|---|
notifications | array of Notification | yes |
PublicNotificationWebhook
| Field | Type | Required | Notes |
|---|---|---|---|
webhook | NotificationWebhook | null | yes |
PublicNotificationWebhookList
| Field | Type | Required | Notes |
|---|---|---|---|
webhooks | array of NotificationWebhook | yes |
PublicPipeline
| Field | Type | Required | Notes |
|---|---|---|---|
headlessStartable | boolean | yes | |
name | string | yes | |
pipelineId | string | yes | |
public | boolean | yes | |
steps | array of string | yes |
PublicPipelineList
| Field | Type | Required | Notes |
|---|---|---|---|
pipelines | array of PublicPipeline | yes |
PublicPrReviewDecision
| Field | Type | Required | Notes |
|---|---|---|---|
findings | array of object | yes | |
kind | "pr-review" | yes | |
prUrl | string | null | yes | |
selectedFindingIds | array of string | yes | |
slices | array of object | yes | |
status | "reviewing" | "awaiting_selection" | "challenging" | "fixing" | "posting" | "done" | "skipped" | yes | |
summary | string | null | yes |
PublicRejectStep
| Field | Type | Required | Notes |
|---|---|---|---|
reason | string | no | max 2000 characters |
PublicReplyFinding
| Field | Type | Required | Notes |
|---|---|---|---|
reply | string | yes | 1 to 4000 characters |
PublicRequestGateFix
| Field | Type | Required | Notes |
|---|---|---|---|
findings | string | yes | 1 to 10000 characters |
PublicRequestStepChanges
| Field | Type | Required | Notes |
|---|---|---|---|
feedback | string | yes | 1 to 10000 characters |
PublicRequirementsDecision
| Field | Type | Required | Notes |
|---|---|---|---|
findings | array of PublicReviewFinding | yes | |
incorporatedRequirements | string | null | yes | |
iteration | number | yes | |
kind | "requirements-review" | yes | |
maxIterations | number | yes | |
reviewId | string | yes | |
status | "ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated" | yes | |
taskId | string | yes |
PublicResolveAgentDecision
| Field | Type | Required | Notes |
|---|---|---|---|
choice | string | yes | 1 to 4000 characters |
PublicResolveExceeded
| Field | Type | Required | Notes |
|---|---|---|---|
choice | "extra-round" | "proceed" | "stop-reset" | yes |
PublicResolveInputGate
| Field | Type | Required | Notes |
|---|---|---|---|
choice | "recheck" | "proceed" | yes |
PublicResolvePrReview
| Field | Type | Required | Notes |
|---|---|---|---|
action | "finish" | "fix" | "post" | no | |
findingIds | array of string | no |
PublicReviewFinding
| Field | Type | Required | Notes |
|---|---|---|---|
category | "gap" | "clarification" | "assumption" | "risk" | "question" | yes | |
detail | string | yes | |
itemId | string | yes | |
reply | string | null | yes | |
severity | "low" | "medium" | "high" | yes | |
status | "open" | "answered" | "resolved" | "dismissed" | "recommend_requested" | yes | |
title | string | yes |
PublicRun
| Field | Type | Required | Notes |
|---|---|---|---|
createdAt | number | yes | |
currentStep | number | yes | |
error | object | null | yes | |
externalIdentity | string | null | yes | |
externalIdentityWithheld | boolean | yes | |
pullRequest | object | null | yes | |
runId | string | yes | |
status | "running" | "blocked" | "paused" | "done" | "failed" | yes | |
steps | array of object | yes | |
taskId | string | yes |
PublicRunArtifact
| Field | Type | Required | Notes |
|---|---|---|---|
artifactId | string | yes | |
byteSize | number | yes | |
contentType | string | yes | |
createdAt | number | yes | |
hash | string | yes | |
kind | "screenshot" | "reference" | yes | |
scope | "run" | "task" | yes | |
view | string | null | yes |
PublicRunArtifactList
| Field | Type | Required | Notes |
|---|---|---|---|
artifacts | array of PublicRunArtifact | yes |
PublicRunSpec
| Field | Type | Required | Notes |
|---|---|---|---|
anchor | "present" | "absent" | "unparsed" | "not_read" | yes | |
features | array of PublicSpecFeatureFile | yes | |
issues | array of SpecReadIssue | yes | |
provenance | PublicSpecProvenance | null | yes | |
runId | string | yes | |
spec | SpecDoc | null | yes | |
truncations | array of PublicSpecTruncation | yes |
PublicService
| Field | Type | Required | Notes |
|---|---|---|---|
description | string | yes | |
provisioning | object | no | |
serviceId | string | yes | |
status | "planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done" | yes | |
title | string | yes | |
type | "frontend" | "service" | "library" | "document" | "api" | "database" | "queue" | "integration" | "external" | "environment" | yes |
PublicServiceList
| Field | Type | Required | Notes |
|---|---|---|---|
services | array of PublicService | yes |
PublicServiceSpec
| Field | Type | Required | Notes |
|---|---|---|---|
anchor | "present" | "absent" | "unparsed" | yes | |
features | array of PublicSpecFeatureFile | yes | |
issues | array of SpecReadIssue | yes | |
provenance | PublicSpecProvenance | yes | |
serviceId | string | yes | |
spec | SpecDoc | null | yes | |
truncations | array of PublicSpecTruncation | yes |
PublicSetFindingStatus
| Field | Type | Required | Notes |
|---|---|---|---|
status | "dismissed" | "open" | yes |
PublicSpecFeatureFile
| Field | Type | Required | Notes |
|---|---|---|---|
chars | number | yes | |
content | string | yes | |
group | string | yes | |
module | string | yes | |
path | string | yes | |
totalChars | number | yes | |
truncated | boolean | yes |
PublicSpecProvenance
| Field | Type | Required | Notes |
|---|---|---|---|
commit | string | null | yes | |
owner | string | yes | |
provider | "github" | "gitlab" | yes | |
ref | string | yes | |
repo | string | yes |
PublicSpecTruncation
| Field | Type | Required | Notes |
|---|---|---|---|
section | "requirements" | "rules" | "acceptance" | "features" | "issues" | yes | |
shown | number | yes | |
total | number | yes |
PublicSpend
| Field | Type | Required | Notes |
|---|---|---|---|
currency | string | yes | |
dimension | "model" | "agentKind" | "service" | "repo" | "taskType" | "ticket" | "run" | yes | |
generatedAt | number | yes | |
rolledUpThrough | number | null | yes | |
rows | array of PublicSpendRow | yes | |
since | number | yes | |
source | "ledger" | "daily-rollup" | yes | |
totals | PublicSpendTotals | yes | |
truncated | boolean | yes | |
window | "24h" | "7d" | "30d" | "90d" | yes |
PublicSpendRow
| Field | Type | Required | Notes |
|---|---|---|---|
calls | number | yes | |
inputTokens | number | yes | |
key | string | yes | |
label | string | null | yes | |
meteredCost | number | yes | |
outputTokens | number | yes | |
subscriptionCost | number | yes |
PublicSpendTotals
| Field | Type | Required | Notes |
|---|---|---|---|
calls | number | yes | |
inputTokens | number | yes | |
meteredCost | number | yes | |
outputTokens | number | yes | |
subscriptionCost | number | yes |
PublicTask
| Field | Type | Required | Notes |
|---|---|---|---|
autoStartDependents | boolean | yes | |
dependsOn | array of string | yes | |
description | string | yes | |
modelPresetId | string | null | yes | |
progress | number | yes | |
pullRequestUrl | string | null | yes | |
riskPolicyId | string | null | yes | |
runId | string | null | yes | |
serviceId | string | yes | |
status | "planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done" | yes | |
taskId | string | yes | |
taskType | "feature" | "bug" | "document" | "spike" | "review" | "ralph" | "recurring" | string | yes | |
title | string | yes |
PublicTaskDocument
One of 2 shapes.
Shape 1
Shape 2
PublicTaskList
| Field | Type | Required | Notes |
|---|---|---|---|
nextCursor | string | null | yes | |
tasks | array of PublicTask | yes |
PublicTaskSourceDocument
| Field | Type | Required | Notes |
|---|---|---|---|
kind | "source" | yes | |
ref | string | yes | 1 to 500 characters |
source | "confluence" | "notion" | "github" | "figma" | "zeplin" | "linear" | yes |
PublicTaskTicket
| Field | Type | Required | Notes |
|---|---|---|---|
ref | string | yes | 1 to 500 characters |
source | "jira" | "github" | "linear" | "gitlab" | string | yes |
PublicTaskUploadedDocument
| Field | Type | Required | Notes |
|---|---|---|---|
content | string | yes | 1 to 100000 characters |
kind | "upload" | yes | |
title | string | yes | 1 to 200 characters |
PublicUnanswerableWait
| Field | Type | Required | Notes |
|---|---|---|---|
detail | string | yes | |
reason | "human_wait_gate" | "unclassified_gate" | "unwired_interview_gate" | yes | |
stepIndex | number | yes | |
stepKind | string | yes |
PublicUsage
| Field | Type | Required | Notes |
|---|---|---|---|
budget | PublicUsageBudget | yes | |
currency | string | yes | |
periodStart | number | yes | |
rows | array of PublicUsageRow | yes |
PublicUsageBudget
| Field | Type | Required | Notes |
|---|---|---|---|
costLimit | number | yes | |
costSpent | number | yes | |
exceeded | boolean | yes | |
inputTokens | number | yes | |
outputTokens | number | yes |
PublicUsageRow
| Field | Type | Required | Notes |
|---|---|---|---|
billing | "metered" | "subscription" | yes | |
calls | number | yes | |
costEstimate | number | yes | |
inputTokens | number | yes | |
model | string | yes | |
outputTokens | number | yes | |
provider | string | yes | |
vendor | string | null | yes |
PublicVisualConfirmDecision
| Field | Type | Required | Notes |
|---|---|---|---|
attempts | number | yes | |
degradedReason | string | null | yes | |
kind | "visual-confirmation" | yes | |
maxAttempts | number | yes | |
pairs | array of object | yes | |
phase | "awaiting_human" | "fixing" | "approved" | yes |
PutNotificationWebhook
| Field | Type | Required | Notes |
|---|---|---|---|
alertEvents | array of "platform_health.firing" | "platform_health.resolved" | no | |
enabled | boolean | no | |
name | string | no | 1 to 100 characters |
runEvents | array of "run.started" | "run.completed" | "run.failed" | no | |
secret | string | no | 16 to 200 characters |
types | array of "merge_review" | "pipeline_complete" | "ci_failed" | "test_failed" | "requirement_review" | "clarity_review" | "release_regression" | "decision_required" | "human_test_ready" | "visual_confirmation_ready" | "human_review" | "followup_pending" | "fork_decision_pending" | "judge_review" | "pr_review_ready" | "initiative" | "platform_health" | "infra_unreachable" | "budget_paused" | "budget_threshold" | "key_drift" | "merge_tag_request" | no | |
url | string (uri) | no | max 2000 characters, pattern ^https:// |
RequirementGroup
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | 1 to 120 characters |
requirements | array of RequirementItem | no | |
rules | array of DomainRule | no | |
summary | string | no | max 2000 characters |
RequirementItem
| Field | Type | Required | Notes |
|---|---|---|---|
acceptance | array of AcceptanceCriterion | no | |
id | string | yes | 1 to 200 characters |
kind | "functional" | "nonfunctional" | "constraint" | yes | |
priority | "must" | "should" | "could" | yes | |
sourceBlockIds | array of string | no | |
state | "aspirational" | "established" | no | |
statement | string | yes | 1 to 4000 characters |
title | string | yes | 1 to 120 characters |
SpecDoc
| Field | Type | Required | Notes |
|---|---|---|---|
modules | array of SpecModule | no | |
service | string | no | max 120 characters |
summary | string | no | max 2000 characters |
SpecModule
| Field | Type | Required | Notes |
|---|---|---|---|
groups | array of RequirementGroup | no | |
name | string | yes | 1 to 120 characters |
summary | string | no | max 2000 characters |
SpecReadIssue
| Field | Type | Required | Notes |
|---|---|---|---|
dropped | number | null | no | |
kind | "read_failed" | "unparsed" | "partial" | "unread" | yes | |
path | string | yes |
StartPublicTask
| Field | Type | Required | Notes |
|---|---|---|---|
pipelineId | string | no | 1 to 120 characters |
UpdatePublicTask
| Field | Type | Required | Notes |
|---|---|---|---|
autoStartDependents | boolean | no | |
description | string | no | max 2000 characters |
fields | map of string | array of string | boolean | number | no | |
modelPresetId | string | no | 1 to 120 characters |
riskPolicyId | string | no | 1 to 120 characters |
title | string | no | 1 to 200 characters |
Next: Public API for the narrative and the worked examples, or SDKs for a generated client that already speaks all of this.