Version: 1.0 Update Date: November 23, 2025
Accellens provides REST and GraphQL interfaces for managing accessibility audits, interacting with AI services, and integrating with CI/CD processes.
- Base URL:
https://api.accellens.dev/api/v1 - Authentication: JWT (Bearer token) or API Key (
X-Accellens-Key). - Data Isolation: All requests are checked for belonging to the user's organization (
organization_id).
POST /api/v1/auth/login
-
Authenticates the user and returns tokens.
-
Body:
{ "email": "user@example.com", "password": "secret_password" } -
Response
200 OK:{ "accessToken": "ey...", "refreshToken": "ey...", "user": { "id": "uuid", "email": "...", "name": "..." } }
POST /api/v1/auth/refresh
- Updates the access token using a refresh token (if stored in a cookie or passed in the body).
- Response
200 OK:{ "accessToken": "ey..." }
Important: All API endpoints working with organization data (projects, runs, scans, findings, AI endpoints) require passing organization_id in the URI path. This ensures explicit data isolation and a consistent API structure.
GET /api/v1/organizations
-
Returns a list of organizations the current user belongs to.
-
Response
200 OK:[ { "id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "name": "ACME Corp", "slug": "acme-corp", "plan": "pro" } ]
POST /api/v1/organizations/{organization_id}/projects
-
Creates a new project in the specified organization.
-
Parameters:
organization_id(path) — Organization ID (UUID)
-
Body:
{ "name": "E-commerce Store", "slug": "shop-v1", "complianceTargets": ["wcag22-aa", "section508"] } -
Response
201 Created.
GET /api/v1/organizations/{organization_id}/projects
-
Returns a list of projects in the organization.
-
Response
200 OK:[ { "id": "shop-v1", "name": "E-commerce Store", "organizationId": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "createdAt": "2025-11-20T10:00:00.000Z" } ]
POST /api/v1/organizations/{organization_id}/projects/{project_id}/scans
-
Triggers a new scan for the project.
-
Parameters:
organization_id(path) — Organization ID (UUID)project_id(path) — Project ID (UUID)
-
Body:
{ "targetUrl": "https://shop.acme.com", "type": "web", "triggerSource": "api", "platform": "auto" } -
platform(optional, default:auto): Manual target platform/framework selection (html_aria,react,react_native,flutter,angular,vue,svelte). Ifauto, the platform is detected from the DOM. -
Response
202 Accepted:{ "runId": "01JBP8D8Q9M8K2E8V934A5GJ1C" }
GET /api/v1/organizations/{organization_id}/runs/{run_id}
-
Returns the current status of a scan run.
-
Parameters:
organization_id(path) — Organization ID (UUID)run_id(path) — Run ID (UUID)
-
Response
200 OK:{ "id": "01JBP8D8Q9M8K2E8V934A5GJ1C", "status": "completed", "aasScore": 85.5, "summary": { "totalFindings": 42, "critical": 3, "high": 12, "platform": "react" }, "startedAt": "...", "finishedAt": "..." }
GET /api/v1/organizations/{organization_id}/runs/{run_id}/findings
-
Returns a list of accessibility violations found in a run.
-
Parameters:
organization_id(path) — Organization IDrun_id(path) — Run ID
-
Query Parameters:
severity,category,status,limit,offset. -
Response
200 OK:{ "items": [ { "id": "uuid", "ruleId": "color-contrast", "severity": "high", "category": "perceivable", "title": "Insufficient color contrast", "description": "...", "aiExplanation": "...", "impactedUsers": { "blind": true, "low_vision": true }, "suggestedFix": { "technicalDescription": "...", "codeBefore": "...", "codeAfter": "...", "effortEstimation": "low" } } ], "total": 42 }
POST /api/v1/organizations/{organization_id}/projects/{project_id}/runs/{run_id}/reports/archive
-
Generates a report in the specified format and saves it to the organization's archive.
-
Parameters:
organization_id,project_id,run_id(path)
-
Body:
{ "report_type": "pdf", "meta_data": { "custom_sections": [{ "title": "Audit Scope", "content": "..." }] } } -
Response
201 Created: Meta-data of the saved report (includingstorage_keyandexpires_at).
GET /api/v1/organizations/{organization_id}/projects/{project_id}/reports/archives
-
Returns a list of archived reports for the project.
-
Query Parameters:
report_type,run_id,limit,offset. -
Response
200 OK:{ "items": [ { "id": "uuid", "report_type": "pdf", "file_size": 102456, "created_at": "...", "expires_at": "..." } ], "total": 15 }
GET /api/v1/organizations/{organization_id}/reports/archives/{report_id}/download
- Generates a pre-signed S3 URL to download the report.
- Response
200 OK:{ "download_url": "https://s3.accellens..." } - Errors:
404 Not Found— report not found403 Forbidden— no access to organization
GET /api/v1/reports/{run_id}/sarif
-
Generates a SARIF 2.1.0 report for integration with CI/CD platforms (GitHub Security, Azure DevOps, etc.).
-
Format follows the SARIF 2.1.0 standard.
-
Example response:
{ "version": "2.1.0", "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", "runs": [ { "tool": { "driver": { "name": "Accellens", "version": "1.0.0" } }, "results": [...] } ] }
GET /api/v1/assistive/{run_id}/audio
- Returns a list of audio tracks demonstrating screen reader announcements.
- Purpose: Helps developers hear what a screen reader user would hear.
- Important: Audio is generated for demonstration only. Announcement clarity analysis is performed via AI analysis of the Accessibility Tree, not TTS.
- Audio files are generated from Accessibility Tree announcements via TTS providers (OpenAI, ElevenLabs, AWS Polly, or Coqui XTTS v2).
GET /api/v1/assistive/{run_id}/simulations
- Returns a list of text data for assistive technology announcements.
- Includes announcements for screen readers (NVDA, JAWS, VoiceOver, TalkBack), voice control, and keyboard navigation.
- Purpose: Provides a textual representation of what a screen reader would read, based on the Accessibility Tree.
AI endpoints provide intelligent analysis of findings using machine learning. All endpoints require passing organization_id in the URI path.
POST /api/v1/organizations/{organization_id}/ai/explain
-
Generates an AI explanation for a finding, describing the accessibility problem in simple language.
-
Body:
{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "force_regenerate": false } -
Response
200 OK:{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "explanation": "This image lacks alternative text, making it inaccessible to screen reader users...", "cached": false } -
If
force_regenerate: true, the explanation will be re-generated even if it already exists.
POST /api/v1/organizations/{organization_id}/ai/impact
-
Analyzes which user categories are affected by a finding.
-
Body:
{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "force_regenerate": false } -
Response
200 OK:{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "impacted_users": { "blind": true, "low_vision": false, "motor": false, "cognitive": false }, "cached": false }
POST /api/v1/organizations/{organization_id}/ai/effort
-
Estimates the effort required to fix a finding.
-
Body:
{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "force_regenerate": false } -
Response
200 OK:{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "effort_estimation": { "level": "low", "estimated_hours": 0.5, "complexity": "simple" }, "cached": false }
POST /api/v1/organizations/{organization_id}/ai/fix
-
Generates fix suggestions for a finding with code examples for a specific platform/framework.
-
The platform is automatically detected from
Run.summary["platform"](saved during scanning). -
If the platform is not defined (old runs), the HTML/ARIA generator is used.
-
Body:
{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "force_regenerate": false } -
Response
200 OK:{ "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "fix_suggestion": { "technical_description": "Clear technical explanation of the problem and why it needs to be fixed", "code_before": "The problematic code snippet", "code_after": "The fixed code snippet with proper accessibility attributes", "explanation": "Brief explanation of what changed and why it fixes the issue", "confidence": 0.85, "additional_notes": "Any additional considerations, edge cases, or best practices" }, "cached": false } -
Supported Platforms:
html_aria— HTML/ARIA (default)react— React.jsreact_native— React Nativeflutter— Flutterangular— Angularvue— Vue.jssvelte— Svelte
Important:
- All AI endpoints require passing
organization_idin the URI path to ensure data isolation between organizations. - AI analysis results are cached in the database. Use
force_regenerate: truefor forced re-generation. - AI endpoints automatically check user access to the finding via the organization.
GET /api/v1/user/settings
-
Returns personal settings for the current user (email, name, interface language, timezone, theme).
-
Response:
{ "email": "auditor@example.com", "name": "Jane Doe", "language": "en", "timezone": "Europe/Berlin", "theme": "system" }
PATCH /api/v1/user/settings
- Partial profile update.
- Constraints:
language∈ {en,ru,uk}theme∈ {light,dark,system}timezone— valid IANA identifier (America/New_York,UTC, ...)
- Users can change only their own settings (actor_id check on the Python service).
GET /api/v1/user/notifications
-
Returns enabled notifications:
{ "emailNotifications": true, "slackNotifications": false, "scanCompleted": true, "criticalFindings": true, "weeklyDigest": false }
PATCH /api/v1/user/notifications
- Partial update of notification flags (any subset of the five boolean fields).
- Missing fields are not changed.
Important: Notification Rules allow configuring rules for notifications about critical findings based on severity, compliance levels, number of impacted users, and other criteria. Rules can be global for the organization or personal for the user.
POST /api/v1/organizations/{organization_id}/notification-rules
-
Creates a new notification rule for the organization.
-
Parameters:
organization_id(path) — Organization ID (UUID)
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Request Body:
{ "name": "Critical Findings Alert", "enabled": true, "critical_severities": ["critical"], "high_severities": ["high"], "min_impacted_users": 1, "critical_compliance_levels": ["AAA", "AA"], "min_rule_frequency": 1, "quiet_hours_enabled": false, "quiet_hours_start": "22:00", "quiet_hours_end": "08:00", "notification_priority": "high", "additional_config": {}, "user_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ" } -
Fields:
name(required) — rule name (1-255 characters)enabled(optional, default:true) — whether the rule is enabledcritical_severities(optional, default:[]) — list of severity levels considered critical (critical,high,medium,low)high_severities(optional, default:[]) — list of severity levels considered highmin_impacted_users(optional, default:1) — minimum number of impacted users (≥1)critical_compliance_levels(optional, default:[]) — list of compliance levels considered critical (A,AA,AAA)min_rule_frequency(optional, default:1) — minimum rule frequency (≥1)quiet_hours_enabled(optional, default:false) — whether quiet hours are enabledquiet_hours_start(optional) — quiet hours start time (HH:MMformat, e.g.,22:00)quiet_hours_end(optional) — quiet hours end time (HH:MMformat, e.g.,08:00)notification_priority(optional, default:normal) — notification priority (normal,high,urgent)additional_config(optional, default:{}) — additional configurationuser_id(optional) — user ID for a personal rule. If not specified, theactor_idfrom the context is used.
-
Response
201 Created:{ "id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "organization_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "user_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "name": "Critical Findings Alert", "enabled": true, "critical_severities": ["critical"], "high_severities": ["high"], "min_impacted_users": 1, "critical_compliance_levels": ["AAA", "AA"], "min_rule_frequency": 1, "quiet_hours_enabled": false, "quiet_hours_start": null, "quiet_hours_end": null, "notification_priority": "high", "additional_config": {}, "created_at": "2025-11-10T08:22:14.123Z", "updated_at": "2025-11-10T08:22:14.123Z" } -
Errors:
400 Bad Request— invalid data (wrong time format, invalid values)403 Forbidden— no access to organization404 Not Found— organization not found
GET /api/v1/organizations/{organization_id}/notification-rules
-
Returns a list of notification rules for the organization.
-
Parameters:
organization_id(path) — Organization ID (UUID)user_id(query, optional) — filter by User IDenabled(query, optional) — filter by enabled status (true,false)skip(query, optional, default:0) — number of rules to skip (≥0)limit(query, optional, default:100, max:1000) — maximum number of rules
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK:[ { "id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "organization_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "user_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "name": "Critical Findings Alert", "enabled": true, "critical_severities": ["critical"], "high_severities": ["high"], "min_impacted_users": 1, "critical_compliance_levels": ["AAA", "AA"], "min_rule_frequency": 1, "quiet_hours_enabled": false, "quiet_hours_start": null, "quiet_hours_end": null, "notification_priority": "high", "additional_config": {}, "created_at": "2025-11-10T08:22:14.123Z", "updated_at": "2025-11-10T08:22:14.123Z" } ]
GET /api/v1/organizations/{organization_id}/notification-rules/current-user
- Returns the notification rule for the current user.
- Parameters:
organization_id(path) — Organization ID (UUID)
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID (required)
- Response
200 OK: Rule object (format as in the list above). - Response
404 Not Foundif the rule is not found for the current user. - Response
401 Unauthorizedif the user is not authenticated.
GET /api/v1/organizations/{organization_id}/notification-rules/{rule_id}
- Returns a notification rule by ID.
- Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule ID (UUID)
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: Rule object (format as in the list above). - Response
404 Not Foundif the rule is not found or does not belong to the organization.
PATCH /api/v1/organizations/{organization_id}/notification-rules/{rule_id}
-
Updates a notification rule (partial update).
-
Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule ID (UUID)
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Request Body (all fields optional):
{ "name": "Updated Rule Name", "enabled": false, "critical_severities": ["critical", "high"], "quiet_hours_enabled": true, "quiet_hours_start": "23:00", "quiet_hours_end": "07:00", "notification_priority": "urgent" } -
Response
200 OK: Updated rule object. -
Response
404 Not Foundif the rule is not found. -
Response
400 Bad Requestif data is invalid.
DELETE /api/v1/organizations/{organization_id}/notification-rules/{rule_id}
- Deletes a notification rule.
- Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule ID (UUID)
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
204 No Contenton successful deletion. - Response
404 Not Foundif the rule is not found. - Response
403 Forbiddenif no permission to delete.
Important: Notifications API provides real-time notifications about critical findings via Server-Sent Events (SSE). Notifications are filtered based on configured Notification Rules.
GET /api/v1/notifications/critical-findings/stream
-
Establishes an SSE connection to receive real-time notifications about critical findings.
-
Parameters:
projectId(query, optional) — Project ID for filtering (UUID). If not specified, notifications come for all organization projects.
-
Headers:
Authorization: Bearer <token>orX-Accellens-Key: <key>— authenticationX-Organization-Id— Organization ID (required)
-
Response Format:
text/event-stream(SSE) -
Events:
-
connected— connection established:event: connected data: {"status": "connected"} -
critical_finding— new critical finding:event: critical_finding data: { "finding_id": "01JBP7J3Z8CQ9TV3X6A4X5C5DZ", "run_id": "01JBP8D8Q9M8K2E8V934A5GJ1C", "project_id": "01JBP8D8Q9M8K2E8V934A5GJ1D", "severity": "critical", "rule_id": "color-contrast", "title": "Color contrast insufficient", "description": "Element has insufficient color contrast", "impacted_users": { "blind": true, "low_vision": true, "motor": false, "cognitive": false }, "compliance_levels": ["AA", "AAA"], "in_quiet_hours": false, "detected_at": "2025-11-10T08:30:00.000Z" } -
disconnected— connection closed:event: disconnected data: {"status": "disconnected"} -
error— stream error:event: error data: {"error": "Error message"}
-
-
Behavior:
- The connection checks for new findings every 10 seconds
- Notifications are sent only for findings matching active Notification Rules
- Findings in quiet hours are skipped (if quiet hours are enabled in the rule)
- Each finding is sent only once (tracked by
finding_id)
-
Errors:
401 Unauthorized— not authenticated400 Bad Request— missingX-Organization-Idor invalidprojectId403 Forbidden— no access to organization
-
Usage Example:
const eventSource = new EventSource( '/api/v1/notifications/critical-findings/stream?projectId=01JBP8D8Q9M8K2E8V934A5GJ1D', { headers: { Authorization: 'Bearer <token>', 'X-Organization-Id': '<organization_id>', }, }, ); eventSource.addEventListener('connected', (event) => { console.log('Connected to notifications stream'); }); eventSource.addEventListener('critical_finding', (event) => { const finding = JSON.parse(event.data); console.log('New critical finding:', finding); // Show notification to the user }); eventSource.addEventListener('error', (event) => { console.error('Stream error:', event.data); });
-
Notes:
- SSE connection automatically reconnects on disconnect
- Client should handle
Retry-Afterheader on errors - Connection closes on client request cancellation
- For production, connection pooling and rate limiting are recommended
Important: AAS (Accessibility Accuracy Score) is a metric that evaluates the overall accessibility of a project based on findings and compliance rules.
GET /api/v1/organizations/{organization_id}/aas/current
-
Returns the current AAS score for the organization (the latest score across all projects).
-
Parameters:
organization_id(path) — Organization ID (UUID)
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK:{ "aas_score": 85.5, "run_id": "01JBP8D8Q9M8K2E8V934A5GJ1C", "project_id": "01JBP8D8Q9M8K2E8V934A5GJ1D", "created_at": "2025-11-10T08:30:00.000Z", "weighting_config": { "critical": 1.0, "high": 0.7, "medium": 0.5, "low": 0.3 } } -
Response
404 Not Foundif no AAS data exists for the organization.
GET /api/v1/organizations/{organization_id}/projects/{project_id}/aas/current
- Returns the current AAS score for a specific project.
- Parameters:
organization_id(path) — Organization ID (UUID)project_id(path) — Project ID (UUID)
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: similar to organization response, butproject_idalways matches the requested project. - Response
404 Not Foundif the project is not found or no AAS data exists for the project.
GET /api/v1/organizations/{organization_id}/aas/history
-
Returns the AAS score history for the organization (paginated).
-
Parameters:
organization_id(path) — Organization ID (UUID)limit(query, optional, default: 100, max: 1000) — record countoffset(query, optional, default: 0) — pagination offset
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK:{ "items": [ { "id": "01JBP8D8Q9M8K2E8V934A5GJ1E", "aas_score": 85.5, "run_id": "01JBP8D8Q9M8K2E8V934A5GJ1C", "project_id": "01JBP8D8Q9M8K2E8V934A5GJ1D", "created_at": "2025-11-10T08:30:00.000Z", "weighting_config": { "critical": 1.0, "high": 0.7 } } ], "total": 150, "limit": 100, "offset": 0 } -
Records are sorted by
created_atin descending order (newest first).
GET /api/v1/organizations/{organization_id}/projects/{project_id}/aas/history
- Returns AAS score history for a specific project (paginated).
- Parameters:
organization_id(path) — Organization ID (UUID)project_id(path) — Project ID (UUID)limit(query, optional, default: 100, max: 1000) — record countoffset(query, optional, default: 0) — pagination offset
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: similar to organization response, but all records belong to the specified project. - Response
404 Not Foundif the project is not found.
Important: Compliance Rules are accessibility standards compliance rules (WCAG, EN 301 549, etc.). Rules are global (not tied to an organization), but access is controlled via organization authentication.
GET /api/v1/organizations/{organization_id}/rules
-
Returns a list of compliance rules with filtering and pagination.
-
Parameters:
organization_id(path) — Organization ID (UUID, used for access control)standard(query, optional) — filter by standard (wcag,en_301_549)level(query, optional) — filter by level (a,aa,aaa)category(query, optional) — filter by category (perceivable,operable,understandable,robust)enabled(query, optional) — filter by enabled status (true,false)source(query, optional) — filter by source (axe_core,custom,lighthouse)severity(query, optional) — filter by severity level (critical,high,medium,low)search(query, optional) — search byrule_id,title,descriptionlimit(query, optional, default: 100, max: 1000) — record countoffset(query, optional, default: 0) — pagination offsetsort(query, optional, default:rule_id) — sort field (rule_id,title,standard,created_at)
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK:{ "items": [ { "id": "01JBP8D8Q9M8K2E8V934A5GJ1F", "rule_id": "color-contrast", "title": "Color Contrast", "description": "Elements must have sufficient color contrast", "standard": "wcag", "standard_version": "2.1", "level": "aa", "category": "perceivable", "source": "axe_core", "enabled": true, "severity_default": "high", "metadata": { "test": true }, "ai_analytics": { "explanation": "High contrast is essential for users with low vision.", "fix_suggestions": ["Increase contrast ratio to at least 4.5:1"] }, "created_at": "2025-11-10T08:00:00.000Z", "updated_at": "2025-11-10T08:30:00.000Z" } ], "total": 500, "limit": 100, "offset": 0 }
GET /api/v1/organizations/{organization_id}/rules/{rule_id}
- Returns details for a specific rule.
- Parameters:
organization_id(path) — Organization ID (UUID, used for access control)rule_id(path) — Rule identifier (string, e.g.,color-contrast)
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: Rule object (format as in the list above). - Response
404 Not Foundif rule not found.
PATCH /api/v1/organizations/{organization_id}/rules/{rule_id}/enable
- Enables a compliance rule.
- Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule identifier
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: Updated rule object withenabled: true. - Response
404 Not Foundif rule not found.
PATCH /api/v1/organizations/{organization_id}/rules/{rule_id}/disable
- Disables a compliance rule.
- Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule identifier
- Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
- Response
200 OK: Updated rule object withenabled: false. - Response
404 Not Foundif rule not found.
PATCH /api/v1/organizations/{organization_id}/rules/{rule_id}
-
Updates a compliance rule (enabled status and/or default severity).
-
Parameters:
organization_id(path) — Organization ID (UUID)rule_id(path) — Rule identifier
-
Request Body:
{ "enabled": false, "severity_default": "critical" } -
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK: Updated rule object. -
Response
404 Not Foundif rule not found.
POST /api/v1/organizations/{organization_id}/rules/sync
-
Synchronizes rules from the scanner (dynamic fetch).
-
Requires
owneroradminrole. -
Parameters:
organization_id(path) — Organization ID
-
Headers:
X-Organization-Id— Organization IDX-Actor-Id— User ID
-
Response
200 OK: Sync statistics.{ "checked": 150, "new": 5, "updated": 2, "deleted": 0 }
POST /api/v1/organizations/{organization_id}/rules/actions/generate-ai
-
Triggers AI analytics generation for rules (explanation, fix suggestions).
-
Requires
owneroradminrole. -
Parameters:
organization_id(path) — Organization ID
-
Request Body:
{ "rule_ids": ["color-contrast"], "force": false, "pending_only": true }rule_ids(optional) — list of Rule IDs to process. If specified,pending_onlyis ignored.force(default:false) — overwrite existing analytics.pending_only(default:true) — process only rules marked with the regeneration flag.
-
Response
200 OK:{ "task_id": "01JBP...", "status": "triggered" }
API for managing custom accessibility rules.
POST /api/v1/organizations/{organization_id}/custom-rules
-
Creates a new custom rule.
-
Parameters:
organization_id(path) — Organization ID (UUID)
-
Request Body:
{ "rule_id": "custom-button-label", "title": "Buttons must have explicit labels", "description": "All buttons must have a clean and descriptive label.", "category": "operable", "severity": "high", "standard": "wcag", "standard_version": "2.1", "level": "aa", "metadata": {} } -
Validation:
rule_id: unique, lowercase, alphanumeric with hyphens (3-100 chars)
-
Response
201 Created: created rule object. -
Errors:
409 Conflict: rule with thisrule_idalready exists.400 Bad Request: invalid data.
PUT /api/v1/organizations/{organization_id}/custom-rules/{rule_id}
-
Updates a custom rule.
-
Parameters:
organization_id(path) — Organization IDrule_id(path) — Rule ID
-
Request Body (partial update):
{ "title": "Updated Title", "description": "Updated description...", "severity": "critical", "enabled": true } -
Response
200 OK: updated rule object. -
Errors:
404 Not Found: rule not found or not a custom rule.
DELETE /api/v1/organizations/{organization_id}/custom-rules/{rule_id}
- Deletes a custom rule.
- Parameters:
organization_id(path) — Organization IDrule_id(path) — Rule ID
- Response
204 No Content. - Errors:
404 Not Found: rule not found.403 Forbidden: attempt to delete a system rule (not custom).
GET /api/v1/integrations
-
Returns all integrations connected in the user's organization.
-
Example:
[ { "id": "01JFAXG3D53B2YDM7QYF6X0TPR", "type": "github", "name": "GitHub", "description": "Integrate with GitHub for automated scan workflows", "status": "connected", "configuredAt": "2025-11-19T08:15:30.000Z", "settings": { "repository": "acme/site" }, "hasCredentials": true } ]
POST /api/v1/integrations
-
Creates an integration (
github,gitlab,jira,slack,webhook,jenkins,circleci). -
Body:
{ "type": "slack", "settings": { "channel": "#a11y-alerts" }, "credentials": { "webhookUrl": "https://hooks.slack.com/services/..." } } -
credentialsare encrypted by the service before saving. -
Only one instance of each integration type can exist in an organization.
PATCH /api/v1/integrations/{id}
- Updates
name,settings,credentials,status. - Empty
credentialsobject → secret deletion and status change todisconnected.
DELETE /api/v1/integrations/{id}
- Deletes an integration and clears associated secrets.
- Requires organization membership (verified by gateway middleware).
Endpoint: /graphql, Apollo Federation-ready.
Project,Run,Finding,AccessibilityTree,AudioSample,SimulationStep.
query ProjectRuns($projectId: ID!) {
project(id: $projectId) {
id
name
runs(limit: 10) {
id
type
status
summary {
totalFindings
critical
high
medium
low
}
startedAt
finishedAt
}
}
}
mutation UpdateFinding($input: UpdateFindingInput!) {
updateFinding(input: $input) {
finding {
id
status
owner {
id
email
}
}
errors {
message
path
}
}
}
- Apollo Server + Strawberry federation; DataLoader for Postgres request batching.
- Persisted queries for UI. Support for GraphQL Subscriptions (
scanProgress).
-
POST /api/v1/webhooks/scans—scan.completed,scan.failed,scan.timeoutevents. Payload:{ "event": "scan.completed", "runId": "01JBP8D8Q9M8K2E8V934A5GJ1C", "projectId": "shop", "status": "completed", "metrics": { "critical": 3, "high": 7 } } -
Server-Sent Events
/api/v1/projects/{id}/events—scan-progressevent withpercentage,currentPhase,messagefields. -
Resending on 5xx is supported; client should handle
Retry-After.
FastAPI error format:
{
"error": {
"code": "SCAN_NOT_FOUND",
"message": "Run 123 not found",
"details": {}
}
}
- Tracing:
X-Request-Id. - Rate limit:
429withRetry-Afterheaders.
| Code | Message | Reason | Solution |
|---|---|---|---|
PROJECT_NOT_FOUND |
Project slug does not exist | Invalid identifier | Check the slug |
SCAN_LIMIT_REACHED |
Concurrent scans exceeded | Limit of 5 concurrent scans exceeded | Wait for finish/increase limit |
UNSUPPORTED_FORMAT |
Format must be json/pdf/sarif | Invalid format |
Specify a valid format |
ASSISTIVE_DISABLED |
Assistive simulation not enabled | Feature is disabled | Enable via project settings |
- REST:
/api/v1/(MVP) — supported for at least 12 months. Breaking changes will go into/api/v2/. - GraphQL: schema evolves via
@deprecated(reason, removalDate)directive. - Webhooks are versioned via
X-Accellens-Webhook-Versionheader.
- CLI (
accellens) uses REST API (/api/v1/). - TypeScript SDK (Nx workspace
libs/common/sdk) provides typed clients for REST/GraphQL (beta). - Usage examples can be found in
docs/api/cli-reference.md.
- JWT access token with
exp ≤ 3600(60 minutes), refresh tokens (30 days) updated via/api/v1/auth/refreshwith rotation. - Refresh tokens are stored in httpOnly cookies for XSS protection.
- API keys are restricted by projects, scopes (
scan:write,report:read,admin:manage). - Webhook signing with HMAC SHA256 (
X-Accellens-Signature) — string:sha256=+hex_digest. - All report files are served via signed URLs (AWS S3 pre-signed, expire after 15 minutes).
- Maximum 20 pages per scan (MVP), 5 concurrent scans per project (configurable).
- Mobile build ≤ 500 MB, all uploads undergo antivirus scanning.
- SSE connections are closed after 30 minutes of inactivity.