REST APIv1

API Reference

Programmatic WCAG 2.2 / ADA accessibility scanning for CI/CD pipelines, monitoring, and integrations.

Introduction

The ADAGuard Public API v1 lets you run WCAG 2.2 / ADA accessibility scans programmatically and retrieve structured results. Common use cases: automated CI/CD quality gates, continuous site monitoring, and embedding accessibility checks into your CMS or deployment workflow.

Base URL

https://api.adaguard.io

Version

v1 · /v1/...
POST / GET / DELETE/v1/scan{,s}
GET/v1/scan/{id}/status
GET/v1/scan/{id}/report
GET/v1/auth-sessions
GET/v1/scans/stats

Plan requirement: API access requires the Professional plan or above.

Authentication

Every request must include your API key in the X-API-Key header. Generate and manage keys in Settings → API Keys.

[ CURL ]
curl "https://api.adaguard.io/v1/scans" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"
Keep your key secret. Never expose it in client-side code or public repos. Revoke compromised keys immediately from Settings.
Key format: ak_live_<32 chars>
Keys are shown once at creation — store them in GitHub Secrets or a vault.

Available scopes

ScopePermission
scans:writeStart new scans. Also satisfies scans:read checks.
scans:readRead results, poll status, list scans, download reports, list auth sessions
scans:deletePermanently delete scans and stored data
stats:readAccess account-level usage statistics

Quick Start — CI/CD in 60 seconds

The API is async-first: POST /scan returns immediately with a scan_id. Poll /status until done, then use min_score as an automatic pass/fail gate.

[ BASH ]
#!/bin/bash API_KEY="ak_live_YOUR_KEY_HERE" BASE="https://api.adaguard.io" # 1. Start scan RESP=$(curl -s -X POST "$BASE/v1/scan" \ -H "X-API-Key: $API_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com", "scan_mode": "single", "min_score": 80}') SCAN_ID=$(echo $RESP | jq -r '.scan_id') # 2. Poll until completed while true; do STATUS=$(curl -s "$BASE/v1/scan/$SCAN_ID/status" -H "X-API-Key: $API_KEY") STATE=$(echo $STATUS | jq -r '.status') [ "$STATE" = "completed" ] || [ "$STATE" = "failed" ] && break sleep $(echo $STATUS | jq -r '.poll_again_in // 5') done # 3. CI gate PASSED=$(echo $STATUS | jq -r '.passed') [ "$PASSED" = "false" ] && echo "Score below threshold — failing build" && exit 1

Non-blocking

Scan runs in background — no HTTP timeouts

Easy polling

poll_again_in tells you when to check next

Pass/Fail gate

min_score → passed field for pipeline gates

Start a Scan

POSThttps://api.adaguard.io/v1/scan
scans:writeReturns immediately

Queues a new scan and returns a scan_id immediately. The scan runs in the background.

Request body

FieldTypeDefaultDescription
urlstring (URL)Required. https:// only. Private IPs blocked.
scan_modeenum"single"single · crawl · sitemap · layout
max_pagesint 1–50001Max pages for crawl modes. Capped to plan limit.
min_scoreint 0–100nullCI gate. Adds passed: true/false to result.
auth_session_idstringnullReference a stored auth session.
viewportenum"desktop""desktop" or "mobile" (390×844).
exclude_pathsstring[]nullURL path prefixes to skip, e.g. ["/blog"].
include_subdomainsbooleantrueSet false to restrict crawl to exact hostname.

scan_mode values

singleScan only the provided URL. Fastest — ideal for CI/CD.
crawlFollow internal links up to max_pages.
sitemapDiscover URLs from sitemap.xml first, then crawl.
layoutCrawl + deduplicate structurally similar templates.
[ CURL ]
curl -X POST "https://api.adaguard.io/v1/scan" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "scan_mode": "crawl", "max_pages": 25, "min_score": 80 }'

Response

[ JSON ]
{ "scan_id": "550e8400-e29b-41d4-a716-446655440000", "status": "queued", "url": "https://example.com", "created_at": "2026-03-02T10:00:00Z", "poll_url": "/v1/scan/550e8400.../status" }

Poll Scan Status

GEThttps://api.adaguard.io/v1/scan/{scan_id}/status
scans:read

Call repeatedly until status is completed or failed. Use poll_again_in as your retry interval.

[ CURL ]
curl "https://api.adaguard.io/v1/scan/SCAN_ID/status" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response — completed

[ JSON ]
{ "scan_id": "550e8400...", "status": "completed", "score": 74, "passed": false, "pages_scanned": 25, "issues_critical": 8, "issues_warning": 21, "issues_info": 12, "poll_again_in": null }

Get Full Scan Result

