Skip to Content
New: AI Sign Language Avatars now in beta! View Sign Language feature ->
Developer ResourcesRest Api Guide

REST API

The Welcomingweb REST API lets you trigger accessibility scans, poll their status, and pull summary numbers from CI/CD pipelines, monitoring scripts, or any other server-side tooling.

This page documents the v1 API, available at /api/public/v1/web/....

Quick start

# 1. Get your API key from Settings → API in the dashboard. export WW_KEY="ww_..." # the full key you copied at creation time # 2. List your modules to find the one you want to scan. curl https://api.welcomingweb.com/api/public/v1/web/modules \ -H "Authorization: Bearer $WW_KEY" # 3. Trigger a scan. Save the sessionId. SESSION_ID=$(curl -s -X POST \ https://api.welcomingweb.com/api/public/v1/web/modules/123/scan \ -H "Authorization: Bearer $WW_KEY" \ | jq -r .sessionId) # 4. Poll until done. while true; do STATUS=$(curl -s \ https://api.welcomingweb.com/api/public/v1/web/modules/123/sessions/$SESSION_ID \ -H "Authorization: Bearer $WW_KEY" \ | jq -r .status) echo "Scan status: $STATUS" case "$STATUS" in SUCCESS) break ;; FAILED) echo "Scan failed"; exit 1 ;; *) sleep 15 ;; esac done

Authentication

All endpoints require an API key, sent in one of these headers:

HeaderExample
AuthorizationAuthorization: Bearer ww_1a2b3c4d.long-secret-portion
X-API-KeyX-API-Key: ww_1a2b3c4d.long-secret-portion

Create keys at Settings → API → Generate New Key. The full key is shown once at creation; only the prefix is recoverable afterwards. Revoke a key from the same screen.

Keys are account-scoped. They can access any module on your account; there is no per-module key. Treat them like passwords.

The same key works for both the web REST API documented here and the mobile SDK API.

Endpoints

GET /api/public/v1/web/modules

List all accessibility modules visible to the API key’s account.

Response (200):

[ { "id": 123, "domain": "example.com", "plan": "PRO", "status": "ACTIVE" }, { "id": 124, "domain": "other-site.com", "plan": "FREE", "status": "INACTIVE" } ]
FieldDescription
idNumeric module id. Use this in subsequent endpoints.
domainThe site’s primary domain.
planFREE / PRO / ENTERPRISE. Scan triggering requires a paid plan.
statusACTIVE / INACTIVE / EXECUTING / URL_ANALYSE / DELETING. A module showing EXECUTING already has a scan in flight.

POST /api/public/v1/web/modules/{moduleId}/scan

Trigger an on-demand accessibility scan. The scan runs asynchronously; this endpoint returns as soon as the job is dispatched.

Path parameters:

NameDescription
moduleIdThe numeric id returned by GET /modules.

No request body.

Response (200):

{ "status": "queued", "sessionId": 1573, "moduleId": 123, "used": 3, "limit": 5, "remaining": 2, "resetsAt": "2026-06-01T00:00:00+01:00", "message": "Scan started. 2 manual scans remaining this month." }

Quota: each module on a paid plan gets 5 manual scans per calendar month, shared between this API and the dashboard’s Force Run button. Quota resets at the start of the next calendar month in UTC+0 (the server’s timezone).

Error responses:

StatusError codeWhen
401unauthorizedMissing or invalid API key.
402FORBIDDEN_PLANModule is on the FREE plan. Upgrade in the dashboard.
404NOT_FOUNDModule doesn’t exist or isn’t visible to this key.
409ALREADY_RUNNINGA scan is already running for this module. Wait for it to finish.
429QUOTA_EXHAUSTEDMonthly quota used up. Response includes resetsAt.

Every error response also includes the same quota fields (used, limit, remaining, resetsAt) so scripts can log them or warn before they hit the cap.


GET /api/public/v1/web/modules/{moduleId}/sessions/{sessionId}

Get the status and summary of a scan session. Poll this endpoint to wait for a triggered scan to complete.

Response (200) while scan is still running:

{ "sessionId": 1573, "moduleId": 123, "status": "EXECUTING", "startedAt": "2026-05-20T14:32:11", "completedAt": null, "message": null, "pagesDiscovered": 0, "pagesAnalyzed": 0, "uniqueIssues": 0, "totalOccurrences": 0, "p1Count": 0, "p2Count": 0, "p3Count": 0, "p4Count": 0, "wcagBand": null, "qualityScore": 0.0 }

Response (200) after scan completes:

