Skip to main content
digital accessibility compliance for state and local government
Scan a site

Reference

Last updated 28 October 2026 · API version v1

Every endpoint on one page, so your browser’s own search reaches all of it. Each entry is generated from the OpenAPI document the API serves, and each example is a response the sandbox gave.

Reading an entry

Every path below is under the base URL, https://api.barrierops.com/api/v1, and every request but the document’s own sends Authorization: Bearer bo_live_…. An entry gives each method on the path with the scope it needs, its parameters, the body it takes, the fields it answers with and the statuses it can answer. Then one complete example, sent with a bo_test_ key: the command, and the response formatted for reading.

A field whose type is a schema’s name has that schema’s fields in a table of their own, under the first entry on this page that uses it. A field that holds an object of its own is followed by that object’s fields, named by their path, such as assignee.email. A field that holds one of several objects, such as chain in Report, has a table for each object, after the first table on this page that holds the field.

The same description, for a client generator, is the OpenAPI document at /docs/openapi.json and /docs/openapi.yaml. instance is the request id, which is different on every request; this page prints one fixed value in its place.

/openapi.json

This API’s OpenAPI 3.1 document, the one to generate a client from

GET /openapi.json

This document. The OpenAPI 3.1 description of this API, the one clients are generated from. It needs no key, and spends the budget of the address that asks.

Scope: none: this route needs no key

Answers with a JSON object.

Response fields from GET /openapi.json
FieldTypeDescription
  • 200 — The OpenAPI 3.1 document
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support

The document itself is the example: the site publishes it at /docs/openapi.json.

/organizations

The organisations a key reaches: its own, or an agency’s clients

GET /organizations

The organisations this key reaches. An organisation key reaches its own organisation; an agency key, every client of the agency that it has not released — a suspended client is read only; a test key, the sandbox. By name.

Scope: read

Parameters of GET /organizations
NameInTypeRequiredDescription
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.

Answers with a page of Organization: items, nextCursor and total.

Fields of Organization from GET /organizations
FieldTypeDescription
iduuidThe organisation
namestringIts name
readOnlybooleanTrue when this key reads the organisation and can change nothing in it, whatever its scopes: a test key reading the sandbox, or an agency key reaching a client whose link the agency has suspended
  • 200 — The organisations, by name
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /organizations

bash: an example request to /organizations

curl https://api.barrierops.com/api/v1/organizations \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "b7749447-87f3-5d35-beee-99e152f35574",
      "name": "City of Riverbend",
      "readOnly": true
    },
    {
      "id": "ba8d4e08-bff9-5c3b-bb26-cf0b019d840b",
      "name": "Riverbend Public Library",
      "readOnly": true
    },
    {
      "id": "76d68331-b591-5c16-95ea-41d27f95f95a",
      "name": "Riverbend Water District",
      "readOnly": true
    }
  ],
  "nextCursor": null,
  "total": 3
}

Lines are wrapped for printing. The original is one line.

/properties

The assets those organisations audit — list them, and add one

GET /properties

List assets. The live assets of every organisation the key reaches, newest first, or of one of them with orgId.

Scope: read

Parameters of GET /properties
NameInTypeRequiredDescription
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
orgIdqueryuuidNoOnly this organisation’s assets. An organisation the key does not reach matches nothing.

Answers with a page of Property: items, nextCursor and total.

Fields of Property from GET /properties
FieldTypeDescription
iduuidThe asset
orgIduuidThe organisation the asset belongs to
namestringWhat the organisation calls it
baseUrluriThe address scans start from
kindone of website, application or vendor_productwebsite, application, or vendor_product: a system a vendor runs
verificationStateone of unverified, pending, verified, failed, lapsed or revokedWhether the organisation has proved it controls the host. Nothing is scanned until this is verified.
createdAtdate-timeWhen the asset was added
deletedAtdate-time or nullWhen the asset was deleted, or null. A deleted asset is not listed, and is still read by its id so that the evidence about it stays nameable.
  • 200 — The assets, newest first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

POST /properties

Add an asset. Adds an asset to an organisation the key may change: its own, or with orgId, one client of its agency. The asset starts unverified — control of its host is proved in the app — and the edition’s asset limit applies.

Scope: admin

Request body of POST /properties
FieldTypeRequiredDescription
orgIduuidNoThe organisation to add the asset to. Required when the key reaches more than one organisation, as an agency key does; otherwise the key’s own.
namestringYesWhat to call the asset
baseUrluriYesThe address scans will start from
kindone of website, application or vendor_productNowebsite when absent

Answers with Property.

Fields of Property from POST /properties
FieldTypeDescription
iduuidThe asset
orgIduuidThe organisation the asset belongs to
namestringWhat the organisation calls it
baseUrluriThe address scans start from
kindone of website, application or vendor_productwebsite, application, or vendor_product: a system a vendor runs
verificationStateone of unverified, pending, verified, failed, lapsed or revokedWhether the organisation has proved it controls the host. Nothing is scanned until this is verified.
createdAtdate-timeWhen the asset was added
deletedAtdate-time or nullWhen the asset was deleted, or null. A deleted asset is not listed, and is still read by its id so that the evidence about it stays nameable.
  • 201 — The asset, as created
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties

bash: an example request to /properties

curl https://api.barrierops.com/api/v1/properties \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "name": "riverbend.example",
      "baseUrl": "https://www.riverbend.example",
      "kind": "website",
      "verificationState": "verified",
      "createdAt": "2026-07-01T15:40:00.000Z",
      "deletedAt": null
    }
  ],
  "nextCursor": null,
  "total": 1
}

Lines are wrapped for printing. The original is one line.

/properties/{id}

One asset — read it, and change its name or kind

GET /properties/{id}

Read an asset. One asset. A deleted asset is still read by its id, with deletedAt set.

Scope: read

Parameters of GET /properties/{id}
NameInTypeRequiredDescription
idpathuuidYesThe asset

Answers with Property.

Fields of Property from GET /properties/{id}
FieldTypeDescription
iduuidThe asset
orgIduuidThe organisation the asset belongs to
namestringWhat the organisation calls it
baseUrluriThe address scans start from
kindone of website, application or vendor_productwebsite, application, or vendor_product: a system a vendor runs
verificationStateone of unverified, pending, verified, failed, lapsed or revokedWhether the organisation has proved it controls the host. Nothing is scanned until this is verified.
createdAtdate-timeWhen the asset was added
deletedAtdate-time or nullWhen the asset was deleted, or null. A deleted asset is not listed, and is still read by its id so that the evidence about it stays nameable.
  • 200 — The asset
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

PATCH /properties/{id}

Change an asset. Changes an asset’s name or kind; a deleted asset cannot be changed. To monitor a different address, add an asset.

Scope: admin

Parameters of PATCH /properties/{id}
NameInTypeRequiredDescription
idpathuuidYesThe asset
Request body of PATCH /properties/{id}
FieldTypeRequiredDescription
namestringNoA new name
kindone of website, application or vendor_productNoA new kind

Answers with Property.

Fields of Property from PATCH /properties/{id}
FieldTypeDescription
iduuidThe asset
orgIduuidThe organisation the asset belongs to
namestringWhat the organisation calls it
baseUrluriThe address scans start from
kindone of website, application or vendor_productwebsite, application, or vendor_product: a system a vendor runs
verificationStateone of unverified, pending, verified, failed, lapsed or revokedWhether the organisation has proved it controls the host. Nothing is scanned until this is verified.
createdAtdate-timeWhen the asset was added
deletedAtdate-time or nullWhen the asset was deleted, or null. A deleted asset is not listed, and is still read by its id so that the evidence about it stays nameable.
  • 200 — The asset, as changed
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}

bash: an example request to /properties/{id}

