Docs
Conventions
The shape of every response, in one page: envelopes, cursors, typed ids, money, dates and the naming rules both facades share.
The envelope
A single resource is wrapperless. The object is the response body — no
data key to unwrap, no envelope to remember.
A collection is wrapped, because it needs to carry pagination alongside the rows:
data, hasMore, nextCursor and total.
On success the request id travels in the X-Request-Id response header. On failure it
is in the body as well. Log it either way — it is what support will ask you for.
Pagination
Pagination is cursor-based. limit is an integer starting at 1, defaults to
25, and has a per-endpoint maximum — 200 on most collections, lower on a few.
Each endpoint's reference page states its own ceiling. An over-limit value returns
422 validation_failed with a /limit pointer in errors[],
rather than silently clamping.
Treat nextCursor as opaque — its type is not part of the contract. Pass whatever you
received straight back as cursor; never parse it, increment it, or construct one.
Identifiers
Service, invoice and domain ids are integers that come from the client area. Take them from a
listing endpoint and pass them back unchanged. A few internal objects use prefixed ULIDs instead:
req_ (request id), tok_ (API token), job_ (async job) and
pact_ (pending action).
Where a resource has a canonical name, the natural key is the identifier instead: the address for a mailbox or forwarder, the username for a database user, the domain for a zone, the fingerprint for an SSH key.
Money
Money is a decimal JSON number in major units, always paired with a sibling
currency. No integer minor units leak out of the API, and no amount ever appears
without the currency next to it.
Dates
Most timestamps are ISO-8601 UTC with milliseconds and a Z:
"2026-08-29T12:34:56.000Z", suffixed At — paidAt,
createdAt. A few carry a plain YYYY-MM-DD date under the same suffix,
notably expiresAt on services and invoices. Parse defensively.
Booleans and null
Booleans are real JSON booleans, prefixed is, has or can:
isSuspended, hasMore, canBeRenewed. DirectAdmin's
ON/OFF/yes/no/1/0
vocabularies are normalised upstream and never reach you.
unlimited is null — not the string
"unlimited", not -1. Where it helps, a limit is expressed as an object so
the unit is unambiguous.
A field may be absent or explicitly null — handle both. 0 and
false are never treated as empty and are always present.
Naming and paths
- camelCase in JSON, in both facades, with units in the name:
memoryGb,diskUsedMb,ttlSeconds. - REST paths are
/api/v1/{resource}, with/actions/{verb}for anything that is not CRUD. -
On an action path the method expresses intent:
GETprices or previews it,POSTperforms it,DELETEcancels a scheduled one. Destructive operations always have a pairedGETto use as a dry run. - MCP tool names are
snake_caseand verb-object, named by hand rather than derived from the path.