Skip to content

Conventions

Learn these once and every endpoint gets easier, which is the entire argument for having conventions at all.

Every response has the same outer shape:

{
"success": true,
"data": { },
"meta": { }
}

On failure, success is false and the payload carries a stable error code.

This means your client needs exactly one place that understands success and failure, rather than one per endpoint. It also means you should check success rather than inferring it from the HTTP status. The two usually agree. Usually is not a word you want load-bearing in an error path.

List endpoints are cursor-paginated. You get a page of results and a cursor; pass the cursor back for the next page. Keep going until there is no cursor left.

Cursors are opaque. They encode position in a way that survives items being added while you are reading, which offset-based paging does not. Do not parse one, do not construct one, and do not store one and use it a week later.

Most objects are addressed by an id. Some are also addressable by a handle or slug, which is friendlier in a URL and in a support conversation.

Watch the level. Workspace-scoped and app-scoped identifiers look similar and are not interchangeable, and passing one where the other is expected produces a “not found” that is technically honest and completely unhelpful.

Limits are per token. When you hit one you get a failure with a rate-limit error code rather than a silent slowdown.

Back off exponentially and add jitter. Retrying immediately, in a tight loop, from every one of your workers at once is how a rate limit becomes an outage. The limit is doing its job; help it.

Anything that creates or charges should be safe to retry. If a request times out, you do not know whether it landed, and the honest answer to “did that work” is to ask rather than to guess by trying again.