Skip to content

get_discovery_scan

GET
/api/v1/discovery/scan/{id}
curl --request GET \
--url https://example.com/api/v1/discovery/scan/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0 \
--header 'Authorization: Bearer <token>'
id
required
string format: uuid

Scan id returned when the sweep was accepted

Progress, the candidates found so far, and which of them are already device nodes

Media typeapplication/json

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
candidates
required
Array<object>

One device a scan found, with a suggested profile for the operator to confirm on import.

object
address
required
string
matched_credential_id

The stored credential that answered SNMP, by reference (never the value) — the UI preselects it on import so the working secret is bound automatically.

string | null format: uuid
model
string | null
reachable
required
boolean
suggested_profile_id

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.

string | null format: uuid
sysdescr
string | null
sysname
string | null
sysobjectid

sysObjectID (dotted) if it answered SNMP — the authoritative device-type signal the classifier prefers. Shown to the operator and useful for authoring rules.

string | null
vendor

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)”.

string | null
done
required

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.

boolean
pool

The pool the job was actually published to; null for the global subject.

string | null
probed
required

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.

integer format: int32
scan_id
required
string format: uuid
scanning

The address the sweep is currently at (the next unprobed target), while running.

string | null
started_at
required

When the sweep was accepted (RFC 3339) — RFC 3339 rather than epoch millis to match the discovered-endpoint rows this API already serves.

string
state
required

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).

string
Allowed values: queued running cancelling cancelled done
total
required
integer format: int32
updated_at
required

When a result last moved this scan forward (RFC 3339).

string
existing
required

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.

Array<object>

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
address
required

The candidate’s address, spelled exactly as the candidate spells it.

string
nodes
required

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.

Array<object>

A device node an address already belongs to.

object
id
required
string format: uuid
name
required
string
outside_scope
required

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.

boolean
same_device
required

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.

Array<object>

One candidate that looks like a device node monitored at another address.

object
address
required

The candidate’s address, spelled exactly as the candidate spells it.

string
nodes
required

The nodes it may be, the most convincing first.

Array<object>

A device node a candidate may be, and why.

object
address
required

The address the node is monitored at.

string
confidence
required

confident when the node’s interface list carries the candidate’s address and both report the same sysObjectID; possible otherwise.

string
Allowed values: confident possible
evidence
required

own_ip_one_way (the node’s interface list carries the candidate’s address) and/or name (same name and the same sysObjectID).

Array<string>
Allowed values: address serial own_ip own_ip_one_way arp_mac lldp_chassis cdp_device_id name
id
required
string format: uuid
name
required
string
Example
{
"state": "queued",
"same_device": [
{
"nodes": [
{
"confidence": "confident",
"evidence": [
"address"
]
}
]
}
]
}

No valid bearer token

Media typeapplication/json

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
error
required
object
code
required

Stable machine-readable code. Clients branch on this, never on the message.

string
message
required

Operator-facing sentence. Safe to display; never carries an internal error’s own text.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example"
}
}

Role lacks ManageConfig

Media typeapplication/json

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
error
required
object
code
required

Stable machine-readable code. Clients branch on this, never on the message.

string
message
required

Operator-facing sentence. Safe to display; never carries an internal error’s own text.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example"
}
}

No such scan

Media typeapplication/json

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
error
required
object
code
required

Stable machine-readable code. Clients branch on this, never on the message.

string
message
required

Operator-facing sentence. Safe to display; never carries an internal error’s own text.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example"
}
}

Skeleton mode has no write side

Media typeapplication/json

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
error
required
object
code
required

Stable machine-readable code. Clients branch on this, never on the message.

string
message
required

Operator-facing sentence. Safe to display; never carries an internal error’s own text.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example"
}
}