REST reference

Every /api/v2 endpoint: method, path, scopes, parameters, body fields and errors.

The REST API lives under https://v12.sh/api/v2/orgs/<org>, where <org> is the slug of the workspace your token reads. Only GET https://v12.sh/api/v2/me and the OpenAPI document sit outside it. Addresses explains slugs and how to name findings, runs and repositories. Authentication and permissions covers API keys, OAuth and scopes.

The OpenAPI 3.1 document is public, needs no token and may be cached for five minutes: https://v12.sh/api/v2/openapi.json.

None required in an operation's scopes means any valid token can call it, as with GET /me; it does not remove the token requirement.

Requests

  • Paths below are relative to https://v12.sh/api/v2. {org} is organization.slug from GET /me; another workspace's slug gets 404 not_found.
  • {repository} is two path segments, owner/name: its slug or full name, as in /orgs/acme/repositories/acme/api/findings.
  • {finding} is a finding key, such as F-42, or its number, 42. {run} is the run's number in the workspace. {link} is a guest link's number in that run.
  • repository and at go in the query string on every GET that takes them, and on the two finding PATCH operations. A comment's POST takes them in its JSON body.
  • Query lists are comma-separated: status=open,fixed. A repeated list parameter adds its values, so status=open&status=fixed means the same; repeating a single-value parameter, such as limit, returns 400 invalid_request.
  • Other POST and PATCH fields go in a JSON body with Content-Type: application/json. Any other type returns 415.
  • Bodies are limited to 1 MiB. A larger one returns 413.

Errors

Every error response has this body. details is optional. requestId matches the X-Request-Id response header; include it when you ask for help.

{
  "error": {
    "code": "invalid_request",
    "message": "The request is invalid.",
    "details": { "issues": [{ "path": "limit", "message": "Too big: expected number to be <=100" }] }
  },
  "requestId": "e3fbc6dc-1c5e-4b2d-b998-e820319d6cf7"
}
CodeHTTPMeaning
invalid_request400The input, a header, the cursor or the quote is invalid. Validation errors list details.issues.
repository_required400The finding is in several repositories. Pick one from details.repositories.
unauthenticated401The Authorization header is missing or its token is invalid. See WWW-Authenticate.
insufficient_credits402The workspace lacks the credit for the run.
spend_cap_reached402The workspace's monthly spending limit is reached.
insufficient_scope403The token lacks a scope listed in details.required.
forbidden403The token's user has a role that does not allow the action, such as a Member adding a private repository.
not_found404No such endpoint (such as a path without /orgs/<org>), a slug that is not the token's workspace, no such resource in the token's workspace, or the finding is not at that position. A finding that is on no default branch, sent without at, has details.reason not-on-default-branch: pass repository and at.
repository_not_visible404V12 can't see the repository on GitHub, so it can't add it. details.known is private only when your own GitHub account sees it as private. A token an OAuth app holds, including v12 auth login's, always gets unknown. details.recovery holds a next step you may take, such as giving V12's GitHub App access, or null.
repository_not_added404A run target is not added to the workspace. Add it with POST /repositories, then estimate again. details.add names the operation and the repos:write scope it needs; granted says whether this token holds it. When it doesn't, add the repository in the app, or use a token with repos:write.
method_not_allowed405The path does not take this method. See Allow.
position_unavailable409V12 cannot resolve the position. details.reason says why, such as unknown-branch (with details.ref, a branch name without refs/heads/; a hosted repository that has no commit on its default branch yet answers it too, and its message says to push that branch first), unknown-pull-request (with details.number) or repository-empty for a GitHub repository without commits. A finding read that V12's findings service can't place at a repository position also gives details.mirror, the repository's sync state; git-data-unavailable means V12 has no commit to read at the position yet, such as while it is still mirroring the repository.
decision_active409A won't-fix or risk-accepted decision blocks this status. details.findings lists the findings; set status open first.
conflict409The request conflicts with the current state, such as cancelling a completed run.
price_exceeds_max409The price, details.priceCents, is above maxPriceCents.
quote_stale409The quote expired or what it priced changed. Estimate again.
change_refused409The change cannot be reviewed. details.reason is thin, identical, large or detached, and the message says what to send instead. large means more than 3,000 changed files, removed ones included.
nothing_to_review409Nothing in scope has files to review at this position.
repository_not_runnable409Access to the repository was revoked; details.reason is access-revoked.
idempotency_key_reused409The Idempotency-Key was used for a different request.
api_version_retired410/api/v1 is retired. Use /api/v2.
payload_too_large413The body is larger than details.limitBytes.
unsupported_media_type415The body is not application/json.
rate_limited429A rate limit is used up. Wait Retry-After seconds; details.bucket names the limit and details.limit its size. With details.source: "github", GitHub is limiting V12's requests; try again in a few minutes.
internal_error500An unexpected failure on V12's side, including a 500 from V12's findings service.
upstream_error503A request V12 needed failed: to GitHub, or to V12's repository mirror, or a hosted repository's setup hasn't finished. Try again shortly.
platform_unavailable503V12's findings service or repository mirror is unavailable: the findings service answered 429, 502, 503 or 504, or didn't answer, or the mirror couldn't answer in time. When the service said when to retry, the response carries Retry-After, with the same seconds in details.retryAfterSeconds; wait that long.
repository_access_unavailable503V12 could not confirm its GitHub access to the repository. With details.reason: "public-reader-unavailable", V12 cannot read public repositories for this workspace until GitHub is connected.
rate_limit_unavailable503Rate limiting is down, so V12 refuses changes and run estimates. Retry after 30 seconds.
public_api_disabled503The API is turned off for now; the web app still works.

