Overview
The base URL, the conventions every operation shares, and what this reference covers.
The Auralis API is an HTTP/JSON API over the helpdesk: tickets, the customers behind them, the channels they arrive on, and the teams, macros and targets you work them with. Everything Studio does, it does through these operations.
This page is the part you only need to read once. It covers the base URL, how a request is authenticated, the shape every response comes back in, how lists page, and how failures are reported. The rest of the reference assumes it.
Base URL
There is no single hosted base URL to copy. The runtime is deployed per customer, so the host is whatever your deployment serves it on and the rest of the path is fixed:
https://<your-runtime-host>/v1/...On a local development stack that is:
curl -sk https://api.localhost/v1/ticketsDo not guess the host
api.auralis.ai serves other Auralis products and is not the helpdesk
runtime. If you do not know your runtime host, ask whoever operates your
deployment rather than inferring it from another Auralis service.
Every published operation lives under /v1. That prefix is the only version
marker; there is no version header and no date-pinned version. A breaking
change would arrive as a new prefix, not as a silent change under this one.
Authenticating
One header carries every credential:
Authorization: Bearer <credential>Two kinds of credential are accepted, and they are not the same thing in two
forms. A realm access token acts as the person who signed in. A workspace
API key — an opaque secret beginning sk_zr_ — is bound to one workspace and
limited by scopes. Authentication covers the difference,
which one to use, and how to mint a key.
The credential is also what selects the workspace. There is no workspace
parameter on any operation: a key belongs to exactly one workspace, and a token
resolves to the caller's membership. That is why a request for a workspace you
are not a member of returns 404 rather than 403 — see
Tenancy below.
Request and response conventions
Content type. Send Content-Type: application/json on any request with a
body. Responses are always application/json, including failures.
Identifiers are UUIDs, and the ones the runtime generates are UUIDv7, so they sort by creation time. Treat them as opaque strings; do not parse them.
Timestamps are ISO 8601 with an explicit UTC offset, to microsecond
precision — 2026-08-22T07:42:24.906592+00:00. Every timestamp field ends in
_at or _due.
A PATCH changes only what you name. Omitting a field leaves it unchanged.
Sending `null` does not clear a field
null and "omitted" are the same request. Every optional field defaults to
null, so there is no way to distinguish the two, and neither one erases
anything.
Clearing is done with explicit flags instead — on a ticket,
"unassign": true, "unassign_team": true and "unlink_customer": true. Each
operation names its own.
The exception is a list, which is replaced wholesale rather than appended to:
sending "tags": ["billing"] leaves the ticket with exactly one tag, and
"tags": [] empties it.
Every response carries x-request-id:
HTTP/2 200
content-type: application/json
x-request-id: c0427b1f-eb85-4566-91cf-81f4db12f2d0Quote that value when reporting a problem. It is the only handle that ties your request to the runtime's own logs.
Collections
A list operation returns its rows under a named key, never a bare array, so the envelope has room to carry counts alongside them:
{
"tickets": [ { "id": "01a0286b-...", "subject": "...", "status": "open" } ],
"total": 1115,
"counts": { "open": 1115, "pending": 470, "on_hold": 252, "solved": 3061 }
}total describes the filtered set — the number of rows your filters
matched, not the number returned on this page. counts, where an operation
provides it, is deliberately unfiltered, because it exists to power filter
chips, and a chip has to show what selecting it would yield.
Paging
Lists page with limit and offset.
Prop
Type
On GET /v1/tickets limit runs from 1
to 500 and offset from 0 to 2147483647. A value outside the range is a 422,
not a silent clamp.
Ordering is defined per operation and is stable — the ticket queue orders by priority, then most recently updated, then id. Stability is the point: it means a paged traversal returns each row exactly once instead of skipping and repeating rows as the queue moves under you.
There is no cursor pagination and no next link. For a large export, page by
offset and accept that rows updated mid-traversal may shift position within
their priority band.
Filtering
Filters combine with AND. A filter that accepts a list matches any value
in it, so ?status=open&status=pending&priority=urgent reads as (open or
pending) and urgent.
An unknown value in an enumerated filter is a 400 naming the parameter, rather
than an empty result set that would look like "no tickets".
curl -sk -G https://api.localhost/v1/tickets \
-H "Authorization: Bearer $AURALIS_API_KEY" \
-d status=open -d status=pending \
-d priority=urgent \
-d limit=25Two filters take sentinels instead of ids: assignee accepts me or
unassigned, and team_id accepts none.
Tenancy and the 404 rule
Every operation is scoped to one workspace, selected by the credential.
A workspace you are not a member of returns 404, not 403. That is
deliberate and it is not a bug: a 403 would confirm the workspace exists, and
existence is itself information. A caller cannot tell an id that is real but
closed to them from one that was never issued.
The practical consequence: if you get an unexpected 404 on an id you believe
is valid, check which workspace your credential belongs to before you go looking
for the record.
Errors
Every refusal — from the middleware, a route handler or the schema validator
alike — comes back in one envelope with a stable, machine-readable error
identifier:
{
"error": "api_key_out_of_scope",
"message": "this api key's scopes do not cover 'helpdesk-ops:read'"
}Match on error, never on message. The identifier is the contract; the
prose is not, and it will be reworded. The full catalogue is in
Errors.
Where to go next
Authentication
The two credential types, the scope model, and minting your first key.
Errors
The envelope, the identifiers, and what each status actually means.
Roles and permissions
The role floor every guarded operation sits at, and how keys inherit it.
Rate limits
What is capped, what is not, and the limits that bite before any rate limit does.