curl https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4 \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "name": "riverbend.example",
  "baseUrl": "https://www.riverbend.example",
  "kind": "website",
  "verificationState": "verified",
  "createdAt": "2026-07-01T15:40:00.000Z",
  "deletedAt": null
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/scans

An asset’s scan history, and the trigger that starts a scan

GET /properties/{id}/scans

List an asset’s scans. The asset’s scans, newest first, optionally of some statuses only.

Scope: read

Parameters of GET /properties/{id}/scans
NameInTypeRequiredDescription
idpathuuidYesThe asset
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
statusqueryone of queued, crawling, scanning, complete or failed, or several as repeated keysNoOnly scans in these statuses

Answers with a page of Scan: items, nextCursor and total.

Fields of Scan from GET /properties/{id}/scans
FieldTypeDescription
iduuidThe scan
orgIduuidThe organisation of the asset
propertyIduuidThe asset scanned
statusone of queued, crawling, scanning, complete or failedqueued, crawling, scanning, complete or failed. The last two are final.
createdAtdate-timeWhen the scan was asked for
startedAtdate-time or nullWhen it started, or null
finishedAtdate-time or nullWhen it finished, or null
pagesDiscoveredintegerPages the crawl found
pagesScannedintegerPages a browser loaded and tested. A sample of each template is tested and its result attributed to the template’s other pages, so this is smaller than pagesDiscovered by design.
pagesFailedintegerPages the scan tried and could not test
truncatedbooleanThe crawl stopped at the hard limit of 25,000 pages
limitedbooleanThe scan stopped at the edition’s or the pilot’s page limit. Pages it did not reach are not evidence that an issue is absent from them.
engineVersionChangedbooleanThe scan ran on a different version of its engines from the scan before it, so a change between the two can come from the engines rather than the asset
failureReasonone of cancelled, discovery_failed, discovery_incomplete, discovery_not_started, enqueue_failed, pilot_ended, not_verified, vendor_not_authorised, vendor_nothing_tested, vendor_visit_failed, trial_ended, subscription_ended, agency_suspended, agency_released or nullWhy a failed scan ended without results, or null
  • 200 — The scans, newest first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

POST /properties/{id}/scans

Start a scan. Queues a scan of a verified asset whose scope has been confirmed. Refused with a 409 while the organisation already has as many unfinished scans as the edition lets a key start at once, and for the reasons the app refuses one — an unverified asset, an unconfirmed scope, a subscription that has ended.

Scope: write

Parameters of POST /properties/{id}/scans
NameInTypeRequiredDescription
idpathuuidYesThe asset

Answers with Scan.

Fields of Scan from POST /properties/{id}/scans
FieldTypeDescription
iduuidThe scan
orgIduuidThe organisation of the asset
propertyIduuidThe asset scanned
statusone of queued, crawling, scanning, complete or failedqueued, crawling, scanning, complete or failed. The last two are final.
createdAtdate-timeWhen the scan was asked for
startedAtdate-time or nullWhen it started, or null
finishedAtdate-time or nullWhen it finished, or null
pagesDiscoveredintegerPages the crawl found
pagesScannedintegerPages a browser loaded and tested. A sample of each template is tested and its result attributed to the template’s other pages, so this is smaller than pagesDiscovered by design.
pagesFailedintegerPages the scan tried and could not test
truncatedbooleanThe crawl stopped at the hard limit of 25,000 pages
limitedbooleanThe scan stopped at the edition’s or the pilot’s page limit. Pages it did not reach are not evidence that an issue is absent from them.
engineVersionChangedbooleanThe scan ran on a different version of its engines from the scan before it, so a change between the two can come from the engines rather than the asset
failureReasonone of cancelled, discovery_failed, discovery_incomplete, discovery_not_started, enqueue_failed, pilot_ended, not_verified, vendor_not_authorised, vendor_nothing_tested, vendor_visit_failed, trial_ended, subscription_ended, agency_suspended, agency_released or nullWhy a failed scan ended without results, or null
  • 202 — The scan, queued
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/scans

bash: an example request to /properties/{id}/scans

curl "https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/scans?limit=2" \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "50763701-e469-5512-96d1-4181fa293810",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "status": "complete",
      "createdAt": "2026-10-07T14:40:00.000Z",
      "startedAt": "2026-10-07T14:41:00.000Z",
      "finishedAt": "2026-10-07T15:14:00.000Z",
      "pagesDiscovered": 4102,
      "pagesScanned": 4102,
      "pagesFailed": 0,
      "truncated": false,
      "limited": false,
      "engineVersionChanged": false,
      "failureReason": null
    },
    {
      "id": "e68c305d-03b6-59e6-b477-01ecf259aaa4",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "status": "complete",
      "createdAt": "2026-09-06T14:40:00.000Z",
      "startedAt": "2026-09-06T14:41:00.000Z",
      "finishedAt": "2026-09-06T15:14:00.000Z",
      "pagesDiscovered": 4102,
      "pagesScanned": 4102,
      "pagesFailed": 0,
      "truncated": false,
      "limited": false,
      "engineVersionChanged": false,
      "failureReason": null
    }
  ],
  "nextCursor": "WyIyMDI2LTA5LTA2VDE0OjQwOjAwLjAwMDAwMFoiLCJlNjhjMzA1ZC0wM2I2LTU5ZTYtYjQ3Ny0wMWVjZjI1OWFhYTQiXQ",
  "total": 4
}

Lines are wrapped for printing. The original is one line.

/scans/{id}

One scan: where it stands and what it covered

GET /scans/{id}

Read a scan. One scan: where it stands, what it covered, and whether its engines changed.

Scope: read

Parameters of GET /scans/{id}
NameInTypeRequiredDescription
idpathuuidYesThe scan

Answers with Scan.

Fields of Scan from GET /scans/{id}
FieldTypeDescription
iduuidThe scan
orgIduuidThe organisation of the asset
propertyIduuidThe asset scanned
statusone of queued, crawling, scanning, complete or failedqueued, crawling, scanning, complete or failed. The last two are final.
createdAtdate-timeWhen the scan was asked for
startedAtdate-time or nullWhen it started, or null
finishedAtdate-time or nullWhen it finished, or null
pagesDiscoveredintegerPages the crawl found
pagesScannedintegerPages a browser loaded and tested. A sample of each template is tested and its result attributed to the template’s other pages, so this is smaller than pagesDiscovered by design.
pagesFailedintegerPages the scan tried and could not test
truncatedbooleanThe crawl stopped at the hard limit of 25,000 pages
limitedbooleanThe scan stopped at the edition’s or the pilot’s page limit. Pages it did not reach are not evidence that an issue is absent from them.
engineVersionChangedbooleanThe scan ran on a different version of its engines from the scan before it, so a change between the two can come from the engines rather than the asset
failureReasonone of cancelled, discovery_failed, discovery_incomplete, discovery_not_started, enqueue_failed, pilot_ended, not_verified, vendor_not_authorised, vendor_nothing_tested, vendor_visit_failed, trial_ended, subscription_ended, agency_suspended, agency_released or nullWhy a failed scan ended without results, or null
  • 200 — The scan
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /scans/{id}

bash: an example request to /scans/{id}

curl https://api.barrierops.com/api/v1/scans/50763701-e469-5512-96d1-4181fa293810 \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "50763701-e469-5512-96d1-4181fa293810",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "status": "complete",
  "createdAt": "2026-10-07T14:40:00.000Z",
  "startedAt": "2026-10-07T14:41:00.000Z",
  "finishedAt": "2026-10-07T15:14:00.000Z",
  "pagesDiscovered": 4102,
  "pagesScanned": 4102,
  "pagesFailed": 0,
  "truncated": false,
  "limited": false,
  "engineVersionChanged": false,
  "failureReason": null
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/issues

