Programmatic access to the full Site+ Scan (350+ checks) and every individual module. JSON in, JSON out. One header for auth, one body field for the domain, one cap (250 requests/day per account).
API + MCP access is an Agency-plan feature ($99/mo or $1,000/yr).
Free and Pro can read these docs, but only Agency accounts can mint a token. See pricing →
Quickstart
From zero to a scan in four steps.
1Upgrade to Agency. The API surface is Agency-only. See plans →
2Mint your token in /settings → API Token. One active token per account — copy it the moment we show it, because we hash it on save and can't recover the plaintext.
3Send the token as a Bearer header (or x-api-key — pick whichever your client likes).
4Call an endpoint with a JSON body. All POST endpoints take { "domain": "..." }.
Every request must carry a valid API token. Two headers are accepted — pick whichever fits your client. You can only have one active token at a time, and the plaintext is only visible at creation; if you lose it, revoke and mint a fresh one in /settings.
Keys are bound to your account, not to any one IP — use them from any host. Your plan tier is re-checked on every request, so a downgrade demotes API access immediately (even on previously-minted tokens). Revoke the token in /settings if it leaks.
Rate limit
250 requests / 24 h per Agency account.The window is a rolling 24 hours from your oldest in-window call.
When you exceed:
HTTP/1.1 429 Too Many Requests
{ "error": "API daily cap reached (250/day). Resets at 2026-05-14T...Z.",
"code": "rate_limit",
"used": 250,
"cap": 250,
"resetAt": "2026-05-14T..." }
All endpoints return JSON. All POST bodies take a domain field. Base URL: https://acuityscan.com.
POST/api/v1/scan
Run a full Site+ Scan
Runs all 8 modules in parallel and returns the complete result. Synchronous — typical 30s, up to 5 min on heavy sites (the perf module uses real Lighthouse).
Many real-world sites are behind a WAF or bot manager (Cloudflare, Akamai, Imperva, DataDome, etc.) that challenges automated traffic with a JavaScript test before letting it through to the origin. Our scanner can't solve that challenge, so the modules that need to read the page's HTML can't complete.
The response still returns 200 OK. The top-level blocked object tells you which modules were affected and how bad the block was. overallScore is either a partial average (modules that ran) or null depending on severity.
Recommended client code: branch on result.blocked.severity. For major, don't treat overallScore as comparable to other scans (it's null). For partial, surface the message and treat the score as a partial audit. Individual moduleResults[id].blocked carries per-module vendor + reason if you need fine-grained detail.
Error codes
Every error response carries { error, code }. Thecode is the machine tag; branch on it.
Status
Code
Meaning
401
missing
No Authorization or x-api-key header sent.
401
invalid_format
Token doesn't start with asc_live_.
401
unknown
Token isn't in our database — likely typo'd or never existed.
401
revoked
Token was revoked in /settings.
403
downgraded
Account is no longer on the Agency plan. Upgrade to re-enable.
400
invalid_domain
Domain shape rejected. Use "example.com", no protocol or path.
400
unsafe_target
Domain resolved to a private/internal IP. SSRF guard refused the scan.
429
rate_limit
Account hit 250 requests/day. Resets 24 h after the oldest in-window call.
500
internal
Scanner crashed. Check status page; if persistent, contact support.
Use AcuityScan from your AI client
We ship an open-source Model Context Protocol server that wraps every endpoint above as an MCP tool. Drop it into Claude Desktop, Cursor, or Continue and ask in plain English: “run a full AcuityScan on stripe.com.”
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):