/v1 endpoint. The three that most often surprise people are decimal strings, staleness, and clamping.
The envelope
Every success is{ data, meta }.
Failures replace both keys with a single
error object. There is no partial response: you get data and meta, or you get error.
Levels are decimal strings
indexLevel and baseIndexLevel are JSON strings, not numbers.
100 on its inception date, which is what lets a level read on its own without a reference point.
Timestamps
Every timestamp on every endpoint is UTC,Z-suffixed, with microsecond precision.
Field naming
data and meta are camelCase, with one exception: the per-leg components array on the volatility endpoints is snake_case – leg_key, venue, condition_id, fbv_r_pts, passes_depth, observed_at.
Those are the column names the snapshot bundles use for the same per-leg record, so the trailing window and full history join without two vocabularies. The one exception is venue, which the API carries and the bundle does not: published CSV headers are fixed at first publication and never gain a column, and the volatility leg files predate it. Every series published so far trades on a single venue, so a leg file is unambiguous without it.
Staleness is labeled, not hidden
stale is true when a level rests on inputs older than the freshness threshold. The level still publishes, and dataQuality on the latest endpoint reports how many constituents were fresh:
Corrections carry a revision
Every index level onlatest and in history carries revision: 0 for a level exactly as first published, 1 or higher once it has been corrected. The API serves the latest revision of each point. A corrected level is never changed silently, and the level as first published stays in the snapshot downloads. When and how a level is corrected is set out in Index Governance.
History windows clamp, they do not fail
History reaches back 90 days. A request for a longer window is clamped, not rejected: a chart that asked for a year still renders, andmeta reports what it actually got.
clamped before labeling a chart with the range you asked for. A window falling entirely before the floor returns an empty points array with clamped: true rather than an error.
An end in the future is clamped to now as well. What is a real error is a window that is empty once clamped – a start at or after end – because that is a mistake in your input rather than a limit of the free tier. It returns invalid_window, quoting both values as parsed, and names the future-end case outright when that is what emptied the window.
Full history since inception is in the free snapshot bundles.
Ordering
There is no cursor pagination. History is bounded by the window;
limit bounds the list endpoints that take one.
Tickers
Tickers are case-insensitive:conflict and CONFLICT resolve to the same index. Responses always echo the canonical uppercase form.
An unknown ticker, an unlisted series, and a series with no published values yet all return the same 404. A ticker that is not on the API is not distinguishable from one that does not exist.
Request ids
X-Request-Id is on every response, including the two pre-authentication rejections. On an error it is also in the body as error.requestId.
Quote it in any support message. It is what turns “I got a 500 around 14:02” into a single log lookup.
Versioning
/v1 is additive. New fields may appear in data or meta; existing fields will not change type or disappear without a new version. Parse defensively: ignore fields you do not recognize rather than rejecting the response.
Data boundaries states what each lane carries and how /v1 changes over time.