Me

OperationEndpointScopesMCP tool
Get the token identityGET /meNone requiredget_me

Get the token identity

GET /me · operationId getMe · Scopes: None required · MCP tool get_me

The user, organization and scopes behind this credential, plus the organization credit balance when the user may view billing. Any valid token may read it; organization.slug addresses every other endpoint.

Returns 200 with user, organization, token, credits. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Members

OperationEndpointScopesMCP tool
List organization membersGET /orgs/{org}/membersuser:readlist_members

List organization members

GET /orgs/{org}/members · operationId listMembers · Scopes: user:read · MCP tool list_members

Members of the token organization, sorted by username, then email. Use a member email or username to assign findings.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Steers

OperationEndpointScopesMCP tool
List SteersGET /orgs/{org}/steersrepos:readlist_steers
Create a SteerPOST /orgs/{org}/steerssteers:writecreate_steer
Get a SteerGET /orgs/{org}/steers/{steer}repos:readget_steer
Edit a SteerPATCH /orgs/{org}/steers/{steer}steers:writeupdate_steer
Archive a SteerDELETE /orgs/{org}/steers/{steer}steers:writearchive_steer
Restore a SteerPOST /orgs/{org}/steers/{steer}/restoresteers:writerestore_steer

List Steers

GET /orgs/{org}/steers · operationId listSteers · Scopes: repos:read · MCP tool list_steers

Organization-wide Steer documents that guide runs and Autopilot rules. Lists active Steers by default; archived: true lists only archived Steers.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
archivedquerybooleannodefault false

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Create a Steer

POST /orgs/{org}/steers · operationId createSteer · Scopes: steers:write · MCP tool create_steer

Create an organization Steer with a title, emoji and instructions. The returned slug is its stable address. Repeating this request creates another Steer; it does not attach to Autopilot rules.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
titlestringyes1–120 characters
emojistringyesat least 1 characters
instructionsstringyesat most 65536 characters

Returns 201 with slug, title, emoji, archivedAt, webUrl, instructions. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Get a Steer

GET /orgs/{org}/steers/{steer} · operationId getSteer · Scopes: repos:read · MCP tool get_steer

One active or archived Steer by slug, including its instructions and archive status. Archived Steers remain readable for historical references.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
steerpathstringyesSteer slug; 1–200 characters

Returns 200 with slug, title, emoji, archivedAt, webUrl, instructions. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Edit a Steer

PATCH /orgs/{org}/steers/{steer} · operationId updateSteer · Scopes: steers:write · MCP tool update_steer

