Die adasafe-API

Lösen Sie Barrierefreiheits-Scans aus Ihren eigenen Tools, aus CI oder von einem KI-Agenten aus und lesen Sie sie aus. Server-zu-Server, REST, JSON. Basis-URL https://api.adasafe.ai — jeder Pfad unten enthält bereits das Präfix /v1 .

Es gibt keinen Score

Jeder Integrator fragt nach einer einzigen Zahl. Wir liefern sie nicht — weil es keine ehrliche gibt. Die WCAG-Konformität ist pro Kriterium bestanden oder nicht bestanden, ein Score wie „92 % barrierefrei“ wäre also erfunden, nicht gemessen.

Stattdessen enthalten Antworten counts pro Schweregrad, eine kategoriale risk_level (Hoch / Mittel / Niedrig)und einen coverage Block, der angibt, wie viele Seiten im Geltungsbereich nicht geprüft wurden. Sie wissen jederzeit, was geprüft wurde und was nicht. Es gibt kein score, percent, oder grade Feld — by design.

Authentifizierung

Erstellen Sie einen Schlüssel auf Ihrer Seite API-Schlüssel (nur in kostenpflichtigen Plänen). Senden Sie ihn als Bearer-Token. Schlüssel sind ausschließlich serverseitig — ein API-Schlüssel in Browser-JavaScript ist ein kompromittierter Schlüssel, und die API weist Browser-Anfragen zurück.

curl https://api.adasafe.ai/v1/me \
  -H "Authorization: Bearer ada_live_your_key_here"

Einen Scan auslösen

POST /v1/scans benötigt zwei Dinge: ownership_confirmed: true (Sie bestätigen, dass Sie die Site besitzen oder scannen dürfen) und einen Idempotency-Key Header. Der Schlüssel macht Wiederholungen sicher — derselbe Schlüssel liefert denselben Scan und belastet Ihr Kontingent nie doppelt.

curl -X POST https://api.adasafe.ai/v1/scans \
  -H "Authorization: Bearer ada_live_..." \
  -H "Idempotency-Key: 3f9c1e7a-..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "ownership_confirmed": true}'

# → 202 { "scan_id": "…", "status": "pending" }

Fragen Sie GET /v1/scans/{id} für den Status ab (günstig), und rufen Sie dann GET /v1/scans/{id}/results ab, sobald er completeist. Fügen Sie ?format=md hinzu, um einen Markdown-Bericht zu erhalten, der bereit ist, in ein Issue eingefügt oder an einen KI-Assistenten übergeben zu werden.

Endpunkte

  • GET/v1/meIhr Plan, verbleibendes Scan-Kontingent, Scopes und Ratenlimits.
  • POST/v1/scansEinen Scan auslösen. Erfordert ownership_confirmed und einen Idempotency-Key.
  • GET/v1/scansIhre Scans auflisten, neueste zuerst (Cursor-Paginierung).
  • GET/v1/scans/{id}Scan-Status, Zählungen, Abdeckung und Risikostufe — günstig abzufragen.
  • GET/v1/scans/{id}/resultsVollständige Verstöße mit Fixes. Fügen Sie ?format=md für Markdown hinzu.
  • POST/v1/scans/batchMehrere Seiten als einen Job scannen (eine Kontingenteinheit).
  • POST/v1/discoverSeiten im Geltungsbereich einer Site vor dem Scannen auflisten.
  • GET/v1/sitesIhre überwachten Sites auflisten.
  • POST/v1/sitesEine überwachte Site hinzufügen. Erfordert ownership_confirmed.
  • PATCH/v1/sites/{id}Eine überwachte Site aktualisieren (Label, Intervall, aktiv).
  • DELETE/v1/sites/{id}Die Überwachung einer Site beenden.
  • POST/v1/sites/{id}/scanEine überwachte Site jetzt scannen.

Kontingente & Limits

