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

Calling the API from Go

Pass path ids as arguments and everything else in one *alertops.Request; its Fields become the JSON body for POST/PUT/PATCH and query parameters otherwise, and failures are typed errors such as *alertops.NotFoundError.

Overview

Relevant for Developers writing calls against any endpoint

Every generated method has the shape Method(ctx, pathValues…, *alertops.Request) (any, error). Path values come first, in path order. The request carries everything else and follows the Python SDK's keyword convention, so a Python example translates one to one. Responses are schema-free JSON, because AlertOps response shapes vary by endpoint and sometimes by call:

  • Objects are map[string]any.
  • Top-level lists are alertops.AOList, with Items and Raw (the envelope the list came from).
  • Nested lists are []any.

Read results with alertops.Get(v, "a", "b"), or decode them into your own struct with alertops.Decode(v, &target).

Path values and the request

Relevant for Developers building requests

A nil request is an empty one.

FieldDescription
FieldsMerged into the JSON body for POST, PUT, PATCH and body-carrying DELETEs. Sent as query parameters for every other method.
BodyAn explicit body: any JSON value, a []any for bare-array bodies, or alertops.Null for an explicit null. Fields merge into it when it is a map.
ParamsExtra query parameters, also for body methods.
FilesMultipart parts, map[string]alertops.File. The body's fields become form fields.
HeadersExtra request headers.
ao.Groups.List(ctx, &alertops.Request{Fields: alertops.M{"search": "Network", "limit": 100}})   // GET ?search=…&limit=100
ao.Groups.Create(ctx, &alertops.Request{Fields: alertops.M{"group_name": "Network Ops"}}) // POST {"group_name": …}
ao.Groups.Members.Add(ctx, 11, &alertops.Request{Body: []any{alertops.M{"member_type": "User", "member": "7", "sequence": 1, "roles": []any{"Primary"}}}})
ao.EscalationPolicies.UpdateBasic(ctx, 3, &alertops.Request{Body: wholeRecord})

Go maps have no order
Python dicts keep insertion order, and in a few places that order is observable. Examples: attributes that a helper JSON-encodes into a string field, attribute rows, and a status page's group layout. Pass an alertops.OrderedMap there to control the order. Plain maps are written in key order.

Query values follow Python's rules:

  • true and false become true/false.
  • Slices are comma-joined.
  • nil values 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 into a []any) and ListIter (an iter.Seq2[any, error] that fetches lazily). Break out of the loop to stop early.

every, err := ao.Groups.ListAll(ctx, &alertops.Request{Fields: alertops.M{"search": "sdk"}})
for alert, err := range ao.Alerts.ListIter(ctx, &alertops.Request{Fields: alertops.M{"createdFrom": "2026-03-01", "createdTo": "2026-03-08"}}) {
if err != nil {
return err
}
if alertops.Get(alert, "status") == "Open" {
fmt.Println(alertops.Get(alert, "alert_id"))
}
}
StyleUsed byBehaviour
page indexgroups, users, policies, audit trail …limit + offset, where offset is a page index (0, 1, 2), not a row offset. Stops on a short page.
cursorv3 listspageSize + after, read from nextCursor / hasMore.
page numbernotification historypageNumber + pageSize.
metadata cursoralertslimit + next, read from metadata.next.
limit onlyinbound logOne page.

Errors and retries

Relevant for Developers handling failures

Non-2xx answers return an error kind that wraps *alertops.APIError, so both errors.As(err, &nf) with nf *alertops.NotFoundError and errors.As(err, &api) with api *alertops.APIError work. An APIError 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.
ErrorWhen
*BadRequestError400 or 422
*AuthenticationError401
*PaymentRequiredError402, the feature is not in the plan
*PermissionDeniedError403
*NotFoundError404 (alertops.IsNotFound(err))
*ConflictError409
*RateLimitError429 after retries
*ServerError5xx
*TransportErrornetwork failure after retries
*ValueError / *LookupError / *TypeErrora 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 500 ms, capped at 8 s, with ±25 % jitter).
  • Retry-After: honoured when the server sends it, up to 32 s.

Cancelling ctx stops a call and its retries.

Listeners and the escape hatch

Relevant for Developers adding logging or calling unmodelled paths

ao.AddListener(func(e alertops.CallEvent) { log.Println(e.OpID, e.Method, e.URL, e.Status, e.Elapsed) })
res, err := ao.Request(ctx, "GET", "/groups", &alertops.RequestOptions{Base: "v2", Request: alertops.Request{Fields: alertops.M{"search": "Net"}}})

Troubleshooting

Relevant for Anyone debugging a call

Groups.list() does not take a request body

  • You set Body on 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

Need help?

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