Conventions
The response envelope, pagination, content types and identifiers — true of every endpoint.
Four things are true of every endpoint in this reference. Reading them once here saves repeating them on every page.
The response envelope
Successful responses are always HTTP 200 with a two-key envelope. The payload you want is under data — a 201 is never returned, even from a create.
{
"status": "ok",
"data": {
"id": "8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f",
"title": "Cardiology intake",
"description": "Patient handbooks and discharge protocols",
"share_token": "s7Kd0pLm2Qx",
"created_at": "2026-08-05T09:14:22.118Z",
"updated_at": "2026-08-05T09:14:22.118Z"
}
}Errors are the exception to the 200 rule: they carry a real status code. There are two error bodies, depending on which layer rejected the request, and a client has to read both.
{
"status": "failed",
"message": "Workspace not found"
}Pagination
List endpoints paginate. The page object sits inside data, and next is a complete URL you can follow as-is rather than a cursor you have to assemble.
{
"status": "ok",
"data": {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "8f14e45f-ceea-467a-9f4c-1a2b3c4d5e6f",
"title": "Cardiology intake",
"description": "Patient handbooks and discharge protocols",
"share_token": "s7Kd0pLm2Qx",
"created_at": "2026-08-05T09:14:22.118Z",
"updated_at": "2026-08-05T09:14:22.118Z"
}
]
}
}Two query parameters control it. page_size is capped at 200 — asking for more silently gives you 200, not an error.
| Field | Type | Description |
|---|---|---|
page | integer | 1-based page number. Defaults to 1. |
page_size | integer | Results per page. Defaults to 30, capped at 200. |
Content types
Most endpoints accept JSON. Two do not, and it matters:
- Uploading a resource is
multipart/form-dataonly. A JSON body there is a415, even though the endpoint is a normal create. - Sending a chat message accepts both JSON and multipart. Use multipart when you attach an image, JSON otherwise.
Content-Type header yourself. It has to carry a boundary token the HTTP client generates per request, and writing the header by hand overwrites it — the server then parses zero fields and you get a validation error that looks like a field-name bug.Identifiers and trailing slashes
Every identifier is a UUID. Workspace and resource ids appear in paths; external_user_id is the one identifier you choose yourself, and it is an arbitrary string of up to 255 characters.
POST becomes a GET with no body — so the request appears to succeed and silently does nothing.