get_discovery_scan
const url = 'https://example.com/api/v1/discovery/scan/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';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/scan/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \ --header 'Authorization: Bearer <token>'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Scan id returned when the sweep was accepted
Responses
Section titled “Responses”Progress, the candidates found so far, and which of them are already device nodes
A scan’s status, and which of its candidates a device node already stands at.
A view over the scan rather than a field on each candidate: the candidate type is also what the discovery-queue widget serves, where there is no scan read to hang the lookup on and the field would always be empty — which would be untrue.
object
One device a scan found, with a suggested profile for the operator to confirm on import.
object
The stored credential that answered SNMP, by reference (never the value) — the UI preselects it on import so the working secret is bound automatically.
Suggested device profile, resolved server-side via the classification rules (by sysObjectID prefix, else sysDescr regex, else “Generic SNMP” when SNMP answered). An id, not a name, so the UI binds it robustly even if the profile was renamed.
sysObjectID (dotted) if it answered SNMP — the authoritative device-type signal the
classifier prefers. Shown to the operator and useful for authoring rules.
Maker / model best-effort parsed from sysDescr (editable on import) — pre-fills the node’s descriptive metadata so the imported node displays “name (addr) (vendor) (model)”.
Terminal or not. Kept alongside state because it is part of the published contract (the
MCP get_config(kind="discovery_scan") tool serves this type straight through), and derived
from state rather than stored, so the two cannot disagree.
The pool the job was actually published to; null for the global subject.
Targets probed so far, and the sweep’s total. An address counts once a probe has been addressed to it, which is not the same as the sweep having finished identifying it.
The address the sweep is currently at (the next unprobed target), while running.
When the sweep was accepted (RFC 3339) — RFC 3339 rather than epoch millis to match the discovered-endpoint rows this API already serves.
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).
When a result last moved this scan forward (RFC 3339).
The candidates already in the inventory, in candidate order. A candidate absent from this
list is not monitored at its own address — same_device names one that may be monitored at
another. Read when the scan is read, so a node added or removed after
the sweep is reflected.
One candidate address that is already a device node.
A URL or DNS monitor pointed at the same address does not count: those store a resolved address, and the device itself can still be imported.
object
The candidate’s address, spelled exactly as the candidate spells it.
The device nodes at this address that the caller can see. More than one means the address was imported twice before this check existed; nothing is merged.
A device node an address already belongs to.
object
A device node in a folder the caller cannot see also stands here. Its name and id are withheld. That the address is taken is not, because importing it is refused either way.
Candidates that look like a device node already monitored at another address — its
interface list carries the candidate’s address, or its name and model match (ADR-139 Inc.3).
A mark, not a refusal: importing such a candidate is still accepted, because a site that
reuses one private address plan can make either piece of evidence wrong. Only nodes the caller
can see are named. A candidate in existing is never here.
One candidate that looks like a device node monitored at another address.
object
The candidate’s address, spelled exactly as the candidate spells it.
The nodes it may be, the most convincing first.
A device node a candidate may be, and why.
object
The address the node is monitored at.
confident when the node’s interface list carries the candidate’s address and both report
the same sysObjectID; possible otherwise.
own_ip_one_way (the node’s interface list carries the candidate’s address) and/or name
(same name and the same sysObjectID).
Example
{ "state": "queued", "same_device": [ { "nodes": [ { "confidence": "confident", "evidence": [ "address" ] } ] } ]}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" }}No such scan
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 write side
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" }}