An asset’s issues, filtered by impact, status, viewport and success criterion

GET /properties/{id}/issues

List an asset’s issues. The asset’s issues, the most recently found first. Filters take several values as repeated keys: ?impact=critical&status=open&status=assigned.

Scope: read

Parameters of GET /properties/{id}/issues
NameInTypeRequiredDescription
idpathuuidYesThe asset
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
statusqueryone of open, assigned, in_progress, ready_to_verify, verified or deferred, or several as repeated keysNoOnly issues in these statuses
impactqueryone of critical, serious, moderate or minor, or several as repeated keysNoOnly issues of these impacts
viewportqueryone of desktop, mobile or tablet, or several as repeated keysNoOnly issues at these layouts
wcagSCquerystring, or several as repeated keysNoOnly issues failing any of these success criteria, as 1.4.3

Answers with a page of Issue: items, nextCursor and total.

Fields of Issue from GET /properties/{id}/issues
FieldTypeDescription
iduuidThe issue
orgIduuidThe organisation of the asset
propertyIduuidThe asset it was found on
titlestringWhat the barrier is
wcagSCarray of stringThe WCAG success criteria it fails
impactone of critical, serious, moderate or minorcritical, serious, moderate or minor
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredopen, assigned, in_progress, ready_to_verify (reported gone, not yet confirmed), verified (confirmed gone, on evidence) or deferred
outcomeone of violation or incompleteviolation, or incomplete: the engine could not decide, and a person has to review it
reviewStateone of pending, pass, fail or not_applicableWhere a person’s review of an incomplete finding stands. An incomplete issue whose review is pending cannot be marked ready to verify, verified or deferred.
viewportone of desktop, mobile or tabletThe layout it was found at. The same barrier at desktop and at mobile is two issues.
assigneeobject or nullWho owns it, or null
assignee.emailstringThe address the person signs in with
assignee.namestring or nullTheir name, when they gave one
occurrenceCountintegerPages it is present on now, attributed pages included. Not a count that adds up across assets.
firstSeenAtdate-timeWhen a scan first found it
updatedAtdate-timeWhen it last changed
  • 200 — The issues, the most recently found first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/issues

bash: an example request to /properties/{id}/issues

curl "https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/issues?impact=critical&status=open&limit=2" \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "274b937b-fb93-5927-9ba6-c81132eb1e9a",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "title": "Input buttons must have discernible text",
      "wcagSC": [
        "4.1.2"
      ],
      "impact": "critical",
      "status": "open",
      "outcome": "violation",
      "reviewState": "pending",
      "viewport": "desktop",
      "assignee": null,
      "occurrenceCount": 30,
      "firstSeenAt": "2026-10-07T15:14:00.000Z",
      "updatedAt": "2026-10-07T15:14:00.000Z"
    },
    {
      "id": "1ee558db-c390-5838-afd8-c25e3b05e69c",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "title": "ARIA attributes must conform to valid values",
      "wcagSC": [
        "4.1.2"
      ],
      "impact": "critical",
      "status": "open",
      "outcome": "violation",
      "reviewState": "pending",
      "viewport": "desktop",
      "assignee": null,
      "occurrenceCount": 300,
      "firstSeenAt": "2026-07-07T15:14:00.000Z",
      "updatedAt": "2026-10-07T15:14:00.000Z"
    }
  ],
  "nextCursor": "eyJzb3J0IjoiZmlyc3RTZWVuQXQiLCJvcmRlciI6ImRlc2MiLCJkaXIiOiJhZnRlciIsInZhbHVlcyI6WyIyMDI2LTA3LTA3VDE1OjE0OjAwLjAwMDAwMFoiLCIxZWU1NThkYi1jMzkwLTU4MzgtYWZkOC1jMjVlM2IwNWU2OWMiXX0",
  "total": 6
}

Lines are wrapped for printing. The original is one line.

/issues/{id}

One issue, and the status and owner changes that move it

GET /issues/{id}

Read an issue. One issue in full, with its deferral record when it is deferred.

Scope: read

Parameters of GET /issues/{id}
NameInTypeRequiredDescription
idpathuuidYesThe issue

Answers with IssueDetail.

Fields of IssueDetail from GET /issues/{id}
FieldTypeDescription
iduuidThe issue
orgIduuidThe organisation of the asset
propertyIduuidThe asset it was found on
titlestringWhat the barrier is
wcagSCarray of stringThe WCAG success criteria it fails
impactone of critical, serious, moderate or minorcritical, serious, moderate or minor
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredopen, assigned, in_progress, ready_to_verify (reported gone, not yet confirmed), verified (confirmed gone, on evidence) or deferred
outcomeone of violation or incompleteviolation, or incomplete: the engine could not decide, and a person has to review it
reviewStateone of pending, pass, fail or not_applicableWhere a person’s review of an incomplete finding stands. An incomplete issue whose review is pending cannot be marked ready to verify, verified or deferred.
viewportone of desktop, mobile or tabletThe layout it was found at. The same barrier at desktop and at mobile is two issues.
assigneeobject or nullWho owns it, or null
assignee.emailstringThe address the person signs in with
assignee.namestring or nullTheir name, when they gave one
occurrenceCountintegerPages it is present on now, attributed pages included. Not a count that adds up across assets.
firstSeenAtdate-timeWhen a scan first found it
updatedAtdate-timeWhen it last changed
plainDescriptionstring or nullWhat is wrong, in plain language, when someone has written it; else null
regressedAtdate-time or nullWhen it most recently came back after being verified, or null
deferralobject or nullThe deferral record of a deferred issue; null otherwise
deferral.reasonstringWhy it was deferred
deferral.ownerobject or nullWho owns the decision
deferral.owner.emailstringThe address the person signs in with
deferral.owner.namestring or nullTheir name, when they gave one
deferral.reviewAtdateWhen the decision is to be reviewed
  • 200 — The issue
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

PATCH /issues/{id}

Change an issue’s status or owner. Moves an issue to a status, assigns it, or both, by the rules the app applies: an incomplete finding needs a person’s review before it can be marked ready to verify, verified or deferred; ready to verify needs a page it is present on and a scan that recorded its engine. The evidence ledger records, naming the key, an assignment to a person, a move to ready to verify, verified or deferred, and a move back from one of those three; any other change adds no event.

Scope: write

Parameters of PATCH /issues/{id}
NameInTypeRequiredDescription
idpathuuidYesThe issue
Request body of PATCH /issues/{id}
FieldTypeRequiredDescription
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredNoThe status to move the issue to
assigneeEmailemail or nullNoThe person to assign it to, by address; null unassigns
deferredReasonstringNoWhy it is deferred, at least 20 characters. Required to defer.
deferredOwnerEmailemailNoWho owns the deferral, by address. Required to defer.
deferredReviewAtdateNoWhen to review the deferral, YYYY-MM-DD. Required to defer.
verificationMethodone of automated or manualNoHow it was verified, automated or manual. Required to verify.

Answers with IssueDetail.

