NinjaOne API Patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited NinjaOne API Patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The NinjaOne Public API uses OAuth 2.0 for authentication and provides RESTful endpoints for all platform operations.
| Region | Base URL |
|---|---|
| United States | https://app.ninjarmm.com |
| European Union | https://eu.ninjarmm.com |
| Oceania | https://oc.ninjarmm.com |
Use the base URL matching your NinjaOne instance region.
NinjaOne uses OAuth 2.0 with the following scopes:
monitoring - Read monitoring datamanagement - Manage devices and organizationscontrol - Remote control capabilitiesPOST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=monitoring management controlResponse:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "monitoring management control"
}Include in all API requests:
GET /api/v2/organizations
Authorization: Bearer eyJ...Tokens expire after the expires_in period. Request a new token before expiration.
GET /api/v2/organizations
Authorization: Bearer {token}
Accept: application/jsonPOST /api/v2/organizations
Authorization: Bearer {token}
Content-Type: application/json
Accept: application/json
{
"name": "New Organization",
"description": "Description here"
}PATCH /api/v2/device/{id}
Authorization: Bearer {token}
Content-Type: application/json
{
"displayName": "Updated Name"
}NinjaOne uses cursor-based pagination:
GET /api/v2/organizations?pageSize=50{
"results": [...],
"pageInfo": {
"hasNextPage": true,
"endCursor": "abc123xyz"
}
}GET /api/v2/organizations?pageSize=50&after=abc123xyzlet cursor = null;
let allResults = [];
do {
const url = cursor
? `/api/v2/organizations?pageSize=100&after=${cursor}`
: '/api/v2/organizations?pageSize=100';
const response = await fetch(url, { headers });
const data = await response.json();
allResults = allResults.concat(data.results);
cursor = data.pageInfo.hasNextPage ? data.pageInfo.endCursor : null;
} while (cursor);NinjaOne implements rate limiting to ensure API stability:
Watch for these response headers:
X-RateLimit-Limit - Max requests per windowX-RateLimit-Remaining - Requests remainingX-RateLimit-Reset - Window reset timeWhen rate limited:
{
"error": "rate_limit_exceeded",
"message": "Too many requests",
"retry_after": 60
}| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Process response |
| 201 | Created | Resource created successfully |
| 204 | No Content | Success, no body |
| 400 | Bad Request | Check request format |
| 401 | Unauthorized | Refresh token |
| 403 | Forbidden | Check permissions |
| 404 | Not Found | Verify resource exists |
| 409 | Conflict | Resource conflict |
| 422 | Validation Error | Check field values |
| 429 | Rate Limited | Wait and retry |
| 500 | Server Error | Retry with backoff |
{
"error": "validation_error",
"message": "Invalid field value",
"details": {
"field": "name",
"issue": "Required field missing"
}
}async function makeRequest(url, options) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
return makeRequest(url, options);
}
if (response.status === 401) {
await refreshToken();
return makeRequest(url, options);
}
if (!response.ok) {
const error = await response.json();
throw new ApiError(error.message, response.status);
}
return response.json();
}PUT /api/v2/webhook
Content-Type: application/json
{
"url": "https://your-server.com/webhook",
"events": ["ALERT_TRIGGERED", "DEVICE_OFFLINE"]
}DELETE /api/v2/webhook| Event | Description |
|---|---|
ALERT_TRIGGERED | New alert created |
ALERT_CLEARED | Alert resolved |
DEVICE_ONLINE | Device connected |
DEVICE_OFFLINE | Device disconnected |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.