/v1/openapi.jsonСпецификация OpenAPI
Этот самый файл. Открыт без ключа: инструкция не должна быть спрятана от того, кому она нужна.
Ответы
- 200
- Спецификация
Проверка контрагентов из ваших систем: ключ, запрос, ответ
API: эндпоинты ещё закрыты — ключ можно завести заранее, запросы по нему пока не принимаются
Authorization: Bearer … в каждом запросе. первый запрос
export RUVISOR_API_KEY=sb_live_…
curl https://api.ruvisor.pro/v1/companies/7707083893 \
-H "Authorization: Bearer $RUVISOR_API_KEY"Десять знаков ИНН у юрлица, двенадцать у ИП.
Платит компания, а не HTTP-вызов: одно списание открывает окно на 15 минут, и внутри него эту же компанию можно читать сколько угодно раз.
Баланс расходуется медленно
Свежая проверка идёт в государственные реестры, и их темп мы не выбираем: больше двух холодных проверок в минуту не получится. Даже непрерывная работа сутками тратит баланс медленнее, чем кажется, — если вам нужна разовая выгрузка на тысячи компаний, напишите нам, это делается иначе.
Чтение готового досье укладывается в доли секунды. Свежая проверка идёт в государственные реестры, и это минуты — не потому, что мы медленные, а потому что темп там задаём не мы.
Настройте таймауты на своей стороне
На POST /v1/check ставьте не меньше 30 секунд: мы держим соединение до десяти, и обрыв по вашему таймауту не отменит уже начатую сборку — запрос будет списан, а ответ вы не увидите. Остальным вызовам хватит 15 секунд. Заголовок Retry-After при 202 и 429 уважайте: опрос чаще ничего не ускоряет, а частотный бюджет тратит.
Ждать исход проверки опросом не нужно. Заведите адрес на странице API и интеграции, выберите события — и мы придём сами, как только соберём — и принесём досье целиком, а не приглашение зайти за ним. Отвечать надо быстро: примите событие, положите в свою очередь и верните 2xx. Всё, что вы делаете дольше десяти секунд, для нас выглядит как недоступность.
что придёт на ваш адрес
{
"id": "0b5f6e2a-1c3d-5e4f-8a9b-0c1d2e3f4a5b",
"event": "check.completed",
"created_at": "2026-09-10T08:19:41+00:00",
"data": {
"check_id": "3f9a7c2c-0000-4000-8000-0000000000c1",
"inn": "7707083893",
"found": true,
"dossier": {
"found": true,
"company": { "inn": "7707083893", "name_short": "ПАО «ВЕКТОР»", … },
"score": { "score": 82, "risk_level": "low", … },
… все 25 разделов, как в ответе GET /v1/checks/{uuid}
},
"dossier_url": "https://api.ruvisor.pro/v1/checks/3f9a7c2c-0000-4000-8000-0000000000c1"
}
}Конверт одинаков у всех событий: ветвиться надо по event, а id использовать как ключ дедупликации — при повторе он тот же.
Досье приходит целиком
В data.dossier лежит ровно то, что отдаёт GET /v1/checks/{uuid} — все 25 разделов. Проверка оплачена при постановке, и звать вас второй раз за тем, что вы уже купили, мы не станем. Ссылка data.dossier_url приходит рядом: по ней забирают ответ те, кому сотня килобайт в теле вебхука не нужна.
проверка подписи
<?php
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_RUVISOR_SIGNATURE'] ?? '';
$secret = getenv('RUVISOR_WEBHOOK_SECRET');
preg_match('/t=(\d+)/', $header, $m);
$timestamp = (int) ($m[1] ?? 0);
if (abs(time() - $timestamp) > 300) {
http_response_code(400);
exit;
}
$expected = hash_hmac('sha256', $timestamp . '.' . $body, $secret);
$ok = false;
foreach (explode(',', $header) as $part) {
if (str_starts_with($part, 'v1=') && hash_equals($expected, substr($part, 3))) {
$ok = true;
}
}
http_response_code($ok ? 200 : 401);Секрет показывается один раз при создании адреса. Мы храним его зашифрованным и в открытом виде больше не покажем.
Если ваш адрес не ответил
Повторим шесть раз: сразу, через минуту, пять, пятнадцать и час. Этого хватает, чтобы пережить и деплой на вашей стороне, и короткую аварию. Идентификатор события при повторах не меняется — по нему и отсекайте дубль, потому что ответ «принял», потерянный по дороге, для нас неотличим от неответа. Мы ходим только на публичные адреса и только по https, переходы не выполняем.
Оборванная связь не говорит, дошёл ли запрос. Заголовок Idempotency-Key снимает этот вопрос: повтор с тем же ключом и тем же телом вернёт прежний ответ и не спишет второй раз. Ключ живёт сутки, до 64 символов — удобно брать номер заказа.
свежая проверка с ключом повтора
curl -X POST https://api.ruvisor.pro/v1/check \
-H "Authorization: Bearer $RUVISOR_API_KEY" \
-H "Idempotency-Key: order-8421" \
-H "Content-Type: application/json" \
-d '{"inn":"7707083893"}'Без заголовка мы не отличаем ретрай от нового запроса, и каждый вызов списывается.
Тот же ключ с другим телом — ошибка, а не тихая подмена: idempotency_key_reused. Так опечатка в теле не выдаст себя за прежний ответ.
Счётчик частоты свой у каждого ключа: медленная интеграция не страдает от быстрой соседней. Остаток приходит заголовками, гадать не нужно:
Заголовки остатка стоят на успешных ответах. Когда предел уже превышен, приходит 429 и заголовок Retry-After — в нём секунды, а не совет «попробуйте позже». X-Request-Id есть на любом ответе, включая отказы.
Все отказы приходят одной формой. Ветвиться надо по error.code: текст мы вправе переписать, код — нет.
форма ошибки
{
"error": {
"code": "insufficient_funds",
"message": "На балансе недостаточно денег. Пополните баланс в кабинете.",
"details": { "balance_minor": 12000, "price_minor": 30000 }
},
"meta": { "request_id": "3f9a7c2c-0000-4000-8000-0000000000c1" }
}Ключ не принят. Отозванный, просроченный и несуществующий отвечают одинаково — по ответу нельзя понять, какой из случаев, и это защита от перебора, а не скупость.
Доступ по API не входит в ваш тариф либо ключу не выдано нужное право. Права ключа видны в ответе GET /v1/me.
На балансе недостаточно денег. Повторять бесполезно — нужно пополнить баланс. В details видно, сколько есть и сколько стоит запрос.
Этот вид запроса сейчас не продаётся. Отказ навсегда: пополнение баланса тут не поможет.
Исчерпан лимит тарифа. Повтор поможет после обновления периода.
Слишком часто. Через сколько секунд возвращаться — в заголовке Retry-After.
Запрос не прошёл проверку. Что именно не так — в details.fields.
Ничего не найдено. По компании это значит, что ни один реестр не знает такого ИНН; по разделу — что такого имени нет. Денег такой ответ не стоит.
Тот же Idempotency-Key пришёл с другим телом запроса. Возьмите новый ключ — иначе опечатка в теле выдала бы себя за прежний ответ.
Запрос с этим ключом ещё выполняется. Дождитесь и повторите с тем же ключом.
Тестовая среда пока закрыта — используйте боевой ключ.
Реестр не ответил. Это не «ничего не нашлось»: мы не смогли посмотреть, и повтор через минуту осмыслен.
Наш сервис оплаты сейчас не отвечает. Повторите позже.
Внутренняя ошибка на нашей стороне. Назовите в поддержке meta.request_id — по нему найдётся ваш запрос.
Адрес контура — https://api.ruvisor.pro. Список ниже составлен из самой спецификации, а она сверяется с маршрутами машинно: показанного здесь эндпоинта не может не быть.
/v1/openapi.jsonЭтот самый файл. Открыт без ключа: инструкция не должна быть спрятана от того, кому она нужна.
/v1/meОтвечает, какому аккаунту принадлежит ключ, какие права ему выданы, до какого числа он действует, сколько денег на балансе и почём запросы. Запроса не стоит и прав не требует — иначе ключ не смог бы узнать, каких прав ему не хватает. В платёжную систему этот ответ не ходит: баланс и цены — последние известные значения. Баланс меняется списанием и пополнением сразу, но между ними может отставать; когда он был верен, сказано в as_of.
{
"account": {
"id": 412,
"name": "ООО «Вектор»"
},
"key": {
"name": "Интеграция с CRM",
"environment": "production",
"scopes": [
"read:companies",
"read:checks",
"read:persons"
…/v1/companies/{inn}Все сведения о компании одним ответом: реквизиты, руководство, финансы, суды, долги, закупки и оценка риска.
Стоит цену вида dossier и открывает на 15 минут окно, внутри которого эта же компания и любые её разделы читаются бесплатно — сколько угодно раз. Действующие цены — в поле prices ответа GET /v1/me.
Если ни один реестр про такой ИНН ничего не знает, ответ будет 404 и денег он не стоит: мы не сделали работы, за которую можно брать.
innв пути, обязателенИНН компании — десять знаков у юрлица, двенадцать у ИП. Контрольная сумма проверяется: неверный ИНН получает 422 и ничего не стоит.
Idempotency-KeyзаголовокДелает повтор безопасным: тот же ключ с тем же телом вернёт прежний ответ и не спишет второй раз. Живёт сутки, длина до 64 символов — удобно брать номер заказа или задачи на своей стороне.
{
"found": true,
"company": {
"inn": "7707083893",
"type": "legal",
"ogrn": "1027700132195",
"kpp": "773601001",
"okpo": "00032537",
"okato": {
"code": "45293554000",
"name": "Муниципальный округ Якиманка"
},
…/v1/companies/{inn}/{section}Та же часть досье, что и в общем ответе, но отдельно — когда нужны только суды или только финансы.
Внутри 15-минутного окна, открытого досье или свежей проверкой, бесплатен. Если окна нет, стоит цену вида dossier и открывает его.
Длинные разделы отдаются страницами: в ответе поле cursor, его же передают следующим запросом. На последней странице оно пусто.
innв пути, обязателенИНН компании — десять знаков у юрлица, двенадцать у ИП. Контрольная сумма проверяется: неверный ИНН получает 422 и ничего не стоит.
sectionв пути, обязателенИмя раздела. Неизвестное имя — 404, а не пустой ответ: опечатку в пути надо видеть сразу, а не принимать за «данных нет».
cursorв строке запросаКурсор следующей страницы — значение поля cursor из предыдущей.
{
"items": [
{
"case_number": "А40-123456/2025",
"court": "Арбитражный суд города Москвы",
"role": "plaintiff",
"role_title": "истец",
"amount": "1250000.00",
"filed_on": "2025-11-04",
"status": "Рассматривается"
}
],
…/v1/requisites/{inn}То, чем заполняют договор и платёжное поручение: ИНН, КПП, ОГРН, ОКПО, полное и сокращённое название, статус, даты, адрес, руководители и коды статистики.
Лёгкий метод по одному ИНН: только из нашей базы, в реестры за ним мы не ходим. Стоит цену вида requisites — она дешевле досье, действующая цена в поле prices ответа GET /v1/me.
Открывает своё окно на 15 минут. Окно досье реквизиты покрывает: купили досье — реквизиты по той же компании бесплатны. Обратное неверно: досье после реквизитов оплачивается по цене досье, без зачёта — в реквизитах этой работы не было.
Банковских реквизитов здесь нет: расчётного счёта нет ни в одном открытом реестре, его сообщает сам контрагент.
Руководителей может быть несколько: с 2021 года у общества бывает сразу несколько лиц, действующих без доверенности. У предпринимателя руководитель — он сам, а домашний адрес и его муниципальные коды закрыты.
innв пути, обязателенИНН компании — десять знаков у юрлица, двенадцать у ИП. Контрольная сумма проверяется: неверный ИНН получает 422 и ничего не стоит.
Idempotency-KeyзаголовокДелает повтор безопасным: тот же ключ с тем же телом вернёт прежний ответ и не спишет второй раз. Живёт сутки, длина до 64 символов — удобно брать номер заказа или задачи на своей стороне.
{
"inn": "7707083893",
"type": "legal",
"ogrn": "1027700132195",
"kpp": "773601001",
"okpo": "00032537",
"name_full": "ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО «СБЕРБАНК РОССИИ»",
"name_short": "ПАО СБЕРБАНК",
"status": {
"code": "active",
"title": "Действующая"
},
…/v1/banks/{bic}Банк из справочника БИК Банка России: наименование, корреспондентский счёт, адрес, SWIFT, статус и ограничения участника. Справочник обновляется каждый рабочий день.
Запрос бесплатный: справочник открытый, и заполнить банковские реквизиты договора или счёта должно быть можно без покупки досье.
Закрытый банк отдаётся со статусом closed и датой, а не 404: договоры с этим БИК остаются у вас, и знать, что банка больше нет, важно. Коды типов счетов (CRSA — корреспондентский) и ограничений (URRS и др.) — как в классификаторе Банка России, рядом — их текст дословно по документу ЦБ «Кодовые значения реквизитов ЭС».
bicв пути, обязателенБИК банка — девять цифр. Другой формат получает 422.
{
"bic": "048702781",
"name": "\"Северный Народный Банк\" (АО)",
"english_name": "Severny Narodny Bank",
"correspondent_account": "30101810000000000781",
"swift": [
"SENRRU31"
],
"address": {
"postal_code": "167000",
"locality": "г Сыктывкар",
"street": "ул. Первомайская, д. 68",
…/v1/suggestПодсказки при вводе — из нашей базы, без обращения к реестрам: до десяти компаний и ИП с КПП, адресом и руководителями, чтобы заполнить реквизиты прямо из выпадающего списка. Состав и форма значений — как у /v1/requisites.
Бесплатно. Свой предел — 120 запросов в минуту на аккаунт, общий на все его ключи и подключённые CRM; общий предел ключа (60 в минуту) подсказки не расходуют.
Правила строки: - от 3 до 200 символов; поиск по началу слов краткого наименования (полное наименование не индексируется); - цифры любой длины — начало ИНН или ОГРН (ОГРНИП): полный номер находится тоже, а 10–14 цифр не теряют подсказок на полпути; - латиница и слитное написание не находят кириллицу через дефис: «альфабанк» не найдёт «Альфа-Банк».
Подсказки не листаются: полная выдача с реестром — /v1/search. Сначала до семи компаний, затем ИП, остаток — снова компании. У ИП адреса нет. Строка, которой в базе ещё нет, приходит без КПП, адреса и статуса, а руководители — null («не знаем»; у ИП — он сам).
qв строке запроса, обязателенНачало названия, ИНН или ОГРН.
{
"items": [
{
"inn": "7707083893",
"type": "legal",
"kpp": "773601001",
"ogrn": "1027700132195",
"name": "ПАО СБЕРБАНК",
"name_full": "ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО \"СБЕРБАНК РОССИИ\"",
"address": "117312, г. Москва, ул. Вавилова, д. 19",
"heads": [
{
…/v1/searchНайти компанию, предпринимателя или человека по названию, ФИО или ИНН — когда ИНН ещё неизвестен.
Запроса не стоит: вы пока не знаете, кого проверяете, и брать за попытку найти значило бы продавать вопрос вместо ответа. Ключ всё равно нужен — иначе поиск стал бы открытой дверью в наш пул адресов, а его частоту реестры считают на нас.
Частота — 20 поисков в минуту на аккаунт: лимит общий у всех ключей аккаунта и не зависит от адреса, с которого вы ходите. Поиск в кабинете считается отдельно. Сверх лимита — 429 с кодом rate_limited и заголовком Retry-After. Заголовки X-RateLimit-* в ответе показывают бюджет ключа, а не лимит поиска.
qв строке запроса, обязателенЧто ищем — название, ФИО или ИНН. Не короче трёх символов.
kindв строке запросаГде искать. По умолчанию all — первая страница всех групп сразу. Остальные значения листаются независимо друг от друга.
По умолчанию all
pageв строке запросаСтраница выдачи, с первой по двадцатую. Дальше двадцатой листать незачем — там уточняют запрос, а не идут вглубь.
По умолчанию 1
{
"data": {
"query": "вектор",
"kind": "text",
"groups": {
"companies": {
"total": 214,
"has_more": true,
"items": [
{
"kind": "company",
"inn": "7707083893",
…/v1/checkСходить в реестры заново, не полагаясь на то, что у нас уже есть. Стоит цену вида check.
С purpose: requisites проверка нужна ради реквизитов компании, которой у нас ещё нет, и стоит цену вида requisites. Ответ, опрос GET /v1/checks/{uuid} и вебхук check.completed тогда приносят только реквизиты ({"found": true, "requisites": {…}}), а окно покрытия открывается для реквизитов, не для досье.
Ответов два. 200 — данные и так были свежими, досье приходит сразу. 202 — сборка началась: в ответе идентификатор проверки, за её исходом приходят на GET /v1/checks/{uuid}.
202 не отказ и не ошибка: обход всех источников идёт минуты, и держать соединение до его конца значит упереться в таймаут вашего клиента. Мы ждём результата десять секунд и только потом отвечаем 202, — то есть быстрые проверки вы получаете сразу, первым же ответом. Таймаут на своей стороне ставьте не меньше 30 секунд.
Опрашивать готовность не обязательно: если в кабинете заведён адрес вебхука с событием check.completed, исход придёт к вам сам, как только соберётся, — и принесёт досье целиком, а не приглашение зайти за ним.
Idempotency-KeyзаголовокДелает повтор безопасным: тот же ключ с тем же телом вернёт прежний ответ и не спишет второй раз. Живёт сутки, длина до 64 символов — удобно брать номер заказа или задачи на своей стороне.
{
"found": true,
"company": {
"inn": "7707083893",
"type": "legal",
"ogrn": "1027700132195",
"kpp": "773601001",
"okpo": "00032537",
"okato": {
"code": "45293554000",
"name": "Муниципальный округ Якиманка"
},
…/v1/checks/{uuid}Готова ли проверка, заказанная через POST /v1/check. Пока идёт сборка, отвечает 202 и заголовком Retry-After говорит, через сколько секунд зайти снова — уважайте его, опрос чаще ничего не ускоряет и тратит частотный бюджет ключа. Опрашивать можно сколько угодно: денег это не стоит, проверка оплачена при постановке. Но лучше не опрашивать вовсе — подпишите адрес на событие check.completed, и то же самое досье придёт к вам само.
uuidв пути, обязателенИдентификатор проверки — поле check_id из ответа 202.
{
"found": true,
"company": {
"inn": "7707083893",
"type": "legal",
"ogrn": "1027700132195",
"kpp": "773601001",
"okpo": "00032537",
"okato": {
"code": "45293554000",
"name": "Муниципальный округ Якиманка"
},
…/v1/persons/{inn}Где ещё числится этот человек: компании, в которых он руководитель или учредитель. Стоит цену вида person.
Требует права read:persons — граф аффилированности состоит из ФИО живых людей, и такое право выдают ключу отдельно.
Помимо частоты действует суточный предел на число разных ИНН. Повторный взгляд на того же человека его не тратит.
innв пути, обязателенИНН физического лица — двенадцать знаков (у учредителя-организации десять). Контрольная сумма проверяется: неверный ИНН получает 422 и ничего не стоит.
Idempotency-KeyзаголовокДелает повтор безопасным: тот же ключ с тем же телом вернёт прежний ответ и не спишет второй раз. Живёт сутки, длина до 64 символов — удобно брать номер заказа или задачи на своей стороне.
{
"inn": "773601001234",
"kind": "individual",
"full_name": "Иванов Иван Иванович",
"head_count": 2,
"founder_count": 1,
"companies": [
{
"inn": "7707083893",
"ogrn": "1027700132195",
"role": "Руководитель",
"name_short": "ПАО «ВЕКТОР»",
…