On this page
Reference

API Reference

The REST API behind the CLI, the dashboard and Aevrin MCP.

Base URL: https://api.mcp.aevrin.net. Every endpoint here is what the CLI, the dashboard's own frontend, and Aevrin MCP actually call. Nothing is hidden behind a separate "internal" API.

Authentication

Two schemes, depending on the caller:

A long-lived key from aevrin login, or minted manually from Settings → API Keys on the dashboard. Sent as a header:

curl -H "X-API-Key: aevrin_xxxxx" https://api.mcp.aevrin.net/cli/precheck

A few endpoints, such as finding triage, accept either an API key or a 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. On a scan that did not finish, fallback_report may hold a public report from an earlier scan of the same server: someone else's result, never this scan's.
GET /scans/{id}/stagesJWTPer-stage status (resolving, launching, enumerating, analyzing, grading).
GET /scans/{id}/findingsJWTFull findings list for a scan. A finding an AI review looked at carries ai_review (verdict: likely-real, likely-false-positive or unsure, with explanation, provider, model).
GET /scans/{id}/engine-reportJWT or API keyThe scan engine's full JSON report for this scan, exactly as stored. 404 with the reason when there is none (still running, stopped before the engine answered, an older scan or CLI, or larger than 1 MB).
POST /scans/{id}/ai-reviewJWT or API keyAn AI second opinion on each finding, from your own AI provider, saved with the scan. Never changes a finding or the grade. At most 10 an hour. 409 when there is nothing to review; 200 with available: false and a reason when no provider could answer.
GET /scans/{id}/exportJWTOWASP MCP-mapped HTML report with Print / Save as PDF (Pro 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 credit check the CLI calls before running a local scan, so an account without the scan's 50 credits fails fast instead of scanning first.
POST /cli/uploadAPI keyPersists a CLI-run scan's result. The grade is the one the CLI reported; it is not recomputed. An upload that contradicts itself (a grade with no enumerated tools, or an A or B beside a critical or high finding) is refused with 422. It may carry the engine's JSON report (engine_report, at most 1,000,000 bytes, else 422) and each finding's engine id as raw: {"id": ...}. See Concepts → Self-reported results.

Findings

Method & pathAuthDescription
GET /findings/{id}JWTOne finding's full detail, with ai_review when an AI review of its scan looked at it.
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 credits (allowance, used, remaining, top-up balance), the per-action costs, activity counts, and the latest 50 attributed scans with report IDs.

Billing

Method & pathAuthDescription
GET /billing/pricingNonePro's monthly and annual prices and the credit top-up's one-time price in the caller's currency (USD, or INR from India), in cents or paise.
GET /billing/subscriptionJWTStored tier, the tier actually enforced (free or pro; free once the paid cycle has lapsed), and paid-through time.
POST /billing/checkoutJWTCreate a Razorpay order for Pro (tier: "pro", one monthly or annual cycle) or a credit top-up (tier: "credit_topup", cycle: "one_time"), in USD or INR by the caller's location.
POST /billing/verifyJWTVerify checkout signature and activate the paid period, or grant the top-up's 5,000 credits.
POST /billing/webhookRazorpay signatureRecover a captured payment when the browser verification callback did not complete.
GET /billing/paymentsJWTYour checkouts, most recent first, including ones that did not complete.

Capabilities

The routes behind Aevrin MCP. The hosted MCP server calls them with the key your agent sent; you would not normally call them yourself. GET /capabilities/search returns published capabilities only; GET /capabilities/{slug} and the run route also reach an unlisted one by its exact slug, which is obscurity rather than access control. Searching is free; a retrieval spends 1 credit and a run 10 more. A retrieval may be answered from a five-minute cached copy, and it costs the same. The three /capabilities/scans routes are the scan tools: they work like POST /scans and GET /scans/{id} for the key's owner, spend a scan's 50 credits per scan started, and work whether or not capability execution is on.

Method & pathAuthDescription
GET /capabilities/sessionAPI keyConfirms the key is valid and the account is active.
POST /capabilities/scansAPI keyStart a scan of a public GitHub repository (github_repo) or a live https MCP server (live_mcp_server) for the key's owner. Body {target_type, target}; a pasted config is 422. Spends a scan's 50 credits.
GET /capabilities/scans/{id}API keyOne of the key owner's scans, as GET /scans/{id} returns it. 404 for anyone else's. Not counted.
GET /capabilities/scans/{id}/findingsAPI keyIts findings, most severe first, as GET /scans/{id}/findings returns them. Not counted.
GET /capabilities/searchAPI keyPublished capabilities matching a query, with the fields an administrator wrote for each.
GET /capabilities/{slug}API keyOne capability by slug, with the instructions an administrator wrote and the tools Aevrin can run for it. Published, or unlisted by its exact slug. Spends 1 credit.
POST /capabilities/{slug}/runAPI keyRuns one tool of a capability. Body {tool, input, max_age_s}; max_age_s says how old an answer the caller accepts and 0 runs it fresh. The response carries cached, and untrusted: true on every result. Returns 503 not_enabled while capability execution is off, which is the case today.

These routes refuse rather than allow when the account check cannot complete: a database error returns 503, never a result.

Agent posture

What aevrin agent scan --upload sends, and what the dashboard's AI security views read back.

Every route here takes either a JWT or an API key, because the CLI uploads and the dashboard reads.

Method & pathAuthDescription
POST /agents/snapshotsJWT or API keyStore one machine's agent-configuration snapshot. Replaces that machine's previous record, carries no credential value, and is metered as one agent posture scan however many agents it reports.
GET /agentsJWT or API keyEvery device that has reported, with its score.
GET /agents/{id}JWT or API keyOne device in full: capabilities with their evidence, MCP servers, skills, permission rules, and the files that were read.
DELETE /agents/{id}JWT or API keyForget a device. Aevrin's copy goes; the machine's own configuration is untouched.
GET /agents/mcp-serversJWT or API keyEvery MCP server across every reported device, correlated: one entry per server, not per configuration file.
GET /agents/skillsJWT or API keyEvery skill installed on every reported device.
GET /agents/permissionsJWT or API keyEvery permission rule across every device, exactly as written.
GET /agents/attack-pathsJWT or API keyPaths with evidence behind every step. Speculative chains are absent.

Device authorization

The CLI uses 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; 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. The plaintext is shown exactly once.
DELETE /api-keys/{id}JWTRevoke a key.

Errors

Standard HTTP status codes. 402 Payment Required means your credits for the current billing period are not enough for what the action costs, or a plan limit was reached (the monitored-device count, or Aevrin MCP's compute time). The response body always includes bucket, resets_at, and upgrade_url so a caller can build a real message instead of a bare refusal, and the shape is the same whichever limit refused.

402 response shape
{
  "detail": "Not enough credits for an MCP scan: it costs 50, 20 left. The monthly allowance resets on 2026-09-01; upgrading or topping up adds credits now.",
  "bucket": "credits",
  "resets_at": "2026-09-01T00:00:00Z",
  "upgrade_url": "https://varq.aevrin.ai/settings/billing"
}