ConnectWise Automate
ConnectWise Automate is the RMM source. The integration pulls computers and their installed software into the inventory. It follows the shared integration lifecycle.
- Router:
app/api/v1/endpoints/connectwise_automate.py, mounted at/api/v1/connectwise-automate - Client:
app/services/connectwise_automate_client.py(ConnectWiseAutomateClient) - Config collection:
connectwise_automate_config(keyed bytenant_id)
Authentication
Automate uses the Integrator token flow. The client posts the username and
password (plus an optional clientId header) to the token endpoint, gets a bearer
token back, and sends it on subsequent calls:
POST <api_url>/cwa/api/v1/apitoken { "UserName": ..., "Password": ... } (+ optional clientId header) → { "AccessToken": ..., "ExpirationDate": ... }Authorization: Bearer <AccessToken>The token is cached and refreshed ~60s before expiry; a 401 on any request
triggers a single re-auth-and-retry. Config fields (CWAutomateConfig):
| Field | Meaning |
|---|---|
api_url | Automate server base URL (API root is <api_url>/cwa/api/v1) |
username / password | Integrator credentials (password is optional on update so the UI can omit an unchanged secret) |
client_id | Optional clientId header value |
scope_client_ids / scope_client_names | Client scoping — see below |
enabled | Whether the integration is active |
Env seeding (_seed_connectwise_automate_config) reads CW_AUTOMATE_URL,
CW_AUTOMATE_USERNAME, CW_AUTOMATE_PASSWORD and CW_AUTOMATE_CLIENT_ID.
Client scoping (important)
An Automate server is typically an MSP server hosting many client companies.
Pulling every client’s devices is almost never what you want, so the config
carries scope_client_ids — the sync only ingests computers belonging to the
selected client(s).
- Discover clients:
GET /api/v1/connectwise-automate/clientscalls the client’sget_clients()(Automate/Clients) and returns{id, name}for every company, so the UI can present a picker. - Scoped pull: for each configured id, the sync calls
get_computers_for_client(client_id), which fetches/Computerswith the server-side conditionClient.Id=<id>— so filtering happens on the Automate server, not client-side. - Empty scope = everything: if no
scope_client_idsare set, the sync falls back toget_all_computers()(all clients). The UI warns against this on MSP servers.
Client scoping is only overwritten on save when explicitly provided, so partial config saves don’t wipe it.
What the sync pulls
The background _run_sync:
- Computers — scoped as above → upserted into
connectwise_automate_devices(device name, OS + normalizedos_platform, version, domain, IP, agent version, last contact, last user, and the Automate client name). - Installed software per computer — batched (25 computers per batch), via
get_computer_software(computer_id)(/Computers/{id}/Software) → upserted intoinventory_itemstaggedsource="connectwise_automate".
| Data | Written to |
|---|---|
| Computers | connectwise_automate_devices |
| Per-computer installed software | inventory_items (source=connectwise_automate) |
Like Rapid7, software collection uses a circuit breaker: if the /Software
sub-resource is unavailable, it stops after 15 consecutive failures instead
of hammering every computer. Stale devices and inventory rows are deleted, then
rebuild_applications refreshes the Software rollup.
NetBIOS 15-char hostname behavior
ConnectWise Automate reports the 15-character NetBIOS hostname (uppercased),
while Intune and SentinelOne report the full name. To link the same machine
regardless of source, the device-by-name lookup matches on both the
requested name and its upper()[:15] NetBIOS truncation (e.g.
LTG-ARamaraju-LT ↔ LTG-ARAMARAJU-L), case-insensitively.
Routes
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/connectwise-automate/config | Save credentials + scope (password/scope only overwritten when supplied) |
GET | /api/v1/connectwise-automate/config | Get config (password redacted) |
DELETE | /api/v1/connectwise-automate/config | Remove config + synced data |
GET | /api/v1/connectwise-automate/clients | List Automate clients (companies) for the scope picker |
POST | /api/v1/connectwise-automate/test-connection | Live credential test |
POST | /api/v1/connectwise-automate/sync | Start a background sync |
GET | /api/v1/connectwise-automate/sync-status | Poll sync status |
GET | /api/v1/connectwise-automate/stats | Device count + app-row count |
GET | /api/v1/connectwise-automate/devices | List synced computers |
GET | /api/v1/connectwise-automate/device-by-name/{device_name} | Device by hostname (full or NetBIOS match) |
See the overview for the lifecycle these routes share.