Anomaly API · v1.0.0

API reference

Create PINs and read scan results from your own bot or game server. Authenticated with API keys, 1,000 requests per hour per key.

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.

  1. Create a PIN with POST /v1/pins/create. You get a link for the player.
  2. The player opens the link, runs the scanner and enters the PIN.
  3. Read the result with /v1/pins/:code/status until it says completed, then /v1/pins/:code/results.
Requirements. An active license or enterprise membership is needed to create and use API keys. What a key can read follows your enterprise permissions: operators see only their own scans, reviewers and publishers see the team's.

Connection

Base URL
https://anomaly.ac/api/v1
Authentication
Send your key in the x-api-key header on every call. Keys look like byp_live_…, are shown once when created, and only a hash is stored.
Server label
Optional x-server-name header 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_name and 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

POST/v1/pins/createscope: pins:create

Create a single-use scan PIN and get its share link for the player.

labelstring, optionalA name for the PIN, up to 60 characters (the player's name, a ticket number…).
gamestring, optionalWhich game the scan checks. Defaults to "fivem" when left out, so existing integrations keep working unchanged. An unknown or unavailable game answers 400.
requested_bystring, optionalDiscord 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_namestring, optionalDisplay 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).
GET/v1/pins/:code/statusscope: pins:status

Where 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.
GET/v1/pins/:code/resultsscope: pins:results

Summary 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.
GET/v1/scanned-users/lookup/:discordIdscope: scanned-users:lookup

Scan 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.
GET/v1/users/:discordId/risk-scorescope: user:risk-score

Risk 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.
GET/v1/db/query/:discordIdscope: db:query

Detection-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.
GET/v1/versionpublic

Current 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.

400The request is malformed, for example an invalid Discord ID.
401No x-api-key header, or the key is invalid or revoked.
403The key lacks the scope the endpoint needs, its account has no active license or enterprise, or you are not allowed to query that account.
404Not found, not yours to see, or there is no result yet.
409You already have the maximum number of active PINs.
429More 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.