---
title: "Rescan a host"
method: POST
path: "/api/v1/hosts/{id}/rescan"
tags: ["Hosts"]
---

# Rescan a host

`POST /api/v1/hosts/{id}/rescan`

Starts a one-shot scan of this host's addresses and nothing else, answering
"is this host still there, and is its data current?" without sweeping the
whole subnet.

The scan runs on the daemon that last discovered this host — evidence it can
reach the address — and only if that daemon still has an interface on a
subnet containing one of the host's scannable IPs. Where that interface has a
MAC the daemon ARPs the target, which sees a live host even when every port
is firewalled; on a MAC-less interface (a point-to-point tunnel) it falls
back to a TCP probe. When no interface covers any of the host's addresses the
request is refused with the specific reason. A loopback address is not a
scannable IP — it is reached locally and is excluded from the target set.

Returns the session, which streams progress over `/api/v1/discovery/stream`
like any other scan. A `Queued` phase means the daemon is busy; it will start
when the running scan finishes.

## Path parameters

- `id` string, uuid, required

## Response `200`

Rescan session started

- ApiResponseDiscoveryUpdatePayload
  - `data` object — Progress update from daemon to server during discovery
    - `daemon_id` string, uuid, required — The daemon this entity refers to.
    - `discovery_id` string, uuid, nullable — The discovery configuration this session belongs to. Always enriched server-side; daemons do not send this field.
    - `discovery_type` union, required
      - object
        - `host_id` string, uuid, required — The host the daemon is running on.
        - `type` 'SelfReport', required
      - object
        - `host_naming_fallback` 'Ip' | 'BestService', required
        - `snmp_credentials` object — SNMP credentials for querying devices during discovery Server builds this mapping before initiating discovery
        - `subnet_ids` string[], nullable, required — Subnets to sweep. `null` sweeps every subnet on the network.
        - `type` 'Network', required
      - object
        - `host_id` string, uuid, required — The host the daemon is running on.
        - `host_naming_fallback` 'Ip' | 'BestService', required
        - `type` 'Docker', required
      - object — A one-shot verification of a single host: re-check the addresses and ports already recorded for it, rather than sweeping a subnet. Created by the server only (never via the API) and deleted once its session reaches a terminal phase, so it is not a discovery configuration anyone owns or sees in their scan list.
        - `host_id` string, uuid, required — ID of the host that the daemon is running on — same meaning as every other variant. The host being rescanned is `target_host_id`.
        - `ips` string[], required — Addresses to scan on that host.
        - `ports` PortType[] — Ports already known on that host, re-checked to confirm they are still open. Scanned in addition to the standard discovery set, so a rescan also surfaces newly-opened services.
          - `number` integer, required — TCP or UDP port number
          - `protocol` 'Udp' | 'Tcp', required — Transport protocol the port is open on.
          - `type` 'Ssh' | 'Telnet' | 'DnsUdp' | 'DnsTcp' | 'Samba' | 'Nfs' | 'Ftp' | 'Ipp' | 'LdpTcp' | 'LdpUdp' | 'Ldap' | 'Ldaps' | 'Kerberos' | 'Snmp' | 'SnmpAlt' | 'Rdp' | 'Ntp' | 'Sip' | 'SipTls' | 'Rtsp' | 'Dhcp' | 'Http' | 'MySql' | 'PostgreSQL' | 'MongoDB' | 'Redis' | 'MsSql' | 'Docker' | 'DockerTls' | 'Kubernetes' | 'RabbitMqMgmt' | 'Cassandra' | 'Elasticsearch' | 'InfluxDb' | 'CouchDb' | 'Kafka' | 'Http3000' | 'Http5000' | 'Http8080' | 'Http8081' | 'Http8082' | 'Http8888' | 'Http9000' | 'Https' | 'Https8443' | 'Https9443' | 'Https10443' | 'Mqtt' | 'MqttTls' | 'AMQP' | 'AMQPTls' | 'Wireguard' | 'OpenVPN' | 'BACnet' | 'JetDirect' | 'Custom' — Well-known port identifier. Auto-derived from number+protocol, so it is optional on create.
        - `settings` RescanSettings — Scan settings that apply to a single-host rescan. Deliberately narrower than [`ScanSettings`]: a rescan verifies a known host against a known port set, so the full-scan mechanism (`is_full_scan`, `full_scan_interval`) must not be expressible — promoting a rescan to a 65,535-port sweep defeats the feature. The remaining omissions are settings that cannot bind on a one-or-two address target.
          - `arp_retries` integer, nullable — ARP retry rounds. Matters more here than in a sweep: for a rescan, "did it answer" is the entire answer, so a missed round reads as a dead host.
          - `port_scan_batch_size` integer, nullable — Ports scanned concurrently per host.
          - `probe_raw_socket_ports` boolean — Whether to probe raw-socket ports 9100-9107. Correctness-affecting: with this off the scanner drops those ports from its results, so a printer's known JetDirect port would look like it had disappeared.
          - `scan_rate_pps` integer, nullable — Port scan probes per second. Operators lower this for fragile devices or noisy IDS, and a rescan must respect that as much as a discovery does.
          - `use_npcap_arp` boolean — On Windows, use Npcap broadcast ARP instead of SendARP.
        - `target_host_id` string, uuid, required — The host being rescanned.
        - `type` 'Rescan', required
      - object
        - `host_id` string, uuid, required — ID of the host that the daemon is running on
        - `host_naming_fallback` 'Ip' | 'BestService', required
        - `scan_settings` ScanSettings — Scan performance settings. Lives on the discovery entity. Numeric fields are `Option<T>` — `None` means "use daemon default". The daemon unwraps with defaults at point of use.
          - `arp_rate_pps` integer, nullable — ARP packets per second (default: 50)
          - `arp_retries` integer, nullable — ARP retry rounds for non-responsive targets (default: 2 = 3 total attempts)
          - `arp_scan_cutoff` integer, nullable — ARP scan cutoff prefix. Interfaced subnets larger than this prefix are truncated to this many IPs. Default: 15 (= /15, ~131K IPs). Lower values scan more IPs — increase arp_rate_pps accordingly.
          - `full_scan_interval` integer, nullable — Run a full 65k port scan every N scans. Other scans use a light port set. Default: 3. Value of 0 means never full scan. Value of 1 means every scan is full.
          - `is_full_scan` boolean — Whether this specific scan run should do a full 65k port scan. Set by the server before dispatching to the daemon — not user-configurable.
          - `max_discovery_duration` integer, nullable — Hard ceiling on how long a single discovery run may take, in seconds (default: 21600 = 6h). When hit, the run force-completes and any hosts still queued are left un-scanned until the next run. Raise this for very large networks that legitimately need more than the default window.
          - `port_scan_batch_size` integer, nullable — Ports scanned concurrently per host (default: 200, clamped 16-1000)
          - `probe_raw_socket_ports` boolean — Whether to probe raw-socket ports 9100-9107 (default: false). Disabled by default to prevent ghost printing on JetDirect printers.
          - `scan_rate_pps` integer, nullable — Port scan probes per second (default: 500)
          - `use_npcap_arp` boolean — On Windows, use Npcap broadcast ARP instead of SendARP (default: false)
        - `subnet_ids` string[], nullable, required — Subnets to scan. None = scan all interfaced subnets.
        - `type` 'Unified', required
    - `error` string, nullable — Failure message, when the run did not complete.
    - `estimated_remaining_secs` integer, nullable — Rough estimate of the time left, in seconds.
    - `finished_at` string, date-time, nullable — When the run finished. `null` while it is still going.
    - `hosts_discovered` integer, nullable — Hosts found so far.
    - `network_id` string, uuid, required — The network this entity belongs to.
    - `phase` 'AwaitingSnapshot' | 'Queued' | 'Pending' | 'Starting' | 'Started' | 'Scanning' | 'Complete' | 'Failed' | 'Cancelled', required
    - `progress` integer, required — Completion of the current phase, from 0 to 1.
    - `scanned` ScannedEntityIds — Canonical IDs of entities scanned in a discovery session. Populated daemon-side at terminal phase from `EntityBuffer`'s `Created` entries. Travels with the terminal `DiscoveryUpdatePayload` to the server, rides the in-memory `EntityOperation::Created` event published for the historical Discovery row (the event scope carries `Entity::Discovery` with the full struct, including `run_type::Historical { results }`), then is stripped before persisting into the historical Discovery row's JSONB (see the `SqlValue::RunType` bind_value handler in `backend/src/server/shared/storage/generic.rs`). Per-entity-service subscribers extract `results.scanned` from the in-memory event and call `DiscoveryFkUpdater::update_discovery_fks` to backfill `last_discovery_id` / `first_discovery_id` on the matched rows. Naming: `scanned_*` because the daemon scans entities — some submissions match existing rows (refresh), others insert new rows. Both populate the EntityBuffer with canonical (server-assigned) IDs.
      - `binding_ids` string[] — Service bindings touched by this discovery.
      - `host_ids` string[] — Hosts touched by this discovery.
      - `interface_ids` string[] — Interfaces touched by this discovery.
      - `ip_address_ids` string[] — IP addresses touched by this discovery.
      - `port_ids` string[] — Ports touched by this discovery.
      - `service_ids` string[] — Services touched by this discovery.
      - `subnet_ids` string[] — Subnets touched by this discovery.
      - `vlan_ids` string[] — VLANs touched by this discovery.
    - `session_id` string, uuid, required — The discovery run this update belongs to.
    - `started_at` string, date-time, nullable — When the run started.
    - `warnings` string[] — Non-fatal warnings for a completed run (e.g. the scan hit its time limit and left hosts un-scanned). Unlike `error`, these do not mark the run failed.
  - `error` string, nullable — Human-readable failure message. Omitted on success.
  - `meta` ApiMeta, required — API metadata included in all responses
    - `api_version` integer, required — API version (integer, increments on breaking changes)
    - `server_version` string, required — Server version (semver)
  - `success` boolean, required — `true` when the request succeeded. `false` responses carry `error` instead of `data`.

## Other responses

- `400` — Host cannot be rescanned (never scanned, daemon gone, daemon unreachable, or daemon too old)
- `404` — Host not found

---

[API](https://skmtc.net/scanopy/apis/scanopy-api.md) · [All operations](https://skmtc.net/scanopy/apis/scanopy-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/scanopy/scanopy-api/versions/28e466341947/schema)