Update the supplied fields of an active Steer, preserving omitted fields and its slug. Runs already started keep the instructions they started with. Restore an archived Steer before editing it.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
steerpathstringyesSteer slug; 1–200 characters
Body fieldTypeRequiredNotes
titlestringno1–120 characters
emojistringnoat least 1 characters
instructionsstringnoat most 65536 characters

Returns 200 with slug, title, emoji, archivedAt, webUrl, instructions. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Archive a Steer

DELETE /orgs/{org}/steers/{steer} · operationId archiveSteer · Scopes: steers:write · MCP tool archive_steer

Archive a Steer and detach it from every Autopilot rule. Rules keep their active or paused state; a rule with no remaining Steers uses its default review. New runs refuse the Steer, while finding tags and queued, running and completed run snapshots remain intact. Repeating archive is safe.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
steerpathstringyesSteer slug; 1–200 characters

Returns 200 with slug, title, emoji, archivedAt, webUrl, instructions. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Restore a Steer

POST /orgs/{org}/steers/{steer}/restore · operationId restoreSteer · Scopes: steers:write · MCP tool restore_steer

Make an archived Steer available for edits and new runs again, keeping its slug. Former Autopilot attachments are not restored; add them again separately. Repeating restore is safe.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
steerpathstringyesSteer slug; 1–200 characters

Returns 200 with slug, title, emoji, archivedAt, webUrl, instructions. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Repositories

OperationEndpointScopesMCP tool
List repositoriesGET /orgs/{org}/repositoriesrepos:readlist_repositories
Add a repositoryPOST /orgs/{org}/repositoriesrepos:writeadd_repository
Get a repositoryGET /orgs/{org}/repositories/{owner}/{repo}repos:readREST only
List branches, pull requests and tagsGET /orgs/{org}/repositories/{owner}/{repo}/refsrepos:readlist_refs
Create a hosted repositoryPOST /orgs/{org}/repositories/hostedrepos:writecreate_hosted_repository
Get a push URL for a hosted repositoryPOST /orgs/{org}/repositories/{owner}/{repo}/push-credentialsrepos:writecreate_push_credential

List repositories

GET /orgs/{org}/repositories · operationId listRepositories · Scopes: repos:read · MCP tool list_repositories

Repositories registered in the organization, sorted by full name, with their GitHub access and mirror state.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Add a repository

POST /orgs/{org}/repositories · operationId addRepository · Scopes: repos:write · MCP tool add_repository

Add a GitHub repository to this organization. Members can add public repositories; private repositories must be granted by the workspace GitHub connection and added by an owner. Repeating an add returns the existing registration. A "v12/<name>" names a repository V12 hosts, never one on GitHub: it returns that registration, or not_found. This does not start a run.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
repositorystringyesRepository: "owner/name", its github.com URL, or its clone URL; 1–300 characters

Returns 200, 201 with added, tracking, repository. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Get a repository

GET /orgs/{org}/repositories/{owner}/{repo} · operationId getRepository · Scopes: repos:read · REST only

One registered repository by its slug or full name ("owner/name").

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
ownerpathstringyesRepository owner
repopathstringyesRepository name

Returns 200 with slug, fullName, defaultBranch, access, mirror, webUrl. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

List branches, pull requests and tags

GET /orgs/{org}/repositories/{owner}/{repo}/refs · operationId listRefs · Scopes: repos:read · MCP tool list_refs

Branches, pull requests and tags V12 has mirrored for a repository, with whether each head was reviewed. Each list stops at limit (default 100, max 200): truncated says which may hold more and branchCount counts every matching branch. Not paginated; narrow with q. mirror is the repository's sync state.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
ownerpathstringyesRepository owner
repopathstringyesRepository name
qquerystringnoCase-insensitive name filter; at most 200 characters
limitqueryintegerno1–200; default 100

Returns 200 with defaultBranch, branches, pullRequests, tags, asOf, branchCount, truncated, mirror, nextCursor. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Create a hosted repository

POST /orgs/{org}/repositories/hosted · operationId createHostedRepository · Scopes: repos:write · MCP tool create_hosted_repository

