AuralisDocs

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/tickets

Do 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-81f4db12f2d0

Quote 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=25

Two 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

On this page