Fields of IssueDetail from PATCH /issues/{id}
FieldTypeDescription
iduuidThe issue
orgIduuidThe organisation of the asset
propertyIduuidThe asset it was found on
titlestringWhat the barrier is
wcagSCarray of stringThe WCAG success criteria it fails
impactone of critical, serious, moderate or minorcritical, serious, moderate or minor
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredopen, assigned, in_progress, ready_to_verify (reported gone, not yet confirmed), verified (confirmed gone, on evidence) or deferred
outcomeone of violation or incompleteviolation, or incomplete: the engine could not decide, and a person has to review it
reviewStateone of pending, pass, fail or not_applicableWhere a person’s review of an incomplete finding stands. An incomplete issue whose review is pending cannot be marked ready to verify, verified or deferred.
viewportone of desktop, mobile or tabletThe layout it was found at. The same barrier at desktop and at mobile is two issues.
assigneeobject or nullWho owns it, or null
assignee.emailstringThe address the person signs in with
assignee.namestring or nullTheir name, when they gave one
occurrenceCountintegerPages it is present on now, attributed pages included. Not a count that adds up across assets.
firstSeenAtdate-timeWhen a scan first found it
updatedAtdate-timeWhen it last changed
plainDescriptionstring or nullWhat is wrong, in plain language, when someone has written it; else null
regressedAtdate-time or nullWhen it most recently came back after being verified, or null
deferralobject or nullThe deferral record of a deferred issue; null otherwise
deferral.reasonstringWhy it was deferred
deferral.ownerobject or nullWho owns the decision
deferral.owner.emailstringThe address the person signs in with
deferral.owner.namestring or nullTheir name, when they gave one
deferral.reviewAtdateWhen the decision is to be reviewed
  • 200 — The issue, as changed
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /issues/{id}

bash: an example request to /issues/{id}

curl https://api.barrierops.com/api/v1/issues/274b937b-fb93-5927-9ba6-c81132eb1e9a \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "274b937b-fb93-5927-9ba6-c81132eb1e9a",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "title": "Input buttons must have discernible text",
  "wcagSC": [
    "4.1.2"
  ],
  "impact": "critical",
  "status": "open",
  "outcome": "violation",
  "reviewState": "pending",
  "viewport": "desktop",
  "assignee": null,
  "occurrenceCount": 30,
  "firstSeenAt": "2026-10-07T15:14:00.000Z",
  "updatedAt": "2026-10-07T15:14:00.000Z",
  "plainDescription": null,
  "regressedAt": null,
  "deferral": null
}

Lines are wrapped for printing. The original is one line.

/issues/{id}/occurrences

The pages an issue appears on — one row per page

GET /issues/{id}/occurrences

List the pages an issue is on. One row per page, the most recently seen first: the pages a browser loaded and, unless attributed=false, the pages that carry the issue by template.

Scope: read

Parameters of GET /issues/{id}/occurrences
NameInTypeRequiredDescription
idpathuuidYesThe issue
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
statequeryone of present or fixedNoOnly present, or only fixed
attributedquerystringNoInclude the pages that carry the issue by template. true when absent; false lists only the pages a browser loaded.

Answers with a page of Occurrence: items, nextCursor and total.

Fields of Occurrence from GET /issues/{id}/occurrences
FieldTypeDescription
issueIduuidThe issue
pageUrluriThe page
pageTitlestring or nullThe page’s title, when it has one
stateone of present or fixedpresent, or fixed: the latest scan of the page no longer found it. Fixed is about this page alone; the issue’s status says what was confirmed.
evidenceSourceone of captured or attributedcaptured: a browser loaded this page and found it. attributed: the page carries it by template, from a sampled page of the same template.
sampledFromPageUrluri or nullFor an attributed row, the sampled page its evidence comes from; else null
domPathstring or nullWhere on the page the element is, as a path through the document
lastSeenAtdate-timeWhen a scan last saw it on this page
  • 200 — The pages, the most recently seen first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /issues/{id}/occurrences

bash: an example request to /issues/{id}/occurrences

curl "https://api.barrierops.com/api/v1/issues/274b937b-fb93-5927-9ba6-c81132eb1e9a/occurrences?limit=2" \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "issueId": "274b937b-fb93-5927-9ba6-c81132eb1e9a",
      "pageUrl": "https://www.riverbend.example/parks/wagon-wheel-park/trails",
      "pageTitle": "Wagon Wheel Park: trails | City of Riverbend",
      "state": "present",
      "evidenceSource": "attributed",
      "sampledFromPageUrl": "https://www.riverbend.example/parks/founders-park",
      "domPath": null,
      "lastSeenAt": "2026-10-07T15:14:00.000Z"
    },
    {
      "issueId": "274b937b-fb93-5927-9ba6-c81132eb1e9a",
      "pageUrl": "https://www.riverbend.example/parks/red-fox-park/parking",
      "pageTitle": "Red Fox Park: parking | City of Riverbend",
      "state": "present",
      "evidenceSource": "attributed",
      "sampledFromPageUrl": "https://www.riverbend.example/parks/founders-park",
      "domPath": null,
      "lastSeenAt": "2026-10-07T15:14:00.000Z"
    }
  ],
  "nextCursor": "eyJzb3J0IjoibGFzdFNlZW4iLCJvcmRlciI6ImRlc2MiLCJkaXIiOiJhZnRlciIsInZhbHVlcyI6WyIyMDI2LTEwLTA3VDE1OjE0OjAwLjAwMDAwMFoiLCIwMTBlYzVhOS0wZDdjLTU4YzUtYTViNy1lNTNmNTgwMTFkNjYiXX0",
  "total": 245
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/documents

The documents an asset links to, and what checking them found

GET /properties/{id}/documents

List an asset’s documents. The documents the asset links to and what checking each found: failed first, then the largest within each state, including the files that could not be checked.

Scope: read

Parameters of GET /properties/{id}/documents
NameInTypeRequiredDescription
idpathuuidYesThe asset
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
statusqueryone of discovered, triaged, validated or failed, or several as repeated keysNoOnly documents in these statuses

Answers with a page of Document: items, nextCursor and total.

Fields of Document from GET /properties/{id}/documents
FieldTypeDescription
iduuidThe document
orgIduuidThe organisation of the asset
propertyIduuidThe asset it was found on
urluriWhere the document is
titlestring or nullThe title the file carries, exactly as it carries it, or null
formatone of pdf, word, excel, powerpoint or otherpdf, word, excel, powerpoint or other
mimeTypestring or nullThe media type it was served with
byteSizeinteger or nullIts size in bytes
pageCountinteger or nullIts pages, when known
statusone of discovered, triaged, validated or faileddiscovered, triaged, validated (checked, with no failed rule) or failed. Validated is not a statement that the document is accessible.
checkStateone of failed, unreadable, too_large, format_unsupported, triaged, discovered or validatedWhat checking it found, including the files that could not be checked: unreadable, too large, or a format that is recorded and not validated
linkedFromUrluri or nullThe page it was linked from, when it was found by following a link
lastSeenAtdate-timeWhen a crawl last found it
  • 200 — The documents
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/documents

bash: an example request to /properties/{id}/documents

curl "https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/documents?status=failed&limit=2" \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "983ffca1-f9ae-5cfb-b556-de64e93a2c17",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "url": "https://www.riverbend.example/meetings/city-council/2026-09-18/packet.pdf",
      "title": "City Council meeting packet, September 18, 2026",
      "format": "pdf",
      "mimeType": "application/pdf",
      "byteSize": 69710,
      "pageCount": 1,
      "status": "failed",
      "checkState": "failed",
      "linkedFromUrl": "https://www.riverbend.example/meetings/city-council/2026-09-18",
      "lastSeenAt": "2026-10-07T15:14:20.000Z"
    },
    {
      "id": "df7306d2-9af6-52b5-af5a-98a66f5a4472",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "url": "https://www.riverbend.example/meetings/city-council/2026-09-09/packet.pdf",
      "title": "City Council meeting packet, September 9, 2026",
      "format": "pdf",
      "mimeType": "application/pdf",
      "byteSize": 69317,
      "pageCount": 1,
      "status": "failed",
      "checkState": "failed",
      "linkedFromUrl": "https://www.riverbend.example/meetings/city-council/2026-09-09",
      "lastSeenAt": "2026-10-07T15:14:20.000Z"
    }
  ],
  "nextCursor": "eyJzb3J0Ijoic3RhdHVzIiwib3JkZXIiOiJhc2MiLCJkaXIiOiJhZnRlciIsInZhbHVlcyI6WzEsMCwiNjkzMTciLCJkZjczMDZkMi05YWY2LTUyYjUtYWY1YS05OGE2NmY1YTQ0NzIiXX0",
  "total": 16
}

