How do I automate agent deployment across multiple organizations?
If you are an MSP with one Nanitor organization per customer, each customer has its own signup URL, and the signup URL decides which organization an agent goes into. Instead of copying each signup URL from the portal, you can get all of them with one call to the Nanitor API and store them in your RMM platform (for example NinjaOne or Datto RMM). Your RMM deployment scripts then install the agent with the right signup URL for each customer. From Nanitor 7.3.0, the API can also create the customer organizations, so you can script the whole onboarding.
Before you start
- Nanitor 6.8.0 or later. The Organizations API returns
signup_urlfrom this version. curlandjqon the machine where you run the API calls.- An API key created in your own organization, the parent of your customer organizations. Create it under Organization management → API keys, as described in REST API. Read access is enough.
- The key sees its own organization and that organization's direct suborganizations. Customer organizations that are not under your organization are not returned. A key with write access can also change the data of every customer organization, so use a read-only key for these steps.
Create organizations with the API
Available from Nanitor 7.3.0.
You can create customer organizations with POST /system_api/organizations. The new organization is created as a suborganization of the organization that the API key belongs to. It inherits that organization's vulnerability management, AI features and automatic agent upgrade settings.
To create organizations, the API key needs:
- Read and write access. Keep this key separate from the read-only key you use to get the signup URLs.
- To belong to a top-level organization. A key that belongs to a suborganization cannot create organizations, and the request returns 400.
Request body fields (JSON):
| Field | Required | Description |
|---|---|---|
name |
Yes | The name of the organization. |
slug |
No | The URL of the organization in the Nanitor portal. If you leave it out, it is generated from the name. |
customer_reference_id |
No | A reference ID for mapping the organization to your billing or CRM system. At most 64 characters. |
curl -s -X POST 'https://example.nanitor.com/system_api/organizations' \
-H 'Authorization: Bearer <your-api-key>' \
-H 'Content-Type: application/json' \
-d '{"name": "Contoso Ltd", "slug": "contoso-ltd", "customer_reference_id": "CUST-1001"}' \
| jq '.organization | {name, id, slug, signup_url}'
Replace example.nanitor.com with your Nanitor server's address in this and the following examples. The response contains the new organization under the organization key, including its id, slug, name, customer_reference_id and signup_url. You can store the signup_url in your RMM right away, as described in Store the signup URLs in your RMM.
Rules for the slug:
- It may contain only letters, digits and dashes, and it cannot start with a dash. Otherwise the request returns 400 with the message
Validation failedand anerrorslist. - It is stored in lowercase.
- It must be unique among all active organizations on the Nanitor server, not only among your own. If it is already taken, the request returns 400 with the message
Name/slug already exists. - Organization names do not have to be unique. A slug that you leave out is generated from the name, so a second organization with the same name needs its own slug.
Find an organization by name or slug
GET /system_api/organizations accepts name and slug query parameters to filter the list. Both filters are exact matches and case-sensitive. Slugs are stored in lowercase, so use a lowercase slug. The name filter treats commas and semicolons as separators between several values, so ?name=Contoso, Inc. does not find an organization named "Contoso, Inc.". Look up organizations by slug instead, because a slug cannot contain commas or semicolons. For example, check whether you have already created an organization before you create it again:
curl -s 'https://example.nanitor.com/system_api/organizations?slug=contoso-ltd' \
-H 'Authorization: Bearer <your-api-key>' | jq '.items[] | {name, id, slug, signup_url}'
The list only contains your own organization and its direct suborganizations, so an empty result does not guarantee that the slug is free on the server.
To filter by customer reference ID, use ?customer_reference_id=. It matches values that contain the given text, and it is not case-sensitive. You can set customer_reference_id when you create the organization, but you cannot change it through the API. Change it in system management instead.
Get the signup URLs
List all organizations with their signup URLs
curl -s 'https://example.nanitor.com/system_api/organizations?per_page=200' \
-H 'Authorization: Bearer <your-api-key>' | jq '.items[] | {name, id, slug, signup_url}'
Replace example.nanitor.com with your Nanitor server's address. The API returns 20 organizations per page by default. The API returns at most 200 organizations per page. The response also contains pages, the total number of pages, which you can read with jq .pages. If pages is greater than 1, request &page=2, &page=3 and so on up to that number. Do not wait for a short or empty page instead, because a page value past the last page returns page 1 again.
Example response:
{
"name": "Contoso Ltd",
"id": 12,
"slug": "contoso-ltd",
"signup_url": "https://example.nanitor.com/api/agent_get_signup_key/4e417e9b-1675-4e79-bf59-d150e57922dd/xxxxxxxx"
}
{
"name": "Fabrikam Inc",
"id": 13,
"slug": "fabrikam-inc",
"signup_url": "https://example.nanitor.com/api/agent_get_signup_key/8c2f0a61-93d4-4b7e-a0c5-2f6e1d9b7a42/xxxxxxxx"
}
Always use the signup_url exactly as the API returns it. Do not build it yourself from the slug.
Export as CSV
curl -s 'https://example.nanitor.com/system_api/organizations?per_page=200' \
-H 'Authorization: Bearer <your-api-key>' \
| jq -r '.items[] | [.name, .slug, .signup_url] | @csv'
Get one organization's signup URL
curl -s 'https://example.nanitor.com/system_api/organizations/<org-id>' \
-H 'Authorization: Bearer <your-api-key>' | jq -r '.item.signup_url'
Keep the signup URLs safe
Anyone with a signup URL can connect machines to that organization, and it does not expire. Store the signup URLs and your API key in your RMM's secure fields, not in plain-text scripts that others can read.
Store the signup URLs in your RMM
- Match each RMM customer to its Nanitor organization by name or by
slug. The slug is the URL you set when you created the organization. If you created the organization through the API without a slug, the slug was generated from the name. - Store each customer's
signup_urlwhere your deployment script can read it. If your RMM supports a custom field per customer or site, create one, for examplenanitor_signup_url, and fill it in for each customer. - Use the stored value in your agent deployment script, as shown below.
In NinjaOne, set the signup URL as a parameter on a separate installer task for each customer instead. See Ninja RMM and Nanitor CTEM integration for MSPs.
Install the agent with the signup URL
Windows
This PowerShell command is the one the Nanitor portal shows under Agent installers. It downloads the latest agent, installs it and signs it up. Run it as administrator:
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
$signupUrl = "<signup-url>" # Or read it from your RMM custom field.
iex (New-Object System.Net.WebClient).DownloadString('https://nanitor.io/files/installers/install-windows.ps1')
If you have already copied the MSI to the machine, install it with the signup URL instead:
msiexec.exe /i "nanitor-agent.msi" ACCEPTEULA="yes" SIGNUP_URL="$signupUrl" /qn
For more Windows options, see How do I install/distribute the Nanitor Agent on Windows?.
Linux and macOS
The one-line installer downloads the latest agent, installs it, signs it up with the signup URL and starts it. It must run as root. If your RMM already runs scripts as root, leave out sudo.
Linux:
# $SIGNUP_URL comes from your RMM custom field.
sudo SIGNUP_URL="$SIGNUP_URL" /bin/bash -c "$(curl -fsSL https://nanitor.io/files/installers/install-linux.sh)"
macOS:
sudo SIGNUP_URL="$SIGNUP_URL" /bin/bash -c "$(curl -fsSL https://nanitor.io/files/installers/install-osx.sh)"
For other ways to install, see How do I install Nanitor Agent on Linux/BSD/Mac?.
Deploy over SSH without an RMM
If you do not use an RMM, a script can look up each signup URL when it deploys. This example installs the agent on Linux hosts over SSH. Each host must accept your SSH key, and sudo must not ask for a password, because the script cannot answer a prompt.
#!/bin/bash
# Usage: ./deploy_agents.sh <host-list-file>
# Each line of the host list file is "hostname org_id".
NANITOR_API="https://example.nanitor.com/system_api"
# Read the API key from the environment instead of writing it in the script.
API_KEY="${NANITOR_API_KEY:?Set NANITOR_API_KEY first}"
while read -r host org_id; do
signup_url=$(curl -s "${NANITOR_API}/organizations/${org_id}" \
-H "Authorization: Bearer ${API_KEY}" | jq -r '.item.signup_url')
if [ -z "$signup_url" ] || [ "$signup_url" = "null" ]; then
echo "ERROR: No signup URL for organization ${org_id}, skipping ${host}"
continue
fi
echo "Deploying to ${host} (organization ${org_id})..."
ssh -n -o BatchMode=yes "$host" "sudo SIGNUP_URL='${signup_url}' /bin/bash -c \"\$(curl -fsSL https://nanitor.io/files/installers/install-linux.sh)\""
done < "$1"
See also
- REST API: API key setup and basic usage
- Finding your Signup URL: find the signup URL in the portal
- Multi-Tenancy Options: set up one organization per customer