{"openapi":"3.1.0","info":{"version":"1.0.0","title":"barrieretest.at API","description":"Automated accessibility testing API. Runs axe-core checks via @barrieretest/core with an optional AI-powered semantic pass (vision + text LLM) sharing the same browser session. Returns WCAG 2.1 compliance issues with severity, score, and — when enabled — semantic findings.","contact":{"name":"API Support","url":"https://barrieretest.at"}},"servers":[{"url":"http://localhost:4000","description":"Development server"},{"url":"https://api.barrieretest.at","description":"Production server"}],"components":{"schemas":{"CreateAuditResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this audit"},"urls":{"type":"array","items":{"type":"string","format":"uri"},"description":"URLs that will be audited"},"status":{"type":"string","enum":["queued","running","completed","failed"],"description":"Current status of the audit"},"queuePosition":{"type":"number","description":"Position in the processing queue"},"message":{"type":"string","description":"Status message"}},"required":["id","urls","status"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"Error message"},"details":{"type":"string","description":"Additional error details"}},"required":["error"]},"AuditRequestBody":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":10,"description":"List of URLs to perform accessibility audits on"},"webhookUrl":{"type":"string","format":"uri","description":"Optional webhook URL to receive a POST request when the audit completes"},"enableAI":{"type":"boolean","default":false,"description":"Enable AI-powered semantic accessibility analysis (only available for authenticated API key users)"}},"required":["urls"]},"AuditListItem":{"type":"object","properties":{"id":{"type":"string"},"urls":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"type":"string","enum":["queued","running","completed","failed"]},"score":{"type":"number"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/AccessibilityIssue"}},"completedAt":{"type":"string"},"createdAt":{"type":"string"},"severityRating":{"type":"string","enum":["excellent","good","needs-improvement","critical","severe"]},"aiEnabled":{"type":"boolean"},"aiStatus":{"type":"string","nullable":true,"enum":["success","failed",null],"description":"Public API only ever returns null|success|failed (pending is DB-internal)"},"aiScore":{"type":"number","nullable":true}},"required":["id","urls","status","aiEnabled","aiStatus","aiScore"]},"AccessibilityIssue":{"type":"object","properties":{"id":{"type":"string"},"impact":{"type":"string","enum":["critical","serious","moderate","minor"]},"description":{"type":"string"},"help":{"type":"string"},"helpUrl":{"type":"string"},"failureSummary":{"type":"string"},"selector":{"type":"string","nullable":true},"nodes":{"type":"array","items":{"type":"object","properties":{"html":{"type":"string"}},"required":["html"]}},"semantic":{"type":"object","properties":{"checkType":{"type":"string"},"confidence":{"type":"number"},"suggestion":{"type":"string"}},"required":["checkType","confidence"]}},"required":["id","impact","description","help","selector","nodes"],"additionalProperties":{"nullable":true}},"AuditSnapshot":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","description":"Primary URL (urls[0])"},"urls":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"type":"string","enum":["queued","running","completed","failed"]},"score":{"type":"number","nullable":true},"scoreInterpretation":{"$ref":"#/components/schemas/ScoreInterpretation"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/AccessibilityIssue"},"description":"Engine-only accessibility issues (axe-core)"},"completedAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"severityRating":{"type":"string","nullable":true,"enum":["excellent","good","needs-improvement","critical","severe",null]},"aiEnabled":{"type":"boolean"},"aiStatus":{"type":"string","nullable":true,"enum":["success","failed",null],"description":"Public API only ever returns null|success|failed (pending is DB-internal)"},"aiIssues":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/FrontendSemanticIssue"}},"aiScore":{"type":"number","nullable":true},"aiError":{"type":"string","nullable":true},"screenshot":{"$ref":"#/components/schemas/AuditScreenshot"}},"required":["id","urls","status","aiEnabled","aiStatus","aiIssues","aiScore","aiError"]},"ScoreInterpretation":{"type":"object","properties":{"range":{"type":"string"},"level":{"type":"string","enum":["excellent","good","needs-improvement","critical","severe"]},"title":{"type":"string"},"description":{"type":"string"},"action":{"type":"string"},"urgency":{"type":"string","enum":["low","medium","high","urgent"]},"recommendConsulting":{"type":"boolean"},"color":{"type":"string"}},"required":["range","level","title","description","action","urgency","recommendConsulting","color"]},"FrontendSemanticIssue":{"type":"object","properties":{"description":{"type":"string"},"severity":{"type":"string","enum":["critical","serious","moderate","minor"]},"recommendation":{"type":"string"},"context":{"type":"string"}},"required":["description","severity","recommendation"]},"AuditScreenshot":{"type":"object","nullable":true,"properties":{"dataUrl":{"type":"string"},"mimeType":{"type":"string","enum":["image/png"]},"width":{"type":"number"},"height":{"type":"number"},"fullPage":{"type":"boolean"},"capturedAt":{"type":"string"}},"required":["dataUrl","mimeType","width","height","fullPage","capturedAt"]},"AuditStreamEvent":{"type":"object","properties":{"type":{"type":"string","enum":["progress","result","error"]},"percent":{"type":"number"},"message":{"type":"string"},"url":{"type":"string"},"result":{"$ref":"#/components/schemas/CompletedAuditPayload"}},"required":["type"]},"CompletedAuditPayload":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","description":"Primary URL (urls[0])"},"urls":{"type":"array","items":{"type":"string","format":"uri"}},"status":{"type":"string","enum":["completed"]},"score":{"type":"number"},"scoreInterpretation":{"$ref":"#/components/schemas/ScoreInterpretation"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/AccessibilityIssue"},"description":"Engine-only accessibility issues (axe-core)"},"completedAt":{"type":"string","nullable":true},"severityRating":{"type":"string","nullable":true,"enum":["excellent","good","needs-improvement","critical","severe",null]},"aiEnabled":{"type":"boolean"},"aiStatus":{"type":"string","nullable":true,"enum":["success","failed",null]},"aiIssues":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/FrontendSemanticIssue"}},"aiScore":{"type":"number","nullable":true},"aiError":{"type":"string","nullable":true},"screenshot":{"$ref":"#/components/schemas/AuditScreenshot"}},"required":["id","url","urls","status","score","scoreInterpretation","issues","completedAt","severityRating","aiEnabled","aiStatus","aiIssues","aiScore","aiError","screenshot"]}},"parameters":{}},"paths":{"/api/v1/audit":{"post":{"tags":["Accessibility Audit"],"summary":"Start a new accessibility audit","description":"Submit one or more URLs for accessibility testing. The API analyzes each page with axe-core (optional semantic vision checks when `enableAI=true`) and returns accessibility issues.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditRequestBody"},"example":{"urls":["https://example.com","https://example.com/about"]}}}},"responses":{"200":{"description":"Audit started successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAuditResponse"},"example":{"id":"abc123xyz","urls":["https://example.com"],"status":"queued","queuePosition":0,"message":"Audit queued. Position in queue: 1"}}}},"400":{"description":"Invalid request - check your request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"No URLs provided","details":"At least one URL is required"}}}},"403":{"description":"Access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Access denied","details":"Your IP address has been blocked from this service."}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Rate limit exceeded","details":"You have exceeded the daily limit of 10 audits"}}}},"503":{"description":"Service temporarily unavailable - queue is full","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Too many queued tasks","details":"Queue exceeds max limit. Manually retry in a few minutes"}}}}}}},"/api/v1/audits":{"get":{"tags":["Audits"],"summary":"List audits with filtering and pagination","description":"Get a paginated list of audits. Requires authentication. Regular users see only their audits. Admin users see all audits.","parameters":[{"schema":{"type":"string","enum":["queued","running","completed","failed"],"example":"completed"},"required":false,"name":"status","in":"query","description":"Filter by audit status"},{"schema":{"type":"string","example":"20"},"required":false,"name":"limit","in":"query","description":"Number of audits to return (1-100)"},{"schema":{"type":"string","example":"0"},"required":false,"name":"offset","in":"query","description":"Number of audits to skip"}],"responses":{"200":{"description":"List of audits","content":{"application/json":{"schema":{"type":"object","properties":{"audits":{"type":"array","items":{"$ref":"#/components/schemas/AuditListItem"}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}},"required":["audits","total","limit","offset"]},"example":{"audits":[{"id":"abc123xyz","urls":["https://example.com"],"status":"completed","score":92,"severityRating":"good","aiEnabled":false,"aiStatus":null,"aiScore":null}],"total":42,"limit":20,"offset":0}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Authentication required","details":"This endpoint requires a valid API key. Anonymous users cannot access audit lists."}}}}}}},"/api/v1/audits/{id}":{"get":{"tags":["Audits"],"summary":"Get a single audit by ID","description":"Get a snapshot of an audit's current state, including engine issues and (when enabled) the AI semantic pass status/findings. For real-time progress updates, use the streaming endpoint.","parameters":[{"schema":{"type":"string","minLength":1,"example":"abc123xyz"},"required":true,"name":"id","in":"path","description":"The unique identifier of the audit"}],"responses":{"200":{"description":"Audit found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditSnapshot"},"example":{"id":"abc123xyz","urls":["https://example.com"],"status":"completed","score":92,"severityRating":"good","aiEnabled":true,"aiStatus":"success","aiIssues":[],"aiScore":0,"aiError":null}}}},"403":{"description":"Access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Access denied","details":"You do not have permission to access this audit."}}}},"404":{"description":"Audit not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Audit not found","details":"No audit exists with the provided ID"}}}}}},"delete":{"tags":["Audits"],"summary":"Cancel or delete an audit","description":"Cancel a queued audit or delete a completed audit. Active audits cannot be cancelled.","parameters":[{"schema":{"type":"string","minLength":1,"example":"abc123xyz"},"required":true,"name":"id","in":"path","description":"The unique identifier of the audit"}],"responses":{"200":{"description":"Audit cancelled or deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"]},"example":{"success":true,"message":"Audit cancelled successfully"}}}},"403":{"description":"Access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Audit not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Cannot cancel active audit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Cannot cancel audit","details":"The audit is currently running and cannot be cancelled"}}}}}}},"/api/v1/audits/{id}/stream":{"get":{"tags":["Audits"],"summary":"Stream audit progress in real-time","description":"Subscribe to real-time progress updates for an audit using Server-Sent Events (SSE). This endpoint will automatically start the audit if it's queued.","parameters":[{"schema":{"type":"string","minLength":1,"example":"abc123xyz"},"required":true,"name":"id","in":"path","description":"The unique identifier of the audit"}],"responses":{"200":{"description":"SSE stream of audit progress. Each event is a JSON object with one of three types: `progress` (percent + message), `result` (a `CompletedAuditPayload` — the same shape as GET /audits/{id} for completed audits and the webhook `audit.completed` payload), or `error` (message).","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/AuditStreamEvent"}}}},"404":{"description":"Audit not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Audit not found"}}}}}}},"/api/v1/audits/{id}/status":{"get":{"tags":["Audits"],"summary":"Get audit status and queue position","description":"Get the current status of an audit including its position in the queue if it's waiting to be processed.","parameters":[{"schema":{"type":"string","minLength":1,"example":"abc123xyz"},"required":true,"name":"id","in":"path","description":"The unique identifier of the audit"}],"responses":{"200":{"description":"Audit status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed"]},"queuePosition":{"type":"number"},"activeTasksCount":{"type":"number"},"totalQueuedTasks":{"type":"number"},"message":{"type":"string"}},"required":["id","status","activeTasksCount","totalQueuedTasks","message"]},"example":{"id":"abc123xyz","status":"queued","queuePosition":2,"activeTasksCount":4,"totalQueuedTasks":8,"message":"Waiting in queue at position 3"}}}},"403":{"description":"Access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Audit not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/queue/status":{"get":{"tags":["Queue"],"summary":"Get queue statistics","description":"Get current statistics about the task queue including active tasks, queued tasks, and system capacity.","responses":{"200":{"description":"Queue statistics retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"activeTasksCount":{"type":"number","description":"Number of currently running tasks"},"queuedTasksCount":{"type":"number","description":"Number of tasks waiting in queue"},"maxConcurrentTasks":{"type":"number","description":"Maximum number of concurrent tasks"},"availableCapacity":{"type":"number","description":"Available slots for new tasks"},"activeTaskIds":{"type":"array","items":{"type":"string"},"description":"IDs of currently active tasks"}},"required":["activeTasksCount","queuedTasksCount","maxConcurrentTasks","availableCapacity","activeTaskIds"]},"example":{"activeTasksCount":4,"queuedTasksCount":12,"maxConcurrentTasks":4,"availableCapacity":0,"activeTaskIds":["abc123:https://example.com","def456:https://test.com"]}}}}}}}}}