Lines are wrapped for printing. The original is one line.

/documents/{id}

One document

GET /documents/{id}

Read a document. One document and what checking it found.

Scope: read

Parameters of GET /documents/{id}
NameInTypeRequiredDescription
idpathuuidYesThe document

Answers with Document.

Fields of Document from GET /documents/{id}
FieldTypeDescription
iduuidThe document
orgIduuidThe organisation of the asset
propertyIduuidThe asset it was found on
urluriWhere the document is
titlestring or nullThe title the file carries, exactly as it carries it, or null
formatone of pdf, word, excel, powerpoint or otherpdf, word, excel, powerpoint or other
mimeTypestring or nullThe media type it was served with
byteSizeinteger or nullIts size in bytes
pageCountinteger or nullIts pages, when known
statusone of discovered, triaged, validated or faileddiscovered, triaged, validated (checked, with no failed rule) or failed. Validated is not a statement that the document is accessible.
checkStateone of failed, unreadable, too_large, format_unsupported, triaged, discovered or validatedWhat checking it found, including the files that could not be checked: unreadable, too large, or a format that is recorded and not validated
linkedFromUrluri or nullThe page it was linked from, when it was found by following a link
lastSeenAtdate-timeWhen a crawl last found it
  • 200 — The document
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /documents/{id}

bash: an example request to /documents/{id}

curl https://api.barrierops.com/api/v1/documents/983ffca1-f9ae-5cfb-b556-de64e93a2c17 \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "983ffca1-f9ae-5cfb-b556-de64e93a2c17",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "url": "https://www.riverbend.example/meetings/city-council/2026-09-18/packet.pdf",
  "title": "City Council meeting packet, September 18, 2026",
  "format": "pdf",
  "mimeType": "application/pdf",
  "byteSize": 69710,
  "pageCount": 1,
  "status": "failed",
  "checkState": "failed",
  "linkedFromUrl": "https://www.riverbend.example/meetings/city-council/2026-09-18",
  "lastSeenAt": "2026-10-07T15:14:20.000Z"
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/vendors

The vendor products linked to an asset, and the evidence on file for each

GET /properties/{id}/vendors

List the vendor products linked to an asset. The vendor products linked to the asset, with the state of the evidence for each: the oldest VPAT first, and the products with none before them.

Scope: read

Parameters of GET /properties/{id}/vendors
NameInTypeRequiredDescription
idpathuuidYesThe asset
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.

Answers with a page of VendorProduct: items, nextCursor and total.

Fields of VendorProduct from GET /properties/{id}/vendors
FieldTypeDescription
iduuidThe vendor product
orgIduuidThe organisation that bought it
propertyIduuid or nullThe asset it is linked to, or null
vendorIduuidThe vendor
vendorNamestringThe vendor’s name
namestringThe product’s name
vpatVersionstring or nullThe version of the VPAT on file, as written on it, or null
vpatDatedate or nullThe date of the VPAT on file, or null
evidenceStatusone of none, requested, received, stale or acceptednone, requested, received, stale or accepted. Stale when the VPAT is more than 24 months old, whatever was recorded before.
contractClausebooleanAn accessibility clause is on file in the contract
slaDaysinteger or nullDays the contract gives the vendor to remediate, or null
nextReviewAtdate or nullWhen the evidence is next reviewed
notesstring or nullThe organisation’s own notes
createdAtdate-timeWhen the product was recorded
updatedAtdate-timeWhen it last changed
  • 200 — The vendor products
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

POST /properties/{id}/vendors

Record a vendor product for an asset. Records a product bought from a vendor of the asset’s organisation, linked to the asset. Its evidence starts at none.

Scope: write

Parameters of POST /properties/{id}/vendors
NameInTypeRequiredDescription
idpathuuidYesThe asset
Request body of POST /properties/{id}/vendors
FieldTypeRequiredDescription
vendorIduuidYesThe vendor, in the asset’s organisation, the product is bought from
namestringYesThe product’s name
contractClausebooleanNoAn accessibility clause is on file in the contract
slaDaysinteger or nullNoDays the contract gives the vendor to remediate
nextReviewAtdate or nullNoWhen the evidence is next to be reviewed
notesstring or nullNoNotes

Answers with VendorProduct.

Fields of VendorProduct from POST /properties/{id}/vendors
FieldTypeDescription
iduuidThe vendor product
orgIduuidThe organisation that bought it
propertyIduuid or nullThe asset it is linked to, or null
vendorIduuidThe vendor
vendorNamestringThe vendor’s name
namestringThe product’s name
vpatVersionstring or nullThe version of the VPAT on file, as written on it, or null
vpatDatedate or nullThe date of the VPAT on file, or null
evidenceStatusone of none, requested, received, stale or acceptednone, requested, received, stale or accepted. Stale when the VPAT is more than 24 months old, whatever was recorded before.
contractClausebooleanAn accessibility clause is on file in the contract
slaDaysinteger or nullDays the contract gives the vendor to remediate, or null
nextReviewAtdate or nullWhen the evidence is next reviewed
notesstring or nullThe organisation’s own notes
createdAtdate-timeWhen the product was recorded
updatedAtdate-timeWhen it last changed
  • 201 — The vendor product, as recorded
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/vendors

bash: an example request to /properties/{id}/vendors

curl https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/vendors \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "1215dd9d-fc89-5035-aac0-ee10e5dbf851",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "vendorId": "7b1c4f1e-4baf-5118-99c4-0fc13b49199f",
      "vendorName": "Northfork Civic Software (fictional)",
      "name": "Agenda Center",
      "vpatVersion": "2.5Rev",
      "vpatDate": "2025-09-12",
      "evidenceStatus": "received",
      "contractClause": false,
      "slaDays": null,
      "nextReviewAt": null,
      "notes": null,
      "createdAt": "2026-07-15T19:00:00.000Z",
      "updatedAt": "2026-07-15T19:00:00.000Z"
    }
  ],
  "nextCursor": null,
  "total": 1
}

Lines are wrapped for printing. The original is one line.

/vendors/{id}

One vendor product, and the changes a script may make to it

GET /vendors/{id}

Read a vendor product. One vendor product and the state of the evidence for it.

Scope: read

Parameters of GET /vendors/{id}
NameInTypeRequiredDescription
idpathuuidYesThe vendor product

Answers with VendorProduct.

Fields of VendorProduct from GET /vendors/{id}
FieldTypeDescription
iduuidThe vendor product
orgIduuidThe organisation that bought it
propertyIduuid or nullThe asset it is linked to, or null
vendorIduuidThe vendor
vendorNamestringThe vendor’s name
namestringThe product’s name
vpatVersionstring or nullThe version of the VPAT on file, as written on it, or null
vpatDatedate or nullThe date of the VPAT on file, or null
evidenceStatusone of none, requested, received, stale or acceptednone, requested, received, stale or accepted. Stale when the VPAT is more than 24 months old, whatever was recorded before.
contractClausebooleanAn accessibility clause is on file in the contract
slaDaysinteger or nullDays the contract gives the vendor to remediate, or null
nextReviewAtdate or nullWhen the evidence is next reviewed
notesstring or nullThe organisation’s own notes
createdAtdate-timeWhen the product was recorded
updatedAtdate-timeWhen it last changed
  • 200 — The vendor product
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

PATCH /vendors/{id}

Change a vendor product. Changes a vendor product’s name, its contract terms or its notes.

Scope: write

