rustata экономическая статистика РФ - поиск по 2,3 млн рядов

API

Российская статистика приходит прямо в ваши модели, дашборды и внутренние системы: JSON или CSV, готовые ряды вместо разбора выгрузок, с указанием происхождения каждой цифры.

Публичная витрина бесплатна. Программный доступ для компаний работает на коммерческих условиях, но начать можно с бесплатного тарифа: он не урезан по данным, ограничен только объём выгрузки.

Начать Данные по территориям Примеры Справочник

Начать за три шага

  1. Заведите учётную запись В личном кабинете введите почту и получите ссылку для входа. Пароля нет: в следующий раз вход тоже по ссылке на почту.
  2. Выпустите токен Он показывается один раз, поэтому сразу сохраните его. Токенов может быть несколько, например по одному на проект.
  3. Передавайте его заголовком Подходит любой из двух видов: Authorization: Bearer или X-API-Key.

Первый запрос: средняя цена пива по всем регионам с начала 2024 года

curl -H "Authorization: Bearer ВАШ_ТОКЕН" \
  "https://rustata.ru/api/v1/data?dataset=fedstat/indicator_31448&class=3203&geo=region&start=2024-01"

Данные по территориям

Главный метод - GET /api/v1/data. Он отдаёт показатель сразу по многим территориям, поэтому «цены на пиво по всем регионам» это один запрос, а не восемьдесят пять.

Собирать данные пачками выгодно и по расходу квоты: она считается в значениях, поэтому один срез по всем регионам стоит ровно столько, сколько в нём точек, - а восемьдесят пять отдельных запросов стоили бы столько же плюс время на них.

Параметры

ПараметрЧто задаёт
datasetнабор данных, например fedstat/indicator_31448. Обязателен
geoуровень территории или перечень кодов через запятую
classкод продукта в классификаторе набора
measure, transformationвид показателя и преобразование
freq, unitчастота и единица измерения
start, endпериод; можно писать месяцем: 2024-01
formatjson (по умолчанию) или csv
limit, offsetсколько рядов взять и с какого начать
bomтолько для CSV: 1 добавляет BOM для Excel на Windows

Уровни территории

geoЧто вернётсяТерриторий
countryРоссия целиком1
districtфедеральные округа13 с историческими
macroregionэкономические районы (прежнее деление)11
regionсубъекты федерациидо 85
cityгорода и районы внутри субъектовсотни
allвсе уровни сразу-
46000000000,RU-50только перечисленные территориипо списку

Коды принимаются в обоих видах: исходный ОКАТО и наш нормализованный (RU-46). Угадывать территорию по коду не придётся: у каждого ряда в ответе есть geo, geo_label и geo_level.

Все территории с их кодами - в справочнике территорий. Оттуда же удобно брать коды, когда нужны не все регионы, а несколько конкретных.

Коды продуктов

Классификатор у каждого набора свой: в потребительских ценах это номер товара из корзины Росстата, в промышленности - код ОКПД2. Что подставлять в class, показано в справочнике кодов - по каждому набору отдельная таблица с поиском по названию.

Россия приходит двумя рядами

«Российская Федерация» и «Российская Федерация без учёта новых субъектов (с 01.01.2023)» - оба на уровне country.

Это не дубль, а две методики счёта. Различить их можно по полю geo_label, выбор между ними за вами.

Что приходит в ответе

Ответ состоит из двух частей: список рядов с описанием территории и плоский список значений, по строке на каждое.

Такая форма разворачивается в привычную таблицу «период на территории» одной строкой кода и не требует разбирать многоэтажную шапку, как в исходных выгрузках.

{
  "series": [
    { "series_key": "s1_23sqev7ozzer4t73", "geo": "14000000000",
      "geo_label": "Белгородская область", "geo_level": "region",
      "title": "Пиво отечественное, л", "freq": "M", "unit": "RUB" }
  ],
  "observations": [
    { "series_key": "s1_23sqev7ozzer4t73", "period": "2025-06-01",
      "value": 198.23, "as_of": "2025-06-01" }
  ],
  "series_count": 100, "series_total": 470,
  "offset": 0, "has_more": true, "next_offset": 100
}

На каждый период приходит одно значение - последняя опубликованная оценка.

Рядом идёт as_of: дата публикации именно этой оценки. Статистику уточняют задним числом, и по этому полю видно, какая версия цифры у вас на руках.

В CSV те же данные с разделителем ; и колонками series_key;geo;geo_label;geo_level;period;value;as_of. Кодировка UTF-8 без BOM: так её ждут pandas, readr и CSV.jl. Для Excel на Windows добавьте &bom=1, иначе кириллица откроется кракозябрами.

Примеры

Все три примера решают одну задачу: берут среднюю цену пива по регионам с начала 2024 года и разворачивают в таблицу «период на территории». Каждый проверен исполнением.

Python

import pandas as pd
import requests

TOKEN = "rst_ваш_токен"
resp = requests.get(
    "https://rustata.ru/api/v1/data",
    params={"dataset": "fedstat/indicator_31448", "class": "3203",
            "geo": "region", "start": "2024-01"},
    headers={"Authorization": f"Bearer {TOKEN}"},
    timeout=60,
)
resp.raise_for_status()
payload = resp.json()

series = pd.DataFrame(payload["series"]).set_index("series_key")
obs = pd.DataFrame(payload["observations"])
obs["region"] = obs["series_key"].map(series["geo_label"])
obs["period"] = pd.to_datetime(obs["period"])

table = obs.pivot(index="period", columns="region", values="value")
print(table.tail())

# у тарифов без месячной квоты этого заголовка нет, поэтому .get, а не []
print("остаток квоты:", resp.headers.get("X-Quota-Values-Remaining", "без ограничения"))

