API conventions

Paging, sorting, search, identifiers, and timestamps in the Agent Authority management API. The conventions shared across operations, documented once.

These conventions are shared, so reading them once saves reading them on every operation page. Each operation page still lists the parameters it actually accepts, which is what to trust when the two disagree.

Paging

List operations come in three shapes, and the parameters an operation accepts are what tell you which one you are holding. Do not infer the shape from the response body.

Offset paging

Most list operations take offset and limit, and return the page under items with the paging state under meta.

ParameterTypeDefaultPurpose
offsetinteger0How many items to skip before returning results.
limitinteger10How many items to return. Maximum 256.
{
  "items": [{ "id": "c81a4f60-2b77-4e19-9d33-58ab0e6c1d92" }],
  "meta": {
    "total": 47,
    "offset": 0,
    "limit": 10
  }
}

total counts every item matching the query, not just the current page, so it is what you page against. Advance by adding limit to offset until offset reaches total.

Because offsets are positions rather than bookmarks, an item created or deleted between two calls shifts the window. Where that matters, filter to a fixed time range instead of relying on offsets staying aligned.

The gateway rejects a limit above the maximum instead of clamping it: the request returns 400 with query/limit in validation_errors.

Cursor paging

GET /audit-events pages differently, because the audit log grows while you read it. It takes cursor and limit (default 20, maximum 100), has no offset, and returns no meta:

{
  "items": [{ "id": "c81a4f60-2b77-4e19-9d33-58ab0e6c1d92" }],
  "next_cursor": "9f2b1d07-5c34-4a91-b0e8-71d9a4c25e3f"
}

Pass next_cursor back as cursor to fetch the following page. The field is absent on the last page, which is the only signal that you have read everything. The response carries no total, so you cannot know the size of the result up front.

Stopping when a response carries no meta truncates an audit query at the first 20 events. Follow next_cursor until it is absent.

No paging

The remaining list operations return a bounded collection whole and accept no paging parameters at all. Most return it under items; GET /inference/bindings, GET /seat-assignments and GET /seat-pricing return a bare JSON array with no wrapper object. Read these once.

One operation carries meta without accepting paging parameters. GET /analytics/llm-user-percentiles reports over the whole population, so its meta.total is a headcount rather than a page count.

Sorting

Sorting is not universal. Six list operations accept it, and each one has its own accepted keys and its own default. Check the parameter name before you use it: four take sort_by, and two take sort.

EntityParameterAcceptsDefaultsort_order
Agent instancessort_bycreated_at, display_name, last_used_atcreated_atdesc
Groupssort_bycreated_at, namecreated_atdesc
Tagssort_byname, created_atnameasc
Userssort_bycreated_at, display_name, emailcreated_atdesc
Anomaly findingssortrecent, severity, scorerecentdesc
LLM sessionssortcost, tokens, recentcostnone

Where sort_order exists it is asc or desc. GET /analytics/llm-sessions is the exception: it takes no sort_order, because each of its keys already implies a direction. An operation that lists none of these parameters returns its own fixed order, which its page describes.

Four operations accept a search parameter: a free-text term, up to 255 characters, matched case-insensitively as a substring. Agent instances, groups, tags and users each search their own display name. Agent instances also match the owning user's display name and the agent slug. Combine search with paging to walk a filtered set.

Identifiers

Every resource is addressed by a UUID, in the canonical hyphenated form. A path parameter named {…_id} is always one, mcp_id included. UUIDs are opaque: do not parse them or infer ordering from them.

A few paths key on something else, and their parameters are named for it rather than ending in _id:

PathKeyed by
/policies/evaluate/agents/{agent_slug}An agent type's slug, such as claude-code
/tag-assignments/{target_type}agent_slug, mcp, or tool
/tag-assignments/{target_type}/{target_key}The target's own key, for that type
/nhi/providers/{provider}/testA provider name, currently microsoft_entra

Outside those paths a slug identifies rather than addresses. An MCP server has a slug such as github: policies match on it (mcp.slug == "github") and it names the server in the single-MCP gateway URL, but GET /mcps/{mcp_id} still wants the UUID.

A slug identifies a type of agent, while a UUID identifies one registered instance of it. A policy scoped to the slug applies to every instance; one scoped to an instance ID applies to that connection alone.

Timestamps

Timestamps are RFC 3339 in UTC, for example 2026-09-16T09:14:22Z. Fields ending in _at are instants, so treat them as opaque points in time rather than parsing their parts.

Next steps

On this page