{ "sessionId": 1573, "moduleId": 123, "status": "SUCCESS", "startedAt": "2026-05-20T14:32:11", "completedAt": "2026-05-20T14:36:42", "message": null, "pagesDiscovered": 47, "pagesAnalyzed": 47, "uniqueIssues": 521, "totalOccurrences": 4264, "p1Count": 0, "p2Count": 268, "p3Count": 583, "p4Count": 29, "wcagBand": "Fails A", "qualityScore": 79.5 }

Status values:

statusMeaning
PENDINGCreated but not yet started.
EXECUTINGScan is running. Summary fields are zero.
URL_ANALYSEInitial discovery phase (sitemap, link analysis).
SUCCESSScan complete. Summary fields populated.
FAILEDScan failed. message carries the reason.

Summary fields (populated only when status == SUCCESS):

FieldDescription
pagesDiscoveredTotal pages found via sitemap / crawling.
pagesAnalyzedSubset actually scanned (may be smaller if the plan caps page count).
uniqueIssuesDeduplicated finding count. The “521 unique issues” headline.
totalOccurrencesRaw node-level occurrences.
p1Countp4CountIssues per priority tier. P1 = Critical.
wcagBand"Fails A" / "A" / "AA" / "AAA" / "N/A". The conformance verdict.
qualityScore0–100, weighted across A (50%), AA (40%), AAA (10%). -1 if not computable.

Errors:

StatusWhen
401Missing or invalid API key.
404Module or session doesn’t exist for this account.

CI/CD integration examples

GitHub Actions

name: Accessibility scan on: push: branches: [main] jobs: scan: runs-on: ubuntu-latest steps: - name: Trigger scan and wait env: WW_KEY: ${{ secrets.WELCOMINGWEB_API_KEY }} MODULE_ID: 123 MIN_QUALITY: 70 run: | set -euo pipefail API=https://api.welcomingweb.com/api/public/v1/web SESSION_ID=$(curl -s -X POST \ "$API/modules/$MODULE_ID/scan" \ -H "Authorization: Bearer $WW_KEY" \ | jq -r .sessionId) echo "Started session $SESSION_ID" for i in {1..60}; do RESP=$(curl -s "$API/modules/$MODULE_ID/sessions/$SESSION_ID" \ -H "Authorization: Bearer $WW_KEY") STATUS=$(echo "$RESP" | jq -r .status) echo "Attempt $i: $STATUS" case "$STATUS" in SUCCESS) SCORE=$(echo "$RESP" | jq -r .qualityScore) P1=$(echo "$RESP" | jq -r .p1Count) echo "Quality score: $SCORE, P1 issues: $P1" if [ "$P1" -gt 0 ]; then echo "::error::Scan found $P1 P1 (critical) issues" exit 1 fi if [ "$(echo "$SCORE < $MIN_QUALITY" | bc)" -eq 1 ]; then echo "::error::Quality score $SCORE below threshold $MIN_QUALITY" exit 1 fi exit 0 ;; FAILED) echo "::error::Scan failed"; exit 2 ;; *) sleep 15 ;; esac done echo "::error::Timed out after 15 minutes"; exit 3

GitLab CI

accessibility: stage: test script: - apt-get update && apt-get install -y curl jq - | SESSION_ID=$(curl -s -X POST \ "$WW_API/modules/$MODULE_ID/scan" \ -H "Authorization: Bearer $WW_KEY" | jq -r .sessionId) while true; do STATUS=$(curl -s \ "$WW_API/modules/$MODULE_ID/sessions/$SESSION_ID" \ -H "Authorization: Bearer $WW_KEY" | jq -r .status) [ "$STATUS" = "SUCCESS" ] && exit 0 [ "$STATUS" = "FAILED" ] && exit 1 sleep 15 done variables: WW_API: https://api.welcomingweb.com/api/public/v1/web MODULE_ID: "123"

Rate limits and quotas

ResourceLimit
Manual scans (per module, per calendar month)5 on PRO plans
Read endpoints (GET /modules, GET /sessions)No hard rate limit, but cache responses where you can — polling every 15–30 seconds is plenty.

Status codes summary

CodeMeaning
200Success.
401Missing or invalid API key.
402Payment Required — module is on the FREE plan.
404Resource not found, or not visible to this key.
409Conflict — a scan is already running.
429Too Many Requests — monthly quota exhausted.
500Internal server error. Retry after a short backoff.

Versioning policy

  • The current API is v1. Breaking changes will go to v2 at a new path.
  • Within v1, we may add fields to responses without notice. Your client should ignore unknown fields.
  • We will not change field types, rename fields, or remove fields within v1.

Need help?

Email support@welcomingweb.com with your API key prefix (the first 8 characters, never the full key) and the response body of the failing request.

Last updated on