Calling the API from TypeScript
Pass path ids as arguments and everything else in one options object; its fields become the JSON body for POST/PUT/PATCH and query parameters otherwise, and failures throw typed errors such as NotFoundError.
Overview
Relevant for Developers writing calls against any endpoint
Every generated method takes its path values first, in path order, then one optional options argument. The options follow the Python SDK's keyword convention exactly, so a Python example translates one to one. Responses are schema-free JSON (AOValue), because AlertOps response shapes vary by endpoint and sometimes by call.
Path values and options
Relevant for Developers building requests
Every key in the options object that isn't reserved is a field.
| Key | Description |
| any field | Merged into the JSON body for POST, PUT, PATCH and body-carrying DELETEs. Sent as a query parameter for every other method. |
| body | An explicit body (any JSON value). Fields merge into it when it is an object. |
| params | Extra query parameters, also for body methods. |
| files | Multipart parts, { file: ["log.txt", bytes, "text/plain"] }. The body's fields become form fields. |
| headers | Extra request headers. |
| signal | An AbortSignal that cancels the call and its retries. |
A bare array passed instead of options is the whole body.
await ao.groups.list({ search: "Network", limit: 100 }); // GET ?search=…&limit=100
await ao.groups.create({ group_name: "Network Ops" }); // POST {"group_name": …}
await ao.groups.members.add(11, [{ member_type: "User", member: "7", sequence: 1, roles: ["Primary"] }]);
await ao.escalationPolicies.updateBasic(3, { body: wholeRecord }); // record may contain any key
Pass server records as body, not as fields
A record with a top-level body, params, files or headers key would be read as an option. Ingest payloads often have a body field. Whenever you send a record you read from the API, wrap it: { body: record }.
Query values follow Python's rules:
- true and false become true/false.
- Arrays are comma-joined.
- null and undefined are dropped.
- Numbers use Python's float 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) and listIter (an async iterator that fetches lazily).
const every = await ao.groups.listAll({ search: "sdk" });
for await (const alert of ao.alerts.listIter({ createdFrom: "2026-03-01", createdTo: "2026-03-08" })) {
if (alert.status === "Open") console.log(alert.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 keeps the envelope as list.raw, which holds paging metadata and counts.
Errors and retries
Relevant for Developers handling failures
Non-2xx answers throw a subclass of APIError. Each carries status, body, method, url, op (the Python op id, such as Groups.get) and 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, or a named thing (role, zone, type) does not exist |
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) => console.log(e.op, e.method, e.url, e.status, e.elapsed));
await ao.request("GET", "/groups", { base: "v2", search: "Net" });
Troubleshooting
Relevant for Anyone debugging a call
TypeError: … does not take a request body
- You passed body or an array to a GET. Use fields or params 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 { 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 TypeScript SDK
- Helpers and the Semantic Layer in TypeScript
- Testing the TypeScript SDK
Need help?
Email support@alertops.com or contact your AlertOps representative.