Skip to content

Developers

Scanpoof API

Run accessibility scans from your pipeline, pull scores and issues into your own dashboards, and fetch ready-to-apply fixes for a site you own. Everything the WordPress plugin does, it does through this API.

https://scanpoof.com/api/v1Get an API key →

Quick start

  1. 1. Add and verify the site in your Scanpoof account. Fixes and scans only work on domains you have proved you control.
  2. 2. Create an API key from Sites → API keys. The key is shown once — store it as a secret.
  3. 3. Activate the key on the domain. One key works on exactly one site.
curl -X POST https://scanpoof.com/api/v1/activate \
  -H "Authorization: Bearer adap_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"domain":"scanpoof.com"}'

Authentication

Send your key as a bearer token on every request. Keys start with adap_. We store only a SHA-256 hash of the key, so a lost key cannot be recovered — generate a new one instead.

Authorization: Bearer adap_your_key_here

One key, one site. A key binds to the first domain it is activated on and only works for that domain afterwards. This keeps a leaked key from touching the rest of your account. Move a key with /deactivate, or mint a new one per site.

Errors

Errors return a JSON body with a human-readable error and, where you might want to branch on it, a stable code.

{ "error": "Activate this key on the site first.", "code": "activate_required" }
StatusCodeMeaning
401Missing, malformed or unknown API key.
402upgrade_requiredApplying fixes needs a paid plan. Scanning still works.
403activate_requiredThe key has not been activated on a domain yet.
403no_siteThat domain is not in your account.
403verify_requiredThe domain is added but ownership is not verified.
404No matching site, scan or resource.
409bound_elsewhereThis key is already active on another domain.

Endpoints

GET/api/v1/me

Who this key belongs to, and every site in the account with its latest accessibility score. Useful as a connectivity check.

auth: API key

curl https://scanpoof.com/api/v1/me -H "Authorization: Bearer adap_..."

Response

{
  "org": { "name": "Scanpoof", "plan": "agency" },
  "sites": [
    { "id": "cmx...", "domain": "scanpoof.com", "score": 76 }
  ]
}
POST/api/v1/activate

Bind this key to one domain. Required before /fixes, /rescan and /scan-status will work.

auth: API key

FieldMeaning
domainThe site's hostname. Scheme, port, path and a leading www. are stripped for you.
curl -X POST https://scanpoof.com/api/v1/activate \
  -H "Authorization: Bearer adap_..." \
  -H "Content-Type: application/json" \
  -d '{"domain":"scanpoof.com"}'

Response

{ "activated": true, "domain": "scanpoof.com" }
The domain must already be added and verified in your account. Activating a domain that another key already holds retires that older key, so re-installing never leaves a stale key behind.
POST/api/v1/deactivate

Release the key from its domain so it can be activated somewhere else.

auth: API key

curl -X POST https://scanpoof.com/api/v1/deactivate -H "Authorization: Bearer adap_..."

Response

{ "deactivated": true }
GET/api/v1/overview

The full dashboard bundle for the activated site: composite score and letter grades, severity counts, 30-scan history, top issues ranked by impact with a fix-effort estimate, per-tool scores (performance, SEO, AI-readiness, security, uptime), remediation progress and alerts.

auth: API key · must be activated

Response

{
  "site": "scanpoof.com",
  "overall": 61,
  "grades": { "overall": "D", "accessibility": "F", "performance": "F",
              "seo": "D", "aeo": "B", "security": "B" },
  "score": 76,
  "counts": { "critical": 0, "serious": 12, "moderate": 28, "minor": 5, "total": 45 },
  "history": [ { "at": "2026-09-14T07:00:00Z", "score": 61, "issues": 57 } ],
  "topIssues": [
    { "ruleId": "image-of-text-suspect", "name": "Text baked into an image",
      "impact": "serious", "wcag": "1.4.5", "occurrences": 43,
      "effort": "20 min", "fixBy": "content" }
  ],
  "tools": { "performance": { "score": 41 }, "aeo": { "score": 67 } },
  "fixes": { "remediation": { "open": 3, "fixed": 1 } },
  "alerts": []
}
Fields are additive — new keys may appear over time, so parse defensively.
GET/api/v1/fixes

Everything needed to actually repair the site: a remediation stylesheet, per-element patches (alt text, labels, language), corrected contrast colours, and the issues that no tool can fix automatically.

