Overview
Your scanner flow, without the web: your server asks for a PIN, sends the link to the player, and reads the result when the scan is done. Data comes back as JSON; times are Unix seconds.
- Create a PIN with
POST /v1/pins/create. You get a link for the player. - The player opens the link, runs the scanner and enters the PIN.
- Read the result with
/v1/pins/:code/statusuntil it sayscompleted, then/v1/pins/:code/results.
Connection
- Base URL
https://anomaly.ac/api/v1- Authentication
- Send your key in the
x-api-keyheader on every call. Keys look likebyp_live_…, are shown once when created, and only a hash is stored. - Server label
- Optional
x-server-nameheader to tag which server made the call (shown in your usage logs). - Scopes
- Each key carries the scopes you chose when you created it. A call without the scope its endpoint needs gets a 403. Enterprise leaders and the owner can add
db:query.
Who asked for a scan
The API key belongs to one account (usually the enterprise owner), so every PIN created with it would be attributed to that account. To record the staff member who really asked, pass their Discord ID in requested_by when you create the PIN, for example the ID of the person who ran the command in your bot or resource.
- Verified — the ID belongs to a member of the key owner's enterprise. Their name and avatar appear on the scan, in the scan list, in the member filters and in the Enterprise page.
- Unverified — any other valid ID. It is stored and shown with the name you sent in
requested_by_nameand an unverified mark, because Anomaly cannot check who pressed the button on your side. Keep one key per server so each call can be traced. - Without the field — the scan is attributed to the key owner, as before. PINs created earlier keep working the same way.
The same ID is returned as requested_by by the status, results and history endpoints. If that staff member's own Discord account is logged in on the PC being scanned, the scan is rejected as a self-scan, as it already is for the key owner.
curl -X POST https://anomaly.ac/api/v1/pins/create \
-H "x-api-key: byp_live_xxxxxxxx" \
-H "x-server-name: my-fivem-server" \
-H "content-type: application/json" \
-d '{"label": "Juan P.", "requested_by": "123456789012345678"}'Endpoints
/v1/pins/createscope: pins:createCreate a single-use scan PIN and get its share link for the player.
label | string, optional | A name for the PIN, up to 60 characters (the player's name, a ticket number…). |
game | string, optional | Which game the scan checks. Defaults to "fivem" when left out, so existing integrations keep working unchanged. An unknown or unavailable game answers 400. |
requested_by | string, optional | Discord ID (17–20 digits) of the staff member who asked for the scan. See “Who asked for a scan”. Ignored if it is not a valid ID. |
requested_by_name | string, optional | Display name for that staff member, up to 40 characters. Shown when they are not a member of your enterprise. |
curl -X POST https://anomaly.ac/api/v1/pins/create \
-H "x-api-key: byp_live_xxxxxxxx" \
-H "content-type: application/json" \
-d '{"label": "Juan P.", "requested_by": "123456789012345678", "requested_by_name": "Pedro"}'{
"pin": "442887",
"game": "fivem",
"url": "https://anomaly.ac/p/442887",
"expires_at": 1794175575,
"requested_by": "123456789012345678"
}- 400 — the game is not valid or not available yet.
- 409 — you already have the maximum number of active PINs (10 in an enterprise).
/v1/pins/:code/statusscope: pins:statusWhere a PIN is: waiting, used, expired, revoked, or completed with a scan.
{
"pin": "442887",
"status": "completed",
"progress": 100,
"scanned": true,
"requested_by": "123456789012345678",
"requested_by_name": "Pedro",
"result": { "scan_id": "7d98…", "verdict": "suspicious", "findings": 3 }
}- 404 — the PIN does not exist or is not yours to see.
/v1/pins/:code/resultsscope: pins:resultsSummary of the scan done with a PIN: verdict, finding counts by severity, rights, country and VPN.
{
"id": "7d98…",
"pin": "442887",
"verdict": "detected",
"findings": 2,
"severity": { "high": 1, "medium": 0, "low": 1 },
"elevated": true,
"country": "ES",
"vpn": false,
"scanned_at": 1794173786,
"requested_by": "123456789012345678",
"requested_by_name": "Pedro"
}- 404 — no such PIN, or the player has not run the scan yet.
/v1/scanned-users/lookup/:discordIdscope: scanned-users:lookupScan history of a Discord account you can see: the PIN owner and, in an enterprise, the teammates your permissions allow.
{
"discord_id": "1255107975165771816",
"username": "Pedro",
"summary": { "total": 4, "detections": 1, "needs_review": 2, "last_verdict": "detected" },
"scans": [ { "id": "7d98…", "pin": "442887", "verdict": "detected", "findings": 2, "…": "…" } ]
}- 400 — not a valid Discord ID.
- 404 — no data for that account, or not permitted.
/v1/users/:discordId/risk-scorescope: user:risk-scoreRisk score (0–100) of an account, taken from its most severe scan. level is none (0), low (1–32), medium (33–65) or high (66 and up).
{
"discord_id": "1255107975165771816",
"risk_score": 62,
"level": "medium",
"scans": 4,
"detections": 1
}- 400 — not a valid Discord ID.
- 404 — no data for that account, or not permitted.
/v1/db/query/:discordIdscope: db:queryDetection-database profile of an account. Never exposes the signatures themselves.
{
"discord_id": "1255107975165771816",
"known": true,
"username": "Pedro",
"scans": 4,
"detections": 1,
"flagged": true,
"risk_level": "medium"
}- 403 — only the owner and enterprise leaders can query this, and only within their enterprise.
/v1/versionpublicCurrent Anomaly version. The only endpoint that needs no key.
{ "name": "Anomaly", "version": "1.0.0", "platform": "windows" }Verdicts are clean, suspicious (needs review) or detected (a high-confidence finding). The web shows a risk level (Low, Medium, High, Critical) instead; the API still returns the verdict and the 0–100 risk score. An MCP server for agents is planned and not yet available.
Errors
Errors come back as { "error": "message" } with one of these status codes.
400 | The request is malformed, for example an invalid Discord ID. |
401 | No x-api-key header, or the key is invalid or revoked. |
403 | The key lacks the scope the endpoint needs, its account has no active license or enterprise, or you are not allowed to query that account. |
404 | Not found, not yours to see, or there is no result yet. |
409 | You already have the maximum number of active PINs. |
429 | More than 1,000 requests in the hour with this key. |
Limits and logging
1,000 requests per hour per API key, shared across all endpoints. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers.
Every authenticated call is logged with the first 12 characters of the key, the endpoint, the calling IP and the optional x-server-name, kept for 90 days. Reading a scan through the API is also recorded in that scan's access history.
Your API keys
Sign in to create and manage API keys.