Skip to content
  • There are no suggestions because the search field is empty.

Administration, Account, Analytics and Lookups with the AlertOps SDKs

Use the admin resource for alert types, roles, topics and other account-wide settings, account and lookups for plan, time zone and limit checks, and analytics for reports, remembering that several of these objects can't be deleted and some writes are blocked for API keys.

Overview

Relevant for App Admins and developers automating account-wide settings

Account-wide configuration sits behind a few resources: administration objects (alert types, roles, topics, attributes), the account and its plan, the shared lookup catalogs the UI uses for its pickers, analytics reports, and the paid add-ons (call routing, AIOps). Most are plain CRUD. The surprises are objects that can't be deleted, writes that API keys may not make, and report parameters that change format between endpoints.

Key capabilities:

  • Idempotent setup — admin.alert_types.ensure and the find helpers let scripts rerun without creating duplicates.
  • Plan checks — lookups.can_add("User") tells you whether the plan allows one more user, group, policy or workflow.
  • Readable dashboards — analytics.dashboard_sections turns the flat dashboard rows into a map keyed by section.
  • Safe JSON configs — aiops.config and aiops.set_config handle AIOps' double-encoded config_data.

Reading the operation names

Relevant for Developers using any of the five AlertOps SDKs

This guide applies to every AlertOps SDK. It names each operation by its resource path and operation name, such as groups.members.add_users, lists positional arguments in order, and shows request bodies and options as JSON. Where a task needs real code, the example is given in all five languages. Each SDK spells the same call in its own style:

SDKThe same callOptions and request fields
Pythonao.groups.members.add_users(group_id, [101, 102], roles=["Primary"])Keyword arguments, such as search="Net"
TypeScriptawait ao.groups.members.addUsers(groupId, [101, 102], ["Primary"])One trailing options object keyed by the names in this guide, such as { search: "Net" }
Goao.Groups.Members.AddUsers(ctx, groupID, []any{101, 102}, []any{"Primary"})&alertops.Request{Fields: alertops.M{"search": "Net"}} for endpoints, alertops.M{…} for helper options
Javaao.groups().members().addUsers(groupId, List.of(101, 102), List.of("Primary"))Request.of("search", "Net") for endpoints, a Map keyed by the names in this guide for helper options
.NETawait ao.Groups.Members.AddUsersAsync(groupId, new object?[] { 101, 102 }, new object?[] { "Primary" })new Kwargs { ["search"] = "Net" }
  • Names follow each language's style: update_basic is updateBasic in TypeScript and Java, UpdateBasic in Go and UpdateBasicAsync in .NET. Go keeps initialisms upper case (create_api is CreateAPI, post_to_url is PostToURL).
  • Paginated operations also have variants that collect every page or iterate lazily (…All / …Iter; in Python, .all() and .iter() on the operation).
  • Helpers that look something up return null (None in Python, nil in Go) when nothing matches. **ensure helpers** return the record together with a flag that says whether it was created.
  • Errors are the same classes in every SDK, such as NotFoundError and BadRequestError.
  • Code examples come in the order Python, TypeScript, Go, Java, .NET. Each assumes a client named ao (and, in Go, a ctx and a function that returns error), created as in that SDK's Getting Started article.

For one language's details, see Calling the API from Python, TypeScript, Go, Java or .NET.

Before you start

Relevant for Developers finding the right resource

