API overview
REST, MCP and the CLI over one API: what they cover and the rules they share.
V12 has one API with three ways in: REST for scripts and services, an MCP server for AI assistants, and the v12 command-line tool. All three cover findings, runs, context documents, repositories, focuses and members. REST offers all 24 operations, and MCP offers 21 of them as tools.
Every token acts on exactly one workspace, an organization or your personal workspace, and cannot switch to another.
API quickstart
Create an API key and make your first REST call.
Connect an MCP client
Give your AI assistant V12's tools at https://v12.sh/api/mcp.
CLI
Install the v12 command and use it in a terminal or in CI.
Recipes
Triage the inbox and start a run within a price limit.
REST reference
Every endpoint under https://v12.sh/api/v2, with its scopes and errors.
Authentication
Send Authorization: Bearer <token> with every request, where the token is an API key or an OAuth access token. Authentication and permissions explains scopes, which workspace a token reads, and why a request is refused.
Positions
Operations that read code state take an optional at, which names a position in a repository:
at | Position |
|---|---|
default | The head of the default branch V12 uses for the repository |
branch:<name> | The head of a branch |
pr:<number> | The head of a pull request |
commit:<sha> | A commit, by its full 40-character SHA |
Leaving out at means default.
Responses report the commit they evaluated as position.at, pinned to its SHA, for example branch:main@<sha>. Send that value back to stay on the same commit after the branch moves on.
If V12 cannot resolve the position, the API answers 409 position_unavailable, and details.reason says why, for example unknown-branch or unknown-pull-request.
Pagination
Lists return items and nextCursor. For the next page, repeat the request with cursor set to nextCursor and the same filters, until nextCursor comes back null. A cursor sent with different filters is refused with 400 invalid_request.
Where a list takes limit, it sets the page size: 1 to 100, 50 by default.
Safe retries
A run start and a comment accept an idempotency key: the Idempotency-Key header in REST, or the requestId argument in MCP. A retry with the same key and the same request returns the original result instead of starting a second run or posting a second comment. Reusing a key for a different request is refused with 409 idempotency_key_reused.
POST /runs needs either a key or the quote from an estimate. The CLI sends a key for you.
Finding changes set a state, so repeating one changes nothing: findings already in the requested state are skipped.
Errors and limits
Every error has the same JSON body: error.code, error.message, optional error.details, and a requestId that matches the X-Request-Id header. The error reference lists every code.
Each user has request budgets, reported in X-RateLimit-* headers on every response; see Rate limits.
The retired /api/v1 answers every request with 410 api_version_retired. Move to /api/v2, and to version 1.0 of the CLI.