Create an empty Git repository that V12 hosts. It answers to "v12/<name>", and to the slug in the response. Push code to it with a URL from create_push_credential, the default branch first: V12 does not enforce that, but until it exists, finding reads and full reviews at the default position answer 409 position_unavailable. V12 imports each push. Only owners may create one. A name already in use, or whose "v12/<name>" is another repository's slug, is a conflict. This does not start a run.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
namestringyesName: 1 to 100 lowercase letters, numbers, dots, underscores or hyphens, starting and ending with a letter or number, e.g. "payments-api"; 1–100 characters

Returns 201 with repository. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Get a push URL for a hosted repository

POST /orgs/{org}/repositories/{owner}/{repo}/push-credentials · operationId createPushCredential · Scopes: repos:write · MCP tool create_push_credential

A Git remote URL that can push to one branch of a repository V12 hosts, valid for one hour. Push with `git -c credential.helper= push <url> HEAD:<branch>`: the empty helper keeps Git from saving the credential. The URL is the credential; treat it as a secret. Only owners may get one, and GitHub repositories have none. V12 does not make you push the default branch first, but until it exists, finding reads and full reviews at the default position, and branch changes without since, answer 409 position_unavailable.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
ownerpathstringyesRepository owner
repopathstringyesRepository name
Body fieldTypeRequiredNotes
branchstringyesThe one branch the URL may push to, e.g. "main": a name Git accepts. "refs/heads/main" names main; other refs, such as "refs/tags/x", are refused; 1–255 characters

Returns 201 with branch, url, expiresAt. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Findings

OperationEndpointScopesMCP tool
List a repository's findings at a positionGET /orgs/{org}/repositories/{owner}/{repo}/findingsfindings:readlist_repository_findings
List organization findingsGET /orgs/{org}/findingsfindings:readlist_findings
Change findingsPATCH /orgs/{org}/findingsfindings:writeupdate_findings
Get a findingGET /orgs/{org}/findings/{finding}findings:readget_finding
Change a findingPATCH /orgs/{org}/findings/{finding}findings:writeREST only
Comment on a findingPOST /orgs/{org}/findings/{finding}/commentsfindings:writecomment_on_finding

List a repository's findings at a position

GET /orgs/{org}/repositories/{owner}/{repo}/findings · operationId listRepositoryFindings · Scopes: findings:read · MCP tool list_repository_findings

The repository inbox at one commit: every finding with its code state there. Without at, the default branch head. The response pins the evaluated commit in position.at; later pages stay on it. Highest finding number first; counts are before filters, total after.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
ownerpathstringyesRepository owner
repopathstringyesRepository name
atquerystringnoRepository position: "default", "branch:<name>[@<sha>]", "pr:<number>[@<sha>]" or "commit:<sha>". Omitted means "default"; at most 512 characters
statusquery("open" | "investigating" | "fixed" | "wont-fix" | "false-positive" | "duplicate")[]noat most 6 items
severityquery("info" | "low" | "medium" | "high" | "critical")[]noat most 5 items
assigneequerystringno"me", "none", a member email, or a member username. A username several members share matches all of them; 1–320 characters
steerquerystringnoSteer slug; 1–200 characters
limitqueryintegerno1–100; default 50
cursorquerystringno`nextCursor` from the previous page; 1–2048 characters

Returns 200 with nextCursor, items, repository, position, reviewCoverage, counts, total, asOf. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

List organization findings

GET /orgs/{org}/findings · operationId listFindings · Scopes: findings:read · MCP tool list_findings

Findings across every registered repository at its default branch head, highest finding number first (numbers grow as findings are created; firstObservedAt can be older). counts covers every finding before filters; total counts the filtered result. unavailableRepositories lists the slugs of repositories whose default branch V12 cannot read; list_repository_findings on one says why.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
statusquery("open" | "investigating" | "fixed" | "wont-fix" | "false-positive" | "duplicate")[]noat most 6 items
severityquery("info" | "low" | "medium" | "high" | "critical")[]noat most 5 items
assigneequerystringno"me", "none", a member email, or a member username. A username several members share matches all of them; 1–320 characters
steerquerystringnoSteer slug; 1–200 characters
limitqueryintegerno1–100; default 50
cursorquerystringno`nextCursor` from the previous page; 1–2048 characters