Parameters of PATCH /vendors/{id}
NameInTypeRequiredDescription
idpathuuidYesThe vendor product
Request body of PATCH /vendors/{id}
FieldTypeRequiredDescription
namestringNoA new name
contractClausebooleanNoAn accessibility clause is on file in the contract
slaDaysinteger or nullNoDays the contract gives the vendor to remediate
notesstring or nullNoNotes

Answers with VendorProduct.

Fields of VendorProduct from PATCH /vendors/{id}
FieldTypeDescription
iduuidThe vendor product
orgIduuidThe organisation that bought it
propertyIduuid or nullThe asset it is linked to, or null
vendorIduuidThe vendor
vendorNamestringThe vendor’s name
namestringThe product’s name
vpatVersionstring or nullThe version of the VPAT on file, as written on it, or null
vpatDatedate or nullThe date of the VPAT on file, or null
evidenceStatusone of none, requested, received, stale or acceptednone, requested, received, stale or accepted. Stale when the VPAT is more than 24 months old, whatever was recorded before.
contractClausebooleanAn accessibility clause is on file in the contract
slaDaysinteger or nullDays the contract gives the vendor to remediate, or null
nextReviewAtdate or nullWhen the evidence is next reviewed
notesstring or nullThe organisation’s own notes
createdAtdate-timeWhen the product was recorded
updatedAtdate-timeWhen it last changed
  • 200 — The vendor product, as changed
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /vendors/{id}

bash: an example request to /vendors/{id}

curl https://api.barrierops.com/api/v1/vendors/1215dd9d-fc89-5035-aac0-ee10e5dbf851 \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "1215dd9d-fc89-5035-aac0-ee10e5dbf851",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "vendorId": "7b1c4f1e-4baf-5118-99c4-0fc13b49199f",
  "vendorName": "Northfork Civic Software (fictional)",
  "name": "Agenda Center",
  "vpatVersion": "2.5Rev",
  "vpatDate": "2025-09-12",
  "evidenceStatus": "received",
  "contractClause": false,
  "slaDays": null,
  "nextReviewAt": null,
  "notes": null,
  "createdAt": "2026-07-15T19:00:00.000Z",
  "updatedAt": "2026-07-15T19:00:00.000Z"
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/evidence

The evidence ledger, oldest first, in the order the hash chain is walked

GET /properties/{id}/evidence

Read an asset’s evidence ledger. The asset’s ledger, oldest first — the order the hash chain is walked in — optionally of one issue, some events or a range of time.

Scope: read

Parameters of GET /properties/{id}/evidence
NameInTypeRequiredDescription
idpathuuidYesThe asset
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
issueIdqueryuuidNoOnly events about this issue
eventqueryone of discovered, fixed, regressed, assigned, verified, accepted or reopened, or several as repeated keysNoOnly these events
fromquerydate-timeNoOnly events recorded at or after this
toquerydate-timeNoOnly events recorded at or before this

Answers with a page of EvidenceEvent: items, nextCursor and total.

Fields of EvidenceEvent from GET /properties/{id}/evidence
FieldTypeDescription
idstringThe event, a decimal string: it outgrows a JavaScript number
propertyIduuidThe asset whose chain it is in
issueIduuid or nullThe issue it is about, or null
scanIduuid or nullThe scan that recorded it, or null
eventone of discovered, fixed, regressed, assigned, verified, accepted or reopeneddiscovered, fixed (on one page), regressed, assigned, verified, accepted (a deferral decided) or reopened
pageUrlstring or nullThe page it is about, or null
actorEvidenceActorWho recorded the event: a person in the app, an API key by its name, or automated — a scan, or the reconciliation that follows one
createdAtdate-timeWhen it was recorded
eventHashstringThe event’s hash in the chain, 64 lowercase hexadecimal characters: the value the evidence package’s sidecar carries for it
Fields of EvidenceActor when type is person
FieldTypeDescription
typeperson
emailstringTheir address
namestring or nullTheir name, when they gave one
Fields of EvidenceActor when type is api_key
FieldTypeDescription
typeapi_key
namestringThe key’s name
Fields of EvidenceActor when type is automated
FieldTypeDescription
typeautomated
  • 200 — The ledger, oldest first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/evidence

bash: an example request to /properties/{id}/evidence

curl "https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/evidence?limit=2" \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "1",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "issueId": "3bb0d247-96bf-57e6-bd39-e1f832023670",
      "scanId": "1f991ae8-c29d-5a0c-ac20-e2ecdc086aa8",
      "event": "discovered",
      "pageUrl": "https://www.riverbend.example/",
      "actor": {
        "type": "automated"
      },
      "createdAt": "2026-07-07T15:14:00.000Z",
      "eventHash": "d248208409812b5a1bf5a865ff8ad742e8c9a645af46234fd28854bbaab673ad"
    },
    {
      "id": "2",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "issueId": "a9e10f40-7697-5ad9-aa24-c67c9e432d05",
      "scanId": "1f991ae8-c29d-5a0c-ac20-e2ecdc086aa8",
      "event": "discovered",
      "pageUrl": "https://www.riverbend.example/",
      "actor": {
        "type": "automated"
      },
      "createdAt": "2026-07-07T15:14:00.000Z",
      "eventHash": "dc6a00d18a2c4cc4017cd57538fb17655f343ae4e3967e0900d32c096ac33446"
    }
  ],
  "nextCursor": "eyJzb3J0IjoiY3JlYXRlZCIsImRpciI6ImFmdGVyIiwiYXQiOiIyMDI2LTA3LTA3VDE1OjE0OjAwLjAwMDAwMVoiLCJpZCI6IjIifQ",
  "total": 5710
}

Lines are wrapped for printing. The original is one line.

/properties/{id}/evidence/verify

Recompute the hash chain and return what the walk found

POST /properties/{id}/evidence/verify

Verify an asset’s evidence chain. Recomputes every hash of the asset’s ledger and says what the walk found: intact, broken at a named event, or unverifiable with the reason. There is no fourth outcome, and a walk that read nothing is unverifiable. The check is recorded in the audit log, naming the key.

Scope: write

Parameters of POST /properties/{id}/evidence/verify
NameInTypeRequiredDescription
idpathuuidYesThe asset

Answers with EvidenceVerification.

Fields of EvidenceVerification from POST /properties/{id}/evidence/verify when status is intact
FieldTypeDescription
propertyIduuid
statusintact
eventCountinteger
fromdate-time
todate-time
Fields of EvidenceVerification from POST /properties/{id}/evidence/verify when status is broken
FieldTypeDescription
propertyIduuid
statusbroken
firstBrokenEventIdstring
firstBrokenEventPositioninteger
firstBrokenEventAtdate-time
Fields of EvidenceVerification from POST /properties/{id}/evidence/verify when status is unverifiable
FieldTypeDescription
propertyIduuid
statusunverifiable
reasonstring
  • 200 — What the walk found
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /properties/{id}/evidence/verify

bash: an example request to /properties/{id}/evidence/verify

curl -X POST https://api.barrierops.com/api/v1/properties/9ccf6432-ad06-5afe-8a30-52373a0346a4/evidence/verify \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 403

{
  "type": "https://barrierops.app/problems/forbidden",
  "title": "This key does not permit this action",
  "status": 403,
  "detail": "Test keys read the fixture organisation and change nothing.",
  "instance": "00000000-0000-4000-8000-000000000000"
}

Lines are wrapped for printing. The original is one line.

A test key is refused this, as every change. With a live key that has the write scope, the answer is one of three outcomes — the ones the fields above list — and a client that treats anything but intact as a failure is reading it correctly:

The outcomes a chain verification can return, and what each one means. 3 rows.
statusWhat it means
intactEvery event recomputed, with eventCount and the range the walk covered, from and to
brokenThe walk found an event that does not verify: its id, its position in the chain and when it was recorded
unverifiableThe chain could not be read, with the reason — and that is not a pass

