Cat Factory
Home
Get Started
GitHub
Home
Get Started
GitHub
  • Start

    • Introduction
    • Core Concepts
    • Quick Start
    • Tutorial: Your First Task to a Merged Pull Request
  • Guides

    • Recipes

      • Cookbook
    • Plan the work

      • Design Your Board
      • Clarify Requirements
      • Author a Document
      • Plan an Initiative
    • Run pipelines

      • Choose and Edit a Pipeline
      • Run a Pipeline
      • Schedule Recurring Work
      • Review and Merge Pull Requests
      • Control Spend with Budgets
    • Connect

      • Connect a Repository
      • Connect Issue & Document Sources
      • Feed Design Context to Agents
      • Preview and Test a Frontend
    • Models & prompts

      • Connect a Model Provider
      • Apply Standards with Prompt Fragments
      • Run a Claude Skill as a Step
      • Compare Prompts and Models in the Sandbox
    • Collaborate

      • Invite and Manage Your Team
      • Share Services Across Workspaces
      • Register Foundational Services
  • Deploy

    • Run Locally
    • Deploy to Node.js
    • Deploy to Cloudflare
    • Deploy on Kubernetes
    • Lay Out a Kubernetes Cluster
    • Set Up a Local Kubernetes Cluster on Windows
    • Register the GitHub App
    • Set Up Enterprise SSO
    • Set Up Your Deployment Repository
    • Configuration
  • Operate

    • Observability
    • Set Up Notifications
    • Run Jobs on Your Own Runners
    • Provision Ephemeral Environments
    • Debug a Run from Outside the Browser
    • Troubleshooting
    • Upgrades & Data Retention
  • Extend

    • Add a Custom Agent Kind
    • Add a Custom Gate or Judge
    • Add a Custom Provider
    • Extend the App with Frontend Modules
    • Integration Manifests
    • Give Agents External Tools (MCP)
    • Package a Reusable Operation
    • Register an Initiative Preset
    • Public API
    • Official SDKs
    • MCP Server
    • Cloudflare OS Gatekeeper
  • Reference

    • Architecture
    • Agent Isolation Model
    • Security Model & Hardening
    • Packages & Repository Layout
    • GitHub and GitLab Support Matrix
    • Environment Variables
    • API Endpoint Reference
    • Glossary

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

NameTypeRequiredNotes
snapshotIdstringyes

Query parameters

NameTypeRequiredNotes
bodyCharsintegerno0 to 200000, pattern ^\d+$
bodyOffsetintegerno0 to 2000000, pattern ^\d+$

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
callIdstringyes

Query parameters

NameTypeRequiredNotes
bodyCharsintegerno0 to 200000, pattern ^\d+$
bodyOffsetintegerno0 to 2000000, pattern ^\d+$
view"raw" | "messages"no

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
status"running" | "blocked" | "done" | "paused" | "failed"no
sinceintegernomin 0, pattern ^\d+$
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
stepIndexintegernomin 0, pattern ^\d+$
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
agentKindstringno1 to 120 characters
phasestringnomax 120 characters
outcome"ok" | "warning" | "error"no
containsstringno1 to 256 characters
order"newest" | "oldest"no
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters
bodyCharsintegerno0 to 4000, pattern ^\d+$

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
order"oldest" | "newest"no
bodyCharsintegerno0 to 4000, pattern ^\d+$

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Query parameters

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters
jobIdstringno
order"recent" | "trajectory"no
outcome"ok" | "error"no

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
approvalIdstringyes