auth: API key · must be activated · paid plan

Response

{
  "plan": "agency",
  "aiFixes": true,
  "sites": [{
    "site": "scanpoof.com",
    "scannedAt": "2026-09-14T07:00:00Z",
    "pagesScanned": 34,
    "score": 76,
    "css": "/* remediation stylesheet */",
    "patches": [ { "selector": "img[src$='logo.png']", "alt": "Company logo" } ],
    "contrast": [ { "selector": ".menu a", "color": "#5a3b2e" } ],
    "unfixable": [ { "ruleId": "pdf-no-text-layer", "occurrences": 4,
                     "reason": "This PDF is a scan with no text inside…" } ],
    "issues": [ { "ruleId": "image-alt", "wcag": "1.1.1", "impact": "critical",
                  "selector": "img.hero", "occurrences": 2,
                  "explanation": "…", "wpFix": "…", "codeFix": "…" } ]
  }]
}
unfixable is deliberate: scanned PDFs and images of text cannot be repaired by any script, and we would rather tell you than pretend. The AI-written explanation, wpFix and codeFix fields are populated only with the AI Fix add-on.
POST/api/v1/rescan

Queue a fresh scan of the activated site. If a scan is already queued or running you get that one back instead of a duplicate.

auth: API key · must be activated

curl -X POST https://scanpoof.com/api/v1/rescan -H "Authorization: Bearer adap_..."

Response

{ "queued": true, "runId": "cmx..." }
Scans run one at a time per platform. Paid Growth and Agency plans jump the queue.
GET/api/v1/scan-status

Poll the latest scan for the activated site — use it to show progress, or to block a deploy until the scan finishes.

auth: API key · must be activated

Response

{
  "status": "running",   // queued | running | done | error | none
  "active": true,
  "runId": "cmx...",
  "pagesScanned": 12,
  "score": null,          // filled in once status is "done"
  "startedAt": "2026-09-20T07:00:00Z",
  "finishedAt": null
}
POST/api/v1/scan

Scan any single URL, without adding it to your account. Handy for auditing a page before you own it. Returns immediately with an id to poll.

auth: API key

FieldMeaning
urlThe page to scan. https:// is assumed if you leave the scheme off.
curl -X POST https://scanpoof.com/api/v1/scan \
  -H "Authorization: Bearer adap_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://scanpoof.com/pricing"}'

Response

{ "id": "cmx...", "status": "running" }   // 201 Created
GET/api/v1/scan/{id}

Fetch the result of a single-URL scan.

auth: API key

Response

{
  "id": "cmx...",
  "url": "https://scanpoof.com/pricing",
  "status": "done",
  "score": 64,
  "critical": 1, "serious": 4, "moderate": 2, "minor": 0,
  "issues": [ { "ruleId": "image-alt", "impact": "critical",
                "wcag": "1.1.1", "help": "Images must have alt text", "count": 2 } ]
}

Plugin endpoints

These two are public — WordPress fetches them with no credentials, and the plugin is inert until a valid key is activated inside it.

GET/api/v1/plugin-update— current version, changelog and download URL.
GET/api/v1/plugin.zip— the plugin itself, always the latest build.

The plugin identifies itself with an X-Scanpoof-Plugin: 1.2.8 header so the dashboard can show which version each site is running. Your own integrations can send it too.

Example: fail CI on a regression

Queue a scan, wait for it, and stop the pipeline if the score drops below your bar.

#!/usr/bin/env bash
set -euo pipefail
API="https://scanpoof.com/api/v1"
AUTH="Authorization: Bearer $SCANPOOF_KEY"
MIN_SCORE=70

curl -fsS -X POST "$API/rescan" -H "$AUTH" > /dev/null

for _ in $(seq 1 60); do
  body=$(curl -fsS "$API/scan-status" -H "$AUTH")
  [ "$(echo "$body" | jq -r .active)" = "false" ] && break
  sleep 20
done

score=$(curl -fsS "$API/scan-status" -H "$AUTH" | jq -r .score)
echo "accessibility score: $score"
[ "$score" -ge "$MIN_SCORE" ] || { echo "below $MIN_SCORE — failing build"; exit 1; }

Questions

Something missing or unclear? Email [email protected] — a real person answers. The API is versioned under /v1; breaking changes get a new version, and new fields are added without one.