Response envelope & sideloading
Every list and single-resource response carries a consistent envelope. An opt-in ?include= parameter sideloads related resources into a deduplicated included block, so a single request can return everything the caller needs to render rich views without secondary lookups.
Envelope shape
List, single-resource, and filter responses share the same outer shape:
?include= tokens. Present (with empty arrays where nothing matches) once ?include= is used.next_cursor, has_more). Present on list endpoints; absent on single-resource endpoints.data always carry the minimal embed shape (id plus a few render-critical fields). The full objects live in included. Expanding a relationship never rewrites the references in data.The ?include= parameter
Pass ?include=<token>[,<token>...] on a GET endpoint to expand related resources. Each token names a relationship — not a field.
Filter endpoints take the same tokens as a JSON body field instead of a query string, keeping the request self-contained:
/.../count) do not support include. Their response is just {"count": N}, with no data for related resources to attach to.Token rules
Tokens follow a small set of rules that hold across every resource:
- Tokens name relationships, not fields.
?include=typemeans “expand the type”, which implicitly carries everything needed to render that type. - Multiple tokens are comma-separated:
?include=type,tags. - Duplicate tokens are silently deduplicated.
?include=type,typeis equivalent to?include=type. - There is no per-request maximum on the number of tokens. Callers requesting expensive expansions pay the latency cost themselves.
- Unknown tokens return
400 Bad Requestwith a payload listing the valid tokens for that endpoint (see Validation below).
Dot-notation for cross-resource expansion
Dot-notation crosses resource boundaries. ?include=instrument.type on the time series values endpoint expands the referenced instrument and that instrument’s type — both appear in included under their respective resource keys.
- Dot-notation is only valid between different resources. Same-resource drill-downs (e.g.
type.fields, sincefieldsis a sub-property of the type object) are rejected with400. - Maximum depth: 2 levels (
a.bworks,a.b.cis rejected with400). Two levels covers every observed dashboard rendering need; deeper nesting is deferred until a concrete use case appears.
Default minimal embed vs. expanded included
Without ?include=, references in data are minimal — enough to render a list row without a follow-up request:
With ?include=type,tags, the references in data are unchanged. The full objects appear once each in included, deduped by ID across the response page:
Dedup is by resource ID and scoped to a single response page. When a list is paginated, each cursor page carries its own included block; clients are responsible for caching across pages if they need workspace-wide dedup.
Frontend consumption pattern
Build lookup tables once per response page, then resolve references on every data row:
Validation
Unknown tokens return 400 Bad Request. The payload enumerates the valid tokens for that endpoint exactly — no spelling correction or near-match suggestion.
The exact token set for any given endpoint is documented on the relevant API reference page (e.g. Time Series).