Returns 200 with nextCursor, items, counts, total, asOf, unavailableRepositories. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Change findings

PATCH /orgs/{org}/findings · operationId updateFindings · Scopes: findings:write · MCP tool update_findings

Apply one change to up to 100 findings: status, severity, or assignee. fixed and open are recorded at a commit (the default branch head unless repository/at say otherwise) and carry forward to later commits while the affected files are unchanged; false-positive marks the finding's reports and shows at every commit that has them; investigating and wont-fix apply everywhere. repository and at also locate findings that exist only off the default branch, such as ones a change review reported (send each position.at that list_run_findings reports with its repository): for investigating, wont-fix, severity and assignee they only locate the findings, and the change still applies everywhere. Findings already in the requested state are left unchanged and listed in skipped.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
repositoryquerystringnoRepository that `at` refers to. Needed with `at` when a finding spans several repositories
atquerystringnoWhere to find the findings: "default", "branch:<name>[@<sha>]", "pr:<number>[@<sha>]" or "commit:<sha>", such as a `position.at` a finding reports; omitted means "default". open, fixed and false-positive are recorded at this position. For every other change it only locates a finding that exists there, such as one found only off the default branch, and the change still applies everywhere; at most 512 characters
Body fieldTypeRequiredNotes
findings(integer | string)[]yes1–100 items
status"open" | "investigating" | "fixed" | "wont-fix" | "false-positive"nofixed and open apply at a commit and carry forward; false-positive marks the finding's reports; investigating and wont-fix apply everywhere
severity"info" | "low" | "medium" | "high" | "critical"no
assigneestring | nullno"me", a member email, a member username, or null or "none" to unassign. A username several members share is refused; use the email

Returns 200 with findings, skipped, asOf. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Get a finding

GET /orgs/{org}/findings/{finding} · operationId getFinding · Scopes: findings:read · MCP tool get_finding

