Read-only доступ к данным о политических преследованиях в России
API предоставляет структурированный доступ к данным о политических преследованиях в России. Данные обновляются несколько раз в сутки.
Это экспериментальный API — структура эндпоинтов и набор полей могут меняться.
Базовый URL: https://api-data.ovd.info · Swagger UI: /docs
Все запросы (кроме GET /datasets и ссылок на фото — см. «Фотографии») требуют заголовок:
X-API-Key: <ваш_ключ>
Для получения ключа обратитесь к команде ОВД-Инфо по адресу [email protected]. Ключ выдаётся один раз — сохраните его.
| Метод | Путь | Описание | Ключ |
|---|---|---|---|
| GET | /datasets | Схема датасетов: колонки, фильтры | Нет |
| GET | /persons | Список персон с фильтрацией и поиском | Да |
| GET | /persons/{id} | Персона по UUID | Да |
| GET | /organisations | Список организаций | Да |
| GET | /organisations/{id} | Организация по UUID | Да |
| GET | /pp_persecutions | Политические преследования | Да |
| GET | /profiles | Карточки персон (адрес для писем, «Весточка», имя/история/статус) | Да |
| GET | /profiles/{id} | Карточка персоны по id (?subset=full — + уголовные дела, реестры, оценки правозащитников, хронология событий одним ответом) | Да |
| GET | /v1/persons/{id}/photo/{photo_id}[/{size}] | Фото персоны — оригинал или один из размеров, см. «Фотографии» | Нет |
| Параметр | Тип | Описание |
|---|---|---|
limit | int | Строк в ответе (по умолчанию 100, макс. 1000) |
offset | int | Смещение для пагинации. Ответ содержит total — общее число строк с учётом фильтров. Взаимоисключим с cursor |
cursor | str | Значение next_cursor из предыдущего ответа — устойчивая keyset-пагинация без дублей/пропусков при обходе больших списков (в отличие от offset, не зависит от того, есть ли в данных повторяющиеся значения sort-колонки, например updated_at у пачки записей одного импорта). Переопределяет sort/order значениями, с которыми был выпущен — см. «Пагинация» ниже |
q | str | Поиск подстроки по всем search-полям одновременно |
{col} | str | Точный фильтр по filter-полю. Поддерживает операторы — см. ниже |
subset | str | Подмножество колонок: rfm или inoteka — подробнее ниже |
sort | str | Имя колонки для сортировки. Только колонки, входящие в текущий ответ |
order | str | asc (по умолчанию) или desc |
timeline | bool | Только /persons/{id} — добавляет persecutions[] с преследованиями |
Все filter-поля поддерживают расширенные операторы через суффикс __{оператор}:
| Синтаксис | Оператор | Пример |
|---|---|---|
?{col}=val | Точное совпадение | ?persecution_status=Осуждён |
?{col}__gt=val | Больше чем | ?start_year__gt=2021 |
?{col}__gte=val | Больше или равно | ?updated_at__gte=2026-08-01 |
?{col}__lt=val | Меньше чем | ?verdict_date__lt=2024-01-01 |
?{col}__lte=val | Меньше или равно | ?verdict_date__lte=2023-12-31 |
?{col}__in=a,b,c | Одно из значений | ?region__in=Москва,Санкт-Петербург |
Операторы можно комбинировать: ?start_year__gte=2020&start_year__lt=2023
По умолчанию возвращаются только базовые поля (имя, дата рождения, ИНН). Параметр subset добавляет тематический блок:
| Значение | Добавляет |
|---|---|
subset=rfm | Флаги источников, pp_person_id и все поля из реестра Росфинмониторинга |
subset=inoteka | Поля из реестра иностранных агентов: статус, основание признания, тематика, год признания/исключения, флаги прекращения работы |
Для /organisations параметра subset нет — все поля возвращаются всегда. Записи с do_not_publish возвращаются, но с обнулёнными идентификаторами и описаниями.
Рекомендуется — курсор (cursor). Сортировка на большом списке почти всегда содержит повторяющиеся значения (например, у пачки записей, обновлённых одним импортом, совпадает updated_at) — офсетная пагинация в этом случае может отдать одну и ту же строку дважды или пропустить её при переходе между страницами. Курсор кодирует позицию последней строки (значение сортировки + внутренний id-тайбрейкер) и не зависит от такого совпадения. Задайте sort в первом запросе — дальше просто передавайте next_cursor из ответа, пока он не станет null; sort/order повторно передавать не нужно, курсор уже их несёт.
# Загрузить все записи, устойчиво к дублям/пропускам import requests API = "https://api-data.ovd.info" KEY = {"X-API-Key": "<ваш_ключ>"} params = {"limit": 1000, "sort": "updated_at", "order": "desc"} rows = [] while True: r = requests.get(f"{API}/persons", headers=KEY, params=params).json() rows.extend(r["data"]) if not r["next_cursor"]: break params = {"limit": 1000, "cursor": r["next_cursor"]}
Альтернатива — offset. Проще для разовой выгрузки небольшого списка, но не гарантирует отсутствие дублей/пропусков при сортировке с повторяющимися значениями.
# Загрузить все записи постранично (offset) import requests API = "https://api-data.ovd.info" KEY = {"X-API-Key": "<ваш_ключ>"} params = {"limit": 1000, "offset": 0} rows = [] while True: r = requests.get(f"{API}/persons", headers=KEY, params=params).json() rows.extend(r["data"]) if params["offset"] + 1000 >= r["total"]: break params["offset"] += 1000
persons/organisations/profiles отдают updated_at, а pp_persecutions — last_updated; обе колонки filter, то есть поддерживают операторы __gt/__gte/__lt/__lte (см. таблицу операторов выше). Для регулярного (например, ежедневного) импорта не нужно перечитывать весь датасет — достаточно отфильтровать по отметке времени последней успешной синхронизации, отсортировать по той же колонке и пройти курсором:
# Только записи, изменённые после последней синхронизации import requests API = "https://api-data.ovd.info" KEY = {"X-API-Key": "<ваш_ключ>"} params = { "limit": 1000, "updated_at__gte": "2026-08-25T00:00:00", # отметка предыдущего запуска "sort": "updated_at", "order": "asc", } rows = [] while True: r = requests.get(f"{API}/profiles", headers=KEY, params=params).json() rows.extend(r["data"]) if not r["next_cursor"]: break params = {"limit": 1000, "cursor": r["next_cursor"]} # следующий запуск — updated_at__gte = время начала ЭТОГО запуска (не последней строки из rows)
Отметку для следующего запуска берите из времени начала текущего запуска, а не из updated_at последней полученной записи — иначе запись, изменённая в БД в момент между вашими запросами первой и последней страницы, может быть пропущена.
Ссылки на фото — в полях photos и photo_variants датасета profiles. Это готовые публичные URL для прямой вставки в <img src>: ключ им не нужен.
photos — список ссылок на оригиналы (JPEG/PNG как загружены, часто несколько мегабайт). photo_variants — для каждой ссылки из photos, в том же порядке, набор уменьшенных копий:
"photo_variants": [{
"original": "https://api-data.ovd.info/v1/persons/<id>/photo/<photo_id>",
"thumb": "https://api-data.ovd.info/v1/persons/<id>/photo/<photo_id>/thumb",
"card": "…/card",
"medium": "…/medium",
"og": "…/og"
}]
| Размер | Пиксели | Формат | Для чего |
|---|---|---|---|
thumb | 128×128, квадрат | WebP | Списки, аватарки |
card | 512×512, квадрат | WebP | Карточки |
medium | до 1024 по длинной стороне, пропорции оригинала | WebP | Страница персоны, статьи |
og | 1200×630 | JPEG | Превью ссылок в соцсетях (og:image) — часть соцсетей не показывает WebP |
Квадраты и og обрезаются по центру по горизонтали и со смещением вверх по вертикали, чтобы не срезать лицо. Фото меньше нужного размера не увеличиваются. Из уменьшенных копий удалены метаданные (EXIF: геометка, модель камеры, дата съёмки).
Шаблон URL стабилен: размер можно получить, дописав /{size} к ссылке из photos. Ответы кэшируются на сутки (Cache-Control: public, max-age=86400). Если фото сняли с публикации или персона попросила скрыть данные, все ссылки на это фото, включая размеры, начинают отдавать 404 сразу, не дожидаясь обновления датасета.
# Поиск по имени curl "https://api-data.ovd.info/persons?q=Иванов" \ -H "X-API-Key: <ваш_ключ>" # Персоны с полным набором полей РФМ curl "https://api-data.ovd.info/persons?subset=rfm&in_rosfinmon=true" \ -H "X-API-Key: <ваш_ключ>" # Иностранные агенты — все поля + фильтр по статусу (contains-any по всем статусам записи) curl "https://api-data.ovd.info/persons?subset=inoteka&in_inoteka=true&inoteka_statuses=Физическое лицо — иностранный агент" \ -H "X-API-Key: <ваш_ключ>" # Организации — иноагенты, не прекратившие работу, признанные с 2020 года curl "https://api-data.ovd.info/organisations?inoteka_stopped_working=false&inoteka_first_recognition_year__gte=2020" \ -H "X-API-Key: <ваш_ключ>" # Персона с историей преследований curl "https://api-data.ovd.info/persons/<uuid>?timeline=true" \ -H "X-API-Key: <ваш_ключ>" # Активные преследования curl "https://api-data.ovd.info/pp_persecutions?is_actual=true" \ -H "X-API-Key: <ваш_ключ>"
Изменения, затрагивающие ответы Public API и Legacy V1. новое — добавлено, старое поведение не меняется; изменено — меняется существующий ответ.
/v1/persons/{id}/photo/{photo_id}/{thumb|card|medium|og} и поле profiles.photo_variants — см. «Фотографии». Поле photos не изменилось.person_photo/photo ведут на квадрат 512×512 WebP (…/card) вместо оригинала. Оригинал — та же ссылка без /card. Старые ссылки без размера продолжают работать.profiles.accepting_letters/online_letters_now, в Legacy V1 — online_letters и пресеты letters/letters-now — false, если известна смерть.pp_persecutions.case_group_names — группы дел (filter).persecution_action_fact_en теперь заполнено; без перевода в *_en приходит русский текст, а не null.pp_persecutions: case_name_en, verdict_essence_en, verdict_court_en, first_verdict_essence_en, first_verdict_court_en, imprisonment_location_en. profiles: personal_info_en, imprisonment_location_en. В GET /datasets у колонок появился label_en.pp_persecutions.counts_since_2012, profiles.counts_since_2012 и profiles.persecution_ongoing_since_2012 (есть незакрытое дело с 2012 года). Сами данные до 2012 года остаются в выдаче.pp_persecutions больше не исключает дела персон, скрытых из продуктовой выдачи, — вместо этого у строк колонка hide_from_products (filter), как в profiles.Актуальная схема — колонки, какие из них фильтруемые и поисковые, к какому subset относятся. Ключ не нужен.
registries и timeline сюда не попадают — это не колонки profiles.parquet, а поля, которые добавляются на лету только в ответе GET /profiles/{id}?subset=full (не в списке GET /profiles и не в этой схеме). cases/evaluations — настоящие колонки (subset: full), появятся в таблице ниже.