API Reference
The REST API behind the CLI, hook, and dashboard.
Base URL: https://api-production-2617.up.railway.app. Every endpoint here is what the CLI, the
hook, and the dashboard's own frontend actually call — nothing hidden behind a separate
"internal" API.
Authentication
Two schemes, depending on the caller:
A long-lived key from aevrin login / aevrin hook setup, or minted manually from
Settings → API Keys on the dashboard. Sent as a header:
curl -H "X-API-Key: aevrin_xxxxx" https://api-production-2617.up.railway.app/cli/precheckA few endpoints (like finding triage) accept either — API key or JWT — since both the
dashboard and aevrin findings triage need to call them.
Scans
| Method & path | Auth | Description |
|---|---|---|
POST /scans | JWT | Start a scan (dashboard-initiated). Runs async; poll stages/status. |
GET /scans | JWT | List your 25 most recent scans, newest first. |
GET /scans/{id} | JWT | Get one scan's status, score, and reliability info. |
GET /scans/{id}/stages | JWT | Per-stage status (cloning, static analysis, secrets, dependencies, tool description check, aggregating). |
GET /scans/{id}/findings | JWT | Full findings list for a scan. |
GET /scans/{id}/export | JWT | OWASP MCP-mapped HTML report with Print / Save as PDF (Hobby/Team only). |
DELETE /scans/{id} | JWT | Delete one owned scan with its stages and findings. |
DELETE /scans | JWT | Clear all scan history owned by the current account. |
CLI upload
| Method & path | Auth | Description |
|---|---|---|
GET /cli/precheck | API key | Read-only quota check the CLI calls before running a local scan, so a quota-exhausted account fails fast instead of scanning first. |
POST /cli/upload | API key | Persists a CLI-run scan's result. The score is recomputed server-side from the submitted findings — the client-submitted score is never trusted outright. See Concepts → Self-reported results. |
Hook
| Method & path | Auth | Description |
|---|---|---|
POST /hook/cache | API key | Body-based cached-decision lookup the current hook calls before every install, keeping pasted configuration out of request URLs. Never runs a scan synchronously; triggers a background scan on a cache miss. |
GET /hook/cache | API key | Backward-compatible URL-query lookup for older hooks. Current clients use POST. |
POST /hook/override | API key | Backs aevrin hook allow <target> — grants a 10-minute install-anyway override. |
Findings
| Method & path | Auth | Description |
|---|---|---|
GET /findings/{id} | JWT | One finding's full detail. |
PATCH /findings/{id} | JWT or API key | Update triage status (open, fixed, false_positive); false positives require a stored reason. |
Account
| Method & path | Auth | Description |
|---|---|---|
GET /account/usage | JWT | Current-period limits plus the latest 50 attributed CLI, hook, and dashboard scans with report IDs. |
Billing
| Method & path | Auth | Description |
|---|---|---|
GET /billing/subscription | JWT | Stored and effective tier plus paid-through time. |
POST /billing/checkout | JWT | Create a USD Razorpay order for one monthly or annual cycle. |
POST /billing/verify | JWT | Verify checkout signature and activate the paid period. |
POST /billing/webhook | Razorpay signature | Recover a captured payment when the browser verification callback did not complete. |
Device authorization
The CLI and hook use an RFC 8628-style browser approval flow. POST /device/code issues the
one-time user code and polling secret; POST /device/token returns only pending/slow-down/error
states until the signed-in browser approves that code. These endpoints are used by aevrin login
and aevrin hook setup; applications should prefer manually created API keys for automation.
API keys
| Method & path | Auth | Description |
|---|---|---|
GET /api-keys | JWT | List your API keys (never returns plaintext after creation). |
POST /api-keys | JWT | Mint a new API key — plaintext shown exactly once. |
DELETE /api-keys/{id} | JWT | Revoke a key. |
Errors
Standard HTTP status codes. 402 Payment Required specifically means a scan quota is used up
for the current billing period — the response body always includes bucket, resets_at, and
upgrade_url so a caller can build a real message instead of a bare refusal.
{
"detail": "cli quota exceeded",
"bucket": "cli",
"resets_at": "2026-09-01T00:00:00Z",
"upgrade_url": "https://mcp.aevrin.net/pricing"
}