API-Scans schöpfen aus dem selben monatlichen Pool wie das Dashboard — ein gemeinsames Kontingent, kein separater Topf. Sind keine Scans mehr übrig, wird 402 zurückgegeben (Upgrade zum Fortfahren); zu schnelle Anfragen liefern 429 mit einem Retry-After Header (langsamer). Unterschiedliche Situationen, unterschiedliche Lösungen.

Über die Fixes

Jeder Verstoß kann einen vorgeschlagenen fixenthalten. Er nennt stets seinen source und ob er durch einen erneuten Scan verified wurde. Ein KI-vorgeschlagener Fix, der nicht validiert wurde, ist als solcher gekennzeichnet — er wirkt nie als bestätigt. Wenden Sie alles mit Urteilsvermögen an; der Scan ist ein Werkzeug, keine Zertifizierung.

Webhooks

Lieber Push statt Polling? Fügen Sie auf Ihrer Benachrichtigungsseite einen Webhook hinzu, und adasafe sendet per POST eine signierte JSON-Nutzlast, sobald ein Scan oder Batch abgeschlossen ist — dieselbe ehrliche Struktur wie die API: Anzahlen, Abdeckung und ein kategorischer Risikograd, niemals ein Score und niemals Seiteninhalte.

{
  "event": "scan.completed",
  "occurred_at": "2026-08-26T10:15:00+00:00",
  "data": {
    "type": "scan",
    "id": "sc_…",
    "url": "https://example.com/",
    "status": "complete",
    "risk_level": "High",
    "counts": { "critical": 1, "serious": 3, "moderate": 5, "minor": 2, "total": 11 },
    "coverage": { "pages_scanned": 1, "failed_pages": 0 },
    "delta": { "new_issue_types": 2, "resolved": 1, "unchanged": 8, "first_scan": false },
    "dashboard_url": "https://adasafe.ai/dashboard?scan_id=sc_…"
  }
}

Jede Zustellung enthält diese Header:

X-Adasafe-Event:     scan.completed
X-Adasafe-Delivery:  d3f1…             # stable across retries — dedupe on this
X-Adasafe-Signature: ts=1756202100;h1=<hmac-sha256 hex>
Content-Type:        application/json
User-Agent:          adasafe-webhooks/1

Signatur überprüfen

Jeder Webhook hat seinen eigenen Signaturschlüssel, der beim Erstellen einmalig angezeigt wird. Der Header X-Adasafe-Signature lautet ts=<unix>;h1=<hmac>. Berechnen Sie den HMAC-SHA256 des rohen Anfragetexts mit vorangestelltem Zeitstempel neu, vergleichen Sie ihn in konstanter Zeit und weisen Sie alles zurück, dessen Zeitstempel älter als fünf Minuten ist.

import hmac, hashlib, time

def verify(secret: str, header: str, body: bytes) -> bool:
    ts, _, h1 = header.partition(";")
    ts, h1 = ts.removeprefix("ts="), h1.removeprefix("h1=")
    if abs(time.time() - int(ts)) > 300:            # 5-minute replay window
        return False
    expected = hmac.new(secret.encode(), f"{ts}:".encode() + body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, h1)

Ereignisse

Wählen Sie, welche Ereignisse jeder Webhook abonniert. Der Header X-Adasafe-Event und das Feld event in der Nutzlast tragen den Namen:

scan.completed        a single-page scan finished
batch.completed       a whole-site / batch scan finished
monitoring.completed  a scheduled monitoring run finished
scan.failed           a scan errored or was blocked (counts = null)

Eine Antwort außerhalb des 2xx-Bereichs oder ein Timeout wird bis zu 24 Stunden lang mit Backoff wiederholt. Nach 20 aufeinanderfolgenden Fehlern deaktiviert sich der Webhook automatisch und wir benachrichtigen den Inhaber per E-Mail. Wiederholungen senden denselben Text erneut — behandeln Sie X-Adasafe-Delivery daher als Idempotenzschlüssel.