The scans this core is holding, newest first.
const url = 'https://example.com/api/v1/discovery/scans';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/v1/discovery/scans \ --header 'Authorization: Bearer <token>'Exists so a sweep survives leaving the page: the scan id used to live only in the browser tab
that started it, so navigating away lost a sweep the poller was still running. What bounds this
list is the runner’s retention (finished scans age out, running ones are never capped away),
not the caller’s limit.
A restarted core answers an empty list even while a poller is still sweeping — scan state is in memory by decision (ADR-068). That is why the WebUI must render “this core does not know that scan” for a 404 on a remembered id, rather than an empty page.
ManageConfig and 503 in skeleton mode, matching GET /discovery/scan/{id} rather than the
candidates queue: this list is the Discovery screen’s own state, and a screen that cannot scan
has no scans to list. (The candidates queue answers 200 [] instead because it backs a
dashboard widget, where an error would break a page that otherwise works.)
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Responses
Section titled “Responses”Retained scans, newest first
One row of the scan list — everything [ScanStatus] has except the candidates themselves.
The omission is the point: 20 retained scans of up to 4096 candidates each would make listing them far more expensive than the question deserves. A caller that wants a scan’s candidates asks for that scan.
object
How many devices answered so far.
The pool the job was actually published to; null for the global subject.
Where a scan is in its life (ADR-068).
Deliberately has no Unknown variant, unlike the enums built by stored_enum::token_enum!:
those degrade a token a newer writer put in a database column, and this value is never read
back from storage — it only ever travels outward. The corresponding defensiveness lives on the
TypeScript side, which narrows the wire value and renders anything it does not recognise
neutrally. ⚠️ Rendering an unrecognised state as a failure is a real bug this codebase has
already shipped once (report runs, painted red by a switch with a default: arm).
Example
[ { "state": "queued" }]No valid bearer token
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Role lacks ManageConfig
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}Skeleton mode has no discovery runner
The ADR-019 envelope every failure renders as. pub(crate) and schema-bearing so the OpenAPI
document can name one error shape for every endpoint (ADR-035) instead of leaving 4xx/5xx bodies
undescribed — a client that has to guess the failure shape ends up parsing the success shape and
reading undefined.
object
object
Stable machine-readable code. Clients branch on this, never on the message.
Operator-facing sentence. Safe to display; never carries an internal error’s own text.
Examplegenerated
{ "error": { "code": "example", "message": "example" }}