Public API
Authenticate with personal access tokens or OAuth, and connect to V12's REST API or MCP server.
V12 exposes a REST API at /api/v1/* and a remote MCP server at /api/mcp, so you can run audits, read findings, and triage results from your own tools and scripts.
- Connecting an IDE or agent → MCP server
- Calling from scripts or CI → REST API or the CLI
- Full schema →
/api/v1/openapi.json
Authentication
Authenticated API requests take a Bearer token in the Authorization header:
curl -H 'Authorization: Bearer <token>' https://v12.sh/api/v1/meTwo token kinds work on authenticated endpoints:
- Personal access tokens (
v12p_*)—created at Settings → Developer for the currently selected organization. Shown once on creation. PATs don’t expire by default. - OAuth access tokens (
v12a_*)—issued via the OAuth flow. Access tokens last 1 hour; refresh tokens (when issued) last 30 days. The consent flow binds them to the organization you had selected when you approved the client.
OAuth
Use OAuth when a third-party tool needs to act on your behalf. Paste the V12 server URL into the tool and complete the sign-in prompt—the tool handles the token exchange itself. Claude Desktop, Cursor, Codex, VS Code, and Windsurf are known to work end-to-end. Manage authorized apps at Settings → Developer.
Implementing your own OAuth client
If you’re building the client side yourself:
-
Read the metadata from
GET /.well-known/oauth-authorization-server. -
Register at
POST /api/oauth/register(Dynamic Client Registration, RFC 7591). -
Send the user to
/oauth/authorize:/oauth/authorize?response_type=code&client_id=<client_id>&redirect_uri=<redirect_uri>&state=<random>&code_challenge=<S256(verifier)>&code_challenge_method=S256&scope=runs:read+runs:write -
Exchange the returned code at
POST /api/oauth/token(grant_type=authorization_code). -
Refresh with
grant_type=refresh_tokenonly if the client registered with the explicitrefresh_tokengrant. DCR clients default to authorization-code-only access.
Scopes
| Scope | Label | Description |
|---|---|---|
runs:read |
View runs | List runs, read reports and findings |
runs:write |
Create runs | Start new audit runs and upload source archives. Consumes credits. |
runs:manage |
Manage runs | Cancel runs you own through the public API and MCP |
findings:write |
Edit findings | Change finding status, add comments, and update triage decisions |
repos:read |
View repositories | List GitHub repositories connected to V12 for your account |
user:read |
View profile | Read your account information and credit balance |
New tokens default to runs:read, user:read, and repos:read. Writes (runs:write, runs:manage, findings:write) are opt-in via the scope picker in Settings → Developer.
Vocabulary
Severity (severity filter values, PATCH payloads, finding fields): critical, high, medium, low, info, qa.
Validity (validity filter values, PATCH payloads, finding fields): valid, invalid (false positive), unreviewed, acknowledged (real but accepted).
Run states (state field on run objects): queued, running, completed, failed, cancelled. Terminal states (no further transitions): completed, failed, cancelled.
Rate limits
Limits are per-user buckets. Hitting a limit returns 429 Too Many Requests with a Retry-After header.
| Bucket | Limit | Window |
|---|---|---|
Writes (runs:write) |
20 | 1 hour |
Management (runs:manage) |
30 | 1 hour |
Finding writes (findings:write) |
60 | 1 hour |
| Reads | 300 | 1 minute |
| MCP protocol requests | 120 | 1 minute |