GEThttps://api.adaguard.io/v1/scan/{scan_id}
scans:read

Returns the complete result including every accessibility issue. For large scans use the instead.

[ CURL ]
curl "https://api.adaguard.io/v1/scan/SCAN_ID" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response

[ JSON ]
{ "id": "550e8400...", "status": "completed", "score": 74, "pages_scanned": 25, "elements_checked": 12840, "issues_critical": 8, "issues": [ { "severity": "critical", "type": "alt-text-missing", "description": "Image is missing alt text", "wcag": ["1.1.1"], "help_url": "https://www.w3.org/WAI/WCAG22/quickref/#non-text-content", "elements": [{"html": "<img src='hero.jpg'>", "selector": "main > img"}] } ] }

List Scans

GEThttps://api.adaguard.io/v1/scans
scans:read

Returns a paginated list of completed scans. Filter by URL prefix.

[ CURL ]
curl "https://api.adaguard.io/v1/scans?limit=20&url=https://example.com" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response

[ JSON ]
{ "scans": [ {"id": "550e8400...", "url": "https://example.com", "score": 74, "status": "completed", "pages_scanned": 25} ], "total": 42, "limit": 20, "offset": 0, "has_more": true }

Scan Statistics

GEThttps://api.adaguard.io/v1/scans/stats
stats:read
[ CURL ]
curl "https://api.adaguard.io/v1/scans/stats" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response

[ JSON ]
{"total_scans": 42, "completed_scans": 40, "scans_used": 40, "scans_limit": 200, "average_score": 78.4}

Delete a Scan

DELETEhttps://api.adaguard.io/v1/scan/{scan_id}
scans:delete

Permanent. Cannot be undone.

[ CURL ]
curl -X DELETE "https://api.adaguard.io/v1/scan/SCAN_ID" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response

[ JSON ]
{"success": true, "message": "Scan deleted successfully", "scan_id": "550e8400..."}

Download Report

GEThttps://api.adaguard.io/v1/scan/{scan_id}/report?format=...
scans:read
format=json

JSON (default)

Machine-readable — ideal for CI/CD

format=html

HTML

Self-contained report page

format=csv

CSV

Issue spreadsheet sorted by severity

format=pdf

PDF

Professional report for compliance review

[ CURL ]
curl "https://api.adaguard.io/v1/scan/SCAN_ID/report?format=pdf" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE" \ -o report.pdf

Authenticated Scanning

To scan login-protected pages, create a session in Settings → Authenticated Scans and pass the session ID in your request. Raw credentials are never accepted through the API.

[ CURL ]
curl -X POST "https://api.adaguard.io/v1/scan" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{"url": "https://app.example.com/dashboard", "scan_mode": "crawl", "auth_session_id": "sess_abc123"}'

auth_status values

ValueMeaning
not_requestedNo session provided — scanned as public visitor
authenticatedSession valid — private pages accessible
expired_fallbackSession expired — fell back to public pages
public_onlySite is fully public — no auth needed

Auth Sessions

GEThttps://api.adaguard.io/v1/auth-sessions
scans:read

Returns all authenticated sessions stored on your account.

Sessions are created in the dashboard, not via API — go to Settings → Authenticated Scans and click Launch Browser. Sessions expire after 30 days.

[ CURL ]
curl "https://api.adaguard.io/v1/auth-sessions" \ -H "X-API-Key: ak_live_YOUR_KEY_HERE"

Response

[ JSON ]
{ "auth_sessions": [ {"session_id": "a1b2c3...", "domain": "app.example.com", "status": "active", "expires_at": "2026-03-17T09:30:00Z"} ], "total": 1, "note": "Use session_id as auth_session_id in POST /v1/scan." }

Errors

CodeStatusCause
401UnauthorizedMissing or invalid X-API-Key
403ForbiddenKey lacks required scope
404Not FoundScan or session not found
422Unprocessable EntityBad URL, max_pages over limit, wrong field type
429Too Many RequestsRate limit or monthly scan limit exceeded
500Server ErrorUnexpected — contact support
[ JAVASCRIPT ]
// 422 — validation error {"error": "Invalid request", "details": [{"field": "url", "message": "Cannot scan private addresses"}]} // 429 — monthly limit {"detail": {"error": "Monthly scan limit reached", "scans_used": 200, "scans_limit": 200, "upgrade_url": "/billing"}}

Rate Limits

Per-key sliding 1-hour window. Limit headers on every response.

PlanReq / hourScans / monthPages / scan
Professional10030200
Business5001501,000
EnterpriseCustomCustomCustom
[ HTTP ]
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 97 X-RateLimit-Reset: 1740916800 # HTTP 429: Retry-After: 120