/v1 endpoint. The four that most often surprise people are decimal strings, the volatility timestamp format, 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
Timestamps are UTC with microsecond precision.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:
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.