One finding with its reports (each report's analysis, proof of concept and fix are in reports[].analysis), evidence and activity. Comments are activity entries of kind "comment"; their id is the replyTo for comment_on_finding. A false-positive change shows in status, not in activity. With at, code state and status are read at that commit. Send a returned position.at with its repositories[i].repository; without repository, inference reports repository_required if several registered repositories hold the finding at that position. A finding on no default branch answers not_found unless you send at.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
findingpathinteger | stringyesFinding key such as "F-42", or its number
repositoryquerystringnoRepository slug or full name, "owner/name"
atquerystringnoRepository position: "default", "branch:<name>[@<sha>]", "pr:<number>[@<sha>]" or "commit:<sha>". Omitted means "default"; at most 512 characters

Returns 200 with number, key, title, severity, status, investigating, decision, duplicateOf, assignee, steer, firstObservedAt, reportCount, sources, runs, repositories, webUrl, description, reports, evidence, activity, related, asOf. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Change a finding

PATCH /orgs/{org}/findings/{finding} · operationId updateFinding · Scopes: findings:write · REST only

Apply one change to a finding: status, severity, or assignee. repository and at locate a finding that exists only off the default branch, such as one a change review reported: for investigating, wont-fix, severity and assignee they only locate it, and the change still applies everywhere. A change that would not alter the finding leaves it unchanged and lists it in skipped.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
findingpathinteger | stringyesFinding key such as "F-42", or its number
repositoryquerystringnoRepository that `at` refers to. Needed with `at` when a finding spans several repositories
atquerystringnoWhere to find the findings: "default", "branch:<name>[@<sha>]", "pr:<number>[@<sha>]" or "commit:<sha>", such as a `position.at` a finding reports; omitted means "default". open, fixed and false-positive are recorded at this position. For every other change it only locates a finding that exists there, such as one found only off the default branch, and the change still applies everywhere; at most 512 characters
Body fieldTypeRequiredNotes
status"open" | "investigating" | "fixed" | "wont-fix" | "false-positive"nofixed and open apply at a commit and carry forward; false-positive marks the finding's reports; investigating and wont-fix apply everywhere
severity"info" | "low" | "medium" | "high" | "critical"no
assigneestring | nullno"me", a member email, a member username, or null or "none" to unassign. A username several members share is refused; use the email

Returns 200 with findings, skipped, asOf. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Comment on a finding

POST /orgs/{org}/findings/{finding}/comments · operationId commentOnFinding · Scopes: findings:write · MCP tool comment_on_finding

Add a comment, or a reply to one, to a finding. A finding that exists only off the default branch, such as one a change review reported, needs repository and at (a position.at that list_run_findings reports); the comment belongs to the finding everywhere.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
findingpathinteger | stringyesFinding key such as "F-42", or its number
Idempotency-KeyheaderstringnoRepeat a request safely: the same key and body return the original result; 1–255 characters
Body fieldTypeRequiredNotes
bodystringyes1–20000 characters
replyTostringnoComment id to reply to; 1–255 characters
repositorystringnoRepository that `at` refers to. Needed with `at` when a finding spans several repositories
atstringnoWhere to find the finding: "default", "branch:<name>[@<sha>]", "pr:<number>[@<sha>]" or "commit:<sha>", such as a `position.at` a finding reports; omitted means "default". Needed for a finding that exists only off the default branch; at most 512 characters

Returns 201 with comment. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Runs

OperationEndpointScopesMCP tool
List runsGET /orgs/{org}/runsruns:readlist_runs
Start a runPOST /orgs/{org}/runsruns:writestart_run
Get a runGET /orgs/{org}/runs/{run}runs:readget_run
List a run's findingsGET /orgs/{org}/runs/{run}/findingsruns:read, findings:readlist_run_findings
Estimate a runPOST /orgs/{org}/runs/estimateruns:writeestimate_run
Cancel a runPOST /orgs/{org}/runs/{run}/cancelruns:managecancel_run
List guest linksGET /orgs/{org}/runs/{run}/linksruns:sharelist_run_links
Create a guest linkPOST /orgs/{org}/runs/{run}/linksruns:share, findings:readcreate_run_link
Change a guest linkPATCH /orgs/{org}/runs/{run}/links/{link}runs:share, findings:readupdate_run_link
Revoke a guest linkDELETE /orgs/{org}/runs/{run}/links/{link}runs:sharerevoke_run_link

List runs

GET /orgs/{org}/runs · operationId listRuns · Scopes: runs:read · MCP tool list_runs

Runs of the organization, newest first. state filters raw states (failed alone misses compilation_failed and analysis_failed); phase filters the phase each run reports. With phase, a page can hold fewer than limit items: keep following nextCursor.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
repositoryquerystringnoRepository slug or full name, "owner/name"
steerquerystringnoSteer slug; 1–200 characters
statequery("queued" | "in_progress" | "compilation_in_progress" | "compilation_completed" | "compilation_failed" | "analysis_in_progress" | "analysis_completed" | "analysis_failed" | "complete" | "failed" | "cancelled")[]no1–11 items
phasequery("before" | "live" | "complete" | "failed" | "cancelled")[]no1–5 items
limitqueryintegerno1–100; default 50
cursorquerystringno`nextCursor` from the previous page; 1–2048 characters

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Start a run

POST /orgs/{org}/runs · operationId startRun · Scopes: runs:write · MCP tool start_run

Start a paid run. Send the quote from estimate_run and a maxPriceCents the user approved; the run is refused when its price exceeds it. A repeated Idempotency-Key (REST) or requestId (MCP) returns the original response with replayed: true. A replay, or a start refused before billing (an invalid or expired quote, its repository, a price above maxPriceCents, its documents), spends nothing from the start limit; a start that reaches billing counts even when it is refused there, as when its quoted change or commit has moved (quote_stale). Without a quote, the estimate the start makes counts toward the estimate limit.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Idempotency-KeyheaderstringnoRepeat a request safely: the same key and body return the original result; 1–255 characters
Body fieldTypeRequiredNotes
repositorystringyesRepository slug or full name, "owner/name"
atstringnoFull review position (default "default"). Mutually exclusive with change; at most 512 characters
changeobjectnoReview a change: { pr } (GitHub repositories only) or { branch, since? } (GitHub and hosted repositories)
steersstring[]noSaved Steers whose documents guide the run; at most 5 items
scopestring[]noFolders (ending in /) and files to review, relative to the repository root. Required for a full review: V12 reviews only what it names, and refuses a path that names no file it reviews at the position; at most 200 items
repositoriesobject[]noExtra repositories reviewed alongside; full reviews only; at most 8 items
steeringstringnoInstructions for the reviewers; at most 65536 characters
documentsstring[]no
maxPriceCentsintegeryesHighest price, in cents, the caller accepts; at least 0
quotestringno1–4096 characters

Returns 200, 201 with run, priceCents, replayed. Errors: 400, 401, 402, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Get a run

GET /orgs/{org}/runs/{run} · operationId getRun · Scopes: runs:read · MCP tool get_run

One run with its stages, progress, cost and finding import state. A failed or partial import says why in import.reason and on the inbox stage. import.count counts the run's reports; a report can join an existing finding, whose status (for example a won't-fix decision) then applies.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12