There are exactly three outcomes and none of them is “ok”.

/reports

Generate a report, and list the reports there are

GET /reports

List reports. Reports across every organisation the key reaches, newest first; or of one organisation, one asset or one kind.

Scope: read

Parameters of GET /reports
NameInTypeRequiredDescription
cursorquerystringNoThe nextCursor of the page before this one; absent for the first page. Opaque and not signed: do not parse or build one. A cursor the API cannot read is answered with the first page; a readable one is read as the position it names, so pass back exactly the value you were given.
limitqueryinteger from 1 to 200NoHow many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.
orgIdqueryuuidNoOnly this organisation’s reports
propertyIdqueryuuidNoOnly this asset’s reports
kindqueryone of executive_summary, technical_detail or evidence_packageNoOnly reports of this kind

Answers with a page of Report: items, nextCursor and total.

Fields of Report from GET /reports
FieldTypeDescription
iduuidThe report
orgIduuidThe organisation of the asset
propertyIduuidThe asset it reports on
kindone of executive_summary, technical_detail or evidence_packageexecutive_summary, technical_detail or evidence_package
statusone of queued, rendering, ready or failedqueued, rendering, ready or failed. Only a ready report has a PDF.
languagestringThe report’s language, as a BCP 47 tag
scanIduuid or nullThe scan it is built from, or null
compareScanIduuid or nullThe scan an executive summary compares with, or null
periodFromdate-time or nullAn evidence package’s first instant, or null
periodTodate-time or nullThe instant after an evidence package’s last, or null: the range is half-open
chainobject, or anything or nullAn evidence package’s chain verification, frozen when it was made; else null
requestedByReportRequesterWho asked for the report: a person, a schedule, or an API key by its name
requestedAtdate-timeWhen it was asked for
completedAtdate-time or nullWhen it became ready, or null
failedReasonstring or nullWhy it failed, or null
linkExpiresAtdate-time or nullUntil when the report can be downloaded, 90 days from when it became ready unless the link is renewed in the app; null until it is ready
downloadUrluri or nullA link to the PDF, signed for 15 minutes from this response. Null unless the report is ready and its link has not expired, and always null in a demo or sandbox organisation, from which no file is exported.
downloadUrlExpiresAtdate-time or nullWhen downloadUrl stops working, or null
Fields of chain in Report when status is intact
FieldTypeDescription
statusintact
eventCountinteger
fromdate-time
todate-time
Fields of chain in Report when status is broken
FieldTypeDescription
statusbroken
firstBrokenEventIdstring
Fields of chain in Report when status is unverifiable
FieldTypeDescription
statusunverifiable
reasonstring
Fields of ReportRequester when type is person
FieldTypeDescription
typeperson
emailstringTheir address
namestring or nullTheir name, when they gave one
Fields of ReportRequester when type is scheduled
FieldTypeDescription
typescheduled
Fields of ReportRequester when type is api_key
FieldTypeDescription
typeapi_key
namestringThe key’s name
  • 200 — The reports, newest first
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

POST /reports

Generate a report. Queues a report on an asset: an executive summary or a technical report built from a completed scan, or an evidence package of a range of days. It is queued, not finished: read it until its status is ready, or subscribe to report.ready.

Scope: write

Request body of POST /reports when kind is executive_summary — one of these shapes
FieldTypeRequiredDescription
kindexecutive_summaryYes
propertyIduuidYesThe asset to report on
scanIduuidYesA completed scan of the asset
compareScanIduuid or nullNoA second completed scan to compare with, or null
languagestringNoen-US when absent
Request body of POST /reports when kind is technical_detail
FieldTypeRequiredDescription
kindtechnical_detailYes
propertyIduuidYesThe asset to report on
scanIduuidYesA completed scan of the asset
statusarray of one of open, assigned, in_progress, ready_to_verify, verified or deferredNoOnly issues in these statuses; every status when empty
impactarray of one of critical, serious, moderate or minorNoOnly issues of these impacts; every impact when empty
languagestringNoen-US when absent
Request body of POST /reports when kind is evidence_package
FieldTypeRequiredDescription
kindevidence_packageYes
propertyIduuidYesThe asset to report on
fromdateYesThe first day, YYYY-MM-DD
todateYesThe last day, YYYY-MM-DD, included
languagestringNoen-US when absent

Answers with Report.

Fields of Report from POST /reports
FieldTypeDescription
iduuidThe report
orgIduuidThe organisation of the asset
propertyIduuidThe asset it reports on
kindone of executive_summary, technical_detail or evidence_packageexecutive_summary, technical_detail or evidence_package
statusone of queued, rendering, ready or failedqueued, rendering, ready or failed. Only a ready report has a PDF.
languagestringThe report’s language, as a BCP 47 tag
scanIduuid or nullThe scan it is built from, or null
compareScanIduuid or nullThe scan an executive summary compares with, or null
periodFromdate-time or nullAn evidence package’s first instant, or null
periodTodate-time or nullThe instant after an evidence package’s last, or null: the range is half-open
chainobject, or anything or nullAn evidence package’s chain verification, frozen when it was made; else null
requestedByReportRequesterWho asked for the report: a person, a schedule, or an API key by its name
requestedAtdate-timeWhen it was asked for
completedAtdate-time or nullWhen it became ready, or null
failedReasonstring or nullWhy it failed, or null
linkExpiresAtdate-time or nullUntil when the report can be downloaded, 90 days from when it became ready unless the link is renewed in the app; null until it is ready
downloadUrluri or nullA link to the PDF, signed for 15 minutes from this response. Null unless the report is ready and its link has not expired, and always null in a demo or sandbox organisation, from which no file is exported.
downloadUrlExpiresAtdate-time or nullWhen downloadUrl stops working, or null
  • 201 — The report, queued
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 403 — The key cannot make this change: its scopes do not include the one the operation needs, it is a test key, or the agency has suspended its link to this organisation (type agency-read-only)
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 409 — The change conflicts with the current state: detail says why
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /reports

bash: an example request to /reports

curl https://api.barrierops.com/api/v1/reports \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "items": [
    {
      "id": "5d07da36-9e7c-5cf8-83c6-2ac4cb46b4df",
      "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
      "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
      "kind": "evidence_package",
      "status": "ready",
      "language": "en",
      "scanId": null,
      "compareScanId": null,
      "periodFrom": "2026-07-01T00:00:00.000Z",
      "periodTo": "2026-10-09T00:00:00.000Z",
      "chain": {
        "status": "intact",
        "eventCount": 5710,
        "from": "2026-07-07T15:14:00.000Z",
        "to": "2026-10-07T15:14:00.002Z"
      },
      "requestedBy": {
        "type": "person",
        "email": "ruth.delacroix@riverbend.example",
        "name": "Ruth Delacroix"
      },
      "requestedAt": "2026-10-08T15:30:00.000Z",
      "completedAt": "2026-10-08T15:30:00.000Z",
      "failedReason": null,
      "linkExpiresAt": "2027-01-06T15:30:00.000Z",
      "downloadUrl": null,
      "downloadUrlExpiresAt": null
    }
  ],
  "nextCursor": null,
  "total": 1
}

Lines are wrapped for printing. The original is one line.

/reports/{id}

One report: its status, and its link once it is ready

GET /reports/{id}

Read a report. One report: its status, and once it is ready and while its link policy holds, a link to its PDF signed for fifteen minutes.

Scope: read

Parameters of GET /reports/{id}
NameInTypeRequiredDescription
idpathuuidYesThe report

Answers with Report.

