{
  "openapi": "3.1.0",
  "info": {
    "title": "BarrierOps API",
    "version": "1.0.0",
    "description": "The public API of BarrierOps: the assets an organisation audits, their scans, issues, documents and vendor products, the evidence ledger and its verification, and reports. Path-versioned: within /api/v1 a change is additive only -- a new field, a new endpoint, a new optional parameter -- and a breaking change is a new version, with both served for at least 12 months.\n\n**Authentication.** An API key in `Authorization: Bearer`, never in a query string or a cookie. A key is `bo_live_` or `bo_test_` followed by 48 characters; it is shown once, when it is created in the app under Settings, API keys, and is hashed at rest. Its scopes follow the app’s roles: `read` reads, and every key has it; `write` starts scans, changes an issue’s status and owner, records vendor products, generates reports and verifies the evidence chain; `admin` adds and changes assets. A `bo_test_` key reads the sandbox -- fictional organisations, cloned from the demo -- and changes nothing.\n\n**Tenancy.** A key reaches its own organisation or, for an agency’s key, each client of the agency that it has not released. An id outside what the key reaches is a 404, never a 403, so an id cannot be probed.\n\n**Pagination.** A list takes `cursor` and `limit` -- 50 by default, 200 at most, a larger limit refused -- and answers `{ items, nextCursor, total }`. `nextCursor` is null on the last page. The cursor is opaque.\n\n**Rate limits.** Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`, errors included, but two: a browser’s CORS preflight, answered before any key is read, and a 500 when the rate limiter itself fails. Each key has its own budget a minute, set by the organisation’s edition; a request without an accepted key spends its network’s, 60 a minute -- an IPv4 address, or an IPv6 /64. Checking a key’s secret is the costly step of a request, so a request whose key the server has not checked in the last five minutes also spends one request of its network’s budget, before the check; while that budget is spent, such a request is refused with a 429 that carries the network’s figures. A 429 carries `Retry-After`.\n\n**Errors.** Every error is `application/problem+json`. Branch on `type`; quote `instance`, the request id, to support.\n\n**Webhooks.** The messages under `webhooks` are sent to the endpoints an organisation configures in the app, signed with HMAC-SHA256 in `BarrierOps-Signature`. Each carries ids and a link, never findings."
  },
  "servers": [
    {
      "url": "https://api.barrierops.com/api/v1",
      "description": "Live and test keys alike"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "organizations",
      "description": "The organisations a key reaches"
    },
    {
      "name": "properties",
      "description": "Assets: the sites and applications an organisation audits"
    },
    {
      "name": "scans",
      "description": "An asset’s scans, and starting one"
    },
    {
      "name": "issues",
      "description": "Issues, the changes that move them, and the pages they are on"
    },
    {
      "name": "documents",
      "description": "The documents an asset links to, and what checking found"
    },
    {
      "name": "vendors",
      "description": "Vendor products, and the accessibility evidence for each"
    },
    {
      "name": "evidence",
      "description": "The evidence ledger, and verifying its hash chain"
    },
    {
      "name": "reports",
      "description": "Generating reports, and reading their status and link"
    },
    {
      "name": "cms",
      "description": "A CMS’s view of one page: the issues its author can fix"
    },
    {
      "name": "document",
      "description": "This document"
    },
    {
      "name": "webhooks",
      "description": "The messages sent to an organisation’s endpoints"
    }
  ],
  "components": {
    "headers": {
      "X-RateLimit-Limit": {
        "description": "The requests this budget allows in a minute, which is also the most it serves back to back: the key’s; or its network’s, for a request without an accepted key and for one refused before its key’s secret was checked.",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "example": 300
        }
      },
      "X-RateLimit-Remaining": {
        "description": "The requests left before the budget refuses one.",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 0,
          "example": 297
        }
      },
      "X-RateLimit-Reset": {
        "description": "When the budget is whole again, as a Unix timestamp in seconds.",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 0,
          "example": 1790000001
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before the budget serves another request.",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "example": 12
        }
      },
      "WWW-Authenticate": {
        "description": "The scheme to authenticate with: a bearer token, as RFC 6750 asks of a 401. The same value for every refusal.",
        "required": true,
        "schema": {
          "type": "string",
          "example": "Bearer realm=\"BarrierOps API\""
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key: `bo_live_` or `bo_test_` followed by 48 lowercase hexadecimal characters, created in the app under Settings, API keys, and shown once."
      }
    },
    "schemas": {
      "ScanCompletedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "scan.completed"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "scanId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "scanId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "A scan finished. The message carries ids and a link to /api/v1/scans/{id}, never the findings: read the rest with a key."
      },
      "ScanFailedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "scan.failed"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "scanId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "scanId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "A scan could not finish. The message carries ids and a link to /api/v1/scans/{id}, never the findings: read the rest with a key."
      },
      "IssueDiscoveredEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "issue.discovered"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "issueId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "scanId": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "issueId",
              "propertyId",
              "scanId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "An issue was found for the first time. The message carries ids and a link to /api/v1/issues/{id}, never the findings: read the rest with a key."
      },
      "IssueRegressedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "issue.regressed"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "issueId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "scanId": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "issueId",
              "propertyId",
              "scanId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "An issue was found again on a page where a scan or a journey run had stopped finding it. The message carries ids and a link to /api/v1/issues/{id}, never the findings: read the rest with a key."
      },
      "IssueReadyToVerifyEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "issue.ready_to_verify"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "issueId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "issueId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "An issue was reported gone and is waiting to be verified. The message carries ids and a link to /api/v1/issues/{id}, never the findings: read the rest with a key."
      },
      "IssueVerifiedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "issue.verified"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "issueId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "issueId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "An issue was confirmed gone, by a scan or by a person who retested it. The message carries ids and a link to /api/v1/issues/{id}, never the findings: read the rest with a key."
      },
      "DocumentValidatedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "document.validated"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "documentId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "A document finished validation. The message carries ids and a link to /api/v1/documents/{id}, never the findings: read the rest with a key."
      },
      "VendorEvidenceStaleEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "vendor.evidence_stale"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "vendorProductId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "vendorProductId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "A vendor product’s VPAT became more than 24 months old. The message carries ids and a link to /api/v1/vendors/{id}, never the findings: read the rest with a key."
      },
      "ReportReadyEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "report.ready"
            ]
          },
          "created": {
            "type": "string",
            "pattern": "\\+00:00$"
          },
          "orgId": {
            "type": "string",
            "format": "uuid"
          },
          "test": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "reportId": {
                "type": "string",
                "format": "uuid"
              },
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "reportId",
              "propertyId",
              "url"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "type",
          "created",
          "orgId",
          "test",
          "data"
        ],
        "additionalProperties": false,
        "description": "A generated report is ready to download. The message carries ids and a link to /api/v1/reports/{id}, never the findings: read the rest with a key."
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "minLength": 1
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "instance"
        ],
        "description": "An error, as application/problem+json. `type` names the kind of error and is what to branch on; `detail` says what happened in a sentence; `instance` is the request id, the reference to quote to support.",
        "example": {
          "type": "https://barrierops.app/problems/not-found",
          "title": "Not found",
          "status": 404,
          "detail": "No such resource, or it is not yours",
          "instance": "0f6c3b2a-9d8e-4f7a-8b6c-5d4e3f2a1b0c"
        }
      },
      "OrganizationList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Organization"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "The organisations this key reaches, by name."
      },
      "Organization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Its name."
          },
          "readOnly": {
            "type": "boolean",
            "description": "True 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."
          }
        },
        "required": [
          "id",
          "name",
          "readOnly"
        ],
        "description": "An organisation the key reaches: its own, for an organisation key; each active or suspended client, for an agency key; the sandbox, for a test key.",
        "example": {
          "id": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "name": "City of Riverbend",
          "readOnly": false
        }
      },
      "PropertyList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Property"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "Live assets, newest first, across every organisation the key reaches unless narrowed."
      },
      "Property": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The asset."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation the asset belongs to."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "What the organisation calls it."
          },
          "baseUrl": {
            "type": "string",
            "format": "uri",
            "description": "The address scans start from."
          },
          "kind": {
            "type": "string",
            "enum": [
              "website",
              "application",
              "vendor_product"
            ],
            "description": "website, application, or vendor_product: a system a vendor runs."
          },
          "verificationState": {
            "type": "string",
            "enum": [
              "unverified",
              "pending",
              "verified",
              "failed",
              "lapsed",
              "revoked"
            ],
            "description": "Whether the organisation has proved it controls the host. Nothing is scanned until this is verified."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the asset was added."
          },
          "deletedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When 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."
          }
        },
        "required": [
          "id",
          "orgId",
          "name",
          "baseUrl",
          "kind",
          "verificationState",
          "createdAt",
          "deletedAt"
        ],
        "description": "An asset: a site or application the organisation audits.",
        "example": {
          "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "name": "City of Riverbend",
          "baseUrl": "https://www.riverbend.example",
          "kind": "website",
          "verificationState": "verified",
          "createdAt": "2026-06-01T15:04:05.000Z",
          "deletedAt": null
        }
      },
      "PropertyCreate": {
        "type": "object",
        "properties": {
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The 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."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "What to call the asset."
          },
          "baseUrl": {
            "type": "string",
            "format": "uri",
            "description": "The address scans will start from."
          },
          "kind": {
            "type": "string",
            "enum": [
              "website",
              "application",
              "vendor_product"
            ],
            "default": "website",
            "description": "website when absent."
          }
        },
        "required": [
          "name",
          "baseUrl"
        ],
        "description": "A new asset. It starts unverified, and is not scanned until control of its host is proved in the app.",
        "example": {
          "name": "Riverbend Parks",
          "baseUrl": "https://parks.riverbend.example"
        }
      },
      "PropertyUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "A new name."
          },
          "kind": {
            "type": "string",
            "enum": [
              "website",
              "application",
              "vendor_product"
            ],
            "description": "A new kind."
          }
        },
        "additionalProperties": false,
        "description": "The fields of an asset to change: its name, its kind, or both. At least one is required, and any other field is refused.",
        "example": {
          "name": "City of Riverbend main site"
        }
      },
      "ScanList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Scan"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "An asset’s scans, newest first."
      },
      "Scan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The scan."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation of the asset."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset scanned."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "crawling",
              "scanning",
              "complete",
              "failed"
            ],
            "description": "queued, crawling, scanning, complete or failed. The last two are final."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the scan was asked for."
          },
          "startedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it started, or null."
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it finished, or null."
          },
          "pagesDiscovered": {
            "type": "integer",
            "minimum": 0,
            "description": "Pages the crawl found."
          },
          "pagesScanned": {
            "type": "integer",
            "minimum": 0,
            "description": "Pages 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."
          },
          "pagesFailed": {
            "type": "integer",
            "minimum": 0,
            "description": "Pages the scan tried and could not test."
          },
          "truncated": {
            "type": "boolean",
            "description": "The crawl stopped at the hard limit of 25,000 pages."
          },
          "limited": {
            "type": "boolean",
            "description": "The 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."
          },
          "engineVersionChanged": {
            "type": "boolean",
            "description": "The 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."
          },
          "failureReason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "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",
              null
            ],
            "description": "Why a failed scan ended without results, or null."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "status",
          "createdAt",
          "startedAt",
          "finishedAt",
          "pagesDiscovered",
          "pagesScanned",
          "pagesFailed",
          "truncated",
          "limited",
          "engineVersionChanged",
          "failureReason"
        ],
        "description": "One scan of an asset: where it stands and what it covered.",
        "example": {
          "id": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c01",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "status": "complete",
          "createdAt": "2026-10-05T14:00:00.000Z",
          "startedAt": "2026-10-05T14:00:02.000Z",
          "finishedAt": "2026-10-05T14:31:40.000Z",
          "pagesDiscovered": 4102,
          "pagesScanned": 96,
          "pagesFailed": 0,
          "truncated": false,
          "limited": false,
          "engineVersionChanged": false,
          "failureReason": null
        }
      },
      "IssueList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "An asset’s issues, the most recently found first."
      },
      "Issue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The issue."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation of the asset."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset it was found on."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "What the barrier is."
          },
          "wcagSC": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The WCAG success criteria it fails."
          },
          "impact": {
            "type": "string",
            "enum": [
              "critical",
              "serious",
              "moderate",
              "minor"
            ],
            "description": "critical, serious, moderate or minor."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "assigned",
              "in_progress",
              "ready_to_verify",
              "verified",
              "deferred"
            ],
            "description": "open, assigned, in_progress, ready_to_verify (reported gone, not yet confirmed), verified (confirmed gone, on evidence) or deferred."
          },
          "outcome": {
            "type": "string",
            "enum": [
              "violation",
              "incomplete"
            ],
            "description": "violation, or incomplete: the engine could not decide, and a person has to review it."
          },
          "reviewState": {
            "type": "string",
            "enum": [
              "pending",
              "pass",
              "fail",
              "not_applicable"
            ],
            "description": "Where 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."
          },
          "viewport": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile",
              "tablet"
            ],
            "description": "The layout it was found at. The same barrier at desktop and at mobile is two issues."
          },
          "assignee": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "email": {
                "type": "string",
                "description": "The address the person signs in with."
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Their name, when they gave one."
              }
            },
            "required": [
              "email",
              "name"
            ],
            "description": "Who owns it, or null.",
            "example": {
              "email": "leah.hartwell@riverbend.example",
              "name": "Leah Hartwell"
            }
          },
          "occurrenceCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Pages it is present on now, attributed pages included. Not a count that adds up across assets."
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When a scan first found it."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it last changed."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "title",
          "wcagSC",
          "impact",
          "status",
          "outcome",
          "reviewState",
          "viewport",
          "assignee",
          "occurrenceCount",
          "firstSeenAt",
          "updatedAt"
        ],
        "description": "One barrier on one asset, grouped across the pages it appears on: an issue, never a count of findings.",
        "example": {
          "id": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "title": "Images must have alternative text",
          "wcagSC": [
            "1.1.1"
          ],
          "impact": "critical",
          "status": "open",
          "outcome": "violation",
          "reviewState": "pending",
          "viewport": "desktop",
          "assignee": null,
          "occurrenceCount": 12,
          "firstSeenAt": "2026-09-14T15:00:00.000Z",
          "updatedAt": "2026-10-05T14:31:40.000Z"
        }
      },
      "IssueDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The issue."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation of the asset."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset it was found on."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "What the barrier is."
          },
          "wcagSC": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The WCAG success criteria it fails."
          },
          "impact": {
            "type": "string",
            "enum": [
              "critical",
              "serious",
              "moderate",
              "minor"
            ],
            "description": "critical, serious, moderate or minor."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "assigned",
              "in_progress",
              "ready_to_verify",
              "verified",
              "deferred"
            ],
            "description": "open, assigned, in_progress, ready_to_verify (reported gone, not yet confirmed), verified (confirmed gone, on evidence) or deferred."
          },
          "outcome": {
            "type": "string",
            "enum": [
              "violation",
              "incomplete"
            ],
            "description": "violation, or incomplete: the engine could not decide, and a person has to review it."
          },
          "reviewState": {
            "type": "string",
            "enum": [
              "pending",
              "pass",
              "fail",
              "not_applicable"
            ],
            "description": "Where 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."
          },
          "viewport": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile",
              "tablet"
            ],
            "description": "The layout it was found at. The same barrier at desktop and at mobile is two issues."
          },
          "assignee": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "email": {
                "type": "string",
                "description": "The address the person signs in with."
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Their name, when they gave one."
              }
            },
            "required": [
              "email",
              "name"
            ],
            "description": "Who owns it, or null.",
            "example": {
              "email": "leah.hartwell@riverbend.example",
              "name": "Leah Hartwell"
            }
          },
          "occurrenceCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Pages it is present on now, attributed pages included. Not a count that adds up across assets."
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When a scan first found it."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it last changed."
          },
          "plainDescription": {
            "type": [
              "string",
              "null"
            ],
            "description": "What is wrong, in plain language, when someone has written it; else null."
          },
          "regressedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it most recently came back after being verified, or null."
          },
          "deferral": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "reason": {
                "type": "string",
                "description": "Why it was deferred."
              },
              "owner": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "The address the person signs in with."
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Their name, when they gave one."
                  }
                },
                "required": [
                  "email",
                  "name"
                ],
                "description": "Who owns the decision.",
                "example": {
                  "email": "leah.hartwell@riverbend.example",
                  "name": "Leah Hartwell"
                }
              },
              "reviewAt": {
                "type": "string",
                "format": "date",
                "description": "When the decision is to be reviewed."
              }
            },
            "required": [
              "reason",
              "owner",
              "reviewAt"
            ],
            "description": "The deferral record of a deferred issue; null otherwise."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "title",
          "wcagSC",
          "impact",
          "status",
          "outcome",
          "reviewState",
          "viewport",
          "assignee",
          "occurrenceCount",
          "firstSeenAt",
          "updatedAt",
          "plainDescription",
          "regressedAt",
          "deferral"
        ],
        "description": "One issue in full.",
        "example": {
          "id": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "title": "Images must have alternative text",
          "wcagSC": [
            "1.1.1"
          ],
          "impact": "critical",
          "status": "open",
          "outcome": "violation",
          "reviewState": "pending",
          "viewport": "desktop",
          "assignee": null,
          "occurrenceCount": 12,
          "firstSeenAt": "2026-09-14T15:00:00.000Z",
          "updatedAt": "2026-10-05T14:31:40.000Z",
          "plainDescription": null,
          "regressedAt": null,
          "deferral": null
        }
      },
      "IssueUpdate": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "open",
              "assigned",
              "in_progress",
              "ready_to_verify",
              "verified",
              "deferred"
            ],
            "description": "The status to move the issue to."
          },
          "assigneeEmail": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "description": "The person to assign it to, by address; null unassigns."
          },
          "deferredReason": {
            "type": "string",
            "description": "Why it is deferred, at least 20 characters. Required to defer."
          },
          "deferredOwnerEmail": {
            "type": "string",
            "format": "email",
            "description": "Who owns the deferral, by address. Required to defer."
          },
          "deferredReviewAt": {
            "type": "string",
            "format": "date",
            "description": "When to review the deferral, YYYY-MM-DD. Required to defer."
          },
          "verificationMethod": {
            "type": "string",
            "enum": [
              "automated",
              "manual"
            ],
            "description": "How it was verified, automated or manual. Required to verify."
          }
        },
        "description": "A change to an issue’s status, its owner, or both. The evidence ledger records, naming the key that made it, 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.",
        "example": {
          "status": "assigned",
          "assigneeEmail": "leah.hartwell@riverbend.example"
        }
      },
      "OccurrenceList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Occurrence"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "The pages an issue appears on, the most recently seen first."
      },
      "Occurrence": {
        "type": "object",
        "properties": {
          "issueId": {
            "type": "string",
            "format": "uuid",
            "description": "The issue."
          },
          "pageUrl": {
            "type": "string",
            "format": "uri",
            "description": "The page."
          },
          "pageTitle": {
            "type": [
              "string",
              "null"
            ],
            "description": "The page’s title, when it has one."
          },
          "state": {
            "type": "string",
            "enum": [
              "present",
              "fixed"
            ],
            "description": "present, 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."
          },
          "evidenceSource": {
            "type": "string",
            "enum": [
              "captured",
              "attributed"
            ],
            "description": "captured: a browser loaded this page and found it. attributed: the page carries it by template, from a sampled page of the same template."
          },
          "sampledFromPageUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "For an attributed row, the sampled page its evidence comes from; else null."
          },
          "domPath": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where on the page the element is, as a path through the document."
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When a scan last saw it on this page."
          }
        },
        "required": [
          "issueId",
          "pageUrl",
          "pageTitle",
          "state",
          "evidenceSource",
          "sampledFromPageUrl",
          "domPath",
          "lastSeenAt"
        ],
        "description": "One page an issue appears on, and where the evidence for it comes from.",
        "example": {
          "issueId": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "pageUrl": "https://www.riverbend.example/council/agendas",
          "pageTitle": "Agendas and minutes",
          "state": "present",
          "evidenceSource": "captured",
          "sampledFromPageUrl": null,
          "domPath": "html>body>main>img:nth-child(2)",
          "lastSeenAt": "2026-10-05T14:31:40.000Z"
        }
      },
      "DocumentList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Document"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "An asset’s documents: failed first, then the largest within each state."
      },
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The document."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation of the asset."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset it was found on."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Where the document is."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "The title the file carries, exactly as it carries it, or null."
          },
          "format": {
            "type": "string",
            "enum": [
              "pdf",
              "word",
              "excel",
              "powerpoint",
              "other"
            ],
            "description": "pdf, word, excel, powerpoint or other."
          },
          "mimeType": {
            "type": [
              "string",
              "null"
            ],
            "description": "The media type it was served with."
          },
          "byteSize": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Its size in bytes."
          },
          "pageCount": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Its pages, when known."
          },
          "status": {
            "type": "string",
            "enum": [
              "discovered",
              "triaged",
              "validated",
              "failed"
            ],
            "description": "discovered, triaged, validated (checked, with no failed rule) or failed. Validated is not a statement that the document is accessible."
          },
          "checkState": {
            "type": "string",
            "enum": [
              "failed",
              "unreadable",
              "too_large",
              "format_unsupported",
              "triaged",
              "discovered",
              "validated"
            ],
            "description": "What checking it found, including the files that could not be checked: unreadable, too large, or a format that is recorded and not validated."
          },
          "linkedFromUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The page it was linked from, when it was found by following a link."
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "description": "When a crawl last found it."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "url",
          "title",
          "format",
          "mimeType",
          "byteSize",
          "pageCount",
          "status",
          "checkState",
          "linkedFromUrl",
          "lastSeenAt"
        ],
        "description": "A document an asset links to, and what checking it found.",
        "example": {
          "id": "7f6e5d4c-3b2a-4190-8f7e-6d5c4b3a2901",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "url": "https://www.riverbend.example/files/council-minutes-2026-09.pdf",
          "title": "Council minutes, September 2026",
          "format": "pdf",
          "mimeType": "application/pdf",
          "byteSize": 482133,
          "pageCount": 14,
          "status": "failed",
          "checkState": "failed",
          "linkedFromUrl": "https://www.riverbend.example/council/agendas",
          "lastSeenAt": "2026-10-05T14:20:11.000Z"
        }
      },
      "VendorProductList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorProduct"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "The vendor products linked to an asset, the oldest VPAT first and those with none before them."
      },
      "VendorProduct": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The vendor product."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation that bought it."
          },
          "propertyId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The asset it is linked to, or null."
          },
          "vendorId": {
            "type": "string",
            "format": "uuid",
            "description": "The vendor."
          },
          "vendorName": {
            "type": "string",
            "minLength": 1,
            "description": "The vendor’s name."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "The product’s name."
          },
          "vpatVersion": {
            "type": [
              "string",
              "null"
            ],
            "description": "The version of the VPAT on file, as written on it, or null."
          },
          "vpatDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The date of the VPAT on file, or null."
          },
          "evidenceStatus": {
            "type": "string",
            "enum": [
              "none",
              "requested",
              "received",
              "stale",
              "accepted"
            ],
            "description": "none, requested, received, stale or accepted. Stale when the VPAT is more than 24 months old, whatever was recorded before."
          },
          "contractClause": {
            "type": "boolean",
            "description": "An accessibility clause is on file in the contract."
          },
          "slaDays": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "Days the contract gives the vendor to remediate, or null."
          },
          "nextReviewAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "When the evidence is next reviewed."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "The organisation’s own notes."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the product was recorded."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it last changed."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "vendorId",
          "vendorName",
          "name",
          "vpatVersion",
          "vpatDate",
          "evidenceStatus",
          "contractClause",
          "slaDays",
          "nextReviewAt",
          "notes",
          "createdAt",
          "updatedAt"
        ],
        "description": "A product bought from a vendor, and the accessibility evidence filed for it.",
        "example": {
          "id": "2a3b4c5d-6e7f-4809-9a1b-2c3d4e5f6081",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "vendorId": "2a3b4c5d-6e7f-4809-9a1b-2c3d4e5f6071",
          "vendorName": "Riverside Civic Software",
          "name": "Agenda Manager",
          "vpatVersion": "2.5Rev",
          "vpatDate": "2024-03-01",
          "evidenceStatus": "stale",
          "contractClause": true,
          "slaDays": 90,
          "nextReviewAt": "2027-01-15",
          "notes": null,
          "createdAt": "2026-06-02T16:00:00.000Z",
          "updatedAt": "2026-09-20T18:12:00.000Z"
        }
      },
      "VendorProductCreate": {
        "type": "object",
        "properties": {
          "vendorId": {
            "type": "string",
            "format": "uuid",
            "description": "The vendor, in the asset’s organisation, the product is bought from."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The product’s name."
          },
          "contractClause": {
            "type": "boolean",
            "description": "An accessibility clause is on file in the contract."
          },
          "slaDays": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "maximum": 365,
            "description": "Days the contract gives the vendor to remediate."
          },
          "nextReviewAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "When the evidence is next to be reviewed."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 5000,
            "description": "Notes."
          }
        },
        "required": [
          "vendorId",
          "name"
        ],
        "description": "A vendor product, linked to the asset in the path. Its VPAT is recorded in the app, where receiving one is part of the audit trail.",
        "example": {
          "vendorId": "2a3b4c5d-6e7f-4809-9a1b-2c3d4e5f6071",
          "name": "Permit Portal",
          "contractClause": true
        }
      },
      "VendorProductUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "A new name."
          },
          "contractClause": {
            "type": "boolean",
            "description": "An accessibility clause is on file in the contract."
          },
          "slaDays": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "maximum": 365,
            "description": "Days the contract gives the vendor to remediate."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 5000,
            "description": "Notes."
          }
        },
        "description": "The fields of a vendor product to change. At least one is required.",
        "example": {
          "slaDays": 60
        }
      },
      "EvidenceEventList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvidenceEvent"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "An asset’s evidence ledger, oldest first: the order the hash chain is walked in."
      },
      "EvidenceEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^\\d+$",
            "description": "The event, a decimal string: it outgrows a JavaScript number."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset whose chain it is in."
          },
          "issueId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The issue it is about, or null."
          },
          "scanId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The scan that recorded it, or null."
          },
          "event": {
            "type": "string",
            "enum": [
              "discovered",
              "fixed",
              "regressed",
              "assigned",
              "verified",
              "accepted",
              "reopened"
            ],
            "description": "discovered, fixed (on one page), regressed, assigned, verified, accepted (a deferral decided) or reopened."
          },
          "pageUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "The page it is about, or null."
          },
          "actor": {
            "$ref": "#/components/schemas/EvidenceActor"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was recorded."
          },
          "eventHash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The event’s hash in the chain, 64 lowercase hexadecimal characters: the value the evidence package’s sidecar carries for it."
          }
        },
        "required": [
          "id",
          "propertyId",
          "issueId",
          "scanId",
          "event",
          "pageUrl",
          "actor",
          "createdAt",
          "eventHash"
        ],
        "description": "One event of the evidence ledger: an append-only, hash-chained record of what was found, changed and confirmed.",
        "example": {
          "id": "58213",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "issueId": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "scanId": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c01",
          "event": "discovered",
          "pageUrl": "https://www.riverbend.example/council/agendas",
          "actor": {
            "type": "automated"
          },
          "createdAt": "2026-09-14T15:00:00.000Z",
          "eventHash": "9f2c4d6e8a0b1c3d5e7f9a1b3c5d7e9f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d"
        }
      },
      "EvidenceActor": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "person"
                ]
              },
              "email": {
                "type": "string",
                "description": "Their address."
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Their name, when they gave one."
              }
            },
            "required": [
              "type",
              "email",
              "name"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "api_key"
                ]
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "description": "The key’s name."
              }
            },
            "required": [
              "type",
              "name"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "automated"
                ]
              }
            },
            "required": [
              "type"
            ]
          }
        ],
        "description": "Who recorded the event: a person in the app, an API key by its name, or automated -- a scan, or the reconciliation that follows one.",
        "example": {
          "type": "automated"
        }
      },
      "EvidenceVerification": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string",
                "enum": [
                  "intact"
                ]
              },
              "eventCount": {
                "type": "integer",
                "exclusiveMinimum": 0
              },
              "from": {
                "type": "string",
                "format": "date-time"
              },
              "to": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "propertyId",
              "status",
              "eventCount",
              "from",
              "to"
            ]
          },
          {
            "type": "object",
            "properties": {
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string",
                "enum": [
                  "broken"
                ]
              },
              "firstBrokenEventId": {
                "type": "string",
                "pattern": "^\\d+$"
              },
              "firstBrokenEventPosition": {
                "type": "integer",
                "exclusiveMinimum": 0
              },
              "firstBrokenEventAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "propertyId",
              "status",
              "firstBrokenEventId",
              "firstBrokenEventPosition",
              "firstBrokenEventAt"
            ]
          },
          {
            "type": "object",
            "properties": {
              "propertyId": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string",
                "enum": [
                  "unverifiable"
                ]
              },
              "reason": {
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "propertyId",
              "status",
              "reason"
            ]
          }
        ],
        "description": "The result of recomputing an asset’s hash chain: intact, with the count and the range walked; broken, with the first event that does not verify; or unverifiable, with the reason. A walk that read nothing is unverifiable, never intact.",
        "example": {
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "status": "intact",
          "eventCount": 5710,
          "from": "2026-06-01T15:04:05.000Z",
          "to": "2026-10-05T14:31:40.000Z"
        }
      },
      "ReportList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Report"
            },
            "description": "This page of the list, in its documented order."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "The cursor of the page after this one, or null when this is the last page. Null is the end of the list: not an empty array, and not a 404."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "How many items the whole list holds under these filters, not this page."
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ],
        "description": "Reports across every organisation the key reaches unless narrowed, newest first."
      },
      "Report": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The report."
          },
          "orgId": {
            "type": "string",
            "format": "uuid",
            "description": "The organisation of the asset."
          },
          "propertyId": {
            "type": "string",
            "format": "uuid",
            "description": "The asset it reports on."
          },
          "kind": {
            "type": "string",
            "enum": [
              "executive_summary",
              "technical_detail",
              "evidence_package"
            ],
            "description": "executive_summary, technical_detail or evidence_package."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "rendering",
              "ready",
              "failed"
            ],
            "description": "queued, rendering, ready or failed. Only a ready report has a PDF."
          },
          "language": {
            "type": "string",
            "description": "The report’s language, as a BCP 47 tag."
          },
          "scanId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The scan it is built from, or null."
          },
          "compareScanId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The scan an executive summary compares with, or null."
          },
          "periodFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "An evidence package’s first instant, or null."
          },
          "periodTo": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "The instant after an evidence package’s last, or null: the range is half-open."
          },
          "chain": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "intact"
                    ]
                  },
                  "eventCount": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "from": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "to": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "status",
                  "eventCount",
                  "from",
                  "to"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "broken"
                    ]
                  },
                  "firstBrokenEventId": {
                    "type": "string",
                    "pattern": "^\\d+$"
                  }
                },
                "required": [
                  "status",
                  "firstBrokenEventId"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "unverifiable"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "status",
                  "reason"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "An evidence package’s chain verification, frozen when it was made; else null."
          },
          "requestedBy": {
            "$ref": "#/components/schemas/ReportRequester"
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was asked for."
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it became ready, or null."
          },
          "failedReason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it failed, or null."
          },
          "linkExpiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Until 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."
          },
          "downloadUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "A 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."
          },
          "downloadUrlExpiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When downloadUrl stops working, or null."
          }
        },
        "required": [
          "id",
          "orgId",
          "propertyId",
          "kind",
          "status",
          "language",
          "scanId",
          "compareScanId",
          "periodFrom",
          "periodTo",
          "chain",
          "requestedBy",
          "requestedAt",
          "completedAt",
          "failedReason",
          "linkExpiresAt",
          "downloadUrl",
          "downloadUrlExpiresAt"
        ],
        "description": "A report on one asset, and the link to its PDF once it is ready.",
        "example": {
          "id": "5d6e7f80-91a2-4b3c-8d4e-5f6a7b8c9d01",
          "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "kind": "executive_summary",
          "status": "queued",
          "language": "en-US",
          "scanId": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c01",
          "compareScanId": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c00",
          "periodFrom": null,
          "periodTo": null,
          "chain": null,
          "requestedBy": {
            "type": "api_key",
            "name": "Monthly dashboard"
          },
          "requestedAt": "2026-10-06T09:00:00.000Z",
          "completedAt": null,
          "failedReason": null,
          "linkExpiresAt": null,
          "downloadUrl": null,
          "downloadUrlExpiresAt": null
        }
      },
      "ReportRequester": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "person"
                ]
              },
              "email": {
                "type": "string",
                "description": "Their address."
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Their name, when they gave one."
              }
            },
            "required": [
              "type",
              "email",
              "name"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "scheduled"
                ]
              }
            },
            "required": [
              "type"
            ]
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "api_key"
                ]
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "description": "The key’s name."
              }
            },
            "required": [
              "type",
              "name"
            ]
          }
        ],
        "description": "Who asked for the report: a person, a schedule, or an API key by its name.",
        "example": {
          "type": "api_key",
          "name": "Monthly dashboard"
        }
      },
      "ReportCreate": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "executive_summary"
                ]
              },
              "propertyId": {
                "type": "string",
                "format": "uuid",
                "description": "The asset to report on."
              },
              "scanId": {
                "type": "string",
                "format": "uuid",
                "description": "A completed scan of the asset."
              },
              "compareScanId": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid",
                "default": null,
                "description": "A second completed scan to compare with, or null."
              },
              "language": {
                "type": "string",
                "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$",
                "default": "en-US",
                "description": "en-US when absent."
              }
            },
            "required": [
              "kind",
              "propertyId",
              "scanId"
            ]
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "technical_detail"
                ]
              },
              "propertyId": {
                "type": "string",
                "format": "uuid",
                "description": "The asset to report on."
              },
              "scanId": {
                "type": "string",
                "format": "uuid",
                "description": "A completed scan of the asset."
              },
              "status": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "open",
                    "assigned",
                    "in_progress",
                    "ready_to_verify",
                    "verified",
                    "deferred"
                  ]
                },
                "default": [],
                "description": "Only issues in these statuses; every status when empty."
              },
              "impact": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "critical",
                    "serious",
                    "moderate",
                    "minor"
                  ]
                },
                "default": [],
                "description": "Only issues of these impacts; every impact when empty."
              },
              "language": {
                "type": "string",
                "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$",
                "default": "en-US",
                "description": "en-US when absent."
              }
            },
            "required": [
              "kind",
              "propertyId",
              "scanId"
            ]
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "evidence_package"
                ]
              },
              "propertyId": {
                "type": "string",
                "format": "uuid",
                "description": "The asset to report on."
              },
              "from": {
                "type": "string",
                "format": "date",
                "description": "The first day, YYYY-MM-DD."
              },
              "to": {
                "type": "string",
                "format": "date",
                "description": "The last day, YYYY-MM-DD, included."
              },
              "language": {
                "type": "string",
                "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$",
                "default": "en-US",
                "description": "en-US when absent."
              }
            },
            "required": [
              "kind",
              "propertyId",
              "from",
              "to"
            ]
          }
        ],
        "description": "The report to generate. A summary or a technical report is built from a completed scan; an evidence package covers a range of days of the ledger.",
        "example": {
          "kind": "executive_summary",
          "propertyId": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
          "scanId": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c01",
          "compareScanId": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c00"
        }
      },
      "ContentLookup": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "The address as it was looked up."
          },
          "nodeId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The nodeId sent, or null."
          },
          "contentType": {
            "type": [
              "string",
              "null"
            ],
            "description": "The contentType sent, or null."
          },
          "revisionId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The revisionId sent, or null."
          },
          "property": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "The asset."
              },
              "orgId": {
                "type": "string",
                "format": "uuid",
                "description": "Its organisation."
              },
              "name": {
                "type": "string",
                "description": "Its name."
              }
            },
            "required": [
              "id",
              "orgId",
              "name"
            ],
            "description": "The asset the address belongs to, or null when no asset has its host."
          },
          "page": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "url": {
                "type": "string",
                "description": "The page, as the crawl recorded it."
              },
              "lastScannedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When 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."
              }
            },
            "required": [
              "url",
              "lastScannedAt"
            ],
            "description": "The page, or null when no crawl has found the address."
          },
          "contentAuthored": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContentAuthoredIssue"
            },
            "description": "Issues the page’s author can fix in the editor."
          },
          "templateLevel": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContentIssue"
            },
            "description": "Every other issue present on the page: its template’s or its theme’s, fixed in the code rather than the content."
          }
        },
        "required": [
          "url",
          "nodeId",
          "contentType",
          "revisionId",
          "property",
          "page",
          "contentAuthored",
          "templateLevel"
        ],
        "description": "The issues known for one address, split into the content author’s and the template’s. Never a score: the issues themselves.",
        "example": {
          "url": "https://www.riverbend.example/news/library-hours",
          "nodeId": "1482",
          "contentType": "article",
          "revisionId": "9921",
          "property": {
            "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e01",
            "orgId": "6a4f2c1e-8b3d-4e5f-9a1b-2c3d4e5f6a01",
            "name": "City of Riverbend"
          },
          "page": {
            "url": "https://www.riverbend.example/news/library-hours",
            "lastScannedAt": "2026-10-05T14:22:09.000Z"
          },
          "contentAuthored": [
            {
              "issueId": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
              "title": "Images must have alternative text",
              "impact": "critical",
              "status": "open",
              "wcagSC": [
                "1.1.1"
              ],
              "guidance": null
            }
          ],
          "templateLevel": []
        }
      },
      "ContentAuthoredIssue": {
        "type": "object",
        "properties": {
          "issueId": {
            "type": "string",
            "format": "uuid",
            "description": "The issue; read it at /issues/{id}."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "What the barrier is."
          },
          "impact": {
            "type": "string",
            "enum": [
              "critical",
              "serious",
              "moderate",
              "minor"
            ],
            "description": "critical, serious, moderate or minor."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "assigned",
              "in_progress",
              "ready_to_verify",
              "verified",
              "deferred"
            ],
            "description": "Its status, one of the six."
          },
          "wcagSC": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The WCAG success criteria it fails."
          },
          "guidance": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "summary": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The fix, in a sentence."
              },
              "whyItMatters": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Who it stops, and how."
              },
              "howToFix": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The steps, in Markdown."
              }
            },
            "required": [
              "summary",
              "whyItMatters",
              "howToFix"
            ],
            "description": "The content-editor guidance for the issue’s rule when it is published; else null.",
            "example": {
              "summary": "Describe what the image shows in its alternative text.",
              "whyItMatters": "A person using a screen reader hears the alternative text instead.",
              "howToFix": "Open the image in the editor and fill in its alternative text."
            }
          }
        },
        "required": [
          "issueId",
          "title",
          "impact",
          "status",
          "wcagSC",
          "guidance"
        ],
        "description": "An issue introduced by the page’s own content: its rule is routed to the content editor and the page’s template does not share it.",
        "example": {
          "issueId": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "title": "Images must have alternative text",
          "impact": "critical",
          "status": "open",
          "wcagSC": [
            "1.1.1"
          ],
          "guidance": null
        }
      },
      "ContentIssue": {
        "type": "object",
        "properties": {
          "issueId": {
            "type": "string",
            "format": "uuid",
            "description": "The issue; read it at /issues/{id}."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "What the barrier is."
          },
          "impact": {
            "type": "string",
            "enum": [
              "critical",
              "serious",
              "moderate",
              "minor"
            ],
            "description": "critical, serious, moderate or minor."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "assigned",
              "in_progress",
              "ready_to_verify",
              "verified",
              "deferred"
            ],
            "description": "Its status, one of the six."
          },
          "wcagSC": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The WCAG success criteria it fails."
          }
        },
        "required": [
          "issueId",
          "title",
          "impact",
          "status",
          "wcagSC"
        ],
        "description": "An issue present on the page.",
        "example": {
          "issueId": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c01",
          "title": "Links must have discernible text",
          "impact": "serious",
          "status": "open",
          "wcagSC": [
            "2.4.4",
            "4.1.2"
          ]
        }
      },
      "ContentLookupRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "description": "The page’s canonical address."
          },
          "nodeId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The CMS’s own id for the content. Returned as sent, and never stored."
          },
          "contentType": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "The CMS’s content type. Returned as sent, and never stored."
          },
          "revisionId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The CMS’s revision id. Returned as sent, and never stored."
          }
        },
        "required": [
          "url"
        ],
        "description": "A content identity from a CMS. Reading it changes nothing: the API looks the address up and records nothing about the request.",
        "example": {
          "url": "https://www.riverbend.example/news/library-hours",
          "nodeId": "1482",
          "contentType": "article",
          "revisionId": "9921"
        }
      }
    },
    "parameters": {}
  },
  "paths": {
    "/openapi.json": {
      "get": {
        "tags": [
          "document"
        ],
        "security": [],
        "summary": "This document",
        "description": "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.",
        "responses": {
          "200": {
            "description": "The OpenAPI 3.1 document",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {}
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/organizations": {
      "get": {
        "tags": [
          "organizations"
        ],
        "summary": "The organisations this key reaches",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The organisations, by name",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties": {
      "get": {
        "tags": [
          "properties"
        ],
        "summary": "List assets",
        "description": "The live assets of every organisation the key reaches, newest first, or of one of them with `orgId`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "Only this organisation’s assets. An organisation the key does not reach matches nothing."
            },
            "required": false,
            "description": "Only this organisation’s assets. An organisation the key does not reach matches nothing.",
            "name": "orgId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The assets, newest first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PropertyList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "properties"
        ],
        "summary": "Add an asset",
        "description": "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.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PropertyCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The asset, as created",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Property"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}": {
      "get": {
        "tags": [
          "properties"
        ],
        "summary": "Read an asset",
        "description": "One asset. A deleted asset is still read by its id, with `deletedAt` set.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The asset",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Property"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "properties"
        ],
        "summary": "Change an asset",
        "description": "Changes an asset’s name or kind; a deleted asset cannot be changed. To monitor a different address, add an asset.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PropertyUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The asset, as changed",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Property"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/scans": {
      "get": {
        "tags": [
          "scans"
        ],
        "summary": "List an asset’s scans",
        "description": "The asset’s scans, newest first, optionally of some statuses only.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "queued",
                      "crawling",
                      "scanning",
                      "complete",
                      "failed"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "queued",
                    "crawling",
                    "scanning",
                    "complete",
                    "failed"
                  ]
                }
              ],
              "description": "Only scans in these statuses."
            },
            "required": false,
            "description": "Only scans in these statuses.",
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The scans, newest first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "scans"
        ],
        "summary": "Start a scan",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "202": {
            "description": "The scan, queued",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Scan"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/scans/{id}": {
      "get": {
        "tags": [
          "scans"
        ],
        "summary": "Read a scan",
        "description": "One scan: where it stands, what it covered, and whether its engines changed.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The scan"
            },
            "required": true,
            "description": "The scan",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The scan",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Scan"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/issues": {
      "get": {
        "tags": [
          "issues"
        ],
        "summary": "List an asset’s issues",
        "description": "The asset’s issues, the most recently found first. Filters take several values as repeated keys: `?impact=critical&status=open&status=assigned`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "open",
                      "assigned",
                      "in_progress",
                      "ready_to_verify",
                      "verified",
                      "deferred"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "open",
                    "assigned",
                    "in_progress",
                    "ready_to_verify",
                    "verified",
                    "deferred"
                  ]
                }
              ],
              "description": "Only issues in these statuses."
            },
            "required": false,
            "description": "Only issues in these statuses.",
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "critical",
                      "serious",
                      "moderate",
                      "minor"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "critical",
                    "serious",
                    "moderate",
                    "minor"
                  ]
                }
              ],
              "description": "Only issues of these impacts."
            },
            "required": false,
            "description": "Only issues of these impacts.",
            "name": "impact",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "desktop",
                      "mobile",
                      "tablet"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "desktop",
                    "mobile",
                    "tablet"
                  ]
                }
              ],
              "description": "Only issues at these layouts."
            },
            "required": false,
            "description": "Only issues at these layouts.",
            "name": "viewport",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                {
                  "type": "string",
                  "minLength": 1
                }
              ],
              "description": "Only issues failing any of these success criteria, as `1.4.3`."
            },
            "required": false,
            "description": "Only issues failing any of these success criteria, as `1.4.3`.",
            "name": "wcagSC",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The issues, the most recently found first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/issues/{id}": {
      "get": {
        "tags": [
          "issues"
        ],
        "summary": "Read an issue",
        "description": "One issue in full, with its deferral record when it is deferred.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The issue"
            },
            "required": true,
            "description": "The issue",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The issue",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueDetail"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "issues"
        ],
        "summary": "Change an issue’s status or owner",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The issue"
            },
            "required": true,
            "description": "The issue",
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The issue, as changed",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueDetail"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/issues/{id}/occurrences": {
      "get": {
        "tags": [
          "issues"
        ],
        "summary": "List the pages an issue is on",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The issue"
            },
            "required": true,
            "description": "The issue",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "present",
                "fixed"
              ],
              "description": "Only present, or only fixed."
            },
            "required": false,
            "description": "Only present, or only fixed.",
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "default": true,
              "description": "Include the pages that carry the issue by template. true when absent; false lists only the pages a browser loaded."
            },
            "required": false,
            "description": "Include the pages that carry the issue by template. true when absent; false lists only the pages a browser loaded.",
            "name": "attributed",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The pages, the most recently seen first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OccurrenceList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/documents": {
      "get": {
        "tags": [
          "documents"
        ],
        "summary": "List an asset’s documents",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "discovered",
                      "triaged",
                      "validated",
                      "failed"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "discovered",
                    "triaged",
                    "validated",
                    "failed"
                  ]
                }
              ],
              "description": "Only documents in these statuses."
            },
            "required": false,
            "description": "Only documents in these statuses.",
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The documents",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/documents/{id}": {
      "get": {
        "tags": [
          "documents"
        ],
        "summary": "Read a document",
        "description": "One document and what checking it found.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The document"
            },
            "required": true,
            "description": "The document",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The document",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/vendors": {
      "get": {
        "tags": [
          "vendors"
        ],
        "summary": "List the vendor products linked to an asset",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The vendor products",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorProductList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "vendors"
        ],
        "summary": "Record a vendor product for an asset",
        "description": "Records a product bought from a vendor of the asset’s organisation, linked to the asset. Its evidence starts at none.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VendorProductCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The vendor product, as recorded",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorProduct"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/vendors/{id}": {
      "get": {
        "tags": [
          "vendors"
        ],
        "summary": "Read a vendor product",
        "description": "One vendor product and the state of the evidence for it.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The vendor product"
            },
            "required": true,
            "description": "The vendor product",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The vendor product",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorProduct"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "vendors"
        ],
        "summary": "Change a vendor product",
        "description": "Changes a vendor product’s name, its contract terms or its notes.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The vendor product"
            },
            "required": true,
            "description": "The vendor product",
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VendorProductUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The vendor product, as changed",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorProduct"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/evidence": {
      "get": {
        "tags": [
          "evidence"
        ],
        "summary": "Read an asset’s evidence ledger",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "Only events about this issue."
            },
            "required": false,
            "description": "Only events about this issue.",
            "name": "issueId",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "discovered",
                      "fixed",
                      "regressed",
                      "assigned",
                      "verified",
                      "accepted",
                      "reopened"
                    ]
                  }
                },
                {
                  "type": "string",
                  "enum": [
                    "discovered",
                    "fixed",
                    "regressed",
                    "assigned",
                    "verified",
                    "accepted",
                    "reopened"
                  ]
                }
              ],
              "description": "Only these events."
            },
            "required": false,
            "description": "Only these events.",
            "name": "event",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only events recorded at or after this."
            },
            "required": false,
            "description": "Only events recorded at or after this.",
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Only events recorded at or before this."
            },
            "required": false,
            "description": "Only events recorded at or before this.",
            "name": "to",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The ledger, oldest first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvidenceEventList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/properties/{id}/evidence/verify": {
      "post": {
        "tags": [
          "evidence"
        ],
        "summary": "Verify an asset’s evidence chain",
        "description": "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.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The asset"
            },
            "required": true,
            "description": "The asset",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "What the walk found",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvidenceVerification"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/reports": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "List reports",
        "description": "Reports across every organisation the key reaches, newest first; or of one organisation, one asset or one kind.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 4096,
              "description": "The 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."
            },
            "required": false,
            "description": "The 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.",
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
              "example": 50
            },
            "required": false,
            "description": "How many items to return, 1 to 200; 50 when absent. A larger value is refused with a 400 rather than trimmed.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "Only this organisation’s reports."
            },
            "required": false,
            "description": "Only this organisation’s reports.",
            "name": "orgId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "Only this asset’s reports."
            },
            "required": false,
            "description": "Only this asset’s reports.",
            "name": "propertyId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "executive_summary",
                "technical_detail",
                "evidence_package"
              ],
              "description": "Only reports of this kind."
            },
            "required": false,
            "description": "Only reports of this kind.",
            "name": "kind",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "The reports, newest first",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportList"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "Generate a report",
        "description": "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`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The report, queued",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "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`)",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with the current state: `detail` says why",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/reports/{id}": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "Read a report",
        "description": "One report: its status, and once it is ready and while its link policy holds, a link to its PDF signed for fifteen minutes.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The report"
            },
            "required": true,
            "description": "The report",
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "The report",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Report"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/cms/content": {
      "post": {
        "tags": [
          "cms"
        ],
        "summary": "Look up a page’s known issues for a CMS",
        "description": "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.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContentLookupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The address’s issues, split",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentLookup"
                }
              }
            }
          },
          "400": {
            "description": "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",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "No key, or the key was not accepted: unknown, revoked, expired, or a secret a rotation has retired. Every reason gets the same sentence",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No such resource, or it is in an organisation this key does not reach",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "The body has no Content-Type, or one other than application/json: `detail` says so",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "The budget is spent. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed. Quote `instance` to support",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "A test key’s sandbox is still being prepared. Retry after the number of seconds in Retry-After",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "scan.completed": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "A scan finished",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanCompletedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "scan.failed": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "A scan could not finish",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanFailedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "issue.discovered": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "An issue was found for the first time",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueDiscoveredEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "issue.regressed": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "An issue was found again on a page where a scan or a journey run had stopped finding it",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueRegressedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "issue.ready_to_verify": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "An issue was reported gone and is waiting to be verified",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueReadyToVerifyEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "issue.verified": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "An issue was confirmed gone, by a scan or by a person who retested it",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueVerifiedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "document.validated": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "A document finished validation",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentValidatedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "vendor.evidence_stale": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "A vendor product’s VPAT became more than 24 months old",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VendorEvidenceStaleEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    },
    "report.ready": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "A generated report is ready to download",
        "description": "Sent to every endpoint of the organisation subscribed to it, signed in BarrierOps-Signature. Delivery is at least once and in no set order. An attempt with no answer in 10 seconds, or any answer but a 2xx -- a redirect included, which is not followed -- is retried, 8 attempts over 24 hours, after which an endpoint that delivered nothing in that time is disabled and its owners and admins are told by email.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
              "example": "t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            },
            "required": true,
            "description": "`t=<Unix seconds>,v1=<signature>`: the HMAC-SHA256, in lowercase hexadecimal, of the timestamp, a full stop and the raw request body, keyed with the endpoint’s signing secret. While a rolled secret’s overlap runs, a second `v1=` signed with the previous secret follows; accept the message if either matches. Verify the raw bytes before parsing them, and refuse a timestamp more than 5 minutes old.",
            "name": "BarrierOps-Signature",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "description": "The message’s `type`, so a receiver can route it before parsing it.",
              "example": "scan.completed"
            },
            "required": true,
            "description": "The message’s `type`, so a receiver can route it before parsing it.",
            "name": "BarrierOps-Event",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once."
            },
            "required": true,
            "description": "The event’s `id`. Every attempt and every replay of one event carries the same one: handle each id once.",
            "name": "BarrierOps-Event-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid",
              "description": "This delivery: one per endpoint, and a replay is a new one."
            },
            "required": true,
            "description": "This delivery: one per endpoint, and a replay is a new one.",
            "name": "BarrierOps-Delivery-Id",
            "in": "header"
          },
          {
            "schema": {
              "type": "string",
              "example": "BarrierOps-Webhooks/1.0"
            },
            "required": true,
            "name": "User-Agent",
            "in": "header"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportReadyEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx response marks the delivery delivered."
          }
        }
      }
    }
  }
}
