Request conventions: context headers, errors, localization
Every org-scoped /api/v1/* endpoint shares the same request contract: a bearer token, two context headers that pick the organization and team you act in, JSON bodies (file uploads use multipart or tus instead), one error shape, and cursor pagination on list endpoints. This page is the contract; per-domain pages assume it.
Context headers
Section titled “Context headers”Almost everything in the DUST API belongs to an organization, and within it a team. You choose which org/team a request acts in with two headers:
| Header | Required | Value |
|---|---|---|
Dust-Ctx-Org-Id |
Yes, on org-scoped endpoints | Organization UUID. |
Dust-Ctx-Team-Id |
No | Team UUID. Defaults to the organization’s root team when omitted. |
curl -fsS "https://apid.dustid.io/api/v1/threads" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -H "Dust-Ctx-Team-Id: $DUST_TEAM_ID"Details that matter in practice:
- Header values must be UUIDs; a malformed value is rejected with
400 INVALID_REQUESTbefore the endpoint runs. X--prefixed variants (X-Dust-Ctx-Org-Id,X-Dust-Ctx-Team-Id, and the legacy pair) are accepted as aliases.- Endpoints that require context but don’t receive it fail with error codes
ORG_ID_REQUIREDorTEAM_ID_REQUIRED. - A few endpoints are user-scoped and need no context —
GET /api/v1/meis the common one.
Context is an authorization boundary
Section titled “Context is an authorization boundary”Authorization is evaluated for your user acting in the team named by the headers. The same call with a different Dust-Ctx-Team-Id can return different results: what you can list, read, and write is what that team can see — its own records plus whatever has been shared with it. Sending a context you don’t belong to doesn’t escalate anything; requests are checked against your actual memberships. See Teams and sharing.
Localization
Section titled “Localization”The optional Dust-Ctx-Locale header selects the language for server-generated, user-facing text — most visibly error message strings:
Dust-Ctx-Locale: zh-CNSupported locales are en (default) and zh-CN. When the header is absent the server falls back to the standard Accept-Language header, then to English. Error codes are stable identifiers and never localized — branch on code, display message.
Errors
Section titled “Errors”Failed requests return a JSON body with a single, consistent shape:
{ "code": "UNAUTHORIZED", "message": "You are not authorized to perform this action", "status": 401, "detail": { }}| Field | Type | Meaning |
|---|---|---|
code |
string | Stable, machine-readable error code. Branch on this. |
message |
string | Human-readable description, localized per Dust-Ctx-Locale. |
status |
number | Mirrors the HTTP status code. |
detail |
object (optional) | Extra context for this error, e.g. validation specifics. |
Codes you will encounter early:
| Code | Typical status | When |
|---|---|---|
INVALID_REQUEST |
400 | Malformed body, query, or header (validation detail in detail). |
UNAUTHORIZED |
401 | Missing, expired, or invalid bearer token. |
FORBIDDEN |
403 | Authenticated, but this team context may not do that. |
NOT_FOUND / NO_DATA_FOUND |
404 | No such record visible in this context. |
ORG_ID_REQUIRED / TEAM_ID_REQUIRED |
400 | Context header missing on a scoped endpoint. |
THREAD_DATA_CONFLICT |
409 | Optimistic-concurrency conflict: your view of the thread was stale. |
Every response also carries an x-request-id header. Log it, and include it when contacting support — it pinpoints your request in server traces.
Pagination
Section titled “Pagination”List endpoints (threads, bundles, files, events, templates, …) use cursor pagination:
- Request:
pageSize(page length) andcursor(opaque string from a previous page) query parameters. - Response: the items array plus optional
nextandprevcursor strings. A missingnextmeans you’re on the last page.
# First pagecurl -fsS "https://apid.dustid.io/api/v1/threads?pageSize=50" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID"
# Follow the cursorcurl -fsS "https://apid.dustid.io/api/v1/threads?pageSize=50&cursor=$NEXT" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID"{ "threads": [ ... ], "next": "eyJjcmVhdGVkQXQiOi...", "prev": "eyJjcmVhdGVkQXQiOi..."}Cursors are opaque — persist and replay them, never parse them. List endpoints that support ordering take order (asc/desc) and an endpoint-specific orderCol (for threads: createdAt, updatedAt, name).
Authorization tiers
Section titled “Authorization tiers”Every operation requires one of three privilege levels, and the path prefix tells you which before you read a single schema:
| Prefix | Who can call it | Notes |
|---|---|---|
/api/v1/org/* |
Organization admins — users with the admin (or owner) role in the Organization named by Dust-Ctx-Org-Id |
Team creation, team updates, memberships |
/api/v1/connections/* |
Team admins — admins of the acting Team named by Dust-Ctx-Team-Id |
Connection lifecycle and amendments |
| everything else | Members of the request context, unless the operation says otherwise | Standard feature surface |
Each operation also carries an x-required-role extension in the OpenAPI spec (member, publisher, team-admin, or org-admin) — treat that as the authoritative per-operation policy; an operation without the annotation requires member. publisher is a grant on a Team membership rather than a tier of its own: it is required to make a Team’s data publicly readable, and Team admins always have it. Calling an operation above your tier returns 403 FORBIDDEN regardless of payload.
Bodies, IDs, and timestamps
Section titled “Bodies, IDs, and timestamps”- Requests are
Content-Type: application/jsonunless an endpoint explicitly takes multipart form data (identifier scans on/api/v1/tags/*, file uploads). - IDs are RFC 4122 UUID strings (
threadId,eventId, organization and team ids, …). Treat them as opaque. - Timestamps (
createdAt,updatedAt,archivedAt, …) are UTC timestamp strings. - Writes are evented: mutating a thread appends to its event history rather than silently overwriting — reads like
GET /api/v1/threads/{thread_id}return{ thread, events }.
See also
Section titled “See also”- API quickstart — these conventions in one working flow.
- Authentication and API keys — where the bearer token comes from.
- Core model — what threads, teams, and identifiers mean.
- Full API reference — per-endpoint parameters and schemas, generated from the live spec.
