{"openapi":"3.1.0","info":{"title":"Ariawalk API","version":"1.0.0","description":"Ariawalk runs task-based accessibility tests. You describe a task a user wants to do, like booking a time slot, and an AI agent tries it on your site the way a blind person would: with the NVDA or JAWS screen reader (emulated), deciding every key press only from what it hears. Every run reports what blocked it, scores, findings with WCAG criteria, how well every control is named, and a screen reader review with fixes.\n\nUse this API, or the MCP server, to run tests from scripts, CI pipelines and AI agents.\n\n## Quick start\n\n1. **Create an API key** in Ariawalk under **API and MCP** ([open](https://ariawalk.com/settings/api)). Choose *Read and run* to start runs.\n2. **Find a test.** List your applications and their tests:\n\n```bash\ncurl https://ariawalk.com/api/v1/applications \\\n  -H \"Authorization: Bearer aw_YOUR_KEY\"\n```\n\n3. **Start a run** and wait for it (runs usually take 20-90 seconds):\n\n```bash\ncurl -X POST https://ariawalk.com/api/v1/tests/TEST_ID/runs -H \"Authorization: Bearer aw_YOUR_KEY\"\ncurl \"https://ariawalk.com/api/v1/runs/RUN_ID?wait=60\" -H \"Authorization: Bearer aw_YOUR_KEY\"\n```\n\n4. **Read the report**, as JSON or as compact Markdown with every issue and its fix:\n\n```bash\ncurl \"https://ariawalk.com/api/v1/runs/RUN_ID/report?format=markdown\" -H \"Authorization: Bearer aw_YOUR_KEY\"\n```\n\n## Run tests on your machine and in CI (CLI)\n\nThe full guide is at [https://ariawalk.com/docs/cli](https://ariawalk.com/docs/cli).\n\nThe `ariawalk` CLI runs the same tests with the browser on your own machine or CI runner, so it can test `localhost`, staging sites behind a VPN and preview deployments. The agent's decisions, the review and the report stay in Ariawalk. It can test any address the machine reaches.\n\n```bash\nnpx ariawalk install          # once: the Chromium the CLI drives\nnpx ariawalk login            # confirm a code in your browser\nnpx ariawalk tests            # your tests and their ids\nnpx ariawalk run <testId> --base-url http://localhost:3000\n```\n\n`ariawalk run` without an id lets you pick tests from a checklist; `--app <name>` runs every test of an application. Runs from your machine land in your own *local* environment and runs in CI in `ci:<branch>`, so they never become the baseline for production runs. Secret test data is never sent to the CLI: pass it with `--data key=value` or `ARIAWALK_DATA_<KEY>`.\n\n**Pass or fail.** `--fail-on` decides what fails the build: `blocked` (the default: the task couldn't be finished), `regression` (worse than the baseline: the last run on the branch, else on the default branch), `new-serious` (new serious or blocker issues since the baseline) or `none`; combine them with commas. `--min-score 80` fails tests scoring lower. Exit codes: `0` passed, `1` an accessibility check failed, `2` a run couldn't finish (setup, quota, network), which never counts as an accessibility failure.\n\n**Results.** `--junit results.xml`, `--markdown summary.md` and `--json-file results.json`. On GitHub Actions the summary is added to the job's step summary automatically.\n\n**GitHub Actions** (create an API key with *Read and run* access and store it as a secret):\n\n```yaml\n- uses: actions/setup-node@v5\n  with: { node-version: 24 }\n- run: npx ariawalk install --with-deps\n- run: npx ariawalk run --app \"My shop\" --base-url ${{ steps.deploy.outputs.url }} --fail-on blocked,regression --junit ariawalk.xml\n  env:\n    ARIAWALK_API_KEY: ${{ secrets.ARIAWALK_API_KEY }}\n    ARIAWALK_DATA_PASSWORD: ${{ secrets.STAGING_PASSWORD }}\n```\n\nTo test the build inside the job instead, start it first (`npm run build && npm start &`) and use `--base-url http://localhost:3000`. Behind a VPN, use a self-hosted runner inside it or a VPN step (WireGuard, Tailscale) before the run.\n\n**GitLab CI:**\n\n```yaml\naccessibility:\n  image: node:24\n  script:\n    - npx ariawalk install --with-deps\n    - npx ariawalk run --app \"My shop\" --base-url \"$PREVIEW_URL\" --junit ariawalk.xml\n  artifacts:\n    reports: { junit: ariawalk.xml }\n```\n\n**Coding agents** can test the dev server too. `npx ariawalk mcp` is a local MCP server (stdio) whose browser runs on your machine, so agents can run tests against `localhost`, read the findings and fix them: `claude mcp add ariawalk -- npx -y ariawalk mcp` (log in once with `npx ariawalk login`; put secret test data in its environment as `ARIAWALK_DATA_<KEY>`). Agents that run shell commands can use the CLI directly instead: `npx ariawalk skills install` adds a skill (`.claude/skills/ariawalk/SKILL.md`) that teaches them how.\n\n## Connect an AI agent (MCP)\n\nAriawalk is an MCP server at `https://ariawalk.com/mcp` (streamable HTTP), authenticated with an API key. Its runs use Ariawalk's browsers, so they test public sites; to test `localhost` from an agent, use the local server `npx ariawalk mcp` (see the CLI section). Agents can then create tests, run them, wait for results, read reports and compare runs.\n\n**Claude Code**\n\n```bash\nclaude mcp add --transport http ariawalk https://ariawalk.com/mcp --header \"Authorization: Bearer aw_YOUR_KEY\"\n```\n\n**Cursor, Claude Desktop and other MCP clients** (`mcp.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"ariawalk\": {\n      \"type\": \"http\",\n      \"url\": \"https://ariawalk.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer aw_YOUR_KEY\" }\n    }\n  }\n}\n```\n\n**Tools:** `list_applications`, `get_application`, `get_test`, `create_test`, `start_run` (can wait for the result), `run_all`, `get_run`, `get_report` (Markdown with every issue and fix, or JSON), `compare_runs`, `cancel_run`, `get_batch`, `get_usage`.\n\nTry asking your agent: *\"Use Ariawalk to run the checkout test, then fix the issues it finds.\"*\n\n## Authentication\n\nSend your key in the `Authorization` header: `Bearer aw_…`. Keys belong to one organization and only see its data.\n\n- **Read only** keys can list and read applications, tests, runs and reports.\n- **Read and run** keys can also create tests and start or stop runs.\n\nA key acts as the member who created it, with their current role: only owners' and admins' keys can create tests (`403 forbidden` otherwise); members' keys can run the tests that exist. A key stops working when it's revoked, or when the member who created it leaves the organization. Keep keys secret: anyone with a key can use your organization’s usage.\n\n## Runs, domains and usage\n\n- Tests can run on **any public site**; hosted runs only reach public addresses. Secret test data is only typed on the test's start site and the application's sites. A site you haven't verified you own has a daily run limit (50 runs per organization, and a shared limit across organizations); starting past it returns `402 quota_exceeded`.\n- Runs use **credits** from your organization's monthly allowance, then from bought credits: 2 when a run starts, plus 1 for every AI call (4 on the advanced model). A typical run uses about 12. `GET /usage` shows what's left. When usage is used up, starting a run returns `402 quota_exceeded`, and a run in progress stops with status `cancelled`. With paid usage on, more credits are bought automatically, up to the monthly limit set on the billing page.\n- As a safeguard there's also a daily run limit (a fifth of the month's usage) and a monthly and daily AI budget. Past either, starting a run also returns `402 quota_exceeded`, and a running run stops with an error.\n- `GET /runs/{id}?wait=` counts each check while it waits toward the rate limit, like a request of its own.\n- Runs are queued and start as soon as a slot is free. Poll `GET /runs/{runId}?wait=60`: the answer comes as soon as the run finishes, or after 60 seconds.\n- `comparison` on a run is the verdict against the previous run of the same test: `regression`, `improved`, `path-changed` or `same`.\n- Every run belongs to an **environment**. Runs started in Ariawalk, by a schedule or through this API are `production`. Baselines, latest results and run lists stay within one environment; pass `?environment=` to see another. `/runs/{runId}/comparison?with=` can still compare across environments.\n\n## Errors and limits\n\nErrors are JSON: `{ \"error\": { \"code\": \"…\", \"message\": \"…\" } }`. The message is written for people.\n\n| Status | Code | Meaning |\n| --- | --- | --- |\n| 400 | `invalid_request` | A field is missing or invalid |\n| 401 | `unauthorized` | Missing, invalid or revoked key |\n| 402 | `quota_exceeded` | This month's usage, the daily run limit or the AI budget is used up |\n| 403 | `forbidden` | The key can only read, or its creator's role doesn't allow this |\n| 404 | `not_found` | Not found, or not in your organization |\n| 429 | `rate_limited` | Over 120 requests per minute for this key |\n"},"tags":[{"name":"Applications","description":"Websites you test, with their sites (verified or not)."},{"name":"Tests","description":"Saved tasks a user wants to do, like \"book a time slot\"."},{"name":"Runs","description":"One execution of a test: status, scores, report and comparison."},{"name":"Batches","description":"Every test of an application run together (\"run all\")."},{"name":"Account","description":"Your organization’s usage."},{"name":"Local runs","description":"Used by the `ariawalk` CLI: the browser runs on your machine or CI runner (so it can test localhost and sites behind a VPN), while decisions, the review and the report stay in Ariawalk. Per-step calls authenticate with the run token returned when the run is created."}],"servers":[{"url":"https://ariawalk.com/api/v1"}],"security":[{"apiKey":[]}],"paths":{"/applications":{"get":{"operationId":"listApplications","summary":"List applications","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Application"}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Applications"]}},"/applications/{applicationId}":{"get":{"operationId":"getApplication","summary":"An application with its tests and their latest results","parameters":[{"name":"applicationId","in":"path","required":true,"schema":{"type":"string"},"description":"Application id"},{"name":"environment","in":"query","schema":{"type":"string","default":"production"},"description":"Only runs in this environment: \"production\" (the default), a named environment like \"staging\", \"ci:<branch>\" or \"local:<userId>\"."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationDetail"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Applications"]}},"/applications/{applicationId}/tests":{"post":{"operationId":"createTest","summary":"Create a test (run access, owners and admins)","description":"The start URL must be on one of the application's sites. The key's creator must be an owner or admin of the organization.","parameters":[{"name":"applicationId","in":"path","required":true,"schema":{"type":"string"},"description":"Application id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Test"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Tests"]}},"/applications/{applicationId}/runs":{"post":{"operationId":"runAll","summary":"Run all of an application's tests (run access)","parameters":[{"name":"applicationId","in":"path","required":true,"schema":{"type":"string"},"description":"Application id"}],"responses":{"202":{"description":"Started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchStarted"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/QuotaExceeded"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/tests/{testId}":{"get":{"operationId":"getTest","summary":"A test","parameters":[{"name":"testId","in":"path","required":true,"schema":{"type":"string"},"description":"Test id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Test"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Tests"]}},"/tests/{testId}/runs":{"get":{"operationId":"listRuns","summary":"A test's latest 20 runs in one environment, newest first","parameters":[{"name":"testId","in":"path","required":true,"schema":{"type":"string"},"description":"Test id"},{"name":"environment","in":"query","schema":{"type":"string","default":"production"},"description":"Only runs in this environment: \"production\" (the default), a named environment like \"staging\", \"ci:<branch>\" or \"local:<userId>\"."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Run"}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]},"post":{"operationId":"startRun","summary":"Start a run of a test (run access)","description":"Starts one run per screen reader of the test, each using its own usage. They are queued and start as soon as a slot is free. The response is the first run; when there are several, `runs` lists each one's id and screen reader. Poll GET /runs/{runId}?wait=60.","parameters":[{"name":"testId","in":"path","required":true,"schema":{"type":"string"},"description":"Test id"}],"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartedRun"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/QuotaExceeded"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/me":{"get":{"operationId":"whoAmI","summary":"Who this key belongs to: user, organization and the key itself","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}}},"organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"key":{"type":"object","properties":{"name":{"type":"string"},"scope":{"enum":["read","run"]}}}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Account"]}},"/cli/organizations":{"get":{"operationId":"listCliOrganizations","summary":"`ariawalk login`: the organizations the logged-in user can pick (device-login session token)","description":"The CLI logs in with Better Auth's device authorization (POST /api/auth/device/code, then /api/auth/device/token while the user confirms the code at /device) and calls this with the session token it gets.","security":[{"sessionToken":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Account"]}},"/cli/key":{"post":{"operationId":"createCliKey","summary":"`ariawalk login`: a \"Read and run\" API key for one organization; signs the device-login session out","security":[{"sessionToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organizationId","clientName"],"properties":{"organizationId":{"type":"string"},"clientName":{"type":"string","description":"The machine, for the key name \"CLI · <machine>\""}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Account"]}},"/cli/logout":{"post":{"operationId":"logOut","summary":"Revoke the key making this request (`ariawalk logout`)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Account"]}},"/local-runs":{"post":{"operationId":"createLocalRun","summary":"Start a run whose browser runs on your machine (run access)","description":"Uses the organization’s credits. The start URL moves to `baseUrl`; any address the machine reaches works, localhost and private hosts included. Runs belong to the `local:<userId>` environment, or `ci:<branch>` with `ci`. Secret test data values are never returned: supply them locally.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLocalRun"}}}},"responses":{"201":{"description":"Started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocalRun"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/QuotaExceeded"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/heartbeat":{"post":{"operationId":"heartbeatLocalRun","summary":"Keep the run alive (run token): call every 30 s; runs silent for 2 minutes are interrupted","description":"Any other call of the run counts too. A run stopped in Ariawalk (or interrupted) answers 409 with the reason, and the CLI stops.","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"enum":["running"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/decide":{"post":{"operationId":"decideLocalRunStep","summary":"The next screen reader command, from what the user heard (run token)","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/verify":{"post":{"operationId":"verifyLocalRunCompletion","summary":"Check a claim that the task is done (run token)","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"confirmed":{"type":"boolean"},"reason":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/events":{"post":{"operationId":"recordLocalRunEvents","summary":"Record steps and findings, in order (run token)","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"recorded":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/screenshots/{n}":{"put":{"operationId":"uploadLocalRunScreenshot","summary":"A step's screenshot, as a JPEG of at most 3 MB (run token)","description":"Stored like a hosted run's. The CLI then sets screenshotKey on the step; the key is always made by Ariawalk.","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"},{"name":"n","in":"path","required":true,"schema":{"type":"integer","minimum":1},"description":"Step number"}],"requestBody":{"required":true,"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/local-runs/{runId}/finish":{"post":{"operationId":"finishLocalRun","summary":"End the run: outcome, scores and transcript; Ariawalk writes the review and comparison (run token)","security":[{"runToken":[]}],"parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/RunEnded"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Local runs"]}},"/runs/{runId}":{"get":{"operationId":"getRun","summary":"A run's status and scores","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"},{"name":"wait","in":"query","schema":{"type":"integer","minimum":0,"maximum":60},"description":"Wait up to this many seconds for the run to finish before answering."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/runs/{runId}/report":{"get":{"operationId":"getReport","summary":"The full report: steps, findings, scores, naming review, screen reader review","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"},{"name":"format","in":"query","schema":{"enum":["json","markdown"]},"description":"markdown: a compact, readable report with every issue and its fix."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}},"text/markdown":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/runs/{runId}/comparison":{"get":{"operationId":"getComparison","summary":"What changed since the previous run (or another run of the same test)","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"},{"name":"with","in":"query","schema":{"type":"string"},"description":"Compare with this run of the same test instead of the previous one."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comparison"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/runs/{runId}/cancel":{"post":{"operationId":"cancelRun","summary":"Stop a queued or running run (run access)","parameters":[{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Run id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Runs"]}},"/batches/{batchId}":{"get":{"operationId":"getBatch","summary":"A \"run all\" batch and its runs","parameters":[{"name":"batchId","in":"path","required":true,"schema":{"type":"string"},"description":"Batch id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Batches"]}},"/usage":{"get":{"operationId":"getUsage","summary":"This month’s usage: the share of the allowance used, credits left and paid usage","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"tags":["Account"]}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An Ariawalk API key, aw_…"},"runToken":{"type":"http","scheme":"bearer","description":"The run token of a local run, rt_…, from POST /local-runs"},"sessionToken":{"type":"http","scheme":"bearer","description":"The session token from device login (Better Auth), used once by ariawalk login"}},"responses":{"Invalid":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks run access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found (or another organization's)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests for this key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"QuotaExceeded":{"description":"The monthly or daily run quota, or the organization's AI budget, is used up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RunEnded":{"description":"The run has ended, timed out or used all its decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}},"Domain":{"type":"object","properties":{"hostname":{"type":"string"},"verified":{"type":"boolean"}}},"Application":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"testCount":{"type":"integer"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}}},"ApplicationDetail":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"domains":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}},"environment":{"type":"string","description":"The environment `tests[].lastRun` and `openIssues` are from."},"tests":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"startUrl":{"type":"string"},"lastRun":{"type":["object","null"],"properties":{"id":{"type":"string"},"status":{"enum":["queued","running","completed","blocked","inconclusive","error","interrupted","cancelled"]},"comparison":{"enum":["regression","improved","path-changed","same",null]},"createdAt":{"type":"string","format":"date-time"}}},"openIssues":{"type":["object","null"],"properties":{"total":{"type":"integer"},"blockers":{"type":"integer"}}},"schedule":{"type":["string","null"],"description":"e.g. \"Every day at 09:00\""}}}}}},"TestData":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":["string","null"],"description":"Null for secrets: they are never returned."},"secret":{"type":"boolean"}},"required":["key"]},"Test":{"type":"object","properties":{"id":{"type":"string"},"applicationId":{"type":"string"},"name":{"type":"string"},"startUrl":{"type":"string"},"task":{"type":"string"},"maxSteps":{"type":"integer","description":"Decisions the agent may make; each is one screen reader command."},"screenReaders":{"type":"array","items":{"type":"string","enum":["nvda","jaws"]},"description":"Screen readers the agent uses: \"nvda\" (NVDA with Chrome), \"jaws\" (JAWS with Chrome). Each start of the test makes one run per screen reader."},"screenReaderLanguage":{"type":"string","enum":["en","sv"],"description":"Language the screen reader speaks its role and state words in."},"extendedVisualChecks":{"type":"boolean","description":"Also checks each page in dark mode, at 320 px wide, with increased text spacing and on hover."},"modelTier":{"type":"string","enum":["standard","advanced"],"description":"The AI that decides each step. Advanced uses 4 credits per call instead of 1."},"milestones":{"type":"array","items":{"$ref":"#/components/schemas/Milestone"}},"signInTestId":{"type":["string","null"],"description":"The sign-in test whose saved sign-in this test’s runs start with; null when the task signs in itself."},"isSignInTest":{"type":"boolean","description":"Whether other tests start signed in with this one."},"savedSignIn":{"type":["object","null"],"description":"For a sign-in test: when its latest completed hosted run saved the sign-in, and until when runs use it (30 minutes). The browser state itself is never returned.","properties":{"capturedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}},"data":{"type":"array","items":{"$ref":"#/components/schemas/TestData"}}}},"Milestone":{"type":"object","description":"A checkpoint the agent checks off on the way: a step (\"Open the reports page\") or a question (\"How many tickets were closed in the last 30 days?\").","required":["text"],"properties":{"text":{"type":"string","minLength":3,"maxLength":300},"expected":{"type":"string","maxLength":200,"description":"For a question: the answer a screen reader user should find, e.g. \"128\". Never shown to the agent; its answer is compared with it."}}},"MilestoneResult":{"type":"object","properties":{"text":{"type":"string"},"expected":{"type":"string"},"step":{"type":"integer","description":"The step it was checked off on; missing when it was never reached."},"evidence":{"type":"string","description":"What the agent heard that proves it."},"answer":{"type":"string","description":"The agent's answer, for a question."},"correct":{"type":"boolean","description":"Whether the answer matches `expected`; missing without one."}}},"CreateTest":{"type":"object","required":["name","startUrl","task"],"properties":{"name":{"type":"string","maxLength":120},"startUrl":{"type":"string","format":"uri"},"task":{"type":"string","minLength":10,"maxLength":2000,"description":"What a user wants to do, e.g. \"Book a time slot for Monday 13:00\"."},"maxSteps":{"type":"integer","minimum":1,"maximum":200,"default":100,"description":"Decisions the agent may make; each is one screen reader command."},"screenReaders":{"type":"array","items":{"type":"string","enum":["nvda","jaws"]},"minItems":1,"default":["nvda"],"description":"Screen readers the agent uses: \"nvda\" (NVDA with Chrome), \"jaws\" (JAWS with Chrome; English only for now). With both, every start of the test makes one run per screen reader, each using its own usage, so it uses twice as much."},"screenReader":{"type":"string","enum":["nvda","jaws"],"deprecated":true,"description":"One screen reader: the same as `screenReaders` with one item."},"screenReaderLanguage":{"type":"string","enum":["en","sv"],"default":"en","description":"Language the screen reader speaks its role and state words in: en (English), sv (Swedish)."},"extendedVisualChecks":{"type":"boolean","default":false,"description":"Also check each page in dark mode, at 320 px wide (reflow), with increased text spacing and on hover. Adds a few seconds per page."},"modelTier":{"type":"string","enum":["standard","advanced"],"default":"standard","description":"The AI that decides each step. Advanced handles long or tricky flows better and uses 4 credits per call instead of 1; where it isn’t offered, runs use standard."},"milestones":{"type":"array","maxItems":10,"items":{"$ref":"#/components/schemas/Milestone"},"description":"Checkpoints the agent checks off on the way, in order."},"signInTestId":{"type":["string","null"],"default":null,"description":"Start signed in: a test of the same application whose task signs in (and doesn’t start signed in itself). Its completed hosted runs save the sign-in for 30 minutes; this test’s runs start with it, running the sign-in test first when none is fresh."},"data":{"type":"array","description":"Values the agent may type. Secrets are encrypted, never sent to the model, and masked in reports.","items":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string"},"value":{"type":"string"},"secret":{"type":"boolean","default":false}}}}}},"Scores":{"type":["object","null"],"description":"Accessibility scores, 0-100.","properties":{"overall":{"type":"integer"},"context":{"type":"integer"},"journey":{"type":["integer","null"],"description":"Screen reader journey: how much effort reaching each control takes with the screen reader, and whether changes are announced."},"keyboard":{"type":["integer","null"],"description":"Keyboard effort, for runs from before screen reader runs."},"design":{"type":"integer"},"partial":{"type":"boolean"}}},"Run":{"type":"object","properties":{"id":{"type":"string"},"testId":{"type":"string"},"applicationId":{"type":"string"},"batchId":{"type":["string","null"]},"status":{"enum":["queued","running","completed","blocked","inconclusive","error","interrupted","cancelled"]},"finished":{"type":"boolean"},"trigger":{"enum":["manual","schedule","app_batch","local","ci"]},"environment":{"type":"string","description":"Where the run belongs: \"production\" for runs started in Ariawalk, by a schedule or the API, a named environment, \"ci:<branch>\" or \"local:<userId>\". Comparisons and latest results stay within one environment."},"origin":{"type":["string","null"],"description":"The origin the run tested, e.g. \"https://example.com\"."},"task":{"type":"string"},"startUrl":{"type":"string"},"screenReader":{"type":["string","null"],"enum":["nvda","jaws",null],"description":"The screen reader this run used; null for runs from before there was a choice (NVDA)."},"screenReaderLanguage":{"type":["string","null"],"enum":["en","sv",null]},"summary":{"type":["string","null"]},"error":{"type":["string","null"]},"stepsCount":{"type":"integer"},"findingsCount":{"type":"integer"},"milestones":{"type":"array","items":{"$ref":"#/components/schemas/MilestoneResult"},"description":"The test's milestones when the run started, and which were reached."},"comparison":{"enum":["regression","improved","path-changed","same",null],"description":"Verdict against the previous run of the same test in the same environment."},"scores":{"$ref":"#/components/schemas/Scores"},"signInTestId":{"type":["string","null"],"description":"The sign-in test this run started signed in with."},"signInRunId":{"type":["string","null"],"description":"The sign-in run this run waited for; null when a saved sign-in was still fresh."},"createdAt":{"type":"string","format":"date-time"},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"url":{"type":"string","description":"The report in the Ariawalk app."}}},"StartedRun":{"allOf":[{"$ref":"#/components/schemas/Run"},{"type":"object","properties":{"runs":{"type":"array","description":"Only when the test has several screen readers: every run started, the first one included. When usage ran out part-way, only those that started.","items":{"type":"object","properties":{"id":{"type":"string"},"screenReader":{"type":"string","enum":["nvda","jaws"]}}}}}}]},"Report":{"type":"object","description":"Steps (with every key press and what the screen reader said, and the tab order seen), findings (task, screen reader, axe and keyboard-focus checks, with WCAG criteria), scores including `scores.context.controls` (every control with its naming issues and fixes), and `review` (an AI screen reader review: summary, strengths, issues with fixes, each citing a WCAG criterion and W3C technique where one applies). `signals` lists what the visited pages held (`forms`, `sign-in`, `images`, `media`, `moving-content`, `gestures`, `several-pages`), which picks the WCAG criteria to check by hand; null for runs from before it was recorded. `site` is the tested host and whether the organization verified it owns it (`{ host, verified }`), or null for private hosts. `run.signInTestId` and `run.signInRunId` name the sign-in test and run it started with, as on Run.","additionalProperties":true},"Comparison":{"type":"object","description":"Verdict, reasons, outcome and score change, path diff, and new / fixed / still-open findings.","additionalProperties":true},"BatchStarted":{"type":"object","properties":{"batchId":{"type":"string"},"started":{"type":"integer","description":"Runs started: one per test and screen reader."},"skippedUnverified":{"type":"integer","description":"Tests a hosted run can't start: plain http or private start URLs (run them with the CLI). Named before anyone could test any site."},"skippedQuota":{"type":"integer","description":"Tests not started because usage ran out."},"url":{"type":"string"}}},"Batch":{"type":"object","additionalProperties":true},"Usage":{"type":"object","properties":{"plan":{"type":"string","enum":["free","starter","pro","team"]},"percentUsed":{"type":"integer","description":"Share of this month’s included credits used, 0–100."},"allowance":{"type":"integer","description":"Credits included this month."},"allowanceUsed":{"type":"integer"},"boughtCredits":{"type":"integer","description":"Bought credits left; used after the allowance."},"remaining":{"type":"integer","description":"Credits left to spend this month, included and bought."},"runsStarted":{"type":"integer"},"resetsAt":{"type":"string","format":"date-time"},"paidUsage":{"type":"object","properties":{"enabled":{"type":"boolean"},"limitCents":{"type":"integer"},"spentCents":{"type":"integer"}}}}},"CreateLocalRun":{"type":"object","required":["testId"],"properties":{"testId":{"type":"string"},"baseUrl":{"type":"string","format":"uri","description":"Replaces the start URL's origin, e.g. http://localhost:3000"},"screenReader":{"type":"string","enum":["nvda","jaws"],"description":"Which of the test's screen readers this run uses; its first when left out. Start one run per screen reader in `screenReaders`."},"ci":{"type":"object","required":["branch"],"description":"Set when running in CI: the run belongs to ci:<branch>, with the default branch as fallback baseline.","properties":{"provider":{"type":"string"},"repo":{"type":"string"},"branch":{"type":"string"},"defaultBranch":{"type":"string"},"sha":{"type":"string"},"pr":{"type":"integer"},"jobUrl":{"type":"string","format":"uri"}}}}},"LocalRun":{"type":"object","properties":{"runId":{"type":"string"},"token":{"type":"string","description":"Run token for the per-step calls (Authorization: Bearer rt_…)."},"environment":{"type":"string","description":"Where the run belongs: \"production\" for runs started in Ariawalk, by a schedule or the API, a named environment, \"ci:<branch>\" or \"local:<userId>\". Comparisons and latest results stay within one environment."},"url":{"type":"string"},"task":{"type":"string"},"startUrl":{"type":"string"},"maxSteps":{"type":"integer"},"screenReader":{"type":"string","enum":["nvda","jaws"],"description":"The screen reader this run uses."},"screenReaders":{"type":"array","items":{"type":"string","enum":["nvda","jaws"]},"description":"All of the test's screen readers: run it once with each."},"speechLanguage":{"enum":["en","sv"]},"extendedVisualChecks":{"type":"boolean"},"milestones":{"type":"array","items":{"$ref":"#/components/schemas/Milestone"}},"allowedHosts":{"type":"array","items":{"type":"string"},"description":"Host patterns the browser may visit; \"*\" is any host."},"secretHosts":{"type":"array","items":{"type":"string"},"description":"Host patterns where secret test data may be typed: the start site and the application's sites."},"data":{"type":"array","items":{"$ref":"#/components/schemas/TestData"}}}}}}}