Errors & Status Codesv7.0.20
How the API signals failure — the status codes it returns, the two validation-error shapes you will meet, why a permission failure is a 401 and not a 403, and how permissions differ from scopes.
The API signals failure with HTTP status codes and a JSON body. As with response envelopes, the exact error shape is not perfectly uniform — the two validation patterns below both appear in the wild — so robust clients should key off the HTTP status first and read the body for detail second.
Status codes you will see
| Status | Meaning |
|---|---|
200 OK | Success. Most reads and many actions. |
201 Created | A resource was created (newer RESTful endpoints). |
400 Bad Request | Validation failed on an endpoint that checks input manually. |
401 Unauthorized | Missing/invalid token — or the user lacks the endpoint’s permission (see below). |
403 Forbidden | Used by a few endpoints for ownership/scope failures. |
404 Not Found | No such resource, or it is outside the caller’s tag scope. |
422 Unprocessable Entity | Validation failed on an endpoint using framework validation. |
429 Too Many Requests | A rate-limited endpoint was called too often; honor Retry-After. |
500 Internal Server Error | An unexpected server-side fault. |
503 Service Unavailable | A capacity limit was hit (for example the concurrent-capture cap). |
Validation errors
Two shapes appear, depending on how the endpoint validates:
Framework validation (most newer endpoints) returns 422 with a top-level message and a field-keyed errors object:
{
"message": "The label field is required.",
"errors": {
"label": ["The label field is required."]
}
}
Manual validation (many endpoints) does not use the framework wrapper. The exact shape varies by endpoint — it takes one of three forms:
{ "errors": { "device_id": ["The device_id field is required."] } } // 400, errors wrapper
{ "label": ["The label field is required."] } // 422, bare field map
{ "error": "Filter cannot be empty." } // 400 or 422, single string
The bare field-map form (the validator’s errors serialized directly, returned with 422) is common on the log and netflow filter endpoints; the errors wrapper with 400 appears on older device endpoints. Because the manual shape is not uniform, key off the HTTP status first: any 4xx here means “your input was rejected,” and the body — whichever of the three forms — tells you which field.
Send Accept: application/json on every request — without it, a framework validation failure can redirect instead of returning JSON.
Permission failures
The API gates each endpoint on a Laravel permission (shown on every entry as the Permission line). If the authenticated user does not hold that permission, the call returns 401 — not 403 — with this body:
{ "status": false, "hasError": true, "message": "You lack the permission to perform this task." }
This is the appliance’s own permission gate, distinct from a missing or expired token (which also returns 401, but from the framework’s auth layer with a {"message": "Unauthenticated."} body). If you get a permission 401 with the hasError body, the token is valid but its user cannot perform that operation — adding the permission to the user (or using a token for a user who has it) is the fix, not re-authenticating.
Permissions versus scopes
Two different mechanisms govern what a token can do, and it is worth being precise about which is which:
- A permission is a capability granted to a user (for example
devices,alerts,system,api, or the all-accesssa). The REST API enforces permissions on every call. This is the gate shown on each endpoint. - A scope (for example
mcp:devices,mcp:logs) is carried by an OAuth or MCP token and describes a functional area. Scopes gate the Model Context Protocol tool surface that AI clients use; they are chosen at consent time and bound to the token. A direct REST call with a bearer token is gated by the user’s permissions, not by the token’s scopes.
In practice: to use the API at all through a personal access token or an OAuth flow, the user needs the api permission. To call a given endpoint, the user needs that endpoint’s permission. The Permissions & Scopes reference maps the permissions to the functional-area scopes and lists the scopes themselves.
Users can be restricted to a subset of device tags. For tag-restricted users, objects outside their tags are simply not visible — a list omits them, and a direct fetch returns 404 rather than 403, so the existence of an out-of-scope object is never disclosed. The super-administrator (sa) bypasses tag scoping entirely.