Base URL
Each workspace has a unique API endpoint based on its workspace identifier.wks{region}{7char} with your workspace’s unique subdomain.
Request Format
Send request bodies as JSON, and setContent-Type: application/json on any request that includes a body (POST, PUT, and PATCH). Requests without a body, such as GET and DELETE, don’t need it.
Responses are always JSON, so an Accept header isn’t required. You’ll see Accept: application/json in the code samples throughout this reference — it’s harmless to include and makes the examples copy-paste ready, but you can safely omit it.
The example above is a
GET request, so neither Content-Type nor Accept is strictly required — only your Authorization header is. Both are shown for consistency with the write examples elsewhere in this reference.Response Format
All responses are returned as JSON. Successful responses use standard HTTP status codes:Error Handling
Every unsuccessful request returns a JSON body — including authentication failures,404s, and unexpected server errors. The API forces a JSON response on all /api/* routes, so you never receive an HTML error page and your client can parse errors exactly the way it parses successful responses.
Error response structure
All application error bodies share the same envelope:string
required
A human-readable description of what went wrong, safe to surface to end users. For
500 responses this is intentionally generic — internal details and stack traces are never exposed to clients.object
Present on validation failures (
422) only. Each key is the name of a field that failed validation, and its value is an array of one or more messages describing why.Status codes
The API uses conventional HTTP status codes. A2xx indicates success (see Response Format); a 4xx means the request needs to change before you retry it; a 5xx or edge error means something failed on our side and the request can usually be retried.
Client errors (4xx)
You should not retry these unchanged — fix the request, credentials, or timing first.Server errors (5xx)
These indicate a problem on our side. They are safe to retry with exponential backoff.Edge & network errors (520–530)
These are returned by our edge network (Cloudflare) when it can’t reach the application or doesn’t get a timely response — before your request reaches our code. They’re transient; retry with backoff.Validation errors
A422 response means one or more fields failed validation. The errors object gives you a field-by-field breakdown so you can map each message back to the input that caused it:
Rate limiting
Rate limits are applied per token (falling back to your client IP) and vary by endpoint — read endpoints allow far more requests than sensitive operations, and many standard endpoints allow up to 200 requests per minute. Rather than hard-coding a number, treat the response headers as the source of truth. Every response includes your current standing:
When you exceed the limit, the API responds with
429 Too Many Requests and adds:
Retrying failed requests
For retryable errors, use exponential backoff with jitter (e.g. 1s, 2s, 4s, 8s…) and cap the number of attempts. For
429, always wait at least the number of seconds given in Retry-After before your next request.
Reporting a problem
If you hit an unexpected error — typically a persistent500 or edge error — capture enough context for support to trace it. Our official CLI records a Bug Report Metadata block for exactly this purpose; include the equivalent when you open a ticket:
The
workspace_id, workspace_user_id, and workspace_device_id come from your credentials, not the error response — include whichever your client has on hand along with the timestamp, status, and request url/method.