Request body (required): PublicApproveStep (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
approvalIdstringyes

Request body (required): PublicRejectStep (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
approvalIdstringyes

Request body (required): PublicRequestStepChanges (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
approvalIdstringyes

Request body (required): PublicResolveExceeded (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes

Request body (required): PublicIncorporate (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes
itemIdstringyes

Request body (required): PublicSetFindingStatus (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes
itemIdstringyes

Request body (required): PublicReplyFinding (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
stagestringyes

Request body (required): PublicResolveExceeded (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Request body (required): PublicSetFindingStatus (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Request body (required): PublicReplyFinding (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicIncorporate (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicResolveExceeded (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Request body (required): PublicAnswerFollowUp (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicChooseFork (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicRequestGateFix (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicResolveInputGate (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicAnswerInterview (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
findingIdstringyes

Request body (required): PublicChallengePrReviewFinding (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
findingIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicResolvePrReview (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
decisionIdstringyes

Request body (required): PublicResolveAgentDecision (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Request body (required): PublicSetFindingStatus (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes
itemIdstringyes

Request body (required): PublicReplyFinding (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicIncorporate (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicResolveExceeded (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Request body (required): PublicRequestGateFix (application/json)

Responses

StatusBodyMeaning
200PublicDecisionList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
201object (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
artifactIdstringyes

Responses

StatusBodyMeaning
200binary (application/octet-stream), binary (image/gif), binary (image/jpeg), binary (image/png), binary (image/webp)The artifact bytes
4XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicRunArtifactList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PrVerificationReport (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicIdentity (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters
status"running" | "succeeded" | "failed"no
sinceintegernomin 0, pattern ^\d+$

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
202PublicJobAccepted (application/json)Accepted — the run has started
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
idstringyes

Responses

StatusBodyMeaning
200PublicJob (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
idstringyes

Responses

StatusBodyMeaning
200PublicJob (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
idstringyes

Responses

StatusBodyMeaning
200string (text/event-stream)An event stream of job updates
4XXErrorResponse (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

StatusBodyMeaning
200PublicApiKeyList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
201CreatedPublicApiKey (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
keyIdstringyes

Responses

StatusBodyMeaning
204emptyNo content
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
recordIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
recordIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicNotificationList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
idstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200Notification (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
idstringyes

Responses

StatusBodyMeaning
200Notification (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicPipelineList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
qstringno

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
201object (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
jobIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicServiceList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
201PublicService (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
serviceIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200PublicService (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
runIdstringyes

Responses

StatusBodyMeaning
200PublicRunSpec (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
serviceIdstringyes

Responses

StatusBodyMeaning
200PublicServiceSpec (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
serviceIdstringyes

Query parameters

NameTypeRequiredNotes
limitintegerno1 to 100, pattern ^\d+$
cursorstringno1 to 200 characters
status"planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done"no

Responses

StatusBodyMeaning
200PublicTaskList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
serviceIdstringyes

Request body (required): CreatePublicTask (application/json)

Responses

StatusBodyMeaning
201PublicTask (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
200PublicTask (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): UpdatePublicTask (application/json)

Responses

StatusBodyMeaning
200PublicTask (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
204emptyNo content
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200PublicTask (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
200PublicTask (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
201object (application/json)Created
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): object (application/json)

Responses

StatusBodyMeaning
204emptyNo content
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
200string (text/event-stream)An event stream of run updates
4XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
202PublicTask (application/json)Accepted — the run has started
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
200PublicRun (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Request body (required): StartPublicTask (application/json)

Responses

StatusBodyMeaning
202PublicTask (application/json)Accepted — the run has started
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
taskIdstringyes

Responses

StatusBodyMeaning
200PublicTask (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicUsage (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
dimension"model" | "agentKind" | "service" | "repo" | "taskType" | "ticket" | "run"yes
window"24h" | "7d" | "30d" | "90d"no
limitintegerno1 to 500, pattern ^\d+$

Responses

StatusBodyMeaning
200PublicSpend (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200object (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicNotificationWebhook (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200NotificationWebhook (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (application/json)Server error

Remove the outbound webhook

DELETE /api/v1/notification-webhook

Minimum scope: admin.

Deregister the endpoint; deliveries stop. Idempotent.

Responses

StatusBodyMeaning
204emptyNo content
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

StatusBodyMeaning
200PublicNotificationWebhookList (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
webhookIdstringyes

Responses

StatusBodyMeaning
200PublicNotificationWebhook (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
webhookIdstringyes

Request body (required): PutNotificationWebhook (application/json)

Responses

StatusBodyMeaning
200NotificationWebhook (application/json)Success
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

NameTypeRequiredNotes
webhookIdstringyes

Responses

StatusBodyMeaning
204emptyNo content
4XXErrorResponse (application/json)Client error (validation, unauthorized, not found, conflict, rate limit)
5XXErrorResponse (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

FieldTypeRequiredNotes
givenstringyesmax 2000 characters
idstringyes1 to 200 characters
outcomestringyesmax 2000 characters
whenstringyesmax 2000 characters

CreateHeadlessPublicApiKey

FieldTypeRequiredNotes
externalIdentitystringno1 to 200 characters, pattern ^[^\x00-\x1f\x7f\x80-\x9f]+$
labelstringyes1 to 120 characters
scope"read" | "write" | "decide"no

CreatePublicJob

FieldTypeRequiredNotes
inputstringyes1 to 50000 characters
pipelineIdstringyesmin 1 character
titlestringnomax 200 characters

CreatePublicTask

FieldTypeRequiredNotes
descriptionstringnomax 2000 characters
documentsarray of PublicTaskDocumentno
fieldsmap of string | array of string | boolean | numberno
modelPresetIdstringno1 to 120 characters
riskPolicyIdstringno1 to 120 characters
taskType"feature" | "bug" | "document" | "spike" | "review" | "ralph" | stringno
ticketPublicTaskTicketno
titlestringyes1 to 200 characters

CreatedPublicApiKey

FieldTypeRequiredNotes
keyPublicApiKeyyes
secretstringyes

DocumentFreshness

One of 3 shapes.

status: "confirmed"

FieldTypeRequiredNotes
change"unchanged" | "reimported" | "revision_only"yes
status"confirmed"yes
versionstringyes

status: "not-applicable"

FieldTypeRequiredNotes
status"not-applicable"yes

status: "unconfirmed"

FieldTypeRequiredNotes
reason"not_connected" | "credentials_unreadable" | "unversioned" | "source_unreachable"yes
status"unconfirmed"yes

DomainRule

FieldTypeRequiredNotes
idstringyes1 to 200 characters
rationalestringnomax 2000 characters
rulestringyes1 to 4000 characters
sourceBlockIdsarray of stringno

ErrorResponse

FieldTypeRequiredNotes
errorobjectyes
error.codestringyes
error.details?no
error.issuesarray of objectno
error.messagestringyes

Notification

FieldTypeRequiredNotes
blockIdstring | nullyes
bodystringyes
createdAtnumberyes
executionIdstring | nullyes
idstringyes
payloadobject | nullno
resolvedAtnumber | nullyes
severity"normal" | "urgent"no
status"open" | "acted" | "dismissed"yes
titlestringyes
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

FieldTypeRequiredNotes
alertEventsarray of "platform_health.firing" | "platform_health.resolved"yes
enabledbooleanyes
hasSecretbooleanyes
idstringyes
namestringyes
runEventsarray of "run.started" | "run.completed" | "run.failed"yes
typesarray 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
updatedAtnumberyes
urlstringyes

PrReportCheck

FieldTypeRequiredNotes
conclusionstring | nullyes
namestringyes
repostring | nullno
urlstring | nullno

PrReportCi

FieldTypeRequiredNotes
failingChecksarray of PrReportCheckyes
fixerAttemptsnumberyes
headShastring | nullno
maxFixerAttemptsnumber | nullno
notestring | nullno
status"reported" | "absent"yes
verdict"pass" | "pending" | "fail" | nullno

PrReportContext

FieldTypeRequiredNotes
documentsarray of PrReportContextDocumentyes
notestring | nullno
status"reported" | "absent"yes

PrReportContextDocument

FieldTypeRequiredNotes
freshnessDocumentFreshnessno
movedDuringRunbooleanyes
origin"confluence" | "notion" | "github" | "figma" | "zeplin" | "linear" | "upload"yes
titlestringyes
urlstring | nullyes

PrReportEnvironments

FieldTypeRequiredNotes
entriesarray of objectyes
evidenceobjectyes
evidence.capturedAtnumber | nullyes
evidence.notestring | nullno
evidence.outcomesnumberyes
evidence.ranAgainst"local" | "ephemeral" | nullyes
evidence.requirementVerdictsnumberyes
evidence.screenshotsarray of objectyes
evidence.status"captured" | "local" | "undeclared" | "absent"yes
evidence.urlstring | nullyes
gapsarray of stringyes
notestring | nullno
proof"complete" | "incomplete" | "not_applicable"yes
status"reported" | "absent"yes
teardown"confirmed" | "unconfirmed" | "pending" | "retained" | "failed" | "not_applicable"yes
timelineobjectyes
timeline.gap"unwired" | "unreadable" | "truncated" | "not_provisioned" | nullyes
timeline.notestring | nullno
timeline.provisionFailuresnumberyes
timeline.provisionedAtnumber | nullyes
timeline.teardownFailuresnumberyes
timeline.teardownsUnconfirmednumberyes
timeline.tornDownAtnumber | nullyes

PrReportIssue

FieldTypeRequiredNotes
externalIdstringyes
sourcestringyes
titlestringyes
urlstringyes

PrReportJudge

FieldTypeRequiredNotes
bouncesnumberyes
disposition"pass" | "park" | "bounce" | "fail" | nullyes
findingsarray of objectyes
maxBouncesnumberyes
modelstring | nullyes
modelPinobject | nullno
rubricNamestring | nullyes
rubricOverriddenbooleanyes
scorenumber | nullyes
stepKindstringyes
summarystring | nullyes
thresholdnumber | nullyes

PrReportJudges

FieldTypeRequiredNotes
notestring | nullno
status"reported" | "absent"yes
verdictsarray of PrReportJudgeyes

PrReportMerge

FieldTypeRequiredNotes
assessmentobject | nullno
notestring | nullno
outcomestring | nullno
presetNamestring | nullno
reasonstring | nullno
status"reported" | "absent"yes

PrReportObservability

FieldTypeRequiredNotes
reportUrlstring | nullyes
runUrlstring | nullyes
trajectoryUrlstring | nullyes

PrReportReproduction

FieldTypeRequiredNotes
alternativeVerificationstring | nullno
atnumber | nullno
attemptsnumberyes
baseobject | nullno
commandstring | nullno
finalobject | nullno
maxAttemptsnumber | nullno
notestring | nullno
observationstring | nullno
omittedTestPathsnumber | nullno
reasonstring | nullno
status"reported" | "absent"yes
testPathsarray of stringyes
verdict"reproduced" | "inconclusive" | "declared_infeasible" | nullno

PrReportRequirements

FieldTypeRequiredNotes
entriesarray of objectyes
metnumberyes
notCoverednumberyes
notMetnumberyes
notestring | nullno
regressionsnumberyes
status"reported" | "absent"yes
totalnumberyes
unmatchedVerdictsnumberno

PrReportRun

FieldTypeRequiredNotes
blockIdstringyes
blockTitlestringyes
executionIdstringyes
issuesarray of PrReportIssueyes
pipelineIdstringyes
pipelineNamestringyes
provider"github" | "gitlab" | nullno
repostring | nullno
startedAtnumber | nullno
stepsarray of PrReportStepyes

PrReportStep

FieldTypeRequiredNotes
agentKindstringyes
indexnumberyes
modelstring | nullno
statestringyes

PrReportTestConcern

FieldTypeRequiredNotes
severitystringyes
titlestringyes

PrReportTestOutcome

FieldTypeRequiredNotes
detailstring | nullno
namestringyes
statusstringyes

PrReportTests

FieldTypeRequiredNotes
concernsarray of PrReportTestConcernyes
environmentstring | nullno
fixerAttemptsnumberyes
greenlightboolean | nullno
maxFixerAttemptsnumber | nullno
notestring | nullno
outcomesarray of PrReportTestOutcomeyes
status"reported" | "absent"yes
summarystring | nullno
testedarray of stringyes

PrReportValidation

FieldTypeRequiredNotes
atnumber | nullno
attemptsnumberyes
commandsarray of PrReportValidationCommandyes
configUnreadableboolean | nullno
maxAttemptsnumber | nullno
notestring | nullno
passedboolean | nullno
status"reported" | "absent"yes
stepKindstring | nullno

PrReportValidationCommand

FieldTypeRequiredNotes
commandstringyes
durationMsnumber | nullno
exitCodenumberyes
labelstringyes
outputTailstring | nullno
passedbooleanyes
timedOutboolean | nullno

PrVerificationReport

FieldTypeRequiredNotes
ciPrReportCiyes
contextPrReportContextyes
environmentsPrReportEnvironmentsyes
generatedAtnumberyes
judgesPrReportJudgesyes
mergePrReportMergeyes
observabilityPrReportObservabilityyes
reproductionPrReportReproductionyes
requirementsPrReportRequirementsyes
runPrReportRunyes
scopeobjectno
scope.frameIdstring | nullno
scope.frameIdsarray of stringno
scope.ownPullRequestobject | nullno
scope.role"own" | "peer"yes
testsPrReportTestsyes
truncationsarray of stringyes
validationPrReportValidationyes
versionnumberyes

PublicAgentDecision

FieldTypeRequiredNotes
decisionIdstringyes
kind"agent-decision"yes
optionsarray of stringyes
questionstringyes
stepKindstringyes

PublicAnswerFollowUp

FieldTypeRequiredNotes
answerstringyes1 to 4000 characters

PublicAnswerInterview

FieldTypeRequiredNotes
answerstringyesmax 2000 characters
questionIdstringyes1 to 80 characters

PublicApiKey

FieldTypeRequiredNotes
accountIdstringyes
actsAsUserIdstring | nullyes
createdAtnumberyes
createdByKeyIdstring | nullyes
createdByUserIdstring | nullyes
externalIdentitystring | nullyes
idstringyes
labelstringyes
lastUsedAtnumber | nullyes
revokedAtnumber | nullyes
scope"read" | "write" | "decide" | "admin"yes
workspaceIdstringyes

PublicApiKeyList

FieldTypeRequiredNotes
keysarray of PublicApiKeyyes

PublicApprovalGateDecision

FieldTypeRequiredNotes
approvalIdstringyes
exceededbooleanyes
feedbackstring | nullyes
kind"approval-gate"yes
proposalstringyes
recordedApprovalsnumberyes
requiredApprovalsnumberyes
status"pending" | "approved" | "changes_requested" | "rejected"yes
stepIndexnumberyes
stepKindstringyes

PublicApproveStep

FieldTypeRequiredNotes
proposalstringnomax 50000 characters

PublicBrainstormDecision

FieldTypeRequiredNotes
convergedDirectionstring | nullyes
iterationnumberyes
kind"brainstorm"yes
maxIterationsnumberyes
optionsarray of PublicReviewFindingyes
sessionIdstringyes
stage"requirements" | "architecture"yes
status"ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated"yes
taskIdstringyes

PublicChallengePrReviewFinding

FieldTypeRequiredNotes
questionstringnomax 4000 characters

PublicChooseFork

FieldTypeRequiredNotes
customstring | nullno
forkIdstring | nullno
notestring | nullno

PublicClarityDecision

FieldTypeRequiredNotes
clarifiedReportstring | nullyes
findingsarray of PublicReviewFindingyes
iterationnumberyes
kind"clarity-review"yes
maxIterationsnumberyes
reviewIdstringyes
status"ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated"yes
taskIdstringyes

PublicDecision

One of 13 shapes.

Shape 1

PublicRequirementsDecision

Shape 2

PublicForkDecision

kind: "judge"

FieldTypeRequiredNotes
bouncesnumberyes
kind"judge"yes
maxBouncesnumberyes
rubricIdstring | nullyes
rubricNamestring | nullyes
status"evaluating" | "awaiting_decision" | "bouncing" | "passed" | "failed" | "skipped"yes
stepKindstringyes
thresholdnumber | nullyes
verdictobject | nullyes

Shape 4

PublicInputGateDecision

Shape 5

PublicApprovalGateDecision

Shape 6

PublicAgentDecision

Shape 7

PublicClarityDecision

Shape 8

PublicBrainstormDecision

Shape 9

PublicPrReviewDecision

Shape 10

PublicHumanTestDecision

Shape 11

PublicVisualConfirmDecision

Shape 12

PublicFollowUpsDecision

Shape 13

PublicInterviewDecision

PublicDecisionList

FieldTypeRequiredNotes
decisionsarray of PublicDecisionyes
parkedbooleanyes
runIdstringyes
status"running" | "blocked" | "paused" | "done" | "failed"yes
taskIdstringyes
unanswerablearray of PublicUnanswerableWaityes

PublicFollowUpItem

FieldTypeRequiredNotes
answerstring | nullyes
detailstringyes
itemIdstringyes
kind"follow_up" | "question"yes
status"pending" | "filed" | "queued" | "answered" | "dismissed"yes
suggestedActionstring | nullyes
ticketExternalIdstring | nullyes
ticketUrlstring | nullyes
titlestringyes

PublicFollowUpsDecision

FieldTypeRequiredNotes
itemsarray of PublicFollowUpItemyes
kind"follow-ups"yes
loopsnumberyes
maxLoopsnumberyes
stepIndexnumberyes
stepKindstringyes

PublicForkDecision

FieldTypeRequiredNotes
forksarray of objectyes
kind"fork"yes
seamSummarystring | nullyes
status"proposing" | "awaiting_choice" | "answering" | "chosen" | "single_path" | "skipped"yes

PublicHumanTestDecision

FieldTypeRequiredNotes
attemptsnumberyes
degradedReasonstring | nullyes
environmentPublicHumanTestEnvironment | nullyes
kind"human-test"yes
maxAttemptsnumberyes
phase"provisioning" | "awaiting_human" | "fixing" | "resolving_conflicts" | "passed"yes

PublicHumanTestEnvironment

FieldTypeRequiredNotes
expiresAtnumber | nullyes
status"provisioning" | "ready" | "failed" | "expired" | "tearing_down" | "torn_down"yes
urlstring | nullyes

PublicIdentity

FieldTypeRequiredNotes
accountIdstringyes
createdAtnumberyes
externalIdentitystring | nullyes
keyIdstringyes
labelstringyes
scope"read" | "write" | "decide" | "admin"yes
workspaceIdstringyes

PublicIncorporate

FieldTypeRequiredNotes
feedbackstringnomax 4000 characters

PublicInputGateDecision

FieldTypeRequiredNotes
checkedAtnumberyes
issuesarray of objectyes
kind"input-gate"yes
mode"standard" | "advisory" | "off"yes
status"off" | "not_applicable" | "passed" | "blocked" | "overridden"yes

PublicInterviewDecision

FieldTypeRequiredNotes
kind"interview"yes
maxRoundsnumberyes
questionsarray of PublicInterviewQuestionyes
roundnumberyes
stepKindstringyes
taskIdstringyes

PublicInterviewQuestion

FieldTypeRequiredNotes
answerstringyes
questionstringyes
questionIdstring | nullyes
status"open" | "answered" | "dismissed"yes

PublicJob

FieldTypeRequiredNotes
createdAtnumberyes
errorobject | nullyes
externalIdentitystring | nullyes
externalIdentityWithheldbooleanyes
jobIdstringyes
pipelineIdstringyes
resultobject | nullyes
status"running" | "succeeded" | "failed"yes

PublicJobAccepted

FieldTypeRequiredNotes
jobIdstringyes
linksobjectyes
links.eventsstringyes
links.selfstringyes
status"running" | "succeeded" | "failed"yes

PublicNotificationList

FieldTypeRequiredNotes
notificationsarray of Notificationyes

PublicNotificationWebhook

FieldTypeRequiredNotes
webhookNotificationWebhook | nullyes

PublicNotificationWebhookList

FieldTypeRequiredNotes
webhooksarray of NotificationWebhookyes

PublicPipeline

FieldTypeRequiredNotes
headlessStartablebooleanyes
namestringyes
pipelineIdstringyes
publicbooleanyes
stepsarray of stringyes

PublicPipelineList

FieldTypeRequiredNotes
pipelinesarray of PublicPipelineyes

PublicPrReviewDecision

FieldTypeRequiredNotes
findingsarray of objectyes
kind"pr-review"yes
prUrlstring | nullyes
selectedFindingIdsarray of stringyes
slicesarray of objectyes
status"reviewing" | "awaiting_selection" | "challenging" | "fixing" | "posting" | "done" | "skipped"yes
summarystring | nullyes

PublicRejectStep

FieldTypeRequiredNotes
reasonstringnomax 2000 characters

PublicReplyFinding

FieldTypeRequiredNotes
replystringyes1 to 4000 characters

PublicRequestGateFix

FieldTypeRequiredNotes
findingsstringyes1 to 10000 characters

PublicRequestStepChanges

FieldTypeRequiredNotes
feedbackstringyes1 to 10000 characters

PublicRequirementsDecision

FieldTypeRequiredNotes
findingsarray of PublicReviewFindingyes
incorporatedRequirementsstring | nullyes
iterationnumberyes
kind"requirements-review"yes
maxIterationsnumberyes
reviewIdstringyes
status"ready" | "incorporating" | "reviewing" | "merged" | "exceeded" | "incorporated"yes
taskIdstringyes

PublicResolveAgentDecision

FieldTypeRequiredNotes
choicestringyes1 to 4000 characters

PublicResolveExceeded

FieldTypeRequiredNotes
choice"extra-round" | "proceed" | "stop-reset"yes

PublicResolveInputGate

FieldTypeRequiredNotes
choice"recheck" | "proceed"yes

PublicResolvePrReview

FieldTypeRequiredNotes
action"finish" | "fix" | "post"no
findingIdsarray of stringno

PublicReviewFinding

FieldTypeRequiredNotes
category"gap" | "clarification" | "assumption" | "risk" | "question"yes
detailstringyes
itemIdstringyes
replystring | nullyes
severity"low" | "medium" | "high"yes
status"open" | "answered" | "resolved" | "dismissed" | "recommend_requested"yes
titlestringyes

PublicRun

FieldTypeRequiredNotes
createdAtnumberyes
currentStepnumberyes
errorobject | nullyes
externalIdentitystring | nullyes
externalIdentityWithheldbooleanyes
pullRequestobject | nullyes
runIdstringyes
status"running" | "blocked" | "paused" | "done" | "failed"yes
stepsarray of objectyes
taskIdstringyes

PublicRunArtifact

FieldTypeRequiredNotes
artifactIdstringyes
byteSizenumberyes
contentTypestringyes
createdAtnumberyes
hashstringyes
kind"screenshot" | "reference"yes
scope"run" | "task"yes
viewstring | nullyes

PublicRunArtifactList

FieldTypeRequiredNotes
artifactsarray of PublicRunArtifactyes

PublicRunSpec

FieldTypeRequiredNotes
anchor"present" | "absent" | "unparsed" | "not_read"yes
featuresarray of PublicSpecFeatureFileyes
issuesarray of SpecReadIssueyes
provenancePublicSpecProvenance | nullyes
runIdstringyes
specSpecDoc | nullyes
truncationsarray of PublicSpecTruncationyes

PublicService

FieldTypeRequiredNotes
descriptionstringyes
provisioningobjectno
serviceIdstringyes
status"planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done"yes
titlestringyes
type"frontend" | "service" | "library" | "document" | "api" | "database" | "queue" | "integration" | "external" | "environment"yes

PublicServiceList

FieldTypeRequiredNotes
servicesarray of PublicServiceyes

PublicServiceSpec

FieldTypeRequiredNotes
anchor"present" | "absent" | "unparsed"yes
featuresarray of PublicSpecFeatureFileyes
issuesarray of SpecReadIssueyes
provenancePublicSpecProvenanceyes
serviceIdstringyes
specSpecDoc | nullyes
truncationsarray of PublicSpecTruncationyes

PublicSetFindingStatus

FieldTypeRequiredNotes
status"dismissed" | "open"yes

PublicSpecFeatureFile

FieldTypeRequiredNotes
charsnumberyes
contentstringyes
groupstringyes
modulestringyes
pathstringyes
totalCharsnumberyes
truncatedbooleanyes

PublicSpecProvenance

FieldTypeRequiredNotes
commitstring | nullyes
ownerstringyes
provider"github" | "gitlab"yes
refstringyes
repostringyes

PublicSpecTruncation

FieldTypeRequiredNotes
section"requirements" | "rules" | "acceptance" | "features" | "issues"yes
shownnumberyes
totalnumberyes

PublicSpend

FieldTypeRequiredNotes
currencystringyes
dimension"model" | "agentKind" | "service" | "repo" | "taskType" | "ticket" | "run"yes
generatedAtnumberyes
rolledUpThroughnumber | nullyes
rowsarray of PublicSpendRowyes
sincenumberyes
source"ledger" | "daily-rollup"yes
totalsPublicSpendTotalsyes
truncatedbooleanyes
window"24h" | "7d" | "30d" | "90d"yes

PublicSpendRow

FieldTypeRequiredNotes
callsnumberyes
inputTokensnumberyes
keystringyes
labelstring | nullyes
meteredCostnumberyes
outputTokensnumberyes
subscriptionCostnumberyes

PublicSpendTotals

FieldTypeRequiredNotes
callsnumberyes
inputTokensnumberyes
meteredCostnumberyes
outputTokensnumberyes
subscriptionCostnumberyes

PublicTask

FieldTypeRequiredNotes
autoStartDependentsbooleanyes
dependsOnarray of stringyes
descriptionstringyes
modelPresetIdstring | nullyes
progressnumberyes
pullRequestUrlstring | nullyes
riskPolicyIdstring | nullyes
runIdstring | nullyes
serviceIdstringyes
status"planned" | "ready" | "in_progress" | "blocked" | "pr_ready" | "done"yes
taskIdstringyes
taskType"feature" | "bug" | "document" | "spike" | "review" | "ralph" | "recurring" | stringyes
titlestringyes

PublicTaskDocument

One of 2 shapes.

Shape 1

PublicTaskSourceDocument

Shape 2

PublicTaskUploadedDocument

PublicTaskList

FieldTypeRequiredNotes
nextCursorstring | nullyes
tasksarray of PublicTaskyes

PublicTaskSourceDocument

FieldTypeRequiredNotes
kind"source"yes
refstringyes1 to 500 characters
source"confluence" | "notion" | "github" | "figma" | "zeplin" | "linear"yes

PublicTaskTicket

FieldTypeRequiredNotes
refstringyes1 to 500 characters
source"jira" | "github" | "linear" | "gitlab" | stringyes

PublicTaskUploadedDocument

FieldTypeRequiredNotes
contentstringyes1 to 100000 characters
kind"upload"yes
titlestringyes1 to 200 characters

PublicUnanswerableWait

FieldTypeRequiredNotes
detailstringyes
reason"human_wait_gate" | "unclassified_gate" | "unwired_interview_gate"yes
stepIndexnumberyes
stepKindstringyes

PublicUsage

FieldTypeRequiredNotes
budgetPublicUsageBudgetyes
currencystringyes
periodStartnumberyes
rowsarray of PublicUsageRowyes

PublicUsageBudget

FieldTypeRequiredNotes
costLimitnumberyes
costSpentnumberyes
exceededbooleanyes
inputTokensnumberyes
outputTokensnumberyes

PublicUsageRow

FieldTypeRequiredNotes
billing"metered" | "subscription"yes
callsnumberyes
costEstimatenumberyes
inputTokensnumberyes
modelstringyes
outputTokensnumberyes
providerstringyes
vendorstring | nullyes

PublicVisualConfirmDecision

FieldTypeRequiredNotes
attemptsnumberyes
degradedReasonstring | nullyes
kind"visual-confirmation"yes
maxAttemptsnumberyes
pairsarray of objectyes
phase"awaiting_human" | "fixing" | "approved"yes

PutNotificationWebhook

FieldTypeRequiredNotes
alertEventsarray of "platform_health.firing" | "platform_health.resolved"no
enabledbooleanno
namestringno1 to 100 characters
runEventsarray of "run.started" | "run.completed" | "run.failed"no
secretstringno16 to 200 characters
typesarray 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
urlstring (uri)nomax 2000 characters, pattern ^https://

RequirementGroup

FieldTypeRequiredNotes
namestringyes1 to 120 characters
requirementsarray of RequirementItemno
rulesarray of DomainRuleno
summarystringnomax 2000 characters

RequirementItem

FieldTypeRequiredNotes
acceptancearray of AcceptanceCriterionno
idstringyes1 to 200 characters
kind"functional" | "nonfunctional" | "constraint"yes
priority"must" | "should" | "could"yes
sourceBlockIdsarray of stringno
state"aspirational" | "established"no
statementstringyes1 to 4000 characters
titlestringyes1 to 120 characters

SpecDoc

FieldTypeRequiredNotes
modulesarray of SpecModuleno
servicestringnomax 120 characters
summarystringnomax 2000 characters

SpecModule

FieldTypeRequiredNotes
groupsarray of RequirementGroupno
namestringyes1 to 120 characters
summarystringnomax 2000 characters

SpecReadIssue

FieldTypeRequiredNotes
droppednumber | nullno
kind"read_failed" | "unparsed" | "partial" | "unread"yes
pathstringyes

StartPublicTask

FieldTypeRequiredNotes
pipelineIdstringno1 to 120 characters

UpdatePublicTask

FieldTypeRequiredNotes
autoStartDependentsbooleanno
descriptionstringnomax 2000 characters
fieldsmap of string | array of string | boolean | numberno
modelPresetIdstringno1 to 120 characters
riskPolicyIdstringno1 to 120 characters
titlestringno1 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.

Last Updated: 8/12/26, 7:59 AM
Prev
Environment Variables
Next
Glossary