Aevrin

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/precheck

A 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 & pathAuthDescription
POST /scansJWTStart a scan (dashboard-initiated). Runs async; poll stages/status.
GET /scansJWTList your 25 most recent scans, newest first.
GET /scans/{id}JWTGet one scan's status, score, and reliability info.
GET /scans/{id}/stagesJWTPer-stage status (cloning, static analysis, secrets, dependencies, tool description check, aggregating).
GET /scans/{id}/findingsJWTFull findings list for a scan.
GET /scans/{id}/exportJWTOWASP MCP-mapped HTML report with Print / Save as PDF (Hobby/Team only).
DELETE /scans/{id}JWTDelete one owned scan with its stages and findings.
DELETE /scansJWTClear all scan history owned by the current account.

CLI upload

Method & pathAuthDescription
GET /cli/precheckAPI keyRead-only quota check the CLI calls before running a local scan, so a quota-exhausted account fails fast instead of scanning first.
POST /cli/uploadAPI keyPersists 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 & pathAuthDescription
POST /hook/cacheAPI keyBody-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/cacheAPI keyBackward-compatible URL-query lookup for older hooks. Current clients use POST.
POST /hook/overrideAPI keyBacks aevrin hook allow <target> — grants a 10-minute install-anyway override.

Findings

Method & pathAuthDescription
GET /findings/{id}JWTOne finding's full detail.
PATCH /findings/{id}JWT or API keyUpdate triage status (open, fixed, false_positive); false positives require a stored reason.

Account

Method & pathAuthDescription
GET /account/usageJWTCurrent-period limits plus the latest 50 attributed CLI, hook, and dashboard scans with report IDs.

Billing

Method & pathAuthDescription
GET /billing/subscriptionJWTStored and effective tier plus paid-through time.
POST /billing/checkoutJWTCreate a USD Razorpay order for one monthly or annual cycle.
POST /billing/verifyJWTVerify checkout signature and activate the paid period.
POST /billing/webhookRazorpay signatureRecover 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 & pathAuthDescription
GET /api-keysJWTList your API keys (never returns plaintext after creation).
POST /api-keysJWTMint a new API key — plaintext shown exactly once.
DELETE /api-keys/{id}JWTRevoke 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.

402 response shape
{
  "detail": "cli quota exceeded",
  "bucket": "cli",
  "resets_at": "2026-09-01T00:00:00Z",
  "upgrade_url": "https://mcp.aevrin.net/pricing"
}