Responses and sources¶
All REST endpoints return JSON in one of two shapes: a success envelope or an error body.
The envelope¶
{
"data": { "...": "endpoint-specific payload" },
"meta": {
"sources": [
{"source_id": "cbr", "fetched_at": "2026-11-13T17:30:30.332163+00:00", "as_of": "2026-11-13"}
],
"request_id": "d6ad2bac8fbe490497fee29ce822951b",
"truncated": false
}
}
| Field | Type | Meaning |
|---|---|---|
data |
object | The payload. List-style endpoints use {"rows": [...], "row_count": n, "truncated": bool}; dossier-style endpoints (product check, company card, restrictions, sanctions check) use named blocks. See each endpoint page. |
meta.sources |
array | One entry per data source that contributed to this response. Empty for responses that carry no data from a source (/v1/health, /v1/sources, /v1/sources/freshness). |
meta.request_id |
string | Hex id of this request. Identical to the X-Request-Id response header. |
meta.truncated |
boolean | true when a row cap cut the result (see below). Mirrors data.truncated when the payload has one, otherwise false. |
Errors use a different body, with no data and no meta: {"error": {"code": "...", "message": "..."}}. See Errors.
meta.sources: source_id, fetched_at, as_of¶
Every number the API returns can be traced to a source. Each entry in meta.sources has three fields:
| Field | Type | Meaning |
|---|---|---|
source_id |
string | Identifier of the data source (cbr, evds, tim, tuik_trade ...). The full list with names is in GET /v1/sources and in Coverage and freshness. |
fetched_at |
string or null | When this source was last refreshed successfully, ISO 8601 timestamp in UTC. null if it has never succeeded. |
as_of |
string or null | The newest data date among the rows of this source in this response. A date (2026-10-01), or a timestamp for news. null when the data has no meaningful date (for example some sanctions lists and the Common High Priority Items List, which carry no dated observations). |
Why two dates? They answer different questions.
fetched_atsays how recently the service checked the publisher. It tells you whether the pipeline is alive.as_ofsays how recent the data itself is. It tells you what period the numbers describe.
A real example from GET /v1/latest: the Bank of Russia key rate is refreshed on the afternoon of 2026-11-13 and its newest value is dated 2026-11-13, so both dates agree. The TİM export figure was fetched the same morning, but the newest month it contains is October 2026 (2026-10-01), because TİM publishes monthly:
{
"sources": [
{"source_id": "cbr", "fetched_at": "2026-11-13T17:30:30.332163+00:00", "as_of": "2026-11-13"},
{"source_id": "tim", "fetched_at": "2026-11-13T09:45:38.503380+00:00", "as_of": "2026-10-01"}
]
}
Reading them together:
- A recent
fetched_atwith an oldas_ofis normal for monthly and quarterly data: the publisher has not released anything newer. It is not a stale pipeline. - An old
fetched_atmeans the refresh has been failing or is overdue; checkGET /v1/sources/freshness(Coverage and freshness). fetched_atis the time of the last successful run, not proof that something changed in that run.- Monthly observations are dated on the first day of the month they describe:
2026-10-01means October 2026.
as_of is computed from the rows in the response, not from the whole series. If you request a window that ends earlier than the newest data, as_of reflects your window.
Warning
When a response is truncated, the rows you received are not necessarily the newest ones. GET /v1/series/ru.key_rate with no start returns the oldest 2000 rows, and its meta.sources[0].as_of is 2023-01-10, not today. Always pass start for long daily series, or use resample.
Truncation and row caps¶
There is no pagination. Instead every endpoint has a cap on rows, and the response tells you when the cap was hit:
data.truncatedandmeta.truncatedaretrue.data.row_countis the number of rows actually returned, not the number that matched.
A real example, GET /v1/changes?since=2026-11-01&limit=3 (the full list has hundreds of entries; three rows were returned):
(Rows abbreviated here; …3 rows… is a placeholder, not part of the response.)
| Endpoint | Row cap |
|---|---|
/v1/series, /v1/series/{id}, /v1/latest, /v1/sources and other table-style results with no limit parameter |
2000 rows |
/v1/changes |
limit, at most 1000 (default 200) |
/v1/companies/search |
limit, at most 100 (default 25) |
/v1/sanctions/check |
limit, at most 50 (default 15) |
/v1/calendar |
300 rows (no limit parameter; narrow with days, kind, country) |
/v1/docs/search |
limit, at most 30 (default 8) |
/v1/border/arrivals |
limit, at most 2000 (default 200) |
/v1/news/search, /v1/news/latest |
limit, 1 to 100 (defaults 20 and 30) |
To get everything when a result is truncated, narrow the request: a shorter start/end window, resample=month, a more specific filter, or several requests with consecutive windows.
Request ids¶
Every response, success or error, carries an X-Request-Id header. On success the same value is in meta.request_id. Error bodies do not contain it, so read the header. When you report a problem (FAQ), include the request id, the URL and the time.
JSON types¶
| Kind | Representation | Example |
|---|---|---|
| Dates | ISO 8601 YYYY-MM-DD strings |
"obs_date": "2026-10-01" |
| Timestamps | ISO 8601 with UTC offset | "fetched_at": "2026-11-13T17:30:30.332163+00:00", "published_at": "2026-11-13T18:48:34+00:00" |
| Numbers | JSON numbers. Decimals are converted to floating point, so large values can carry floating-point noise. | 457415414.52000004 (round it for display) |
| Counts | JSON integers | "visitors": 203733, "row_count": 2 |
| Booleans | true / false |
"truncated": false |
| Missing values | null. Missing is not zero: a null value means no figure, 0.0 means a reported zero. |
"as_of": null, "name_en": null |
| Text | UTF-8, including Turkish and Cyrillic characters. Decode responses as UTF-8. | "name_ru": "ОАО \"РЖД\"" |
| Units | Carried in the data (unit field on series rows: %, USD, RUB per USD, USD bn ...), never implied |
see Series ids and units |
Series observations are in long format: one row per series_id and obs_date.
With resample, rows also carry period (the first day of the week, month, quarter or year) and obs_date (the last observation date inside that period):
Responses over MCP¶
MCP tools return the same data as a JSON string in the tool result text, with the sources as a top-level sources array next to the payload keys instead of an envelope. Fields and values are the same as in REST. Errors come back as {"error": {"code": ..., "message": ...}} inside the tool result. See the MCP pages.
No pagination¶
There are no page, offset or cursor parameters anywhere. Result size is controlled per endpoint by limit (where the endpoint has one), by date windows and by filters. If you need a long history, request it in windows or resample.