---
title: "A11Y Record Scan"
method: POST
path: "/v1/projects/{project_id}/a11y/scan"
tags: ["a11y"]
---

# A11Y Record Scan

`POST /v1/projects/{project_id}/a11y/scan`

## Request

- Base URL: `https://api.sonenta.dev`
- URL: `https://api.sonenta.dev/v1/projects/{project_id}/a11y/scan`
- Auth: none declared

Record ONE mechanical a11y code scan: recap + the keys it SAW (Developer+).

The scan itself runs client-side (`sonenta a11y scan` CLI or the sonenta-a11y
agent): it parses usage sites, infers each key's type and persists it through
the normal key-update paths with `type_source='detected'`. But a retype that
merely CONFIRMS `text` writes nothing, so the server could not tell a key the
scan had looked at from one it had never opened. `seen_key_uuids` carries that
fact: every uuid in it is stamped `type_analyzed_at` + `type_analyzed_scan_id`
(task 1827), whatever the type outcome was — including a `refused_manual`,
which IS a key the scan saw.

BATCHING: omit `scan_id` to open a run (the response carries the minted id),
then echo it on each follow-up batch so one run stamps one id; a `scan_id`
that is not the project's current run is a 422. Recap counters are SET, not
summed — send the run's full totals on every batch. Idempotent: re-posting a
batch stamps the same keys with the same id.

Writes NO translations and no overrides; on keys it writes only the two
analysis-marker fields — no `updated_at` bump, no audit row, so a 16k-key scan
does not flood the activity feed. `last_run_at` is stamped server-side.

## Path parameters

- `project_id` string, required

## Request body

- A11yScanIn
  - `keys_scanned` integer, required
  - `keys_classified` integer, required
  - `tool` string, required
  - `tool_version` string, required
  - `scan_id` string, nullable
  - `seen_key_uuids` string[]

## Response `200`

Successful Response

- A11yScanOut: The recap PLUS what this call stamped (task 1827). `seen_unresolved` is reported, never silently dropped: a uuid that matches no live key of the project is a client-side bug worth seeing.
  - `last_run_at` string, date-time, required
  - `keys_scanned` integer, required
  - `keys_classified` integer, required
  - `tool` string, required
  - `tool_version` string, required
  - `scan_id` string, nullable
  - `recorded_by_user_uuid` string, nullable
  - `recorded_by_api_key_uuid` string, nullable
  - `seen_submitted` integer
  - `seen_stamped` integer
  - `seen_unresolved` integer
  - `seen_total_for_scan` integer

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/sonenta/apis/sonenta-api.md) · [All operations](https://skmtc.dev/sonenta/apis/sonenta-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sonenta/apis/sonenta-api/revisions/f853ea49fb05?raw)
