REST API
Endpoints, request shapes and error codes of the Patchlight API.
curl https://api.patchlight.dev/v1/balance \
-H "Authorization: Bearer pl_sk_..."Every /v1 route takes a workspace API key from the API Keys page of the dashboard and only sees that workspace:
an organization key sees the organization's data, a personal key only personal data.
The SDK wraps all of this, including polling, retries and idempotency, with no runtime dependencies.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/reviews | Submit a diff for review |
GET | /v1/reviews | Recent reviews |
GET | /v1/reviews/:id | Review status, summary, error and timestamps |
GET | /v1/reviews/:id/findings | { status, findings }, empty until the review is done |
POST | /v1/repos/:id/scan | Start a security scan |
GET | /v1/scans/:id | Scan status, cost and findingsCount |
GET | /v1/scans/:id/findings | { status, findings }, empty until the scan is done |
GET | /v1/findings | Recent findings across the workspace |
PATCH | /v1/findings/:id | Triage a finding |
GET | /v1/repos | Repositories in the workspace |
GET | /v1/balance | Remaining USD balance |
GET | /health | Health check, no key needed |
All timestamps (createdAt, startedAt, completedAt, finishedAt) are ISO-8601 strings.
Reviews
POST /v1/reviews returns 202 with { review: { id, status } }.
| Field | Required | Limits | Description |
|---|---|---|---|
repo | yes | 256 chars, [\w./@-] | Repository name shown in the dashboard |
diff | yes | 1 MB | Unified diff to review |
files | no | 100 files, 200 KB each, 5 MB total | Path to content, for review context |
ref | no | 200 chars | Reviewed commit sha or branch |
baseRef | no | 200 chars | Base branch of the diff |
title | no | 500 chars | Review title |
Send an Idempotency-Key header to make the submit safe to repeat for 24 hours. A repeat with the
same key returns the original review with 200 instead of creating a new one.
A review moves queued → running → done, or ends in one of two other final statuses:
failed: the worker errored, and the reason is inerror.skipped: a monthly spend cap or repository budget blocked it before any work started. It never advances, so polling fordoneruns into your timeout.
| Status | error | Meaning |
|---|---|---|
400 | invalid_request | Malformed body. Details in message |
401 | missing_api_key / invalid_api_key | Absent or unknown key |
401 | revoked_key | The key was revoked in the dashboard |
401 | expired_token | A patchlight login session expired. Sign in again |
402 | insufficient_funds | Balance below the review cost. Body includes balance and required, in USD |
402 | spend_cap_reached | Monthly workspace cap or repository budget reached. scope is workspace or repo; body includes capUsd and spentUsd |
404 | not_found | The review is not in this workspace |
413 | payload_too_large | Diff or file limits exceeded |
429 | too_many_pending_reviews | More than 10 API reviews queued or running |
503 | queue_unavailable / reviews_not_configured | Temporary platform issue. Retry later |
Scans
POST /v1/repos/:id/scan returns 202 with { scanId, status }. :id is a repository id from
GET /v1/repos, not an owner/repo name.
A scan reads a whole repository, so it needs one connected through the GitHub App. A repository
created by POST /v1/reviews has no git connection and cannot be scanned. Scans are billed per
token.
| Status | error | Meaning |
|---|---|---|
400 | repo_not_scannable | The repository has no GitHub connection |
402 | insufficient_funds | Balance below the minimum to start a scan |
402 | spend_cap / repo_budget | Monthly workspace cap or repository budget reached |
404 | repo_not_found | The repository is not in this workspace |
409 | already_running | That repository already has a scan queued or running |
424 | github_disconnected | The GitHub App was removed or suspended for this account. Reinstall it |
503 | scan_runner_not_configured | Scan runner unavailable. Retry later |
Findings
Every route that returns findings uses the same shape. Exactly one of reviewId and scanId is
set, and cwe is only set on scan findings.
PATCH /v1/findings/:id takes { "status": "open" | "resolved" | "dismissed" } and returns
{ finding: { id, status } }. It accepts review and scan finding ids alike, and returns 404 when
the finding is not in the key's workspace.