Calling the API from Java
Pass path ids as arguments and everything else in a Request; its fields become the JSON body for POST/PUT/PATCH and query parameters otherwise, and failures throw typed unchecked errors such as NotFoundError.
Overview
Relevant for Developers writing calls against any endpoint
Every generated method takes its path values first, in path order, as Object (ids or names). Then comes one optional Request with the call's options. The options follow the Python SDK's keyword convention exactly, so a Python example translates one to one. Responses are schema-free Jackson JsonNodes, because AlertOps response shapes vary by endpoint and sometimes by call.
Path values and options
Relevant for Developers building requests
Each op has three overloads: path values only, path values plus a Request, and, for body-carrying ops, path values plus the whole body (a Map, List or JsonNode).
| Request method | Description |
| Request.of(k, v, …) / field(k, v) / Request.fields(map) | Fields: merged into the JSON body for POST, PUT, PATCH and body-carrying DELETEs. Sent as query parameters for every other method. |
| Request.withBody(x) / body(x) | An explicit body (any JSON value). Fields merge into it when it is an object. null sends no body at all. |
| param(k, v) / params(map) | Extra query parameters, also for body methods. |
| file(name, FilePart) | Multipart parts, such as FilePart.of("log.txt", bytes, "text/plain"). The body's fields become form fields. |
| header(k, v) | Extra request headers. |
ao.groups().list(Request.of("search", "Network", "limit", 100)); // GET ?search=…&limit=100
ao.groups().create(Request.of("group_name", "Network Ops")); // POST {"group_name": …}
ao.groups().members().add(11, List.of(Map.of("member_type", "User", "member", "7", "sequence", 1, "roles", List.of("Primary"))));
ao.escalationPolicies().updateBasic(3, wholeRecord); // the record is the whole body
Records are never misread as options
Fields, the body and the reserved options are separate parts of Request, so a record with a top-level body or headers key is sent as it is. Pass a record you read from the API straight to the body overload, or with Request.withBody(record).
Query values follow Python's rules:
- Booleans become true/false.
- Lists are comma-joined.
- null is dropped.
- Numbers use Python's formatting.
Path values are percent-encoded, so a name such as Email Official/2 is safe.
Pagination
Relevant for Developers reading long lists
Paginated endpoints have three methods: list (one page), listAll (every page collected into an AOList) and listIter (a lazy Iterable that fetches pages as you go).
AOList every = ao.groups().listAll(Request.of("search", "sdk"));
for (JsonNode alert : ao.alerts().listIter(Request.of("createdFrom", "2026-03-01", "createdTo", "2026-03-08"))) {
if ("Open".equals(alert.path("status").asText())) {
System.out.println(alert.get("alert_id"));
}
}
| Style | Used by | Behaviour |
| page index | groups, users, policies, audit trail … | limit + offset, where offset is a page index (0, 1, 2), not a row offset. Stops on a short page. |
| cursor | v3 lists | pageSize + after, read from nextCursor / hasMore. |
| page number | notification history | pageNumber + pageSize. |
| metadata cursor | alerts | limit + next, read from metadata.next. |
| limit only | inbound log | One page. |
A list unwrapped from an envelope comes back as an AOList. Its raw() is the envelope, which holds paging metadata and counts.
Errors and retries
Relevant for Developers handling failures
Errors are unchecked and named as in the Python SDK. Non-2xx answers throw a subclass of APIError. Each carries:
- status(), body(), method() and url().
- op(), the Python op id, such as Groups.get.
- opId(), the dotted id, such as groups.get.
- messages(), normalised from the three AlertOps error shapes.
| Error | When |
| BadRequestError | 400 or 422 |
| AuthenticationError | 401 |
| PaymentRequiredError | 402, the feature is not in the plan |
| PermissionDeniedError | 403 |
| NotFoundError | 404 |
| ConflictError | 409 |
| RateLimitError | 429 after retries |
| ServerError | 5xx |
| TransportError | network failure after retries |
| ValueError / LookupError | a helper rejected an argument (an IllegalArgumentException), or a named thing such as a role, zone or type does not exist (a NoSuchElementException) |
Retries are automatic:
- Which calls:
- GET, PUT and DELETE retry on 429, 502, 503 and 504.
- POST retries only on 429 and on connect failures, so a create is never sent twice.
- Delay: backoffFactor × 2^attempt (default 0.5 s, capped at 8 s, with ±25 % jitter).
- Retry-After: honoured when the server sends it, up to 32 s.
Listeners and the escape hatch
Relevant for Developers adding logging or calling unmodelled paths
ao.addListener(e -> System.out.println(e.opId() + " " + e.method() + " " + e.url() + " " + e.status() + " " + e.elapsed()));
ao.request("GET", "/groups", Request.of("search", "Net")); // v2 with the API key
ao.request("GET", "/user_filters", "v3", "key", Request.of("moduleTypeId", 1));
Troubleshooting
Relevant for Anyone debugging a call
IllegalArgumentException: groups.list() does not take a request body
- You passed a body to a GET. Use fields or param(...) instead.
A PUT wiped fields on the record
- Many AlertOps PUTs replace the whole record. Use the read-merge-write helpers (ao.escalationPolicies().update, ao.schedules().updateFields), or GET the record, change it and PUT it back as the body.
Page 2 repeats page 1
- You set offset to a row count. Offset is a page index. Use listAll or listIter instead.
Related Articles
- Getting Started with the AlertOps Java SDK
- Helpers and the Semantic Layer in Java
- Testing the Java SDK
Need help?
Email support@alertops.com or contact your AlertOps representative.