Returns 200 with number, title, state, phase, terminal, createdAt, startedAt, endedAt, source, repository, ref, sha, extraRepositories, retryOf, trigger, costCents, findings, error, webUrl, kind, cancellationRequested, steers, change, repositories, stage, stages, import, publicUrl, pullRequestCommentUrl. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

List a run's findings

GET /orgs/{org}/runs/{run}/findings · operationId listRunFindings · Scopes: runs:read, findings:read · MCP tool list_run_findings

Findings a completed run added to the inbox, positioned at each repository's analyzed commit; send position.at together with its repositories[i].repository for positioned reads. Without repository, inference reports repository_required if several registered repositories hold the finding at that position. Status and codeState describe that commit, not today's default head. Empty until import.state is "imported" or "partial"; a partial import lists only the findings that reached the inbox, and import.reason says why the rest did not. A finding can predate the run: runs lists every run that reported it.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12
limitqueryintegerno1–100; default 50
cursorquerystringno`nextCursor` from the previous page; 1–2048 characters

Returns 200 with nextCursor, items, import, asOf. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Estimate a run

POST /orgs/{org}/runs/estimate · operationId estimateRun · Scopes: runs:write · MCP tool estimate_run

Price a full review (at) or a change review (change) without starting it. Returns a quote to pass to start_run within 15 minutes. targets[].paths (or change.paths) lists up to 500 in-scope paths.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
repositorystringyesRepository slug or full name, "owner/name"
atstringnoFull review position (default "default"). Mutually exclusive with change; at most 512 characters
changeobjectnoReview a change: { pr } (GitHub repositories only) or { branch, since? } (GitHub and hosted repositories)
steersstring[]noSaved Steers whose documents guide the run; at most 5 items
scopestring[]noFolders (ending in /) and files to review, relative to the repository root. Required for a full review: V12 reviews only what it names, and refuses a path that names no file it reviews at the position; at most 200 items
repositoriesobject[]noExtra repositories reviewed alongside; full reviews only; at most 8 items
steeringstringnoInstructions for the reviewers; at most 65536 characters
documentsstring[]no

Returns 200 with kind, priceCents, balanceCents, targets, change, quote, expiresAt. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Cancel a run

POST /orgs/{org}/runs/{run}/cancel · operationId cancelRun · Scopes: runs:manage · MCP tool cancel_run

Cancel a queued or running run. A run that has already started stops at its next checkpoint (result "cancelling").

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12

Returns 200 with run, result. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

GET /orgs/{org}/runs/{run}/links · operationId listRunLinks · Scopes: runs:share · MCP tool list_run_links

A run's guest links, newest first, with their number, role, state and guest count. A link's number addresses it within the run. The full URL is never listed; urlPrefix helps recognise a link.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

POST /orgs/{org}/runs/{run}/links · operationId createRunLink · Scopes: runs:share, findings:read · MCP tool create_run_link

