Automate a site rollout
Create a site, install its daemon, and share its topology with the Scanopy API.
Rolling out a new site takes the same API calls each time: create the site, provision a daemon, install it on a host at the site, wait for the first discovery, and share the topology. Every call uses one API key, so a script or a remote management tool can run the whole sequence.
Each step shows the request fields it uses, taken from the API specification. The link on each call opens its full reference, with the response and example requests.
Prerequisites
- A plan that includes API access and share links. See pricing.
- An API key created in Platform > API Keys by an organization Admin or Owner, with the Admin permission level and All sites. Admin is the level that can create sites and daemons, and All sites gives the key every site it creates. A key never exceeds its creator's access, as API keys describes.
- Root access, or passwordless
sudo, on a host at the new site, and a way to run commands on it. - On a server that sends email, a verified email on an organization owner's account. Until an owner verifies, the organization can run one daemon.
Send each request with the key as a bearer token, as Authentication shows.
1. Create the site
| Field | In | Type | Description |
|---|---|---|---|
name required | body | string | Human-facing name for this site. |
Keep the new site's id. The site's topology is created with it.
2. Provision the daemon
Provisioning creates the daemon's record on the site and mints the key the daemon authenticates with.
| Field | In | Type | Description |
|---|---|---|---|
name | body | string | Human-readable name for the daemon. Required unless daemon_id is set, in which case
the existing record's name is kept. |
site_id | body | uuid | Site this daemon will be associated with. Required unless daemon_id is set, in
which case the existing record's site is kept. |
mode | body | one of server_poll, daemon_poll | How the daemon communicates with the server. Defaults to DaemonPoll (the daemon dials out) for forward-compat with older clients. |
url | body | string | Reachable URL where the server can dial the daemon. Required for ServerPoll, unused for DaemonPoll (the daemon dials out instead). |
seed_credential_refs | body | IntegrationTarget[] | Credential/integration references to seed onto the daemon's first discovery run. References only — never secret material. Empty by default. |
In daemon_poll mode the daemon opens the connection to the server, so the site needs no inbound port. Choosing a polling mode covers both modes.
From the response, keep the daemon record's id, and store daemon_api_key. This response is the only place the key appears.
3. Install the daemon
| Field | In | Type | Description |
|---|---|---|---|
id required | path | uuid | daemon ID |
purpose required | query | one of install, rekey, reconfigure | install or rekey (with the api-key placeholder), or reconfigure (credential-free). |
Set purpose to install. The response holds a command for each platform, such as linux and windows, and a Docker setup in docker. The API key in each is a placeholder: replace it with the key you stored in step 2. For Docker, replace it in both compose and env.
Run the command as root on the host. It asks no questions, installs the daemon as a service, and starts it. To run it again on a host that already has a daemon, see Setting up multiple daemons.
4. Wait for the daemon to connect
| Field | In | Type | Description |
|---|---|---|---|
id required | path | uuid | Daemon ID |
Poll until health is no longer awaiting_connection.
5. Wait for the first discovery
The daemon starts its first discovery when it connects. Each discovery that finishes is recorded as a completed run.
| Field | In | Type | Description |
|---|---|---|---|
daemon_ids | query | uuid[] | Filter by daemon ID. Repeat the parameter to pass several. |
historical | query | boolean | true returns only completed runs (the history view), false only the
configurations that produce them. Omit for both. |
phases | query | one of AwaitingSnapshot, Queued, Pending, Starting, Started, Scanning, Complete, Failed, Cancelled[] | Only runs that ended in one of these phases (run_type.results.phase). Repeat for
several. Configurations, which have no recorded outcome, never match. |
Poll with the daemon's id and historical set to true until a run appears. A run in Complete has populated the topology. A run in Failed or Cancelled has not; Troubleshooting scans covers the causes.
6. Share the topology
Find the site's topology:
| Field | In | Type | Description |
|---|---|---|---|
site_id | query | uuid | Filter by site ID |
Keep the topology's id, and create a share for it:
| Field | In | Type | Description |
|---|---|---|---|
share.topology_id required | body | uuid | The topology this share exposes. |
share.site_id required | body | uuid | The site this entity belongs to. |
share.name required | body | string | Human-facing name for this share. |
share.is_enabled required | body | boolean | Whether the link still resolves. Disabled shares return 404. |
share.options required | body | ShareOptions | What the viewer can see and do. |
share.enabled_views required | body | one of L2Physical, L3Logical, Workloads, Application[] | Which topology views are enabled for this share. None = all views (subject to data availability). Some(list) = only these views in order. First element is the default view shown on load. |
share.password | body | string | Plaintext password on ingest; redacted sentinel ("********") or None on egress.
Never stored — password_hash is the DB column. Wrapped in SecretString so
Debug/logging shows [REDACTED] during the window between request
deserialization and hashing. |
share.expires_at required | body | string | When this record stops being valid. |
share.allowed_domains required | body | string[] | Domains permitted to embed this share. Empty means no restriction. |
To embed the topology on another site, list that site's hostname in allowed_domains. A share with a password asks each visitor for it, including inside an embed.
7. Build the link or embed
The share's response carries its id but no URL. Build the link or embed address from the id, as Share URLs describes.
Product names and logos are trademarks of their respective owners. See credits.