Skip to main content
Documentation

Endpoints

The full, always-current list of endpoints lives in the interactive explorer and the OpenAPI spec. This page covers the conventions every endpoint shares.

Response envelope

Successful responses wrap their result in data:

{ "data": { "id": "...", "ticketNumber": 42 } }

List endpoints add cursor pagination:

{
  "data": [
    /* ... */
  ],
  "pagination": { "nextCursor": "eyJ...", "hasMore": true, "limit": 50 }
}

Pagination

List endpoints are cursor-based. Pass ?limit= (1-100, default 50) and, to fetch the next page, ?cursor= with the previous response's nextCursor. When hasMore is false, nextCursor is null.

Errors

Errors share a consistent shape and use standard HTTP status codes:

{
  "error": {
    "code": "forbidden",
    "message": "Missing required scope(s): tickets:write"
  }
}
Status Code Meaning
400 validation_error Bad request body or query parameter
401 unauthorized Missing or invalid token
403 forbidden Missing scope or wrong token type
404 not_found Resource not found
409 conflict Duplicate, or related records still exist
429 rate_limited Rate limit exceeded
503 bot_unavailable A Discord-affecting action could not reach the bot

Scopes

Each token carries scopes. Read endpoints need a :read scope; writes need :write. Examples: tickets:read, tickets:write, categories:write, transcripts:read, analytics:read, webhooks:write. Organization tokens also use org:servers:read, org:members:read, org:analytics:read, and org:transcripts:read for the aggregate endpoints.

A few resources share a scope with the thing they belong to rather than having their own: automation rules and custom commands use flows:read / flows:write, and canned replies use knowledgebase:read / knowledgebase:write. There is no automations:*, commands:* or canned-replies:* scope. Every endpoint states the scope it wants in the OpenAPI spec, and a 403 for a missing one names the scope.

See Authentication for how to create tokens and assign scopes.

Rate limits

Requests are rate limited per token. Every response includes:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 299
X-RateLimit-Reset: 1780000000

When you exceed the limit you get a 429 with a Retry-After header. Limits scale with plan tier.

Idempotency

POST /v1/tickets accepts an Idempotency-Key header. Retrying with the same key within 24 hours returns the original result instead of creating a duplicate.

Secrets in flow nodes

Flow nodes that call third-party services (API Request, Send Webhook) store credentials in their data object. Reads never return them in the clear.

GET /v1/flows/{id} replaces a stored authToken, authUsername, authPassword and any credential-bearing header (authorization, x-api-key and similar) with the literal string __redacted__. A field that holds no credential is returned absent or empty, so you can still tell "a secret is set" from "there is no secret".

Writes accept the mask back:

You send Result
__redacted__ the stored credential is kept
a real value the credential is rotated
"" the credential is cleared
the field omitted entirely the credential is cleared

That last row is the one to watch. A read-modify-write that strips unfamiliar fields before PATCHing will delete the credential, and the flow will start failing its API calls with no other symptom. Echo data back as you received it and change only what you mean to change.