RMM Setup
The bootstrap script needs exactly one secret from your RMM: your ZenPrint API key. The server URL is already baked into the script when you download it, and your tenant is identified by the key itself.
How endpoints get a client and location
ZenPrint figures out which client and location an endpoint belongs to from what your RMM reports. There are two shapes, and they differ only in whether you do anything by hand.
- RMMs with a fixed organization and site structure, such as NinjaOne and Octoja. The bootstrap reports the org and site, and ZenPrint creates the client and location automatically. No manual mapping. (Datto RMM, ConnectWise Automate, N-able N-central/N-sight, and Tactical RMM share this shape; NinjaOne and Octoja are wired today.)
- RMMs that organize endpoints by groups, folders, or tags with no fixed site, such as Level.io. There’s nothing for ZenPrint to derive a location from, so you map each reported group path to a client and location once, under Settings → Group Mapping (see Clients and Locations). (Kaseya machine groups, Action1, and Automox share this shape; Level.io is the one wired today.)
Either way the onboarding rhythm is the same: an endpoint registers on its first check-in (which the bootstrap runs before whatever mode you scheduled), and printer discovery happens on the next scan once it has a location. For NinjaOne the location resolves automatically on that first check-in. For group-based RMMs the location arrives when you create the mapping. See Scripts → scan for why.
NinjaOne
-
Generate the key in ZenPrint. Settings → API Keys → Create API Key. Leave it as a full-access key (the bootstrap needs to write, so don’t tick read-only). Copy the key, since it’s shown once.
-
Create the NinjaOne custom field. Administration → Organizations → Organization custom fields → Add.
- Name:
zenprintApiKey - Type: Secure (prevents the value from showing in the UI)
- Role: Automations (so scripts can read it)
- Name:
-
Populate the field per-organization. Open each NinjaOne organization you want to onboard and paste the API key into the
zenprintApiKeyfield. -
Download the bootstrap script. In ZenPrint: Settings → Scripts → Download the bootstrap for your RMM. Save it as a script in NinjaOne.
-
Schedule it. Attach the script to the organizations from step 3, with a schedule per mode. See Scripts for the recommended cadence.
The first time the script runs, check-in registers the endpoint with ZenPrint, and from then on the bootstrap pulls the latest sub-script for whatever mode you run. You don’t redeploy the bootstrap when ZenPrint updates; it’s a thin loader that always fetches the latest.
Level.io
The shape is close to NinjaOne, with two Level.io specifics: Level.io can’t pass arguments or inject secrets into a script, so both the API key and the mode are supplied with the {x} picker, and there’s an extra group mapping step because Level.io has no organization/site structure ZenPrint can read automatically.
-
API key field. In Level.io, create an Admin Only custom field holding your ZenPrint API key (it starts with
zpk_). You’ll reference this field with the{x}picker in step 2, so the name is up to you. Download the bootstrap from Settings → Scripts in ZenPrint. Security note: Level.io echoes the substituted script source into its run logs, so the key may appear there. Confirm with Level.io whether Admin Only field values are masked in script output before using a long-lived production key, and rotate the key if you’re unsure. -
Deploy the bootstrap. Add the bootstrap script to your Level.io library once. Level.io can’t pass arguments to a script, so the mode is supplied through an automation variable instead of
-Mode. Create one automation per scheduled mode (Scan, Reconcile, Poll, plus Capture on demand; Cleanup is offboarding-only, so add it when you need it rather than on a schedule). In each automation:-
Define an automation variable holding the mode value (one of
Scan,Reconcile,Capture,Poll,Cleanup). -
Open the script in the Level.io editor and set two values with the
{x}picker. The device context is already pre-filled with fixed Level.io system-variable tokens ({{level_device_id}},{{level_group_path}}in the CONFIGURATION block). Leave those alone.Set this ( {x}picker)To REPLACE_VIA_{x}_PICKER(Mode selection block, near top)the mode automation variable you defined above REPLACE_VIA_{x}_PICKER_API_KEY(CONFIGURATION block, top)the Admin Only API key field from step 1
The same library script serves every mode, so you only update one script when ZenPrint ships a new bootstrap. If you leave the mode or API key unset the run fails with a clear error; the group path is optional (an ungrouped device just stays unassigned).
-
-
Run reconcile once. Check-in registers the endpoints. With
level_group_pathwired, each endpoint reports its group path but still lands unassigned until you map that path to a client and location. -
Map the groups. Go to Settings → Group Mapping and map each reported group path to a client and location. You can create the client and location right there. See Clients and Locations → Group mapping for the full walkthrough. As soon as you save a mapping, the endpoints waiting on that path are routed to the location immediately.
Once the groups are mapped, Level.io behaves like any other RMM: the next scan discovers each site’s printers, and reconcile and capture work the same way.
Octoja
Octoja resolves the client and location automatically from its customer and site, so there’s no group mapping step. Deploy the bootstrap as an Automation (Octoja passes the customer and site to a script only from an Automation, not a Check).
-
Set the API key. Download the bootstrap from Settings → Scripts, then in the SET THESE block at the top set the
$APIKeyline to your ZenPrint API key (it starts withzpk_). The instance URL is already filled in.You can keep the key in an Octoja custom field instead, but we don’t recommend it as the default. Octoja has no secure or masked field type, so the value is readable by anyone who can edit a device or a customer, and because your ZenPrint key is workspace-wide you’d be setting and rotating the same value on every customer rather than once per Automation.
If you’d still rather use one, create a
zenprint_apikeyfield, set the value explicitly on the customer or device, and replace the$APIKeyline with one of the commented lines already in the script:Terminal window $APIKey = '${{ trigger.customerFields.zenprint_apikey }}'.Trim() # per customer$APIKey = '${{ trigger.customFields.zenprint_apikey }}'.Trim() # per deviceKeep the single quotes. In double quotes, PowerShell reads
${...}as one of its own variables and the key silently comes out empty. Note also that Octoja field defaults only apply when a device or customer is first created, so a default won’t fill in records that already exist. -
Create one Automation per mode. The mode is set in the script rather than passed as an argument, so create one Automation for each mode: Scan, Reconcile, Capture, Poll, and Cleanup. In each, paste the bootstrap and set the mode in the SET THESE block at the top (edit
REPLACE_WITH_MODEtoScan,Reconcile, and so on). Leave everything else as it is. -
Run check-in. The first check-in registers each endpoint, and because the Automation reports the customer and site, ZenPrint creates the client and location and maps the endpoint. The next scan discovers each site’s printers, and reconcile and capture work the same way.
If you rename a customer or site in Octoja, ZenPrint treats the new name as a new client or location, so rename it in ZenPrint too if you want the history to follow.