ResourceWhat lives there
adminalert_types (+ fields), postmortem_fields, roles, topics, user_attributes, locations, bridges, audit_trail
accountAccount summary, notification usage, plans, subscription, invoices, sso, quick_start
lookupsRead-only /app/* catalogs: users, groups, time zones, priority types, alert statuses, entitlements, limits …
analyticsDashboard, reports, open_alerts drill-downs, on_call now and calendar
call_routingLive call routing numbers (paid add-on)
aiopsAIOps correlation configs and simulations (add-on)
user_filtersThe calling user's saved list views (new UI)
authThe key's permission context and the web app's login and token-link flows

Alert types, custom fields and postmortem fields

Relevant for App Admins defining alert templates

An alert type is a template of custom fields. Integrations, workflows and escalation policies each reference one. Find or create the type, add a field, then change the field with the read-merge-write helper:

Python

at, created = ao.admin.alert_types.ensure("Database Alert")
field = ao.admin.alert_types.fields.create(at["alert_type_id"], alert_field_name="Cluster",
data_type="ShortString", group_name="")
ao.admin.alert_types.fields.modify(at["alert_type_id"], field["alert_field_id"], required=True)

TypeScript

const [at, created] = await ao.admin.alertTypes.ensure("Database Alert");
const field = await ao.admin.alertTypes.fields.create(at.alert_type_id, {
alert_field_name: "Cluster", data_type: "ShortString", group_name: "",
});
await ao.admin.alertTypes.fields.modify(at.alert_type_id, field.alert_field_id, { required: true });

Go

at, created, err := ao.Admin.AlertTypes.Ensure(ctx, "Database Alert")
if err != nil {
return err
}
atID := alertops.Get(at, "alert_type_id")
field, err := ao.Admin.AlertTypes.Fields.Create(ctx, atID, &alertops.Request{Fields: alertops.M{
"alert_field_name": "Cluster", "data_type": "ShortString", "group_name": "",
}})
if err != nil {
return err
}
_, err = ao.Admin.AlertTypes.Fields.Modify(ctx, atID, alertops.Get(field, "alert_field_id"), alertops.M{"required": true})

Java

Shared.Ensured at = ao.admin().alertTypes().ensure("Database Alert");   // at.record(), at.created()
JsonNode atId = at.record().get("alert_type_id");
JsonNode field = ao.admin().alertTypes().fields().create(atId, Request.of(
"alert_field_name", "Cluster", "data_type", "ShortString", "group_name", ""));
ao.admin().alertTypes().fields().modify(atId, field.get("alert_field_id"), Map.of("required", true));

.NET

var (at, created) = await ao.Admin.AlertTypes.EnsureAsync("Database Alert");
var atId = at!["alert_type_id"]!;
var field = await ao.Admin.AlertTypes.Fields.CreateAsync(atId, new Kwargs
{
["alert_field_name"] = "Cluster", ["data_type"] = "ShortString", ["group_name"] = "",
});
await ao.Admin.AlertTypes.Fields.ModifyAsync(atId, field!["alert_field_id"]!, new Kwargs { ["required"] = true });

Alert types can't be deleted
DELETE /alert_types/{id} answers 200 but the alert type stays (an unknown id is 404). Don't create alert types per test run: reuse one with alert_types.ensure. alert_types.update(atid, {alert_type_name}) renames.

Field PUTs replace the whole row, so send the full field (including sequence) or use fields.modify. Postmortem fields work the same way: admin.postmortem_fields.create({field_name: "Customer impact"}) returns field_id and sequence, and update is a full replace.

Roles, topics and other admin objects

Relevant for App Admins managing access and routing settings

Roles and entitlements

Custom roles are a name plus a set of entitlements. Entitlement ids come from lookups.entitlements(), which returns [{module, entitlements[{id, name}]}] grouped by module.

StepOperationResult
1admin.roles.create({role: "Integration Editors", entitlements: [{entitlement_id: <id>}, …]})The role, with role_id
2admin.roles.assign_users(role_id, [101, 102])The role's users
3admin.roles.unassign_users(role_id, [101, 102])[]
4admin.roles.delete(role_id)Deletes the role

role_id is a GUID (lower case in lists, upper case in detail), and get, update and delete accept the id or the role name. update replaces the entitlement set.

Unassign a role before deleting it
Deleting is blocked for system roles and for roles that still have users. If a user is deleted while still holding a custom role, that role can no longer be deleted. Unassign every user with roles.unassign_users before you delete either the users or the role.

Topics, user attributes, bridges and the audit trail

OperationBody or arguments
admin.topics.create{"topic_name": "Network", "priority": "High", "template": "<p>Network alerts</p>"}
admin.topics.groups.add(topic_id, …){"groups": [67890]}
admin.user_attributes.create{"attribute_name": "Badge", "user_attribute_data_type": "ShortString", "sequence": 1}
admin.bridges.create{"name": "War room", "telephone_number": "+1 202-555-0142", "telephone_access_code": "1234", "telephone_message_body": "Dial +1 202-555-0142,,1234#", "message_priority_type": "High"}
admin.audit_trail.between(from, to)Two dates, such as 2026-11-01 and 2026-11-04
  • Topics — priority is the priority name. Topic groups are added with {groups: [group_id]}.
  • User attributes — the definitions are one tenant-wide ordered list (sequence). Data types are ShortString, LongString, Boolean, Numeric, Date and Time. Set values per user with users.attributes.
  • Bridges — telephone_number is normalised to digits (+1 202-555-0142 reads back as 12025550142).
  • Audit trail — dateFrom and dateTo are MM/DD/YYYY. between takes dates or strings and follows every page. Filter by auditItem from lookups.audit_items().

Location and holiday writes are refused for API keys
Every POST, PUT and DELETE under /location returns 403 "The API key doesn't have permissions to perform the request", even with the account owner's key. Reads (admin.locations.list(), admin.locations.holidays.list()) work. Manage locations and holidays in the UI.

Account, plan and SSO

Relevant for App Admins reading plan and account settings

OperationReturns
account.summary()timezone_standard_name, zone_name, product_package_name, sso …
account.time_zone()"(UTC-06:00) Central Time (US & Canada)": the name user and schedule bodies take
account.notification_usage()Usage per channel, such as monthly.email_messages → {maximum: "Unlimited", current: "42"}

notification_usage values are strings, and an unlimited channel reads "Unlimited" (not -99). account.plans(), account.subscription.get() and account.invoices.list() are reads. On a trial account the subscription has plan_id: null and the invoice list is empty.

Subscription writes are billing actions
subscription.create, cancel, update_plan, update_address, update_card and update_contact change plans, cards or cancel the account. The same goes for account.update_licenses (new UI), which buys or adjusts paid seats with {users: n} or {stakeholders: n}. They carry the BILLING flag and are never called by the live test suites. Run them only on purpose.

SSO is one record, and PUT replaces it. account.sso.modify(changes) reads the record, applies the changes and writes it back. Writing back the identical record changes nothing (verified). The algorithm field is spelled saml_alogorithm. account.quick_start.update is 402 "Package settings do not have Quickstart enabled" on packages without quick start.

Lookups and plan limits

Relevant for Developers filling pickers and checking limits

lookups returns the unpaged lists the UI uses: users(), groups(), time_zones(), priority_types(), alert_status(), alert_types(), integrations(), escalation_policies() and more. Status ids are fixed: 1 Open, 2 Closed, 4 Cancelled, 5 Assigned, 6 On Hold, 9 Merged, 10 Snoozed.

OperationReturns
lookups.can_add("User")true when the plan allows one more. Also Group, EscalationPolicy, Workflow …
lookups.time_zone_name("America/Chicago")"(UTC-06:00) Central Time (US & Canada)"
lookups.limits("EscalationPolicy")The limit record; maximum -99 means unlimited

time_zone_name raises LookupError for an unknown zone. lookups.roles() gives role labels only; use admin.roles.list() for role_id.

Analytics reports

Relevant for Analysts and developers exporting incident metrics

Every report is a read-only GET with query parameters. Dates are YYYY-MM-DD (MM/DD/YYYY is also accepted). Missing or unparseable dates don't fail: the server falls back to its default window, so check your dates.

OperationReturns
analytics.dashboard_sections(from, to, {priority: "Critical"})Sections such as mtta ("005:42:05") and status ({"Open": "3", …}); values are strings
analytics.report("time_to_ack", from, to, {priority: "High", group: [67890]})Any report by op name
analytics.on_call.now({group_id: 67890})Who is on call now

The dashboard takes priority ids, the other reports take names
analytics.dashboard's priorityTypeIdList needs this account's priority type ids (from lookups.priority_types()); 1 or Critical fails with 400 "Invalid Priority Type ID". The other reports' priority takes the priority name (High) and silently ignores an id. dashboard_sections with priority: "Critical" resolves the id for you.

Other quirks seen live:

  • dashboard returns a flat list of {section, category, category_value, datavalue} with string values. dashboard_sections groups it.
  • time_to_resolve names its extrema min_time_to_ack and max_time_to_ack, like time_to_ack.
  • time_to_ack with a topic filter returns 500 (a server bug).
  • alert_assignment spells its count total_assgined, and alert_analysis_groups starts with a Total Count row.
  • Group filters are comma-separated ids. report and dashboard_sections join lists for you.
  • on_call.calendar without dates returns today. call_routing.activity uses MM/DD/YYYY, unlike the reports.

Add-ons: call routing and AIOps

Relevant for Developers using paid features

Call routing

Without the call routing add-on, every /call_routing* route answers 402 "Package settings do not have CallRouting enabled." (PaymentRequiredError) before the id is looked up, so an unknown id is 402 too. The pickers still work: call_routing.catalog.phone_numbers(), create_alert_options() and languages(). With the add-on, call_routing.update changes how real phone calls are routed, and call_routing.set_voice_prompt(cid, "welcome", {text}) sets a prompt as text-to-speech or a recording.

AIOps configs and simulations

AIOps configs are addressed by id: 3 production correlation profiles, 4 the auto-merge switch, 7 the test (simulation) profile. A config's payload is a JSON string inside JSON ({"config_data": "<JSON string>"}), on both read and write.

OperationResult
aiops.profiles(3)The decoded production integration_groups
aiops.config(7)The simulation config, decoded, or null if the add-on has no config
aiops.set_config(7, cfg)Re-encodes config_data and writes it
aiops.simulations.start(7)201, simulation_status Pending, with a run_id
aiops.simulations.is_finished(7, run_id) / results(7, run_id)Poll the run, then read its results

Writing config 3 or 4 changes live alerts
A PUT on config 3 changes live correlation, and enabling config 4 turns on automatic merging of live alerts. Run experiments on config 7 and simulations only. Write back exactly what you read: profiles may hold numbers as strings (time_threshold_mins: "15").

A simulation whose window or integrations hold too few alerts is rejected with 400 and an alertcount in the error body. Alerts ingested minutes earlier aren't counted yet, so simulate over history. Compare simulation_status case-insensitively (Completed live). aiops.create_config is 403 for API keys; configs are written with update_config or set_config.

Saved views and authentication

Relevant for Developers scripting the new UI's views and checking keys

user_filters stores the API-key user's saved list views (new UI). moduleTypeId 1 is Alerts, and attributes is a JSON string that save serialises for you. save creates the view or replaces the one with the same name. There is no single-view GET (405), so use find.

OperationResult
user_filters.save("Open and assigned", {status: ["Open", "Assigned"]})The view, with filterId
user_filters.clone(filter_id, {newFilterName: "Open and assigned (copy)"})A copy
user_filters.set_default(filter_id, {isDefault: true})Makes it the default view
user_filters.share(filter_id, {grants: [{userId: 102}, {groupId: 7}]}){"accessIds": [282]}
user_filters.delete(filter_id)Deletes the view

auth.me() returns the key owner's context (userId, username, organization, capabilities, featureLimits), and auth.organization() returns the account subdomain. Login, refresh, logout and activation are web-app flows: logout and SSO logout need a UI session token, and without one the SDKs raise UnsupportedAuthError before sending anything. The notification-link actions (auth.act_on_link(link)) work without a key; they are covered in Working with Alerts in the AlertOps SDKs.

Operations

OperationHTTPWhat it does
admin.alert_types.ensure(name)GET + POST /alert_typesFind or create an alert type. Returns the type and a created flag
admin.alert_types.fields.modify(atid, fid, changes)GET + PUT .../fields/{id}Change one custom field safely
admin.roles.create / assign_users / unassign_users / delete/rolesCustom roles and their users
admin.topics.*, admin.user_attributes.*, admin.bridges.*/topics, /user_attributes, /bridgesCRUD plus find(name)
admin.audit_trail.between(from, to)GET /audit_trailEvery audit row in a date range
account.summary() / time_zone() / notification_usage()GET /account, /account/notification_usageAccount summary, display time zone, channel usage
account.sso.modify(changes)GET + PUT /account/ssoChange SSO settings safely
lookups.can_add(item) / time_zone_name(zone)GET /app/limits/{item}, /app/time_zonePlan check, IANA zone to display name
analytics.dashboard_sections(from, to, {priority})GET /analytics/dashboardDashboard grouped by section
analytics.report(name, from, to, filters)GET /analytics/*Any report by op name (time_to_ack, alert_details …)
analytics.on_call.now({group_id}) / calendar({startDate, endDate})GET /schedules/oncallnow, /schedules/calendarWho is on call
aiops.config(id) / set_config(id, cfg) / simulations.start(7)/addon/{id}/config, /addon/{id}/simulateAIOps configs and simulations
user_filters.save(name, attrs) / find(name)v3 /user_filtersSaved views
auth.me() / organization()GET {v3}/auth/meThe key's permission context

Each SDK's method reference lists every operation, including the billing writes and the call routing access endpoints.

Best Practices

Relevant for Anyone automating account-wide settings

Setup scripts

  • Use ensure and find helpers so scripts can rerun. Alert types especially, since they can't be deleted.
  • Check lookups.can_add(...) before creating users, groups, policies or workflows in bulk.
  • Take time zone names from account.time_zone() or lookups.time_zone_name(...), never hand-typed.

Safety

  • Never call subscription writes or AIOps config 3 and 4 writes from automation unless that is the job.
  • Unassign roles before deleting users or roles.
  • Read before you write: SSO, alert fields and AIOps configs are whole-record writes.

Reports

  • Pass dates explicitly. A bad date silently becomes the default window.
  • Use priority names for reports, and dashboard_sections with a priority name for the dashboard.

Configuration Examples

Relevant for Starting templates for common setups

Example 1 — Minimal: idempotent account baseline

StepOperation
1admin.alert_types.ensure("Database Alert")
2admin.topics.find("Network"); only if it returns null, admin.topics.create({topic_name: "Network", priority: "High"})
3account.time_zone() and lookups.can_add("Group") before creating groups

Example 2 — Typical: a weekly metrics export

Call analytics.report("time_to_ack", start, today) and analytics.report("time_to_resolve", start, today) for the last seven days. Each result has a created_dates list plus mean_time_to_ack_list or mean_time_to_resolve_list; zip the three lists into rows of date, mean time to acknowledge and mean time to resolve, and write them to a CSV file.

Example 3 — Dashboard and on-call together

analytics.dashboard_sections(today - 7 days, today) and analytics.on_call.now() are independent reads, so the async clients can run them concurrently. Read status from the dashboard and each row's group_name from the on-call list.

Troubleshooting

Relevant for Anyone debugging administration and analytics calls

An alert type is still there after delete

  • DELETE /alert_types/{id} is a no-op that answers 200. Rename the type or leave it, and reuse it with ensure.

A role can't be deleted

  • It is a system role, or users still hold it. Run roles.unassign_users(role_id, user_ids) and retry. A role that was assigned to a user who has since been deleted can't be removed.

403 "The API key doesn't have permissions to perform the request"

  • Location and holiday writes are refused for every API key. Use the UI.
  • aiops.create_config is refused too. Use aiops.set_config.

400 "Invalid Priority Type ID" from the dashboard

  • priorityTypeIdList got a name or a small number. Pass an id from lookups.priority_types(), or use dashboard_sections with priority: "High".

A report ignores the priority or date filter

  • Reports other than the dashboard take the priority name, not the id.
  • The dates were missing or unparseable, so the default window was used. Use YYYY-MM-DD.

500 from time_to_ack

  • The topic filter triggers a server error. Filter by integration or group instead.

402 PaymentRequiredError

  • Call routing: the add-on isn't purchased ("Package settings do not have CallRouting enabled.").
  • Quick start writes: the package has no quick start.
  • Status pages: the page limit is reached (see Status Hub Pages, Incidents and Maintenance with the AlertOps SDKs).

400 with alertcount from simulations.start

  • The simulation window holds too few alerts. Widen from_date/to_date in config 7 or add integrations with history.

UnsupportedAuthError

  • The operation needs a UI session token (logout, SSO logout, AI chat). Pass a session token to the client, or use the UI.

Related Articles

Need help?

Email support@alertops.com or contact your AlertOps representative.