Fields of Report from GET /reports/{id}
FieldTypeDescription
iduuidThe report
orgIduuidThe organisation of the asset
propertyIduuidThe asset it reports on
kindone of executive_summary, technical_detail or evidence_packageexecutive_summary, technical_detail or evidence_package
statusone of queued, rendering, ready or failedqueued, rendering, ready or failed. Only a ready report has a PDF.
languagestringThe report’s language, as a BCP 47 tag
scanIduuid or nullThe scan it is built from, or null
compareScanIduuid or nullThe scan an executive summary compares with, or null
periodFromdate-time or nullAn evidence package’s first instant, or null
periodTodate-time or nullThe instant after an evidence package’s last, or null: the range is half-open
chainobject, or anything or nullAn evidence package’s chain verification, frozen when it was made; else null
requestedByReportRequesterWho asked for the report: a person, a schedule, or an API key by its name
requestedAtdate-timeWhen it was asked for
completedAtdate-time or nullWhen it became ready, or null
failedReasonstring or nullWhy it failed, or null
linkExpiresAtdate-time or nullUntil when the report can be downloaded, 90 days from when it became ready unless the link is renewed in the app; null until it is ready
downloadUrluri or nullA link to the PDF, signed for 15 minutes from this response. Null unless the report is ready and its link has not expired, and always null in a demo or sandbox organisation, from which no file is exported.
downloadUrlExpiresAtdate-time or nullWhen downloadUrl stops working, or null
  • 200 — The report
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /reports/{id}

bash: an example request to /reports/{id}

curl https://api.barrierops.com/api/v1/reports/5d07da36-9e7c-5cf8-83c6-2ac4cb46b4df \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY"

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "id": "5d07da36-9e7c-5cf8-83c6-2ac4cb46b4df",
  "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
  "propertyId": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
  "kind": "evidence_package",
  "status": "ready",
  "language": "en",
  "scanId": null,
  "compareScanId": null,
  "periodFrom": "2026-07-01T00:00:00.000Z",
  "periodTo": "2026-10-09T00:00:00.000Z",
  "chain": {
    "status": "intact",
    "eventCount": 5710,
    "from": "2026-07-07T15:14:00.000Z",
    "to": "2026-10-07T15:14:00.002Z"
  },
  "requestedBy": {
    "type": "person",
    "email": "ruth.delacroix@riverbend.example",
    "name": "Ruth Delacroix"
  },
  "requestedAt": "2026-10-08T15:30:00.000Z",
  "completedAt": "2026-10-08T15:30:00.000Z",
  "failedReason": null,
  "linkExpiresAt": "2027-01-06T15:30:00.000Z",
  "downloadUrl": null,
  "downloadUrlExpiresAt": null
}

Lines are wrapped for printing. The original is one line.

/cms/content

Post a page’s address from a CMS and receive its known issues, split into content-authored and template-level

POST /cms/content

Look up a page’s known issues for a CMS. For a CMS: the issues known for one address, split into those the content’s author can fix in the editor — with the content editor’s guidance where it is published — and those that belong to the template or the theme. A read: nothing is stored, and the content identity is returned as sent.

Scope: read

Request body of POST /cms/content
FieldTypeRequiredDescription
urlstringYesThe page’s canonical address
nodeIdstringNoThe CMS’s own id for the content. Returned as sent, and never stored.
contentTypestringNoThe CMS’s content type. Returned as sent, and never stored.
revisionIdstringNoThe CMS’s revision id. Returned as sent, and never stored.

Answers with ContentLookup.

Fields of ContentLookup from POST /cms/content
FieldTypeDescription
urlstringThe address as it was looked up
nodeIdstring or nullThe nodeId sent, or null
contentTypestring or nullThe contentType sent, or null
revisionIdstring or nullThe revisionId sent, or null
propertyobject or nullThe asset the address belongs to, or null when no asset has its host
property.iduuidThe asset
property.orgIduuidIts organisation
property.namestringIts name
pageobject or nullThe page, or null when no crawl has found the address
page.urlstringThe page, as the crawl recorded it
page.lastScannedAtdate-time or nullWhen a browser last loaded the page in a scan, or null: a page covered by its template’s sample carries the template’s issues and was not loaded itself
contentAuthoredarray of ContentAuthoredIssueIssues the page’s author can fix in the editor
templateLevelarray of ContentIssueEvery other issue present on the page: its template’s or its theme’s, fixed in the code rather than the content
Fields of ContentAuthoredIssue
FieldTypeDescription
issueIduuidThe issue; read it at /issues/{id}
titlestringWhat the barrier is
impactone of critical, serious, moderate or minorcritical, serious, moderate or minor
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredIts status, one of the six
wcagSCarray of stringThe WCAG success criteria it fails
guidanceobject or nullThe content-editor guidance for the issue’s rule when it is published; else null
guidance.summarystring or nullThe fix, in a sentence
guidance.whyItMattersstring or nullWho it stops, and how
guidance.howToFixstring or nullThe steps, in Markdown
Fields of ContentIssue
FieldTypeDescription
issueIduuidThe issue; read it at /issues/{id}
titlestringWhat the barrier is
impactone of critical, serious, moderate or minorcritical, serious, moderate or minor
statusone of open, assigned, in_progress, ready_to_verify, verified or deferredIts status, one of the six
wcagSCarray of stringThe WCAG success criteria it fails
  • 200 — The address’s issues, split
  • 400 — The query, the path or the body is not valid: detail names each field and what is wrong with it, or says that the body is not JSON
  • 401 — No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence
  • 404 — No such resource, or it is in an organisation this key does not reach
  • 415 — The body has no Content-Type, or one other than application/json: detail says so
  • 429 — The budget is spent. Retry after the number of seconds in Retry-After
  • 500 — The request could not be completed. Quote instance to support
  • 503 — A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After

Example: /cms/content

bash: an example request to /cms/content

curl -X POST https://api.barrierops.com/api/v1/cms/content \
  -H "Authorization: Bearer $BARRIEROPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.riverbend.example/services/west/report-an-abandoned-vehicle"}'

Lines are wrapped for printing. The original is one line.

json: its complete response, a 200

{
  "url": "https://www.riverbend.example/services/west/report-an-abandoned-vehicle",
  "nodeId": null,
  "contentType": null,
  "revisionId": null,
  "property": {
    "id": "9ccf6432-ad06-5afe-8a30-52373a0346a4",
    "orgId": "b7749447-87f3-5d35-beee-99e152f35574",
    "name": "riverbend.example"
  },
  "page": {
    "url": "https://www.riverbend.example/services/west/report-an-abandoned-vehicle",
    "lastScannedAt": "2026-10-07T15:11:01.000Z"
  },
  "contentAuthored": [],
  "templateLevel": [
    {
      "issueId": "5b418aa0-7d5e-5633-8e7a-9e942ed8c81e",
      "title": "Form elements must have labels",
      "impact": "critical",
      "status": "deferred",
      "wcagSC": [
        "4.1.2"
      ]
    },
    {
      "issueId": "b3ae5c0a-6991-5d03-953d-8e212bb40f57",
      "title": "ARIA input fields must have an accessible name",
      "impact": "serious",
      "status": "open",
      "wcagSC": [
        "4.1.2"
      ]
    }
  ]
}

Lines are wrapped for printing. The original is one line.

The sandbox has no content-authored issue, so for a bo_test_ key contentAuthored is always empty, as it is here, and templateLevel holds every issue on the page. The fields a live key gets in contentAuthored are in the ContentAuthoredIssue table above.

Why this is one page

There is no search box. Every endpoint, parameter and field is on one reference page, so your browser’s own search reaches all of it.

Every endpoint is in this document, none of it is behind a disclosure, and the whole of it prints. That is what replaces a search field — and it is also what makes the page usable at 400% zoom, where a search result you cannot see the context of is worse than a long page you can scroll.

The changelog records every change to this surface, including the day a deprecation is decided rather than the day it ships. The messages the API sends rather than answers are on Webhooks.

https://barrierops.com/docs/reference