Welcome. This guide walks you through authenticating, issuing your first
request, and using the query language that powers most list endpoints.
All requests go to:
https://api.anzenna.ai/api/v1
The API uses bearer token authentication with an Anzenna API key.
Authorization header:Authorization: Bearer <YOUR_API_KEY>
Example:
curl -H "Authorization: Bearer $ANZENNA_API_KEY" \
https://api.anzenna.ai/api/v1/devices
A missing key returns 401. An invalid or insufficiently scoped key returns
403. Each endpoint declares the scopes it requires under its security
block — check those when provisioning a key.
The query field on every list endpoint accepts a subset of SQL WHERE
clause syntax. The same syntax is used everywhere — once you learn it
for one endpoint it works for all of them.
=, !=, <>, <, <=, >, >=, IN, NOT IN, IS NULL,
IS NOT NULL, LIKE, NOT LIKE, ILIKE, NOT ILIKE.
Combine with AND / OR. Negate with NOT. Group with parentheses.
LOWER(field) and UPPER(field). Functions cannot be nested and cannot
appear on the right-hand side of a comparison.
name='John Smith'. Unquotedname='Alan''s laptop'.AND / OR. Adjacent conditions without a* is not a wildcard. Use LIKE / ILIKE with % (any number of_ (exactly one character). name LIKE 'John%'.ILIKE to ignore case. name ILIKE '%john%' matches John,JOHN, and johnny.happened > '2024-01-01T00:00:00Z'.name='WINPC-4291' AND status IN ('active', 'pending')
risk_score >= 7 AND device_owner IS NOT NULL
(name ILIKE 'john%' OR name ILIKE 'jane%') AND status='active'
happened > '2024-01-01T00:00:00Z' AND happened < '2024-02-01T00:00:00Z'
| Field | Type | Notes |
|---|---|---|
sort | string | Comma-separated, each with optional asc / desc. Example: "name desc, id". |
limit | integer | Page size. Default 500, max 500. Set 0 to count without fetching rows. |
offset | integer | Rows to skip. Default 0. |
include_total_count | boolean | When true, the response's pagination.total_count is populated. |
To paginate, increment offset by limit until items is empty.
To count without retrieving rows:
{ "query": "...", "limit": 0, "include_total_count": true }
Many endpoints expose relations — implicit joins to related objects
that you can reference inside query. Each endpoint that supports them
documents its relations under a Supported Relations section in its
description.
Example: filter devices by their owner's name.
{ "query": "owner.name='John Smith'" }
Notes:
distinct_on todistinct_count — set to a field name to return the distribution ofdistinct_values with { value, count } entries.distinct_on — comma-separated field names. The response contains one{ "distinct_count": "status" }
{ "distinct_on": "host_name, employee_email" }
| Status | Meaning |
|---|---|
400 | Malformed query or request body. The response body explains what failed. |
401 | No API key sent. |
403 | API key lacks the scope required by the endpoint. |
404 | Object not found (typically on GET endpoints). |
429 | Rate limit exceeded. Back off and retry. |
5xx | Server-side error. Safe to retry with backoff. |
Find every active device whose owner's name starts with "Jo", sorted by
risk score descending, fetching the first 25:
curl -X POST https://api.anzenna.ai/api/v1/devices \
-H "Authorization: Bearer $ANZENNA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "status='active' AND owner.name ILIKE 'Jo%'",
"sort": "risk_score desc",
"limit": 25,
"include_total_count": true
}'
Then page forward by repeating with "offset": 25, 50, ... until
items is empty.