R

library(httr)
library(readr)
library(tidyr)

# Windows: если консоль печатает кириллицу как <U+0411><U+0435>…, дело в локали сессии,
# а не в данных - сами строки целы. Лечится одной строкой:
if (.Platform$OS.type == "windows") Sys.setlocale("LC_CTYPE", "Russian_Russia.utf8")

token <- "rst_ваш_токен"
resp <- GET(
  "https://rustata.ru/api/v1/data",
  query = list(dataset = "fedstat/indicator_31448", class = "3203",
               geo = "region", start = "2024-01", format = "csv"),
  add_headers(Authorization = paste("Bearer", token))
)
stop_for_status(resp)

# content(resp, "raw") + locale(): readr сам разбирает UTF-8, без промежуточной строки
df <- read_delim(content(resp, "raw"), delim = ";",
                 locale = locale(encoding = "UTF-8"), show_col_types = FALSE)
table <- pivot_wider(df, id_cols = period, names_from = geo_label, values_from = value)
head(table)

Julia

using HTTP, CSV, DataFrames

token = "rst_ваш_токен"
resp = HTTP.get("https://rustata.ru/api/v1/data";
    query = Dict("dataset" => "fedstat/indicator_31448", "class" => "3203",
                 "geo" => "region", "start" => "2024-01", "format" => "csv"),
    headers = ["Authorization" => "Bearer $token"])

df = CSV.read(IOBuffer(resp.body), DataFrame; delim = ';')
table = unstack(df, :period, :geo_label, :value)
first(table, 5)

Справочник

Методы

МетодЧто делает
GET /api/v1/dataсрез показателя по территориям, JSON или CSV
GET /api/v1/series/searchпоиск рядов по строке, отдаёт series_key
GET /api/v1/series/{series_key}/observationsзначения одного ряда
GET /api/v1/series/{series_key}/evidenceпроисхождение: файл-источник, релиз, прогон загрузки
GET /api/v1/concepts/searchпоиск показателей, а не отдельных рядов
GET /api/v1/concepts/{concept_id}карточка показателя со сводкой

Интерактивный справочник, где запрос можно выполнить своим токеном прямо в браузере - Swagger. Машиночитаемое описание - openapi.json.

Лимиты

ТарифЗначений в месяцЗапросов в минуту
бесплатный100 00020
академическийбез ограничения120
коммерческийбез ограничения120

Квота считается в значениях, а не в запросах. Один запрос возвращает то десяток точек, то десятки тысяч, поэтому счёт запросов не отражал бы ни пользы вам, ни нагрузки на нас.

100 000 значений - это, например, два десятка полных срезов по всем регионам за десять лет или сотни небольших выборок. Для знакомства, учёбы и разовых расчётов этого хватает; для регулярной работы напишите нам.

Отдельно стоит минутный лимит запросов: он про всплески, а не про объём. Отклонённый запрос квоту не расходует.

Остаток приходит в заголовках X-Quota-Values-Remaining и X-RateLimit-Remaining-Minute. При отказе 429 в Retry-After сказано, через сколько секунд повторять.

Академический тариф - для университетов, научных институтов и их сотрудников: месячной квоты у такой учётной записи нет. Для части организаций он включается автоматически при входе с рабочей почты, просить ничего не нужно.

Если вы из научной организации и упёрлись в квоту, напишите через форму связи - подключим. Нужен объём для компании - тоже напишите, обсудим условия под задачу.

Постраничная выдача

За один раз приходит 100 рядов, параметром limit можно взять до 300. Сколько подходит всего, видно в series_total, а next_offset подсказывает, с чего начать следующую страницу.

Постранично идут ряды, а не значения: каждый ряд приходит целиком по времени, склеивать разрезанную историю не нужно.

Потолок ответа - 60 000 значений. Если страница набирает больше, придёт SLICE_TOO_BIG: сузьте период или уменьшите limit. Потолок нужен не для строгости - ответ целиком собирается в памяти сервера, который обслуживает и сайт.

Кэширование

Ответ несёт ETag и Cache-Control на час. Повторите запрос с этим ETag в заголовке If-None-Match - придёт 304 без тела, за десяток миллисекунд и без расхода квоты.

ETag меняется при любом обновлении данных набора: не только когда выходит новый период, но и когда пересматривают старое значение. На него можно опираться в регулярной загрузке: пришло 304 - у вас уже актуальная копия.

curl -H "Authorization: Bearer ВАШ_ТОКЕН" \
     -H 'If-None-Match: W/"b3392e076b592a86b3f8"' \
     "https://rustata.ru/api/v1/data?dataset=fedstat/indicator_31448&class=3203&geo=region"

Ошибки

Все ошибки выглядят одинаково, каким бы методом вы ни пользовались: код, объяснение и номер запроса.

Номер стоит сохранять в логах: по нему мы найдём конкретный запрос и разберём, что пошло не так. Он же приходит в заголовке X-Request-Id при удачных ответах.

{
  "error": { "code": "RATE_LIMITED",
             "message": "Исчерпана месячная квота тарифа: 100 000 значений…" },
  "request_id": "req_4325b22dc77347b1"
}
КодHTTPКогда
UNAUTHENTICATED401токен не передан
INVALID_TOKEN401токен неизвестен или отозван
RATE_LIMITED429исчерпана квота тарифа
SLICE_TOO_BIG400запрос выбирает слишком много данных
NOT_FOUND404под фильтры ничего не подошло
INTERNAL500ошибка на нашей стороне

Что дальше

В планах:

Расскажите через форму связи, чего не хватает вам - это прямо влияет на очередь работ.