# provenance API guide provenance is RODMENA's register for what an organisation builds and owns. It holds software releases and their SBOMs, the vulnerabilities found in them, devices and the hardware bills of materials behind them, and the evidence an auditor asks for under ISO 27001 and Cyber Essentials. This guide is for the people and tools that use its API. The API is at https://provenance.rodmena.com. The old address, provenance.rodmena.co.uk, redirects here permanently with a 301 for GET and HEAD and a 308 for other methods, which keeps a POST and its body intact. Set the new address as your base URL, because a client that does not follow redirects sees the 30x in place of the answer. The route list at the end of this guide is generated whenever the file is requested, from the routes of the API that answers you and the scopes they check. A test fails if the list names a route the API does not serve or misses one it does. The rest of the guide is written by hand. The API publishes no OpenAPI schema in production, and `/openapi.json` answers 404. Use this file as the reference. The `/docs` page on this host is the product documentation for people. ## Signing in There are two kinds of credential. An API key goes in the `Authorization: Bearer prov__` header. An administrator creates it with a list of scopes, and it carries no roles. It expires after 90 days unless the administrator chooses another lifetime, up to 366 days. The secret is shown once, when the key is created, and provenance keeps only its SHA-256 digest. A lost secret cannot be recovered. Revoke the key and create a new one. A person signs in at `/auth/login`, which runs the OpenID Connect sign-in and sets a session cookie. A session carries roles, and the roles expand to permissions. `GET /api/v1/whoami` tells you which credential you sent and what it may do. Start there when a request is refused. For a signed-in person it also returns `locale`, the interface language they saved (`en-GB`, `cy-GB`, `gd-GB`, `ga-GB`, `sco-GB`, `sco-ulster` or `kw-GB`), or `null` if they have not chosen one. `PUT /api/v1/me/locale` with `{"locale": ""}` or `{"locale": null}` saves it for all of their workspaces and answers 204. An unknown tag is 422 `invalid_locale`. A key has no language setting. For a key the field is absent and the PUT answers 403. ### What a key cannot do Nobody can give an API key these five scopes, an administrator included: `admin_policy`, `asset_dispose`, `chain_acknowledge`, `trust_approve` and `vex_approve`. They cover the decisions a person has to make, such as approving a VEX statement or disposing of a device. When a key gets a 403 for one of them, the platform is working as intended. `GET /api/v1/admin/scopes` returns the current list. `pipeline_run` is the reverse case. No person's role carries it, because the record that a scheduled job ran counts as evidence only while the scheduler is the one thing that can write it. Some routes need two scopes because their answer joins data that both guard. Reading findings needs `finding_read` and `sbom_read`, because a finding names a component, a release and a product. The 403 names the scope you are missing. ## How requests are handled - The API refuses an unknown query parameter with 400, and the error lists the parameters the route accepts. A misspelt paging parameter would otherwise hand back the first page forever. - It refuses an unknown field in a JSON body with 400 and names the field. - A field you leave out is never read as an instruction to erase it. On `/amend`, `value` is required, and `"value": null` records "not known". On a scope correction, a field you leave out keeps its value. - Collections report what you received in `X-Total-Count`, `X-Limit`, `X-Offset` and an RFC 8288 `Link` header. Follow `Link` until it has no `rel="next"`, and read the count from the header. A `limit` above 1,000 is refused with 400. - Lists of products, components, assets, findings and environments are bare JSON arrays. - Register records are not deleted. Disposal, retirement and revocation are states, and a correction to an asset goes through `/amend`, which keeps the previous value and your reason. Some records are maintained with PUT. They include ISMS register entries, Statement of Applicability lines, and an asset's scope, firewall policy and installed software. A PUT to an ISMS register entry must carry the required fields. An optional field you leave out keeps its stored value, and an explicit `null` clears it. - DELETE is used in three places, none of which removes a record. It unbinds a key from a device, removes an alert recipient, or withdraws trust in a signing key. - A 403 that comes from row-level security will not change if you retry. A 503 is a fault on our side and carries `Retry-After`. The `workspace_busy` 503 means your workspace has too much in flight. - Changes are written to a hash-chained audit log that can only be appended to, and reads are logged as well. ## Publishing software A CI job needs `sbom_read`, `sbom_publish` and `release_write`. A typical build makes five calls. 1. `POST /api/v1/products` `{"slug": "billing-api", "name": "Billing API", "criticality": "high"}` registers the product, and it is safe to repeat. A new product answers 201. The same details again answer 200 with `already_registered: true` and the same `id`, and different details for an existing slug answer 409 naming what differs. 2. `POST /api/v1/products/{slug}/releases` `{"version": "...", "git_sha": "...", "ci_pipeline": "..."}` creates the release. When the version already exists the answer is 409, and the release you wanted is already there. 3. `POST /api/v1/releases/{release_id}/sbom` takes the CycloneDX JSON your build produced. Posting the same document again returns `already_ingested: true` and is not counted again. When two posts of one document arrive together, the second waits for the first. If it waits longer than four seconds it gets 409 and should be posted again. 4. `POST /api/v1/releases/{release_id}/scan?wait=110` scans the release, which takes a minute or more. The request waits up to `wait` seconds, 110 by default. Keep it at 110 or below, because the web server in front of the API ends requests at 120 seconds. A scan that finishes in time answers 200 with the result. One that does not answers 202 with a `scan_id`, and `GET /api/v1/scans/{scan_id}` then reports `running`, `done`, `failed` or `interrupted`. A 409 means a scan of that release is already running. A 503 with `Retry-After` means the scanner is full and nothing was scanned. 5. `POST /api/v1/deployments` `{"release_id": "...", "environment_slug": "production"}` records that the release shipped. Deployment records are append-only, and posting the same deployment twice creates two of them. Recording a newer release of the same product in an environment closes the older one. When a release is switched off with no replacement, withdraw it with `POST /api/v1/deployments/{deployment_id}/withdraw`. Until then it counts as live, and alerts keep arriving for a service nobody runs. Check `scanner_verified` in a scan result. It is true only when the scanner found the vulnerabilities planted in a known-vulnerable test document before your scan ran. Do not report a clean result from a scanner that failed that test. A release without an SBOM shows no findings because nothing was checked. The evidence pack says so under ISO 27001 A.8.8. ## Reading the register - `GET /api/v1/components?purl=` finds a component by exact purl, and `?name=` matches part of a name. `GET /api/v1/components/{component_id}/releases` lists the releases that ship it. - `GET /api/v1/findings?severity=critical&deployed_only=true&unassessed_only=true` lists findings. The yes-or-no filters all end in `_only`. - `GET /api/v1/assets` lists devices and filters on `custodian`, `state` and `site`. `GET /api/v1/assets/held-by/{custodian_sub}` lists what one person still holds, which is the question when someone leaves. `GET /api/v1/assets/as-of?when=` shows the register as it stood at that moment. - `GET /api/v1/audit/events` is the audit log. To recompute its hash chain, read it from the start with `order=seq_asc`. If the rows you received number the same as `X-Limit` and fewer than `X-Total-Count`, you hold part of the log. Page on before you report a gap. `GET /api/v1/audit/verify` reports the most recent check of the chain and how old it is, and `fresh=true` checks it now. ## The evidence pack With `report_read`, `GET /api/v1/evidence/pack` returns the pack as JSON. Add `?scheme=Cyber%20Essentials` for one scheme or `?ref=A.8.8` for one control. `GET /api/v1/evidence/pack.pdf` is the version a person reads, and `GET /api/v1/evidence/controls` lists the controls. Before the bytes leave, each export is written to the audit log with the SHA-256 of its content, and the digest comes back in `digest_sha256` or the `X-Provenance-Digest` header. Each GET of the pack counts as an export and adds an `evidence.export` entry. Each control section carries a `caveat` stating what provenance cannot show. Pass it on to whoever reads your output. ## Cryptographic inventory (CBOM) A CycloneDX inventory of cryptography goes to the SBOM route, `POST /api/v1/releases/{release_id}/sbom`, on its own or inside an SBOM. provenance reads `cryptographic-asset` components (CycloneDX 1.6), the earlier `crypto-asset` form from NIST SP 1800-38B and IBM's 1.4 layout. A CBOM with no purl component is accepted. The ingest answer adds `crypto_assets_total`, `crypto_assets_skipped`, `crypto_usage_unresolved` and `quantum_vulnerable`. It also adds `crypto_truncated`, because the free plan keeps 2,000 cryptographic assets per document and paid plans keep 50,000. A document is not refused for its size. When the inventory cannot be read, the answer carries `crypto_unreadable: true` and coverage reads "not analysed". The SBOM itself is still accepted. provenance classifies each algorithm itself. `quantum_status` is `vulnerable`, `resistant`, `hybrid`, `not_applicable` or `unknown`. Symmetric ciphers and hashes are `not_applicable` because they fall outside NIST's quantum scope. Do not read `unknown` as safe. Protocols and algorithms carry `kex_status` for key establishment and `auth_status` for signatures. `classically_weak` is a separate flag for DES, RC4, MD5, SHA-1 signatures and RSA keys under 2,048 bits. `claim_conflict` marks a document that claims quantum safety for a vulnerable algorithm. Each row names its `classifier_version` and the reason for its verdict. Counts are distinct by `fingerprint` and cover the current documents of live products. A fingerprint is built from what the document says, which keeps it stable across classifier versions and across an export and re-ingest. Rows carry a priority score with its reasons in `priority.reasons`, and the weights are at `GET /api/v1/quantum-readiness/scoring`. "Expiring within N days" leaves out certificates that have already expired. Those have their own count and the `expired_only` filter. `GET /api/v1/releases/{release_id}/cbom` exports CycloneDX 1.6 with provenance's verdicts as `provenance:*` properties. Re-ingesting it gives the same assets. Certificate-expiry mail at 30 and 7 days (a paid feature) and ISO 27001 A.8.24 in the evidence pack read the same inventory. An ordinary SBOM declares no cryptography. Coverage then reads `no_crypto_declared`, which is not an all-clear. To produce a CBOM, run cbomkit-theia (`podman run --rm ghcr.io/cbomkit/cbomkit-theia:latest image `) or cdxgen's `cbom` mode, whose CycloneDX 1.7 output is accepted. The automation guide has tested recipes and their limits. Lists answer `X-Total-Count` with rows, one per release, and `X-Distinct-Count` with distinct assets, which is what the dashboard tiles count. ## Hardware bills of materials (HBOM) The CISA HBOM Framework (2023) defines a hardware bill of materials as a vendor's document about a hardware product. It lists the parts inside, the companies that made them, and where. provenance attaches it to a hardware model, and the devices in the register are instances of that model. Fifty identical laptops share one HBOM. 1. `POST /api/v1/hardware-models` `{"maker": "Dell", "fga_num": "Latitude 7440", "fga_version": "", "kind": "finished_good"}` (asset_write) creates the model. Sending the same maker, part number and version again answers 200 and names the existing model. Use `kind: "sub_assembly"` for a part that has its own HBOM, such as a mainboard. Parts that name it by maker and part number are linked to it. 2. `POST /api/v1/hardware-models/{id}/hbom` (asset_write) takes the document in one of three forms. CycloneDX 1.2 to 1.7 goes as `application/vnd.cyclonedx+json`, and nesting comes from `components[]` alone (`dependencies` is ignored for structure). A CSV goes as `text/csv` with CISA Appendix C field names as columns, and the template is at `GET /api/v1/hbom/template.csv`. JSON goes as `application/hbom+json` in the shape `{"header": {...}, "parts": [...]}` with the same names. If the vendor gave you no HBOM, `POST /api/v1/hardware-models/{id}/hbom/self-declared` `{"oem": "...", "manufacture_location_code": "CN-JS", "source_note": "device label, read 2026-10-16"}` records what you know. Every read of it shows `origin: self_declared`. 3. To link devices, send `POST /api/v1/assets/{id}/amend` with the field `hardware_model_id`. Only physical devices can be linked, and only to a finished good. `GET /api/v1/hardware-models/suggestions` groups unlinked assets by make and model, and `POST /api/v1/assets/amend-batch` links up to 500 at a time. The ingest answer says what the document can and cannot answer. It carries `parts_total`, `parts_held`, `parts_not_held` and `truncated`, because the free plan keeps 1,000 parts per document and paid plans keep 25,000. `skipped` lists the rows it left out and why. `document_depth` and `completeness` follow the CISA use cases. CISA's Table 4 decides which use case a category serves, and its section C.8 decides which category a field belongs to. The automation guide lists the minimum fields we pin. The answer also carries `answers`, `codes_invalid`, `entities_unreviewed`, `screening` and `subject`. A document about a different product is refused with 409 `subject_mismatch` unless you pass `?accept_mismatch=`. Posting the same bytes again is not charged, and `replay` says what happened. `made_current` means that document became current again. `stays_disavowed` means the document had been disavowed and still is, because re-sending the same bytes does not undo a correction. To ask the register, call `GET /api/v1/hbom/exposure` with `country=CN`, `loc_code=CN-GD`, `location_text=Shenzhen`, `entity=` or `role=`, and `in_use_only=true` by default. It returns the matching roles, the models, the finished goods that contain them through sub-assembly HBOMs, and the distinct in-use devices. In `unknowns` you get counts of what could not be checked. They cover roles with no location, country or subdivision, parts beyond the plan's limit, models in use with no HBOM, and devices with no model. Read any zero against those counts. `in_use_states` lists the lifecycle states that were counted. It is `null` when you ask with `in_use_only=false`, because no lifecycle filter applies and retired and disposed devices are counted too. The other HBOM reads are `/api/v1/hbom/coverage`, `/api/v1/hbom/concentration?by=country` or `by=entity`, and `/api/v1/hbom/locations/facets`. Concentration reports a single source only where the document states one. A document's parts are at `/api/v1/hbom/documents/{id}/parts?parent=&q=`. Its exports are `export.cdx.json` and `export.csv`, both regenerated from the register and labelled as such, and `original` returns the sealed bytes you sent. Screening is a paid feature. An administrator declares restrictions from the organisation's own lists with `POST /api/v1/hbom/restrictions`. A restriction has a kind (`entity`, `name_key`, `name_prefix`, `loc_code` or `country`) and names the list it came from by title and URL. provenance ships no list of its own. A rule's `value` is the form that matching reads. That is a code for a place rule, an entity id for a company rule, and a name key for a name rule, in which look-alike letters are folded and "M4" becomes "rn4". `value_as_entered` keeps the text the administrator typed. An entity's `alias_spellings` pairs each alias key with the spelling typed for it. For rules and aliases added before 10:45 UTC on 17 October 2026 both fields are `null`, because the typed text was not kept then. A match is a prompt for review and carries no legal finding. A person records `not_a_match`, `confirmed` or `accepted_risk`, and the decision reopens when the facts it was about change. On the free plan, screening reads return `not_on_plan` in place of a match count. ISO 27001 A.5.21 in the evidence pack draws on all of this. ## Trust Center A workspace can publish a trust snapshot. One member proposes the exact content, a different member approves it in their own signed-in session, and the platform signs it with DSSE and Ed25519. The signing keys are public at `GET /api/v1/trust/keys` and in the source, in `docs/trust-keys.md`. A valid signature shows who published a snapshot. To learn whether it is still current, ask `GET /api/v1/trust/status/{snapshot_id}`, which is public and answers `current`, `superseded`, `key_revoked` or `withdrawn`. It does not say why a snapshot was withdrawn. The public trust site reads the index at `/api/v1/trust/published`, which carries no bodies, and fetches current envelopes by id from `POST /api/v1/trust/published/envelopes`. Both need a named platform credential. Rotating a workspace's public handle withdraws its current snapshot. ## Plan limits and daily allowances Refusals are JSON with `error`, `detail` and `request_id`. Branch on `error`, because two refusals with the same status can mean different things. | Status | `error` | What it means | What to do | |---|---|---|---| | 402 | `limit_reached` | A plan cap on things that exist was reached. The answer names the `resource`, its `limit` and the `current` count. Caps cover members including pending invitations, assets, products, releases, API keys, and evidence files and bytes. | Retire or dispose of what you no longer hold, or move to a larger plan. Retrying will not help. | | 402 | `plan_required` | The plan does not include the `feature`. Examples are manual pipeline runs, alert recipients and Trust Center publication on the free plan. | Move to the team plan. | | 429 | `quota_exceeded` | A daily allowance is spent. The answer gives `resource`, `policy`, `limit`, `used`, `reset_at` and `retry_after`, and a `Retry-After` header. | Wait until `reset_at`. Allowances run on UTC days and reset at 00:00 UTC. | | 429 | `edge_rate_limited` | The web server in front of the API saw too many requests from your client in a short time. | Slow down and retry after `Retry-After` seconds. | | 503 | `quota_unavailable` | The allowance could not be checked, and nothing was done. | Retry after `Retry-After`. | | 503 | `quota_not_configured` | Your workspace's allowances are not set up. This is our fault and we have been alerted. | Retry later or contact support. | | 503 | `workspace_busy` | The workspace has too much in flight. | Retry after `Retry-After`. | | 413 | `body_too_large` | A JSON body was larger than 256 KiB. SBOM and evidence uploads have their own limits. | Send less in one request. | Re-posting something that already exists is not refused for a cap it does not add to. `POST /api/v1/products` with an existing slug answers 200, and a release version that already exists answers 409. Daily allowances are counted per workspace and per UTC day. They cover SBOM ingests and the components inside them, scans, PDF exports, repository reads and invitations sent. An ingest over the allowance is refused with 429 `quota_exceeded` before anything is stored. `GET /api/v1/plans` lists the caps and allowances of all plans and needs no sign-in. `GET /api/v1/tenants/current/usage` gives your workspace's caps and today's use. ## Health `GET /healthz` and `HEAD /healthz` need no credential and answer with the same status. The answer is 503 only when the database cannot be reached. Other problems answer 200 with `status: "degraded"` and a breakdown by check. A check marked `severity: "blind"` did not run. Do not read its silence as a pass. ## Known limits This section lists what is true today. A defect is fixed when found and is not listed here. - Assets are created one request at a time. `POST /api/v1/assets/amend-batch` corrects up to 500 existing assets in one call, and there is no batch create. Tell us the size of the estate you are importing. - A hardware bill of materials belongs to a hardware model. The release SBOM route, `POST /api/v1/releases/{id}/sbom`, refuses a CycloneDX document whose components are all `device` or `firmware` without a purl (422), and the hardware model route, `POST /api/v1/hardware-models/{id}/hbom`, takes it. - A release cannot be retired. `POST /api/v1/releases/{release_id}/amend` corrects it, but a release created by mistake stays in the register and counts towards the plan's cumulative release limit. ## Reporting a defect Report anything security-related through security.txt. For anything else, send the exact request, the response, its `request_id` header and what you expected. We re-run each report before agreeing or disagreeing with it, and we tell you which. ## Routes Generated from this API's route table. The brackets show the scopes a key needs (a session needs a role that grants them), 'signed in' when any signed-in caller may use the route, 'public' when it needs no credential, or the one other credential the route accepts. ### admin - `DELETE /api/v1/admin/api-keys/{key_id}/assets/{asset_id}` (admin_policy): Unbinds one device from a host-agent API key. Patch reports from that key stop counting as evidence for the device. - `GET /api/v1/admin/api-keys/{key_id}/assets` (admin_policy): Shows the devices bound to a host-agent API key, by asset tag and binding date. - `GET /api/v1/admin/api-keys` (admin_policy): Lists the workspace's API keys, newest first, and counts how many are active, expired or revoked. Pass include_inactive=false to see only live keys. - `GET /api/v1/admin/roles` (admin_policy): Returns the roles and the permissions they grant. A role change made in the identity service takes effect at the member's next sign-in. - `GET /api/v1/admin/scopes` (admin_policy): Returns the scopes an API key may hold and the human-only scopes that no key can be given, even by an administrator. - `POST /api/v1/admin/api-keys/{key_id}/assets` (admin_policy): Lets a host-agent API key report patches for devices named by asset ID or tag. A device that is already bound stays bound. - `POST /api/v1/admin/api-keys/{key_id}/revoke` (admin_policy): Revokes an API key immediately and records your reason. The key stays in the list as revoked. - `POST /api/v1/admin/api-keys` (admin_policy): Creates an API key that lasts 90 days unless you set lifetime_days, and returns its secret once. Store the secret, because it cannot be shown again. - `POST /api/v1/admin/erasures` (admin_policy): Irreversibly replaces a former member's identity with a token across the workspace and withdraws trust snapshots that name them. - `POST /api/v1/admin/sessions/revoke` (admin_policy): Signs a person out of all their current sessions on all devices. They can sign in again until their role is removed in the identity service. ### alerts - `DELETE /api/v1/alerts/recipients/{address}` (admin_policy): Stops sending alerts to an address. It stays in the recipient list marked as removed. - `GET /api/v1/alerts/recipients/confirm` (public): The confirmation email links here. Opening the link confirms the alert address without a sign-in and shows the result as a web page. - `GET /api/v1/alerts/recipients` (finding_read): Lists the workspace's alert addresses and shows which are deliverable, unverified, suppressed or removed. - `POST /api/v1/alerts/recipients/verify` (public): Confirms an alert address from the token in the emailed link and needs no sign-in. A token that fails for any reason gets the same 404. - `POST /api/v1/alerts/recipients` (admin_policy): Adds an alert address on a paid plan and emails it a confirmation link that expires in 7 days. Adding an unconfirmed address again sends a new link. ### attestation - `DELETE /api/v1/attestation/keys/{key_id}` (admin_policy): Stops trusting a signing key for new attestations. Verdicts already recorded against it stand as they were. - `GET /api/v1/attestation/keys` (sbom_read): Lists the trusted and removed signing keys of this workspace, including their public parameters and fingerprints. - `GET /api/v1/releases/{release_id}/attestation` (sbom_read): Returns a release's attestation verdict and all the submissions behind it. One verified submission is enough to make the release verified. - `POST /api/v1/attestation/keys` (admin_policy): Registers an RSA public key that build attestations may be signed with. A key id stays bound to its first key material for good. - `POST /api/v1/releases/{release_id}/attestation` (sbom_publish): Submits a DSSE envelope for a release and records its verdict, even an invalid one. The key needs sbom_read as well. ### audit - `GET /api/v1/audit/events` (report_read): Pages through the audit log, newest first by default, and puts the total in the X-Total-Count header. Use order=seq_asc to recompute the hash chain from the start. - `GET /api/v1/audit/verify` (report_read): Reports whether the audit log's hash chain is intact and names the cause of each break as altered, deleted or forked. It returns the last stored check unless you pass fresh=true. - `GET /api/v1/dashboard` (asset_read): Returns the figures behind the overview screen in one call, from asset and software counts to open findings by severity. - `POST /api/v1/audit/acknowledge` (chain_acknowledge): Records your finding on investigated chain breaks as a new audit entry. The breaks stay in the log and the chain still reports as not intact. ### auth - `GET /auth/callback` (public): Completes browser sign-in by exchanging the identity provider's code for a session cookie. If the sign-in carried an invitation, it is accepted first. - `GET /auth/login` (public): Starts browser sign-in through the identity provider. Pass switch=1 to force the login page when you need to use a different account. - `GET /auth/me` (public): Returns the caller's identity, roles and permissions, or authenticated false when nobody is signed in. - `POST /auth/backchannel-logout` (public): Ends a person's sessions here when the identity provider posts a signed logout token for them. Only the identity provider calls this. - `POST /auth/logout` (public): Revokes the current session and redirects to the identity provider's sign-out page. It still works when the caller is already signed out. ### compliance - `GET /api/v1/approvals` (report_read): Lists up to 500 recorded approvals by the date they were given, newest first. Entries carry the approver's words and whether the source was verified. - `GET /api/v1/assets/{asset_id}/ce-requirements/history` (asset_read): Pages through the Cyber Essentials answers ever recorded for one device, newest first. Rows marked backfilled are the answers that existed when history began on 29 September 2026. - `GET /api/v1/assets/{asset_id}/ce-requirements` (asset_read): Returns the Cyber Essentials answers recorded for one device and lists the requirements nobody has assessed yet. - `GET /api/v1/assets/{asset_id}/cloud-profile` (asset_read): Shows a cloud service's MFA profile and who implements its Cyber Essentials controls. A device that is not a cloud service gets a 409. - `GET /api/v1/assets/{asset_id}/firewall` (asset_read): Returns the firewall policy, active rules and reviews recorded for one device. Storage devices and peripherals are outside the firewall control and get a 409. - `GET /api/v1/assets/{asset_id}/patch-status` (asset_read): Shows a device's latest patch report and the age in days of its pending updates since their release. - `GET /api/v1/ce/answer-sheet/submissions/{submission_id}` (report_read): Returns one frozen answer sheet as it was submitted. The intact field reports whether the stored text still matches its recorded hash. - `GET /api/v1/ce/answer-sheet/submissions` (report_read): Lists frozen answer sheet submissions and their SHA-256 hashes, newest first. - `GET /api/v1/ce/answer-sheet` (report_read): Builds the Cyber Essentials answer sheet for the Danzell 16.3 question set from the current register and the organisation's recorded answer text. - `GET /api/v1/ce/approved-apps` (report_read): Lists the organisation's approved applications by platform, current ones first and retired ones after. - `GET /api/v1/ce/organisation/history` (report_read): Pages through the organisation's past and current Cyber Essentials answers, newest first. - `GET /api/v1/ce/organisation` (report_read): Returns the Cyber Essentials user account requirements that are answered once for the whole organisation, including any not yet assessed. - `GET /api/v1/ce/plus-tests/{test_id}/attachments/{attachment_id}/content` (report_read): Downloads one evidence file from a Cyber Essentials Plus test. The download is logged, and a file that fails its integrity check is refused with a 502. - `GET /api/v1/ce/plus-tests/{test_id}/attachments/{attachment_id}` (report_read): Returns the details of one evidence file on a Cyber Essentials Plus test. - `GET /api/v1/ce/plus-tests/{test_id}/attachments` (report_read): Lists the evidence files on one Cyber Essentials Plus test, including files that were superseded. - `GET /api/v1/ce/plus-tests` (report_read): Lists recorded Cyber Essentials Plus tests, most recent first, and their evidence file counts. - `GET /api/v1/ce/requirements` (public): Returns the Cyber Essentials requirement catalogue by control. Build answer forms from it, because it carries the requirement wording and the device types they apply to. - `GET /api/v1/ce/scope` (report_read): Shows the scope sub-sets and current device exclusions that take devices out of Cyber Essentials counts. Exclusions show the approval that covers them. - `GET /api/v1/isms/coverage` (report_read): Reports a status for each of the 14 trust controls (met, gap, stale or not applicable) and the reason for any gap. - `GET /api/v1/isms/releases/{release_id}/tests` (report_read): Lists the revocation and recovery tests recorded against one release and whether they all passed. A release with no tests recorded reads as not passed. - `GET /api/v1/isms/soa` (report_read): Returns the Statement of Applicability for the 93 ISO 27001:2022 Annex A controls and marks the ones not yet recorded as not assessed. - `GET /api/v1/isms/summary` (report_read): Gives the ISMS counts that need attention, such as overdue reviews, open incidents and tests failed in the last 90 days. - `GET /api/v1/isms/{register}/{record_id}/attachments/{attachment_id}/content` (report_read): Downloads an evidence file from an ISMS record. Downloads are logged, and a file that fails its integrity check is not served. - `GET /api/v1/isms/{register}/{record_id}/attachments/{attachment_id}` (report_read): Returns the details of one evidence file on an ISMS record. - `GET /api/v1/isms/{register}/{record_id}/attachments` (report_read): Lists the evidence files on one ISMS record, including superseded ones. Risks, suppliers, workforce and acknowledgements take no files. - `GET /api/v1/isms/{register}/{record_id}` (report_read): Returns one record from an ISMS register. - `GET /api/v1/isms/{register}` (report_read): Pages through the records in one ISMS register. X-Total-Count gives the total and the Link header carries the next and previous pages. - `POST /api/v1/approvals/{approval_id}/links/asset-events` (admin_policy): Links an approval to a device lifecycle event it covers. A repeat call returns success without adding a second link. - `POST /api/v1/approvals/{approval_id}/links/firewall-rules` (admin_policy): Attaches an approval to a firewall rule as its authorisation. Sending the same pair twice still leaves one link. - `POST /api/v1/approvals` (admin_policy): Records an approval in the approver's words and names its source. A Futex decision is checked and marked verified when approved, and you may record your own approval only when that check succeeds. - `POST /api/v1/assets/{asset_id}/exclusion/end` (admin_policy): Ends a device's current scope exclusion and brings it back into Cyber Essentials counts. The exclusion record is kept. - `POST /api/v1/assets/{asset_id}/exclusion` (admin_policy): Takes a device out of Cyber Essentials scope for a stated reason, citing an approval recorded beforehand. Cloud services cannot be excluded. - `POST /api/v1/assets/{asset_id}/firewall-reviews` (admin_policy): Records a firewall review of a device by a current workspace member. A review cannot be dated in the future. - `POST /api/v1/assets/{asset_id}/firewall-rules/{rule_id}/remove` (asset_write): Marks an active firewall rule on a device as removed and records the reason. The rule leaves the device's firewall view but is kept on record. - `POST /api/v1/assets/{asset_id}/firewall-rules` (asset_write): Adds a firewall rule to a device. An inbound allow rule must state its business need. - `POST /api/v1/assets/{asset_id}/patch-snapshots` (patch_report): Reports the updates still pending on a device, at most one report per device per 15 minutes. Reports from a key bound to the device count as observed and others as declared. - `POST /api/v1/ce/answer-sheet/submissions` (admin_policy): Freezes the current answer sheet as a submission and returns its SHA-256 hash. The API offers no way to change it afterwards. - `POST /api/v1/ce/approved-apps/{app_id}/retire` (admin_policy): Retires an approved application for a stated reason. Its entry stays on the list marked as retired. - `POST /api/v1/ce/approved-apps` (admin_policy): Adds an application to the organisation's approved list for one platform. An app already approved on that platform gets a 409. - `POST /api/v1/ce/plus-tests/{test_id}/attachments` (admin_policy): Uploads an evidence file (PNG, JPEG, PDF or text, up to 20 MiB) to a Cyber Essentials Plus test. Uploading the same bytes again returns the stored file. - `POST /api/v1/ce/plus-tests` (admin_policy): Records a Cyber Essentials Plus test result against a device, an IP address or both. Name the assessor's organisation, because individual assessors are not named. - `POST /api/v1/ce/scope-subsets` (admin_policy): Creates a named sub-set of the estate that is in or out of Cyber Essentials scope. An out-of-scope sub-set must name the boundary device that separates it. - `POST /api/v1/isms/access-requests` (admin_policy): Records a person's request for access to a system and its decision. An approved request cites a recorded approval, and access cannot be granted before that approval was given. - `POST /api/v1/isms/access-reviews` (admin_policy): Records a logical or physical access review by a current member, dated today or earlier. The kind cannot be changed later. - `POST /api/v1/isms/acknowledgements` (admin_policy): Records a person's acknowledgement of the one current file of an approved policy. Acknowledgements cannot be edited once recorded. - `POST /api/v1/isms/backup-tests` (admin_policy): Records a backup restore test and its result, optionally tied to a release or an outside tester. - `POST /api/v1/isms/certifications` (admin_policy): Adds a certificate the organisation holds, such as Cyber Essentials, ISO 27001 or SOC 2. The issue date cannot be in the future. - `POST /api/v1/isms/exercises` (admin_policy): Records an exercise and its result. An incident response exercise must name the plan it tested, and the facilitator cannot be changed later. - `POST /api/v1/isms/incidents` (admin_policy): Records a security incident as open or closed. A closed incident needs the time it was closed. - `POST /api/v1/isms/inherited-controls` (admin_policy): Records an ISO 27001 physical control (A.7) that a supplier carries for you, such as a data centre's. A control can be recorded only once per supplier. - `POST /api/v1/isms/policies` (admin_policy): Adds a policy or governance document. An approved one must cite a recorded approval, and a governance kind can have only one approved document at a time. - `POST /api/v1/isms/revocation-tests` (admin_policy): Records a test that checked revoked access is now refused. Name the member or organisation that ran it. - `POST /api/v1/isms/risks` (admin_policy): Adds a risk to the risk register along with its owner, scores, treatment and review date. The owner must be a current member. - `POST /api/v1/isms/suppliers` (admin_policy): Adds a supplier to the supplier register. A subprocessor must give the country where it holds the data as an ISO 3166 code. - `POST /api/v1/isms/training` (admin_policy): Records a training course that a person in the workforce completed, dated today or earlier. - `POST /api/v1/isms/workforce` (admin_policy): Adds a person to the workforce in scope, whether or not they have a login here. The person identifier cannot be changed later. - `POST /api/v1/isms/{register}/{record_id}/attachments` (admin_policy): Uploads an evidence file of up to 20 MiB to an ISMS record. Pass supersedes to replace an earlier file, and the replaced file stays on record. - `PUT /api/v1/assets/{asset_id}/ce-requirements` (asset_write): Records Cyber Essentials answers for one device and keeps replaced answers in its history. Requirements you leave out stay not assessed. - `PUT /api/v1/assets/{asset_id}/cloud-profile` (admin_policy): Sets a cloud service's MFA profile, replacing any earlier one. Claiming that no MFA option exists requires a reason. - `PUT /api/v1/assets/{asset_id}/cloud-responsibility/{control}` (admin_policy): Sets whether the organisation, the provider or both implement one Cyber Essentials control on a cloud service. User access control cannot be given to the provider. - `PUT /api/v1/assets/{asset_id}/firewall-policy` (asset_write): Sets a device's default inbound firewall policy and how its admin interface is exposed and protected. A new call replaces the old policy. - `PUT /api/v1/ce/answer-sheet/answers/{question_id}` (admin_policy): Saves the organisation's own answer text for one Danzell question, replacing any earlier text. - `PUT /api/v1/ce/organisation` (admin_policy): Records the organisation's answers to the Cyber Essentials user account requirements. Replaced answers are kept in the history. - `PUT /api/v1/isms/access-requests/{record_id}` (admin_policy): Updates an access request and keeps the stored value of any field you omit. Send null to clear a field. - `PUT /api/v1/isms/access-reviews/{record_id}` (admin_policy): Edits an access review record. Its kind is set at creation, and sending a different one returns 409. - `PUT /api/v1/isms/backup-tests/{record_id}` (admin_policy): Updates a backup test record. Only the fields you send change. - `PUT /api/v1/isms/certifications/{record_id}` (admin_policy): Updates a certificate record, such as its expiry date. Omitted fields keep their stored values. - `PUT /api/v1/isms/coverage/{control}` (admin_policy): Declares a trust control not applicable and gives the justification, or withdraws that declaration. Controls that cannot be declared not applicable return 409. - `PUT /api/v1/isms/exercises/{record_id}` (admin_policy): Updates an exercise record except for the facilitator, which is fixed when the record is created. - `PUT /api/v1/isms/incidents/{record_id}` (admin_policy): Updates a security incident, for example when it is closed. Closing one needs the closed status sent together with closed_at. - `PUT /api/v1/isms/inherited-controls/{record_id}` (admin_policy): Edits a physical control carried by a supplier. Fields left out of the request stay as they were. - `PUT /api/v1/isms/policies/{record_id}` (admin_policy): Updates a policy or governance document. Its kind is fixed, and approving it requires a recorded approval. - `PUT /api/v1/isms/revocation-tests/{record_id}` (admin_policy): Updates a revocation test record and changes only the fields sent. - `PUT /api/v1/isms/risks/{record_id}` (admin_policy): Updates a risk, such as its status or review date. A newly named owner must be a current member. - `PUT /api/v1/isms/soa/{control}` (admin_policy): Records the Statement of Applicability entry for one Annex A control, replacing any earlier entry. - `PUT /api/v1/isms/suppliers/{record_id}` (admin_policy): Updates a supplier record and keeps any field you leave out. - `PUT /api/v1/isms/training/{record_id}` (admin_policy): Corrects a training record and leaves unsent fields as they were. - `PUT /api/v1/isms/workforce/{record_id}` (admin_policy): Updates a person's workforce dates, such as the day they left. The person identifier is fixed. ### cryptography - `GET /api/v1/alerts/certificates` (report_read): Lists the certificate expiry warnings sent so far, newest first, up to 500. - `GET /api/v1/components/{component_id}/crypto-assets` (sbom_read): Lists the cryptographic assets a component uses. It takes the same filters, sort and paging as the estate list. - `GET /api/v1/crypto-assets.csv` (sbom_read): Downloads the cryptographic asset list as CSV, up to 50,000 rows. The X-Truncated header says whether rows were cut off. - `GET /api/v1/crypto-assets/facets` (sbom_read): Returns asset counts per value for the filter dimensions. A dimension's counts apply all the other active filters. - `GET /api/v1/crypto-assets/{asset_id}` (sbom_read): Returns one cryptographic asset in full, including how it was classified and why, which components use it and the excerpt it came from. - `GET /api/v1/crypto-assets` (sbom_read): Lists the workspace's cryptographic assets, paged and filterable. Results come in migration priority order unless you pick another sort. - `GET /api/v1/crypto-families` (sbom_read): Counts, per algorithm family, the cryptographic assets, releases and products that use it. - `GET /api/v1/quantum-readiness/scoring` (sbom_read): Returns the weights behind the migration priority score, enough to recompute any row's score yourself. - `GET /api/v1/quantum-readiness/trend` (sbom_read): Returns daily quantum-readiness counts for up to 730 days. A day without a stored snapshot carries the previous counts forward. - `GET /api/v1/quantum-readiness` (sbom_read): Summarises quantum readiness for the whole workspace in one response, covering analysis coverage, asset counts by status, expiring certificates and a paged priority list. - `GET /api/v1/releases/{release_id}/cbom` (sbom_read): Exports a release's cryptographic inventory as a CycloneDX 1.6 CBOM that carries our quantum verdicts as properties. - `GET /api/v1/releases/{release_id}/crypto-assets` (sbom_read): Lists one release's cryptographic assets using the estate list's filters, sort and paging. - `GET /api/v1/releases/{release_id}/crypto-coverage` (sbom_read): Reports whether a release's documents were analysed for cryptography. An empty asset list means none were found only when the state is analysed. - `GET /api/v1/releases/{release_id}/crypto-diff` (sbom_read): Compares a release's cryptography with the release named in against and lists the assets added, removed and reclassified. - `POST /api/v1/alerts/certificates/dispatch` (alert_dispatch): Sends pending warnings for certificates that expire within 30 or 7 days, up to 25 per run, on paid plans only. Set dry_run to preview them. ### deploy - `GET /api/v1/deployments` (sbom_read): Lists deployments newest first, showing which release runs in which environment and since when. You can filter to live or withdrawn ones. - `GET /api/v1/environments` (sbom_read): Lists the workspace's environments by slug and marks which of them are production. - `POST /api/v1/deployments/{deployment_id}/withdraw` (release_write): Marks a deployment as no longer running and keeps it in the history. Withdrawing it a second time returns 409. - `POST /api/v1/deployments` (release_write): Records that a release is running in an environment. A live deployment of another release of the same product there is closed automatically. - `POST /api/v1/environments` (release_write): Creates an environment that releases can be deployed to and marks whether it is production. A slug already in use returns 409. ### evidence - `GET /api/v1/evidence/blocking` (report_read): Lists what would fail Cyber Essentials today and the evidence still missing. Reading it does not count as an evidence pack export. - `GET /api/v1/evidence/controls` (report_read): Returns the controls provenance can evidence and the scheme and caveat attached to them. - `GET /api/v1/evidence/pack.html` (report_read): Exports the evidence pack as printable HTML and records the export in the audit log. Use it when the PDF cannot be rendered. - `GET /api/v1/evidence/pack.pdf` (report_read): Downloads the evidence pack as a PDF and records the export in the audit log. A PDF download counts towards the plan's report export quota. - `GET /api/v1/evidence/pack` (report_read): Exports the evidence pack as JSON with its SHA-256 digest, optionally narrowed by scheme or control ref. The export is recorded in the audit log. ### evidence-files - `GET /api/v1/assets/{asset_id}/attachments/{attachment_id}/content` (asset_read): Downloads one of an asset's evidence files. The file is checked against its recorded SHA-256 first and is withheld with a 502 if it fails. - `GET /api/v1/assets/{asset_id}/attachments/{attachment_id}` (asset_read): Returns the record for one evidence file on an asset, without the file itself. - `GET /api/v1/assets/{asset_id}/attachments` (asset_read): Lists an asset's evidence files, both current and superseded. - `GET /api/v1/assets/{asset_id}/ce-requirements/{requirement}/attachments/{attachment_id}/content` (asset_read): Downloads an evidence file attached to an asset's Cyber Essentials answer. Downloads are recorded in the audit log. - `GET /api/v1/assets/{asset_id}/ce-requirements/{requirement}/attachments/{attachment_id}` (asset_read): Returns the record for one evidence file on an asset's Cyber Essentials answer. - `GET /api/v1/assets/{asset_id}/ce-requirements/{requirement}/attachments` (asset_read): Lists the evidence files on an asset's answer to one Cyber Essentials requirement, including superseded ones. - `GET /api/v1/ce/organisation/{requirement}/attachments/{attachment_id}/content` (report_read): Downloads an evidence file from the organisation's Cyber Essentials answer once it matches its recorded SHA-256. - `GET /api/v1/ce/organisation/{requirement}/attachments/{attachment_id}` (report_read): Shows one evidence file's record from the organisation's Cyber Essentials answer. - `GET /api/v1/ce/organisation/{requirement}/attachments` (report_read): Lists the evidence files on the organisation's answer to a Cyber Essentials requirement. - `POST /api/v1/assets/{asset_id}/attachments` (asset_write): Uploads an evidence file to an asset as the raw request body, up to 20 MiB of PNG, JPEG, PDF or plain text. Sending the same file again returns the existing copy. - `POST /api/v1/assets/{asset_id}/ce-requirements/{requirement}/attachments` (asset_write): Attaches an evidence file to an asset's Cyber Essentials answer once the answer is recorded. Passing supersedes replaces an earlier file and keeps it as superseded. - `POST /api/v1/ce/organisation/{requirement}/attachments` (admin_policy): Attaches an evidence file to the organisation's answer to a Cyber Essentials requirement. A replacement keeps the earlier file as superseded. ### hardware - `GET /api/v1/alerts/support` (asset_read): Lists the 500 most recent support-ending alerts sent for devices and their outcomes, newest first. - `GET /api/v1/assets/as-of` (asset_read): Rebuilds the register as it stood at a given time from the history of lifecycle events. - `GET /api/v1/assets/held-by/{custodian_sub}` (asset_read): Answers the offboarding question of what a person still holds. Devices in repair or reported lost or stolen are included. - `GET /api/v1/assets/{asset_id}/history` (asset_read): Returns a device's lifecycle events in the order they were recorded. - `GET /api/v1/assets/{asset_id}/software` (asset_read): Returns a device's recorded software and its versions and vendor support status. - `GET /api/v1/assets/{asset_id}` (asset_read): Returns one device and the lifecycle events it can take next. - `GET /api/v1/assets` (asset_read): Lists the devices the workspace still holds, one page at a time. Pass include_retired=true for the whole register. - `GET /api/v1/hardware-models/suggestions` (asset_read): Groups in-use devices that have no hardware model by the make and model typed for them, largest group first. - `GET /api/v1/hardware-models/{model_id}` (asset_read): Returns one hardware model and its HBOM documents, showing which document is current. - `GET /api/v1/hardware-models` (asset_read): Lists the workspace's hardware models a page at a time, optionally filtered by kind or HBOM coverage. - `GET /api/v1/hbom-entities/{entity_id}` (asset_read): Returns one company named in HBOMs, including its aliases and how many current HBOM roles name it. - `GET /api/v1/hbom-entities` (asset_read): Lists the companies named in HBOMs. Ask for reviewed=false&referenced=true to get the review queue. - `GET /api/v1/hbom/concentration` (asset_read): Counts component makers across current HBOMs, grouped by country or by company. - `GET /api/v1/hbom/coverage` (asset_read): Reports how many in-use devices are linked to a hardware model and how many current HBOMs the workspace holds. - `GET /api/v1/hbom/documents/{document_id}/export.cdx.json` (asset_read): Exports an HBOM document as CycloneDX 1.6 JSON, regenerated from what the register holds. - `GET /api/v1/hbom/documents/{document_id}/export.csv` (asset_read): Exports an HBOM document in the CISA HBOM fields as CSV, one row per part, regenerated from the register. - `GET /api/v1/hbom/documents/{document_id}/original` (asset_read): Downloads an HBOM document exactly as it was received, after checking it against its SHA-256 digest. A copy that fails the check is not served. - `GET /api/v1/hbom/documents/{document_id}/parts/{ordinal}` (asset_read): Returns one part of an HBOM document and the chain of parts above it. - `GET /api/v1/hbom/documents/{document_id}/parts` (asset_read): Lists one level of an HBOM document's part tree, or searches every level by part number or description. - `GET /api/v1/hbom/documents/{document_id}` (asset_read): Returns the summary of one HBOM document, including its format, origin and how many of its parts are held. - `GET /api/v1/hbom/exposure.csv` (asset_read): Downloads the devices an exposure query finds as CSV, one row per device. - `GET /api/v1/hbom/exposure` (asset_read): Finds the in-use devices whose HBOMs name a given place or company, and the parts that matched. - `GET /api/v1/hbom/locations/facets` (asset_read): Lists the countries or regions named in current HBOMs and the number of roles that name them. - `GET /api/v1/hbom/matches` (asset_read): Lists screening matches against your restrictions. On the free plan the X-Screening header reads not_on_plan because no screening runs there. - `GET /api/v1/hbom/restrictions` (asset_read): Lists the restrictions your administrators have declared, active and retired, newest first. - `GET /api/v1/hbom/screening` (asset_read): Reports the screening state, including how many documents are not yet screened and how many open matches await review. - `GET /api/v1/hbom/template.csv` (asset_read): Downloads a CSV template of the CISA HBOM fields, a header row and one example row. - `GET /api/v1/hbom/vocabulary` (asset_read): Returns the display labels for the keys that HBOM answers use. - `POST /api/v1/alerts/support/dispatch` (alert_dispatch): Emails an alert for each in-scope device whose support ends within 60 days and was not yet alerted. A dry run lists them without sending. - `POST /api/v1/assets/amend-batch` (asset_write): Applies up to 500 device corrections under one reason, all or none. A re-run reports values already set as unchanged. - `POST /api/v1/assets/sites/rename` (asset_write): Renames a site on all the assets recorded there, retired ones included. No asset is recorded as moved. - `POST /api/v1/assets/{asset_id}/amend` (asset_write): Corrects one recorded fact about a device, such as disk encryption, and logs the old value with your reason. - `POST /api/v1/assets/{asset_id}/dispose` (asset_dispose): Disposes of a device permanently once a person approves and the ledger posting succeeds. Re-send with approval_id after the first call's request is approved. - `POST /api/v1/assets/{asset_id}/events` (asset_write): Records a lifecycle event for a device, such as an assignment or a move. Disposal goes through the dispose route, which needs an approval. - `POST /api/v1/assets` (asset_write): Registers a new device, subject to the plan's asset limit. An asset tag already in use is refused. - `POST /api/v1/hardware-models/{model_id}/hbom/self-declared` (asset_write): Records the maker and place of manufacture a person read off a device as a self-declared HBOM for its model. - `POST /api/v1/hardware-models/{model_id}/hbom` (asset_write): Records an HBOM for a hardware model from CycloneDX or CISA CSV or JSON. Re-posting bytes already held makes that document current again unless it was disavowed. - `POST /api/v1/hardware-models` (asset_write): Creates a hardware model, or returns the existing one with 200 when the kind, maker, part number and version already match. - `POST /api/v1/hbom-entities/aliases/undo` (asset_write): Undoes the alias for a printed company name by recording a new entry. Names tied to a restriction or an open match also need admin_policy. - `POST /api/v1/hbom-entities/{entity_id}/aliases` (asset_write): Records that a printed company name belongs to this company and reruns screening. If the change touches a restricted or matched company, admin_policy is required. - `POST /api/v1/hbom-entities/{entity_id}/merge` (asset_write): Merges this company into another and records your reason. Merging a company into itself undoes an earlier merge. - `POST /api/v1/hbom-entities/{entity_id}/review` (asset_write): Marks a company named in HBOMs as reviewed and stores an optional note. - `POST /api/v1/hbom/documents/{document_id}/corrections` (admin_policy): Disavows an HBOM document posted in error and makes the model's previous document current again. The disavowed document is kept but drops out of reads. - `POST /api/v1/hbom/matches/{match_id}/disposition` (admin_policy): Records a decision and reason on a screening match, on a paid plan. The decision lapses if the facts behind the match change. - `POST /api/v1/hbom/restrictions/{restriction_id}/retire` (admin_policy): Retires a restriction and rescreens. To change a restriction, retire it and add a new one. - `POST /api/v1/hbom/restrictions` (admin_policy): Adds a restriction taken from a list you name and screens current HBOMs against it on a paid plan. Restrictions cannot be edited later. - `PUT /api/v1/assets/{asset_id}/scope` (admin_policy): Sets the ownership and minimal-use fields that decide whether a device is in Cyber Essentials scope. Fields left out keep their value. - `PUT /api/v1/assets/{asset_id}/software` (asset_write): Replaces a device's installed software list with the one sent. Employee-owned devices and cloud services are refused. ### identity - `GET /api/v1/whoami` (signed in): Returns who you are signed in as and the permissions your credential holds. - `PUT /api/v1/me/locale` (signed in): Saves your interface language across all your workspaces. API keys cannot set one. ### pipelines - `GET /api/v1/pipelines/runs` (report_read): Lists scheduled workflow runs, newest slot first, paged with a total count. - `GET /api/v1/pipelines/schedule` (report_read): Shows when the scheduled workflows are due, in UTC, and when they last ran. - `POST /api/v1/pipelines/{workflow}/run` (admin_policy): Queues a scheduled workflow to run now and returns 202, on paid plans only. A worker picks it up within about a minute. ### plans - `GET /api/v1/plans` (public): Lists the public plans and their limits and features. Daily allowances reset at 00:00 UTC. ### platform - `GET /api/v1/platform/settings` (platform operators only): Shows a platform operator whether self-service sign-up is on, and answers 404 to anyone else. - `GET /api/v1/platform/tenants` (platform operators only): Lists the workspaces on the platform and their member counts, for platform operators. - `POST /api/v1/platform/tenants/{tenant_id}/plan` (platform operators only): Moves a workspace to another plan and records the reason. If the new usage limits cannot be applied, nothing changes. - `POST /api/v1/platform/tenants/{tenant_id}/resume` (platform operators only): Reactivates a suspended workspace without asking for a reason. - `POST /api/v1/platform/tenants/{tenant_id}/suspend` (platform operators only): Suspends a workspace and records the reason. Scheduled work skips a suspended workspace. - `POST /api/v1/platform/tenants` (platform operators only): Lets a platform operator create a free-plan workspace whose administrator is the given identity-provider subject. - `PUT /api/v1/platform/settings` (platform operators only): Switches self-service sign-up on or off immediately, for platform operators. ### security - `GET /api/v1/alerts` (finding_read): Lists the vulnerability alerts sent about findings, newest first. Pass finding_id to see who was told about one finding and when. - `GET /api/v1/findings/totals` (finding_read + sbom_read): Returns all the header counts of the findings page from one consistent snapshot. - `GET /api/v1/findings/{finding_id}` (finding_read + sbom_read): Returns one finding in detail, including whether its release is deployed, the VEX position in force and the history of its VEX statements. - `GET /api/v1/findings` (finding_read + sbom_read): Lists open findings in active products, most severe first and then newest, paged with a total. Filters cover severity, product, deployment and VEX assessment. - `GET /api/v1/scans/{scan_id}` (sbom_read): Reports the state of a release scan and its result once finished. A scan still running after 30 minutes is reported as interrupted. - `POST /api/v1/alerts/dispatch` (alert_dispatch): Emails alerts about deployed findings, by default critical ones in production. A repeat call sends only alerts that have not yet been delivered. - `POST /api/v1/findings/{finding_id}/vex` (vex_author): Records your VEX position on a finding and replaces the previous one. A not_affected or fixed status waits for human approval before it takes effect. - `POST /api/v1/releases/{release_id}/scan` (sbom_publish): Scans a release's newest SBOM for vulnerabilities and returns the result. If the scan outlasts the wait time, you get 202 and a scan to poll. - `POST /api/v1/vex/{vex_id}/approve` (vex_approve): Approves a VEX statement that someone else wrote. A not_affected or fixed statement becomes effective only once its approval decision is approved. ### service - `GET /healthz` (public): Reports service health for GET and HEAD. It answers 503 only when the database is unreachable. ### software - `GET /api/v1/components/{component_id}/releases` (sbom_read): Lists the releases that ship a component and the environments where they are deployed now. - `GET /api/v1/components` (sbom_read): Searches components in active products by purl, name or scope, paged. Set include_retired to include retired products. - `GET /api/v1/license-policy` (sbom_read): Lists the workspace's licence verdicts by SPDX id, including waivers and their rationale. - `GET /api/v1/licenses` (sbom_read): Lists the licences declared in active products against their policy verdicts. A licence with no recorded verdict shows as unreviewed. - `GET /api/v1/products/{ref}` (sbom_read): Returns one product by slug or id, including the inventory state that explains why a product may have no components. - `GET /api/v1/products/{slug}/releases` (sbom_read): Lists a product's releases newest first, addressed by slug or id. An unknown product returns 404. - `GET /api/v1/products` (sbom_read): Lists active products by slug together with their release and SBOM counts. Set include_retired to list retired products too. - `GET /api/v1/releases/{release_id}/sbom` (sbom_read): Downloads the exact CycloneDX SBOM bytes published for a release. Set form=current for a copy rebuilt from the components on record. - `GET /api/v1/releases` (sbom_read): Lists releases across all products, newest first. Pass product to narrow the list to one product's slug. - `GET /api/v1/sbom-documents/correction-kinds` (sbom_read): Lists the correction kinds an SBOM document accepts and what they mean. - `GET /api/v1/sbom-documents/{sbom_id}/corrections` (sbom_read): Returns an SBOM document's identity and the corrections recorded against it, oldest first. - `GET /api/v1/sbom/estate` (sbom_read): Builds one CycloneDX SBOM of the components deployed now across the workspace, deduplicated by purl. Set production_only to limit it to production. - `POST /api/v1/products/{ref}/amend` (release_write): Changes a product's name, repository URL, criticality or owning team and records the old value with your reason. The slug cannot be changed. - `POST /api/v1/products/{ref}/retire` (release_write): Takes a product out of the working set and stops it taking new releases. Its releases, SBOMs and findings remain readable. - `POST /api/v1/products/{ref}/unretire` (release_write): Puts a retired product back in the working set and lets it accept new releases again. - `POST /api/v1/products/{slug}/releases` (release_write): Creates a release for a product given by slug or id. A version that already exists returns 409, as does a retired product. - `POST /api/v1/products/{slug}/sbom-from-repo` (release_write): Reads the product's repository lockfile and ingests an SBOM under a release named after the branch and commit. Re-running at the same commit reuses that release. - `POST /api/v1/products` (release_write): Registers a product and is safe to repeat with the same details. The same slug sent with different details returns 409. - `POST /api/v1/releases/{release_id}/amend` (release_write): Corrects how a release's git sha relates to the code that ran, through its source kind and source note. Version and sha cannot be changed. - `POST /api/v1/releases/{release_id}/sbom` (sbom_publish): Ingests a CycloneDX document sent as the request body for a release. Sending the same document again returns already_ingested. - `POST /api/v1/releases/{release_id}/source-observations` (release_write): Records what a running process reported about its own source, such as a source digest or git sha, against a release. - `POST /api/v1/sbom-documents/{sbom_id}/corrections` (admin_policy): Marks an SBOM document as withdrawn, superseded or not an attestation and records your reason. The document itself is left unchanged. - `POST /api/v1/sbom/from-repos` (release_write): Generates SBOMs from repositories for a slice of active products, five by default and at most 25 per call. Page through them with offset. - `PUT /api/v1/license-policy/{spdx_id}` (license_waive): Sets the workspace's verdict for a licence and replaces any earlier one. A waiver needs a rationale and records who granted it. ### tenancy - `GET /api/v1/invitations/{token}` (public): Lets someone holding an invitation link see the workspace name, inviter, roles and expiry before signing in. - `GET /api/v1/tenants/current/usage` (signed in): Shows the workspace's plan limits and its usage against them. Only administrators see the API key count. - `GET /api/v1/tenants/current` (signed in): Returns the name, slug, state and plan of the workspace the caller is acting in. Any member can read it. - `GET /api/v1/tenants/invitations` (admin_policy): Lists the workspace's invitations and their states, newest first. Invitation tokens are not returned. - `GET /api/v1/tenants/members` (admin_policy): Lists the workspace's current members and their roles. An email address appears only for people who joined by invitation. - `PATCH /api/v1/tenants/current` (admin_policy): Renames the workspace, which also changes the name printed on its evidence packs. The slug does not change. - `POST /api/v1/tenants/invitations/{invitation_id}/revoke` (admin_policy): Withdraws an invitation that nobody has accepted yet. - `POST /api/v1/tenants/invitations` (admin_policy): Invites a person by email with the given roles and returns the invitation link once. The invitation expires after 7 days and needs a free seat on the plan. - `POST /api/v1/tenants/members/{sub}/remove` (admin_policy): Removes a member from the workspace from their next request onwards. A reason is required and goes into the audit log. - `POST /api/v1/tenants/switch` (signed in): Moves a browser session into another workspace the person belongs to and reissues the session cookie. An API key belongs to one workspace and cannot switch. - `PUT /api/v1/tenants/members/{sub}/roles` (admin_policy): Replaces a member's roles but refuses a change that would leave the workspace with no administrator. ### trust - `GET /api/v1/alerts/trust-expiry` (report_read): Lists the expiry warnings sent for published trust snapshots, newest first, up to 500. - `GET /api/v1/trust/keys` (public): Publishes the signing keys for trust snapshots and their validity dates to anyone, without a sign-in. - `GET /api/v1/trust/preview` (report_read): Shows the content a trust snapshot would publish now, its SHA-256 and anything blocking publication. - `GET /api/v1/trust/profile` (report_read): Returns the workspace's trust profile, or 404 if none has been set up. - `GET /api/v1/trust/publish-requests` (report_read): Lists trust snapshot publication requests, newest first, and whether they are waiting, published or expired. - `GET /api/v1/trust/published` (the trust feed credential): Gives the public trust site its index of current snapshots and recent withdrawals. It needs the trust feed credential. - `GET /api/v1/trust/snapshots/{snapshot_id}/letter.pdf` (report_read): Downloads a trust snapshot's letter as a PDF and records its SHA-256 in the audit log. A PDF download counts towards the plan's report export quota. - `GET /api/v1/trust/snapshots/{snapshot_id}/letter` (report_read): Renders the letter for a trust snapshot as HTML from its verified signed content. - `GET /api/v1/trust/snapshots/{snapshot_id}` (report_read): Returns a trust snapshot's signed payload and envelope after re-checking its hash and signature. - `GET /api/v1/trust/snapshots` (report_read): Lists the workspace's published trust snapshots, newest first, as current, superseded or withdrawn. - `GET /api/v1/trust/status/{snapshot_id}` (public): Tells anyone holding a snapshot ID whether it is current, superseded, withdrawn or signed by a revoked key. The snapshot body is not returned. - `POST /api/v1/alerts/trust-expiry/dispatch` (alert_dispatch): Emails warnings for published trust snapshots that expire within 14 or 3 days. When warnings are due and no confirmed alert address exists, it refuses with 409. - `POST /api/v1/trust/profile/rotate-handle` (admin_policy): Gives the trust profile a new public handle and withdraws the current snapshot. Two members must publish again for it to appear under the new handle. - `POST /api/v1/trust/publish-requests/{request_id}/approve` (trust_approve): Approves another member's publication request, then signs and publishes the trust snapshot. The member who asked cannot approve their own request. - `POST /api/v1/trust/publish-requests` (admin_policy): Requests publication of the previewed trust content by its SHA-256, on paid plans. A second member has to approve it. - `POST /api/v1/trust/published/envelopes` (the trust feed credential): Returns signed envelopes for up to 50 snapshot IDs that are still current. Only the public trust site calls it, using the trust feed credential. - `POST /api/v1/trust/snapshots/{snapshot_id}/withdraw` (admin_policy): Stops a published trust snapshot being served. Its record is kept, and it cannot become current again. - `PUT /api/v1/trust/profile` (admin_policy): Creates or replaces the workspace's trust profile and keeps its public handle. The security contact must be a role address such as security@. ### vulnerabilities - `POST /api/v1/vulnerabilities/advisory-dates` (sbom_publish): Looks up publication dates on OSV for up to 500 undated vulnerabilities per call. The key also needs finding_read.