API roschart.ru
Rosstat statistics in JSON — the same dataset used to draw the website pages: 26 thousand datasets, 49 million values, updated every day
Quick start
Без ключа отвечает только первый запрос — сводка о базе. Для остальных нужен ключ: он бесплатный и выдаётся сразу после регистрации.
# what is available in the database and when it was updated
curl 'https://roschart.ru/api/meta'
# find datasets on inflation
curl -H 'X-API-Key: rk_…' 'https://roschart.ru/api/catalog?q=инфляция&limit=5'
# download one dataset with rows and values
curl -H 'X-API-Key: rk_…' 'https://roschart.ru/api/dataset/ipc-mes-06-2026-indeksy-potrebitelskih-cen-na-neprodovolstve'
Без ключа такие запросы получают ответ 401 со ссылкой на получение ключа.
Key and limitations
The key is passed in one of three ways:
X-API-Key: rk_…— mainAuthorization: Bearer rk_…;?key=rk_…— only for quick check: the key will be logged on the server and in the browser history
| Mode | Requests per minute | Per day | Records per request |
|---|---|---|---|
| without key | только /api/meta, остальное — 401 | ||
| with key | 120 | no cap | 1000 |
Access is free, including for commercial projects. A per-minute threshold is set to protect the server from looped requests; there is no limit on the volume of data retrieved
The limit is calculated per account, not per key: keys under the same account share a common quota. Using a separate key for each application is standard practice to track usage more clearly
Each response includes X-RateLimit-Tier,
X-RateLimit-Limit and X-RateLimit-Remaining. On failure — 429 and Retry-After in seconds: time to wait before retrying
Register and personal account.
General rules
All endpoints accept GET and return JSON in UTF-8 with the
okfield
{"ok": false, "error": "dataset not found"}
| Code | What happened |
|---|---|
| 200 | everything is fine |
| 304 | response unchanged since last time (see ETag below) |
| 400 | required parameter missing |
| 401 | key not found or disabled |
| 404 | no such dataset or path |
| 429 | frequency limit exceeded |
| 500 | server-side error |
Caching
Data is updated daily, but queried more frequently. Each response ETag, calculated from the body itself. Send it back If-None-Match and get 304 in a few bytes instead of a megabyte of JSON:
curl -H 'If-None-Match: "a1b2c3…"' 'https://roschart.ru/api/meta'
Even cheaper: remember upload_id from
/api/meta and do not re-download anything at all if it remains the same. This is one line for the entire export — if it has not changed, no value in the database has changed
Pages
Where there is a list, limit and
offsetwork, and the response contains total (total number of matches), count (number returned) and
offset. limit is silently truncated to the ceiling of your level — check count, not hoping that you requested a thousand and received a thousand
Cross-domain requests
Allowed from anywhere: Access-Control-Allow-Origin: *, so you can make a request directly from the browser. Note that the key in the page code is visible to everyone — anyone can spend your quota
Identifiers
The dataset identifier is a readable Latin string like
ipc-mes-06-2026-indeksy-potrebitelskih-cen-na-neprodovolstve. It is also in the website page address: /dataset/<id>. Identifiers are stable but not eternal: when correcting the name of a dataset, the address changes, and the old one starts redirecting to the new one. If you store the id yourself — check against
/api/changes.
What is a dataset
A dataset is a single sheet from a Rosstat book standardized to a common format. It is not an indicator: if Rosstat published industrial production in three tables, there will be three datasets
Within a dataset, everything is based on two parallel arrays:
periods[]— column captions:"2024","2024-Q1","2024-01"or arbitrary text if the table is not time-basedvalues[]each row has numbers of the same length and in the same ordernullmeans 'no data', and this is not zero. Gaps in statistics are common, and replacing them with zero is not allowed in any calculations
Two types of datasets differ by the kind:
timeseriesfield — time runs along the columns, there isfreq(annual,quarterly,monthly);crosssection— a snapshot at one point in time: regions, industries, age groups. Thenfreqequalsnone, and theperiodscontain the column captions of the table
A row, in addition to label, may have row and
col: in the original table the header is often two-tiered ('men / urban population'), and we keep both parts separately, while label — what is shown to the user
Unit of measurement (unit) may occur null: at Rosstat it is often written in the table title, there is no separate field in the book. Then see title and
footnotes.
Field title — cleaned-up name suitable for display
title_raw — exactly as printed in the book, with footnote numbers and years in brackets. Link to the dataset — source_url, it leads to the dataset page on the website; a direct link to the Rosstat book is in source_file.
Handles
GET /api/meta — database status
Weighs less than a kilobyte. It is convenient to start synchronization with it: if
upload_id has not changed, the rest does not need to be
{
"ok": true, "ready": true,
"upload_id": "90ae18251ef86537",
"generated_at": "2026-08-11T18:23:48+00:00",
"committed_at": "2026-08-11T19:02:51+00:00",
"source": "https://rosstat.gov.ru/",
"n_datasets": 26461,
"n_values": 49100146,
"breakdown": [{"kind": "crosssection", "freq": "none", "c": 18141, "v": 44485654}, …]
}
generated_at — when the parser parsed the books,
committed_at — when the upload was accepted by the site
ready: false means that the upload is currently in progress: the data being provided at this moment are the previous, complete data
GET /api/sections — sections
Rosstat rubrics with the number of datasets and values in each. Section names differing only by the year of publication of the collection are merged into one: the year of publication within the name is irrelevant
{"ok": true, "sections": [ {"section": "Industrial production", "c": 2694, "v": 6329150}, …]}
GET /api/catalog — dataset search
| Parameter | Value |
|---|---|
q | search string by name; can be in Russian, case does not matter |
kind | timeseries or crosssection |
freq | annual, quarterly, monthly |
section | section exactly as it came in /api/sections |
flat | 1 — do not collapse releases of the same indicator into one row |
group | group key from group_key: all editions of one indicator |
limit, offset | page; default 60 |
Rosstat publishes the same table every month as a new book, and without grouping, a search for the word "inflation" would return forty almost identical lines. By default, such editions are collapsed into one most recent set with the field
n_editions; expand group — group= with its
group_key, disable collapsing altogether —
flat=1.
{"ok": true, "total": 437, "count": 2, "offset": 0, "items": [ {"ds_id": "ipc-mes-06-2026-…", "title": "consumer price index…", "unit": null, "freq": "monthly", "kind": "timeseries", "section": "Prices, inflation", "n_series": 2, "n_periods": 432, "n_values": 462, "period_first": "1991-01", "period_last": "2026-12", "content_hash": "489e37d1b955a6e4", "group_key": "f9aa1ee825d27982", "n_editions": 1, "source_url": "https://roschart.ru/dataset/…", "source_file": "https://rosstat.gov.ru/storage/…xlsx"}, …]}
content_hash is calculated from the values of the set. If matched — the content is exactly the same as what you have already downloaded, no need to retrieve it
GET /api/ids — all identifiers
Compact list: id, title, kind, frequency. Needed to set up your own mirror of the catalogue without downloading the entire sets
Parameters: limit, offset and
updated_since — date in the format 2026-08-01, after which the set changed. With it, the sweep becomes additional: once every couple of days you ask what has changed since the last reconciliation day, and only transfer that
GET /api/dataset/{id} — entire dataset
| Parameter | Value |
|---|---|
max_series | number of rows to return; regional datasets can have up to two thousand |
q | select rows by substring in the label — for example, only "Moscow |
limit, offset | page by rows |
format=csv | return as table, not JSON |
{"ok": true, "dataset": { "id": "…", "title": "…", "unit": null, "freq": "monthly", "kind": "timeseries", "section": "Prices, inflation", "source_url": "https://roschart.ru/dataset/…", "source_file": "https://rosstat.gov.ru/…xlsx", "source_via": "https://roschart.ru/go/ds/…", "periods": ["1991-01", "1991-02", …], "series": [{"label": "by the end of the previous month", "row": "by the end of the previous month", "col": null, "values": [109.0, 105.9, 104.6, …]}], "series_total": 2, "series_shown": 1, "n_series": 2, "n_periods": 432, "n_values": 462, "footnotes": […], "related": […], "intro": "…", "tags": […], "title_raw": "…", "description": "…"}}
If series_shown less series_total, you did not receive the entire dataset related — adjacent datasets of the same indicator, footnotes — footnotes from the book; they contain Rosstat disclaimers such as "excluding Crimea"
CSV is convenient for export to a table and is provided with a header
Content-Disposition, i.e. downloaded as a file:
curl -o ipc.csv 'https://roschart.ru/api/dataset/ipc-mes-06-2026-…?format=csv'
GET /api/series/{id}/{i} — one series
Series number i: numbering starts from zero, the order is the same as in the dataset. Useful when only one line is needed instead of the entire dataset
GET /api/chart/{id} — ready-made chart
Provides the same as shown on the website page: chart type, selected series, axis labels, colors, footnote. Eliminates the need to decide how to visualize the dataset — as a line, bar chart, or heatmap for two thousand regions
Parameters: q — series selection, theme=dark — colors for dark theme. In addition to the
periods and series, the response includes
chart_kind, y_axis, row_label
and note.
GET /api/revisions/{id} — retroactive revisions
Rosstat revises already published figures: if the methodology is refined, last year's value changes. We store previous values and provide what exactly changed: period, old value, new value, and the date of the revision. The original source does not retain the old value
GET /api/changes — change log
What happened between exports: datasets were added, changed, or removed. Parameters: kind
(added | changed |
removed), id — history of a single dataset,
limit, offset.
{"ok": true, "total": 1123,
"batches": [{"changed_at": "2026-08-10T08:11:13+00:00", "added": 140, "changed": 2, "removed": 1}, …],
"items": [{"changed_at": "…", "ds_id": "…", "kind": "removed", "title": "…",
"old_values": 96, "new_values": 0, "old_last": "2017"}, …]}
The same is available as a feed: /changes/rss.xml.
GET /api/suggest — search suggestions
By the beginning of the word returns clarifications and suitable sets — the same as falls under the search line on the site. For a full-fledged search — /api/catalog.
Recipes
Download the entire catalogue
26 thousand sets — this is 27 queries with a key by 1000 records. Will fit in about three minutes
off=0
while :; do
n=$(curl -s -H "X-API-Key: $KEY" \
"https://roschart.ru/api/ids?limit=1000&offset=$off" \
| tee -a ids.jsonl | grep -o '"count":[0-9]*' | cut -d: -f2)
[ "$n" -lt 1000 ] && break
off=$((off + 1000))
done
Keep your copy up to date
- ask once a day /api/meta;
- if
upload_idthe previous one — finish with this - if the new one — take /api/changes and update only the sets listed there
- compare
content_hashbefore uploading: it changes only together with the values
A full traversal with each download is also possible, but excessive: only a few hundred sets out of twenty-six thousand change with each download
Display the chart on your side without drawing it
For this, the API is not needed: /embed/<id> — a page with iframe,
/og/<id>.png — a 1200×630 image for social networks
What is not in the data
Limitations you should know about in advance:
- Values are transferred from published tables as is: no smoothing, seasonal adjustment, or recalculation into comparable prices
- Series are not stitched between releases: if Rosstat changed the methodology or classifier, adjacent sets may not match
- The unit of measurement may be missing — it is not in the book itself
- Transfer errors are possible: tables are parsed automatically, and merged cells are sometimes read incorrectly. Each page of the dataset has an "Report an error" button
Terms and source reference
Rosstat data are open and available for free use, including commercial use. Requirements of the primary source — to retain the reference to the source and not to distort the figures — also apply to those who take data from us. Details on the page terms of use. What the site does with the data of those who created a key — in personal data processing policy.
Linking to roschart.ru is encouraged: the reader will reach the original table and its footnotes
Machine-readable description of the same endpoints — /openapi.json or /openapi.yaml (OpenAPI 3.0.3, identical content), it is used to generate clients for Swift, Kotlin, Dart and other languages
The catalogue composition is published as a separate snapshot with a permanent identifier: doi.org/10.5281/zenodo.22107658 — metadata for all datasets in a table, with links to each download
Need a higher limit or non-standard download — contact us.