Conventions
Global conventions that apply to every Well API operation: JSON:API envelope, pagination, idempotency, versioning, and graph depth.
These conventions apply to every /v1 operation and are documented once here rather than repeated per endpoint.
JSON:API envelope
Request and response bodies follow a JSON:API-style envelope: a data object with type, id (responses), attributes, and relationships.
// request (create)
{ "data": { "type": "tasks", "attributes": { "title": "Chase invoice" } } }
// response
{
"data": {
"type": "tasks",
"id": "7b2f…",
"attributes": { "title": "Chase invoice", "status": "open", "created_at": "2026-06-07T10:00:00Z" },
"relationships": { "assigned_to": { "data": { "type": "people", "id": "p_1" } } }
}
}- Relationships are
{ "data": { "type", "id" } }(to-one) or{ "data": [ … ] }(to-many). - Related resources may be sideloaded under a top-level
includedarray (e.g. assignees on a task list). - Timestamps are ISO-8601 UTC. Soft-deletable resources carry
deleted_at(null when live).
Pagination
List endpoints are cursor-paginated (keyset, not offset) — the same model the records pipeline uses.
| Param | In | Meaning |
|---|---|---|
limit | query | Page size (default 20, max 500). |
cursor | query | Opaque keyset token. Omit for page 1; pass the previous response's links.next. |
Response carries the next cursor in links.next (and counts in meta):
{
"data": [ … ],
"meta": { "total": 1280, "count": 20 },
"links": { "next": "eyJpZCI6MTAwfQ==" }
}links.next is null on the last page. Cursors are opaque — do not construct or parse them.
page[limit] / page[cursor]). The canonical contract is the flat limit / cursor query params above; new endpoints use it uniformly.Versioning
The surface is versioned in the path: /v1. Changes to /v1 are additive and backward-compatible; breaking changes ship under a new version path, never as a silent mutation of /v1.
Idempotency
Writes that are naturally non-idempotent (e.g. create) may accept an idempotency key where supported; replays within the window return the original result rather than creating a duplicate. Where an endpoint does not document idempotency, treat retries as potentially creating duplicates and guard on the client.
Graph depth (reads)
Read endpoints expose the related graph up to a bounded depth.
- Default
depth=1(the entity + its direct relations, ≈150–200 fields). Selecting every field three hops out explodes to thousands of columns on graph-rich roots (transactions≈6.7k,accounts≈8.4k,payment_means≈9.5k fields at depth 3) — beyond a single SQL statement. - Callers opt into
depth=2/3on smaller-graph roots; a breadth cap bounds field selection regardless. - Nested to-many collections are capped (e.g. 50 rows) at every level, not deeply paginated inline.
meta.nested_capandmeta.capped_relationstell you which nested lists were truncated; page the full collection via its ownGET /v1/<relation>resource endpoint.