Skip to content

HTTP API

Every call is a POST with a JSON body. The type field names the handler, payload carries its fields. The reference pages list every handler with its fields.

Endpoint
POST /api/queryReads data. Never changes anything.
POST /api/writeChanges data: create, update, delete or a specific action.
POST /api/batchRuns several write calls in one transaction.

Send an API token in the Authorization header as Bearer <token>. Requests with a token need no cookie and no CSRF token. The token also fixes the account the request runs in, so you never send an account or tenant ID.

type is the handler name, for example ticketing:query:ticket:detail. payload holds the fields from the reference. requestId is optional, see below. The payload may be nested at most 20 levels deep.

Terminal window
curl -X POST https://ticketing.example.com/api/query \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ticketing:query:ticket:detail",
"payload": {
"id": "00000000-0000-4000-8000-000000000001"
}
}'

A successful read returns data. A successful write returns isSuccess: true and data.

On failure the HTTP status is 4xx or 5xx and the body contains error. Write calls also return isSuccess: false. Branch on error.code and the status. message is meant for people and may change.

CodeHTTP statusMeaning
ambiguous_auth400The request carried both a session cookie and a token. Send only one.
validation_error400The payload does not match the handler’s fields. details names the fields.
invalid_token401The token is unknown, revoked or expired.
missing_token401The Authorization header is missing.
unauthenticated401No valid credentials were sent.
access_denied403The token lacks the scope for this handler, or the endpoint does not accept tokens.
feature_disabled403This function is switched off or not part of your plan.
not_found404The record does not exist or you cannot see it.
conflict409The change conflicts with the current state of the data.
idempotent_replay409This change was already applied under the same idempotency key. The first attempt succeeded, so do not send it again.
precondition_failed409A field of the record no longer has the value the change expected. Read the record again and retry.
record_locked409Another change holds a lock on the record. Retry shortly.
unique_violation409A record with this value already exists.
version_conflict409The record changed after you read it. Read it again and retry with the new version.
unconfigured422A setting this function needs is still empty. Set it up in the app first, then retry.
unprocessable422The data is valid, but a business rule rejects the change. details.reason names the rule.
pat_rate_limited429This token sent too many requests in a short time. Wait a moment and retry.
rate_limited429Too many requests. Wait as many seconds as the Retry-After header says.
internal_error500Unexpected server error. Retry later.
rate_limit_unavailable503The rate limiter is temporarily unavailable, so the request was refused. Retry shortly.
member_read_timeout504A read on the server took too long and was stopped. Retry later.

Every record has a version. An update takes the version you read last. If someone changed the record in between, the call fails with 409 version_conflict. Read the record again, check the change and send it with the new version.

List handlers end in :list and accept these fields:

FieldTypeDescription
cursorstringPosition from nextCursor of the previous page.
limitintegerRows per page, 50 by default, at most 200.
searchstringFull-text search across the searchable fields.
sortstringField to sort by.
sortDirection“asc” | “desc”asc or desc.
offsetintegerNumber of rows to skip. Prefer cursor for paging.
totalCountbooleanSet true to also get total, the number of matching rows.
includeDeletedbooleanSet true to include deleted rows. Only for entities with soft delete.
onlyDeletedbooleanSet true to return only deleted rows. Only for entities with soft delete, not together with includeDeleted.
filterobjectOne field filter with field, op and value. op is one of eq, ne, lt, gt, lte, gte, in.
filtersarray of objectSeveral field filters, each with field, op and value. op is one of eq, ne, lt, gt, lte, gte, in.
namedFilterstringName of a predefined filter of the entity, for example a work queue.
aggregateobjectReturns aggregated values instead of rows.

The response contains rows and nextCursor. For the next page send nextCursor as cursor. On the last page nextCursor is null.

POST /api/batch takes commands, a list of { type, payload } write calls. They run in one transaction: if one fails, none takes effect. The response then has isSuccess: false, the error and failedIndex, the position of the failed command counted from 0.

Send a requestId with write and batch calls, any string that is unique per change. If the connection drops and you send the same call again with the same requestId, you get the first result back and the change does not run twice.