Create a link that opens this run to people outside the organization, without an account. Links are numbered 1, 2, 3… within the run, and a number is never reused. The API returns the full URL only in this response; owners can copy a live link again from the run's Share dialog. Works on any run but a draft, including one still running or with no findings.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12
Body fieldTypeRequiredNotes
role"view" | "comment" | "triage"nodefault "comment"
expiresInDaysintegernoDays from now until the link ends; 1–30; default 14
labelstringno1–80 characters

Returns 201 with link, url. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

PATCH /orgs/{org}/runs/{run}/links/{link} · operationId updateRunLink · Scopes: runs:share, findings:read · MCP tool update_run_link

Change a link's role, label or expiry (days from now), by run number and link number. A new expiry revives an expired link, within the live-link cap. A revoked link cannot change.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12
linkpathinteger | stringyesLink number within the run, e.g. 3
Body fieldTypeRequiredNotes
role"view" | "comment" | "triage"no
expiresInDaysintegernoDays from now until the link ends; 1–30
labelstring | nullnonull removes the label

Returns 200 with link. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

DELETE /orgs/{org}/runs/{run}/links/{link} · operationId revokeRunLink · Scopes: runs:share · MCP tool revoke_run_link

End a link now, by run number and link number; anyone using it loses access at their next request. Revoking twice returns the same link.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
runpathinteger | stringyesRun number within the organization, e.g. 12
linkpathinteger | stringyesLink number within the run, e.g. 3

Returns 200 with link. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Documents

OperationEndpointScopesMCP tool
Request a document upload slotPOST /orgs/{org}/documents/uploadsruns:writerequest_document_upload
Create a context documentPOST /orgs/{org}/documentsruns:writecreate_document
List context documentsGET /orgs/{org}/documentsruns:readlist_documents
Get a context documentGET /orgs/{org}/documents/{document}runs:readREST only
Archive a context documentDELETE /orgs/{org}/documents/{document}runs:writearchive_document

Request a document upload slot

POST /orgs/{org}/documents/uploads · operationId requestDocumentUpload · Scopes: runs:write · MCP tool request_document_upload

Get a URL to PUT a file to (up to 50 MiB, valid 10 minutes), then call create_document with the slot id. Types: PDF, Markdown, text, JSON, DOCX, CSV.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
filenamestringyes1–255 characters
contentTypestringyesMIME type of the file; 1–255 characters

Returns 201 with upload. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

Create a context document

POST /orgs/{org}/documents · operationId createDocument · Scopes: runs:write · MCP tool create_document

Add a context document runs can read: an uploaded file ({ upload }) or a text note ({ note }). Identical content returns the existing document with its original title (created: false); if that document was archived, this restores it (restored: true). An upload slot works once.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
Body fieldTypeRequiredNotes
uploadobjectno
noteobjectno

Returns 201 with document, created, restored. Errors: 400, 401, 403, 404, 405, 409, 413, 415, 429, 500, 503 (Errors).

List context documents

GET /orgs/{org}/documents · operationId listDocuments · Scopes: runs:read · MCP tool list_documents

Context documents of the organization, newest first. Archived documents are left out unless archived: true, which lists them beside the active ones. With repository, documents used by earlier runs on that repository come first and have recommended: true; it ranks, it does not filter.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
repositoryquerystringnoRepository slug or full name, "owner/name"
archivedquerybooleannoTrue also lists archived documents, each marked archived: true; the default lists active documents only; default false
limitqueryintegerno1–100; default 50
cursorquerystringno`nextCursor` from the previous page; 1–2048 characters

Returns 200 with nextCursor, items. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Get a context document

GET /orgs/{org}/documents/{document} · operationId getDocument · Scopes: runs:read · REST only

One context document by id.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
documentpathstringyesContext document id

Returns 200 with document. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

Archive a context document

DELETE /orgs/{org}/documents/{document} · operationId archiveDocument · Scopes: runs:write · MCP tool archive_document

Archive a document so new runs refuse it (estimate_run and start_run answer conflict). Creating identical content again restores it. Only its creator or an owner may archive it.

ParameterInTypeRequiredNotes
orgpathstringyesOrganization slug; must be the token's organization
documentpathstringyesContext document id

Returns 200 with document. Errors: 400, 401, 403, 404, 405, 409, 429, 500, 503 (Errors).

On this page