# Ключи и доступ (/access) Каждый запрос содержит ключ в заголовке `X-API-Key`: ```bash curl "https://api.rewio.ru/v3/reviews?object_id=20" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` Ключи начинаются с `hrev_`. Запрос без ключа или с неверным получает `401` с кодом `unauthorized`. ## Два уровня доступа [#access-levels] | Скоуп | Что можно | Для чего | | ----------- | --------------------------------------------------------------------- | ------------------------------------------------------------------- | | `read_only` | Только чтение: отзывы, аналитика, списки объектов, ссылок и площадок. | Серверная выдача отзывов и интеграции, которым нужно только читать. | | `full` | Чтение и запись: создавать и менять объекты, ссылки, вебхуки. | Серверная интеграция с полным доступом. | Собственные ключи (`full`/`read_only`) рекомендуем хранить только на своём сервере: `read_only` тоже раскрывает ваши данные на чтение, хотя и запрещает любые изменения. Чтобы показать отзывы на публичном сайте, обращайтесь к Rewio со своего бэкенда, а браузеру отдавайте уже готовый ответ. ## Тестовый ключ [#test-key] Только на чтение и только по демо-данным. Им работают примеры на этих страницах и кнопка «Отправить запрос»: ``` hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M ``` ## Где взять боевой ключ [#live-key] В личном кабинете [app.rewio.ru](https://app.rewio.ru). После регистрации аккаунт сразу получает два ключа – **Full** и **Read-only**. Там же можно создать дополнительные, посмотреть значение выданного и отозвать ненужный. Остались вопросы по подключению – напишите: . ## Пробный доступ [#trial] После регистрации аккаунт работает бесплатно **21 день**. В это время действуют два ограничения: | Что | Сколько на пробном доступе | После оплаты | | ---------------- | -------------------------------------- | ---------------- | | Объектов | 30 | Сколько оплачено | | Отзывов в выдаче | 20 самых свежих **по каждой площадке** | Все собранные | Отзывы при этом собираются полностью — ограничена только выдача. Оплата открывает накопленное сразу, пересобирать ничего не нужно. Когда окно действует, ответ методов отзывов и аналитики содержит блок `access`: ```json { "data": [ /* ... */ ], "total": 25, "access": { "reason": "trial", "limit_per_link": 20, "hidden_total": 204, "message": "Пробный доступ показывает 20 самых свежих отзывов по каждой площадке. Ещё 204 отзыва уже собрано — они откроются сразу после оплаты." } } ``` `hidden_total` – сколько отзывов уже собрано сверх окна. Блока `access` нет вовсе, если ограничения нет: его отсутствие и означает полный доступ. Окно считается **до** фильтров и сортировки. `sort_order=asc` или фильтр по рейтингу работают внутри двадцати последних, а не выбирают другие двадцать из архива. ## Версии API [#versions] Актуальная версия — **`/v3`**, она описана на этих страницах. Полная схема: [`api.rewio.ru/openapi.json`](https://api.rewio.ru/openapi.json). `/v1` закрыт: он отвечает только интеграциям, написанным до закрытия, и отдаёт им `Deprecation` в заголовках. Новый ключ на `/v1` получит `410` с кодом `api_version_gone`. `/v2` остаётся рабочим и описан [отдельно](/v2/) — переходить на `/v3` можно постепенно, но новые интеграции пишите сразу на `/v3`. ## Проверка доступности [#health] Два метода работают без ключа: | Метод | Ответ | Что означает | | ---------------------------------------- | ---------------------------------- | ---------------------------------------------------- | | [`GET /health`](/extra/health) | `{"status": "healthy"}` | API на связи. | | [`GET /health/read`](/extra/health-read) | `{"status": "ready"}`, иначе `503` | Чтение работает, методы отзывов и аналитики ответят. | ```bash curl https://api.rewio.ru/health curl https://api.rewio.ru/health/read ``` ## Как не опрашивать нас в цикле [#polling] Отзывы обновляются по расписанию, поэтому тесный цикл запросов ничего не ускоряет. Чтобы узнавать о новых отзывах и ответах, подпишитесь на [вебхуки](/guides/webhooks) – мы пришлём событие сами – или используйте [синхронизацию данных](/guides/sync) через курсор. # Интеграция через AI (/ai) Если вы разрабатываете через AI-агента, передайте ему наш Skill. В этом файле содержится вся необходимая информация с нужными ссылками, чтобы написать качественную интеграцию. При необходимости агент сам найдёт нужные разделы документации или сам напишет в поддержку. ## Где взять ключ и как его передать [#api-key] API-ключ выпускается в личном кабинете [app.rewio.ru](https://app.rewio.ru), раздел «API-ключи». Спросите у своего агента, как безопасно передать ему ключ. ## Попробовать без своего ключа [#try-without-key] Демо-ключ (только чтение, только демо-данные): `hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M`, демо-объект `object_id=20`. ## Машиночитаемые адреса [#machine-readable] Их можно давать агенту напрямую — он выкачает документацию сам. | Адрес | Что внутри | | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | [`docs.rewio.ru/skill/SKILL.md`](https://docs.rewio.ru/skill/SKILL.md) | Skill целиком: модель данных, методы, ловушки, правила. | | [`docs.rewio.ru/llms-full.txt`](https://docs.rewio.ru/llms-full.txt) | Вся документация одним файлом (обзор, быстрый старт, руководства, справочник). | | [`docs.rewio.ru/llms.txt`](https://docs.rewio.ru/llms.txt) | Карта разделов со ссылками — если контекст ограничен, агент выберет нужное. | | [`api.rewio.ru/v3/openapi.json`](https://api.rewio.ru/v3/openapi.json) | OpenAPI 3.1: все эндпоинты, параметры и схемы. **Источник истины** для любых спорных деталей. | ## Проверьте, что агент понял [#verify-agent] Прежде чем принимать код, задайте агенту эти вопросы. Ответы должны совпасть — если нет, он импровизирует: подключите Skill заново или дайте ему `SKILL.md` целиком. | Вопрос | Правильный ответ | | ---------------------------------------------- | --------------------------------------------------------------------------------- | | Как аутентифицироваться? | Заголовок `X-API-Key`, префикс `/v3`. | | Как выглядит список? | `{data, total, limit, offset, has_next}`, элементы всегда в `data`. | | Как узнать, что появилось новое? | Вебхук — не опрос в цикле и не выборка по времени изменения. | | Чем `review_date` отличается от `created_at`? | Публикация в местном времени площадки против UTC-времени захвата. | | Пользователь просит «четвёрки» — какой фильтр? | `min_rating=4&max_rating=4.9`: это корзина, а не число. | | В какой шкале `rating`? | 1–5, нормализованная, дробная; исходная — в `rating_original`. | | Повторный сбор создаёт дубли? | Нет: отзыв опознаётся по паре «ссылка + его id на площадке» и обновляется. | | Что делать сразу после создания объекта? | Ждать `scrape_status` = `success` / `partial` / `failed`, потом читать отзывы. | | Какие ошибки повторять? | `rate_limited`, `5xx`, сетевые. `402` и квотные — никогда. | | Что означает `202` при публикации ответа? | Приняли в работу; результат — только через `GET /v3/reviews/{id}/reply`. | | Откуда берётся формат ссылки? | Из [«Где взять ссылку»](/link-formats) — адреса не конструируются самостоятельно. | Skill описывает API на дату публикации. Если ответ расходится с описанием — верьте [`openapi.json`](https://api.rewio.ru/v3/openapi.json) и напишите нам: [info@rewio.ru](mailto:info@rewio.ru) или [@const\_rewio](https://t.me/const_rewio). Агент со Skill умеет сообщить об этом сам. # Модель данных (/data-model) Всё в Rewio держится на трёх сущностях: объект, ссылка, отзыв. ``` Объект «Гранд Отель» (object_id: 20) ├── Ссылка → Яндекс Карты (link_id: 181, source_id: 1) → отзывы… ├── Ссылка → 2ГИС (link_id: 182, source_id: 3) → отзывы… └── Ссылка → Otzovik (link_id: 183, source_id: 202) → отзывы… ``` **Объект** – ваша конкретная бизнес-сущность: один отель, одна клиника, один врач, один ресторан. **Ссылка** – страница этого объекта на конкретной площадке. Обычно у объекта несколько ссылок, по одной на каждую площадку. **Отзыв** привязан к ссылке и площадке внутри объекта. ## Папка – необязательный уровень выше [#folders] Если объектов много, их можно сложить в папки и запрашивать данные сразу по набору: `GET /v3/reviews?folder_id=…`. Максимальная глубина: два уровня. Один объект может лежать в нескольких папках. Отзывы при этом живут в объекте: папка только адресует запрос. Подробности в [руководстве](/guides/folders). ## Ответ на отзыв [#reply] У отзыва бывает ответ организации: он приходит в полях `reply_text` и `reply_date` и собирается с площадки как есть, кем бы он ни был написан. Ответ, который вы публикуете [через нас](/guides/replies), – это то же самое место на площадке, только заполненное вами: после публикации он приходит в тех же `reply_text` и `reply_date`. Ответ у отзыва ровно один, и место под него на площадке одно. ## Оценки приведены к 1–5 [#ratings] Площадки считают по-разному: пять баллов, десять, сто, «палец вверх». Rewio приводит всё к шкале 1–5. Это поле `rating`, оно может быть дробным. Исходная оценка площадки остаётся рядом, в `rating_original`. У площадок без числовой оценки `rating` пустой. ## Площадки [#sources] [`GET /v3/sources`](/sources/list) отдаёт справочник площадок: числовой `id`, машинное имя `slug`, название для показа `name` и возможности: поддерживает ли площадка ответы организации, бывают ли фотографии, какая у неё исходная шкала. По `id` фильтруют отзывы и аналитику (`source_ids`), `slug` используется в фильтрах вебхуков (`allowed_sources`). # Ошибки (/errors) Любая ошибка приходит одним и тем же телом, с любым статусом `4xx` или `5xx`: ```json { "detail": "Понятное человеку описание, что пошло не так", "code": "machine_readable_code" } ``` `detail` – текст для логов, его формулировка может меняться. `code` – стабильный код. Реализуйте логику по нему. ## Коды состояния [#status-codes] | Статус | `code` | Когда | | ------ | --------------------- | ---------------------------------------------------------------------------------- | | `400` | `bad_request` | Битые параметры или невалидное тело. | | `401` | `unauthorized` | Нет заголовка `X-API-Key` или ключ неверный. | | `402` | `payment_required` | Доступ к API приостановлен. Что именно произошло, написано в `detail`. | | `403` | `forbidden` | Не хватает прав: запись ключом на чтение или чужой ресурс. | | `403` | `session_required` | Операция выполняется только из личного кабинета. Никакой ключ на неё не действует. | | `404` | `not_found` | Ресурс не найден или принадлежит другому аккаунту. | | `405` | `method_not_allowed` | Метод не поддерживается этим адресом. | | `409` | `conflict` | Конфликт состояния, например дубликат. | | `422` | `validation_error` | Тело или параметры не прошли проверку схемы. | | `429` | `rate_limited` | Слишком много запросов подряд. Повторите с задержкой. | | `500` | `internal_error` | Наша ошибка. Стоит повторить с нарастающей задержкой. | | `503` | `service_unavailable` | Сервис временно недоступен. Повторите с задержкой. | ## Адресация и папки [#addressing-and-folders] | Статус | `code` | Когда | | ------ | ---------------------------- | ------------------------------------------------------------------------------------------------- | | `400` | `object_or_folder_required` | В запросе отзывов или аналитики нет ни `object_id`, ни `folder_id`. | | `400` | `object_and_folder_conflict` | Переданы оба сразу. Адресовать нужно ровно один. | | `400` | `folder_depth_exceeded` | Нарушена глубина: родитель сам вложен, у папки есть подпапки, или её делают родителем самой себе. | | `403` | `folder_limit_reached` | Достигнут потолок в 1000 живых папок на аккаунт. | | `404` | `folder_not_found` | Папка не найдена или чужая. | | `409` | `folder_not_empty` | У папки есть живые подпапки. Сначала перенесите или удалите их. | ## Объекты, ссылки и виджет [#objects-links-widget] | Статус | `code` | Когда | | ------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `403` | `object_limit_reached` | Достигнут потолок активных объектов на вашем тарифе. | | `403` | `object_creation_budget_exhausted` | Исчерпан бюджет пересозданий объектов. Это защита от абьюза, а не тарифный лимит: как поднять – написано в `detail`. | | `402` | `source_requires_upgrade` | Площадка не входит в ваш тариф. | | `400` | `pinned_limit_exceeded` | Закреплённых отзывов на объект не больше 30. | | `400` | `duplicate_review_ids` | В `ordered_review_ids` есть повторы. | | `409` | `idempotency_conflict` | Тот же `Idempotency-Key` пришёл с другим телом запроса. | | `409` | `idempotency_in_progress` | Запрос с этим `Idempotency-Key` ещё выполняется. Повторите позже. | Отказы по отдельным ссылкам при создании объекта и добавлении площадок ошибкой не считаются: они приходят внутри `201`, в поле `error_code` каждой ссылки – `source_not_detected`, `source_url_invalid`, `source_requires_upgrade`, `source_already_linked`, `link_already_added`. ## Синхронизация отзывов [#sync] | Статус | `code` | Когда | | ------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `400` | `invalid_cursor` | Курсор не читается: испорчен, изменён или выдан другому аккаунту. Начните обход заново, без `cursor` – [как это работает](/reviews/sync). | | `400` | `cursor_mismatch` | Вместе с курсором передан `object_id`, `folder_id` или `mode`, не совпадающий с тем, для которого курсор выдан. | ## Ответы на отзывы [#replies] | Статус | `code` | Когда | | ------ | ------------------------------ | ------------------------------------------------------------------------------------------------------- | | `402` | `reply_requires_upgrade` | Публикация ответов входит в тариф «Полный». Удалить уже опубликованный ответ можно на любом тарифе. | | `403` | `reply_access_revoked` | Площадка не даёт нам отвечать по этой ссылке: доступ был и отозван. Что сделать, написано в `detail`. | | `404` | `reply_not_found` | У этого отзыва нет вашего ответа. Ответ, написанный не через нас, виден как `reply_text` самого отзыва. | | `409` | `reply_not_supported` | На этой площадке мы пока не публикуем ответы. Смотрите `can_publish_reply` в `GET /v3/sources`. | | `409` | `reply_owned_by_other_account` | На отзыв уже отвечает другой аккаунт: на площадке место под ответ одно. | | `409` | `reply_in_progress` | Предыдущий ответ сейчас публикуется, отменить его нечем. Повторите через несколько секунд. | | `409` | `reply_edit_not_supported` | На этой площадке опубликованный ответ нельзя переписать. | | `409` | `reply_delete_not_supported` | На этой площадке ответ нельзя удалить. | | `422` | `validation_error` | Текст пуст, содержит управляющие символы или длиннее допустимого на площадке. | `202` означает, что задачу мы приняли; опубликованный ответ виден в самом отзыве (`reply_text`) и приходит событием `replies.new`. Если ответ не появился, причина обычно одна из этих – и почти все мы отрабатываем сами: | Причина | Что происходит | | -------------------------------------- | ------------------------------------------------------------------------ | | Наш доступ к площадке обновляется | Ничего делать не нужно, ответ уйдёт сам. | | Площадка просит подождать | Повтор произойдёт автоматически. | | Сеть или сбой на стороне площадки | Повторим сами, до трёх раз. | | Из ссылки не выводится объект площадки | Проверьте адрес ссылки в объекте. | | **Площадка отклонила текст** | **Единственный случай, где нужны вы:** измените текст и отправьте снова. | Ответ не появился – напишите на . ## Как обрабатывать [#handling] * Повторяйте `429` и `5xx` с нарастающей задержкой. Остальные `4xx` повторять бессмысленно – запрос надо чинить. * Логируйте `code` вместе с `detail`: по коду мы быстрее поймём, что случилось. * При добавлении ссылок отказ приходит по каждой ссылке отдельно: текст в `error`, машинная причина в `error_code`. Негодная ссылка не отменяет остальные – они добавятся. Форматы адресов смотрите в [Форматах ссылок](/link-formats). Примеры: ```json // 401 – ключ не передан { "detail": "Missing API key", "code": "unauthorized" } // 403 – запись ключом на чтение { "detail": "This key is read-only", "code": "forbidden" } // 422 – невалидное тело { "detail": "url: field required", "code": "validation_error" } ``` # Где взять ссылку (/link-formats) Для добавления объекта в систему необходимо скопировать ссылку с нужной площадки. Копируйте адрес страницы целиком, ничего не обрезая: площадку мы определим сами и приведём ссылку к нужному формату. Ниже примеры со снимками для каждой площадки. На снимках обведено то, что нужно скопировать: **А** – адрес из строки браузера, **Б** – короткая ссылка из кнопки «Поделиться» там, где она есть. ## Карты [#maps] Откройте карточку организации на Яндекс.Картах. Подойдёт любой из двух – вставляйте ту, что удобнее. **Вариант А. адрес из строки браузера.** Откройте карточку организации и скопируйте адрес из строки браузера. Яндекс.Карты – страница объекта **Вариант Б. короткая ссылка из «Поделиться».** Либо нажмите «Поделиться» – площадка покажет короткую ссылку, её мы развернём сами. Яндекс.Карты – экран «поделиться» с короткой ссылкой Найдите организацию в Google Картах и откройте её карточку. Подойдёт любой из двух – вставляйте ту, что удобнее. **Вариант А. адрес из строки браузера.** Откройте карточку организации и скопируйте адрес из строки браузера. Google Карты – страница объекта **Вариант Б. короткая ссылка из «Поделиться».** Либо нажмите «Поделиться» – площадка покажет короткую ссылку, её мы развернём сами. Google Карты – экран «поделиться» с короткой ссылкой Откройте карточку организации в 2ГИС – кнопка здесь называется «Отправить». Подойдёт любой из двух – вставляйте ту, что удобнее. **Вариант А. адрес из строки браузера.** Откройте карточку организации и скопируйте адрес из строки браузера. 2ГИС – страница объекта **Вариант Б. короткая ссылка из «Поделиться».** Либо нажмите «Поделиться» – площадка покажет короткую ссылку, её мы развернём сами. 2ГИС – экран «поделиться» с короткой ссылкой ## Отели и бронирование [#hotels] Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. Яндекс.Путешествия – страница объекта Откройте страницу отеля. Окно выбора дат можно просто закрыть. Откройте карточку организации и скопируйте адрес из строки браузера. Островок – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. 101Hotels – страница объекта Откройте страницу объекта размещения. Откройте карточку организации и скопируйте адрес из строки браузера. Суточно.ру – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. Tvil.ru – страница объекта Откройте страницу отеля или санатория. Откройте карточку организации и скопируйте адрес из строки браузера. Alean.ru – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. OneTwoTrip – страница объекта Откройте карточку отеля. Откройте карточку организации и скопируйте адрес из строки браузера. TopHotels.ru – страница объекта Домен tripadvisor.ru в России не открывается – пользуйтесь tripadvisor.com. Карточка объекта на обоих доменах одна и та же, и ссылку мы примем любую. Откройте карточку организации и скопируйте адрес из строки браузера. TripAdvisor – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. Booking.com – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. Agoda – страница объекта Откройте страницу отеля. Откройте карточку организации и скопируйте адрес из строки браузера. Trip.com – страница объекта Откройте страницу объекта. Откройте карточку организации и скопируйте адрес из строки браузера. Airbnb – страница объекта ## Медицина [#medicine] Откройте страницу клиники или врача – отзывы соберутся по той странице, чей адрес вы вставили. Откройте карточку организации и скопируйте адрес из строки браузера. ПроДокторов – страница объекта Откройте страницу клиники или врача. Откройте карточку организации и скопируйте адрес из строки браузера. DocDoc.ru – страница объекта Откройте страницу клиники или врача. Откройте карточку организации и скопируйте адрес из строки браузера. НаПоправку – страница объекта Откройте страницу клиники или врача. Откройте карточку организации и скопируйте адрес из строки браузера. Doctu.ru – страница объекта Откройте страницу клиники или врача. Откройте карточку организации и скопируйте адрес из строки браузера. Яндекс.Медицина – страница объекта Откройте страницу специалиста. Откройте карточку организации и скопируйте адрес из строки браузера. B17.ru – страница объекта ## Услуги и специалисты [#services] Откройте профиль специалиста. Откройте карточку организации и скопируйте адрес из строки браузера. Profi.ru – страница объекта Откройте профиль исполнителя. Откройте карточку организации и скопируйте адрес из строки браузера. Яндекс.Услуги – страница объекта Откройте профиль продавца или страницу бренда. Откройте карточку организации и скопируйте адрес из строки браузера. Avito – страница объекта ## Справочники [#directories] Откройте карточку организации на Zoon. Откройте карточку организации и скопируйте адрес из строки браузера. Zoon – страница объекта Откройте страницу компании на Flamp. Откройте карточку организации и скопируйте адрес из строки браузера. Flamp – страница объекта Откройте карточку организации на Yell. Откройте карточку организации и скопируйте адрес из строки браузера. Yell – страница объекта Откройте страницу объекта. Откройте карточку организации и скопируйте адрес из строки браузера. Otzovik – страница объекта Откройте страницу объекта. Откройте карточку организации и скопируйте адрес из строки браузера. iRecommend.ru – страница объекта Откройте страницу компании в разделе отзывов. Откройте карточку организации и скопируйте адрес из строки браузера. Т-Банк – страница объекта Откройте сообщество во ВКонтакте. Подойдёт любой из двух: адрес страницы сообщества или адрес страницы с отзывами. **Вариант А. Адрес сообщества.** Скопируйте адрес сообщества из строки браузера. ВКонтакте – страница объекта **Вариант Б. Адрес страницы отзывов.** Либо откройте раздел «Отзывы» и скопируйте адрес уже этой страницы. ВКонтакте – страница отзывов сообщества Не нашли нужную площадку? на добавление. ## Форматы ссылок [#url-formats] Шаблон адреса и рабочий пример для каждой площадки. `{…}` – переменная часть. ### Карты [#url-maps] | `source_id` | Площадка | Формат ссылки | Пример | | ----------- | -------------- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | `1` | Яндекс.Карты | `yandex.ru/maps/-/{код}`
`yandex.ru/maps/org/{название}/{org_id}`
`yandex.ru/profile/{org_id}` | `https://yandex.ru/maps/org/areal/1262964858`
`https://yandex.ru/profile/7958059620` | | `2` | Google Reviews | `maps.app.goo.gl/{код}`
`google.com/maps/place/{название}/@{координаты}/data=…` | `https://maps.app.goo.gl/dSiPVi4F8MBLvG4w8` | | `3` | 2ГИС / Otello | `go.2gis.com/{код}`
`2gis.ru/{город}/firm/{id}`
`2gis.ru/{город}/geo/{id}`
`otello.ru/hotel/{id}` | `https://go.2gis.com/BQ8Og`
`https://2gis.ru/moscow/firm/70000001079615757` | ### Отели и путешествия [#url-hotels] | `source_id` | Площадка | Формат ссылки | Пример | | ----------- | ------------------ | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | `100` | Alean.ru | `alean.ru/hotels/{страна}/{регион}/{город}/{отель}` | `https://www.alean.ru/hotels/rossiya/moskva/borodino_gostinitsa` | | `101` | OneTwoTrip | `onetwotrip.com/ru/hotels/hotel/{название}-{id}` | `https://www.onetwotrip.com/ru/hotels/hotel/safmar-tverskaia-moskva-296002` | | `103` | Tvil.ru | `tvil.ru/city/{город}/hotels/{id}` | `https://tvil.ru/city/adler/hotels/427565` | | `104` | Яндекс.Путешествия | `travel.yandex.ru/hotels/{регион}/{отель}` | `https://travel.yandex.ru/hotels/moscow/borodino-kongress-otel` | | `105` | 101Hotels | `101hotels.com/main/cities/{город}/{отель}.html` | `https://101hotels.com/main/cities/moskva/gostinitsa_borodino.html` | | `106` | Ostrovok | `ostrovok.ru/hotel/{страна}/{город}/mid{id}/{отель}` | `https://ostrovok.ru/hotel/russia/moscow/mid7599836/borodino_hotel` | | `107` | Суточно.ру | `sutochno.ru/front/searchapp/detail/{id}` | `https://sutochno.ru/front/searchapp/detail/2212277` | | `108` | TopHotels.ru | `tophotels.ru/hotel/al{id}` | `https://tophotels.ru/hotel/al125379` | | `109` | TripAdvisor | `tripadvisor.com/{Тип}_Review-g{гео}-d{id}-Reviews-{Название}.html` | `https://www.tripadvisor.com/Hotel_Review-g298484-d671754-Reviews-Borodino_Alliance_Hotel-Moscow_Central_Russia.html` | | `110` | Airbnb | `airbnb.com/rooms/{id}` | `https://www.airbnb.com/rooms/1187653134175293144` | | `111` | Booking.com | `booking.com/hotel/{код страны}/{отель}.html` | `https://www.booking.com/hotel/th/the-royal-p-phuket.ru.html` | | `112` | Trip.com | `trip.com/hotels/detail/?hotelId={id}` | `https://ru.trip.com/hotels/detail/?hotelId=1530754` | | `113` | Agoda | `agoda.com/{отель}/hotel/{город}-{код страны}.html` | `https://www.agoda.com/ru-ru/berlin-marriott-hotel_3/hotel/berlin-de.html` | ### Медицина [#url-medicine] | `source_id` | Площадка | Формат ссылки | Пример | | ----------- | --------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | `300` | DocDoc.ru | `docdoc.ru/clinic/{клиника}`
`docdoc.ru/doctor/{врач}` | `https://docdoc.ru/clinic/klinika_temed_na_tehnoparke` | | `301` | НаПоправку | `napopravku.ru/{город}/clinics/{клиника}`
`napopravku.ru/doctor-profile/{врач}` | `https://napopravku.ru/moskva/clinics/klinika-1-v-lyublino-mnogoprofilnyy-meditsinskiy-tsentr/` | | `302` | Doctu.ru | `doctu.ru/{город}/doctor/{врач}`
`doctu.ru/{город}/clinic/{клиника}` | `https://doctu.ru/msk/doctor/zabelina-valerija-dmitrievna` | | `303` | ПроДокторов | `prodoctorov.ru/{город}/lpu/{id}-{клиника}`
`prodoctorov.ru/{город}/vrach/{id}-{врач}` | `https://prodoctorov.ru/zelenograd/lpu/39192-nikor-med` | | `305` | Яндекс.Медицина | `yandex.ru/medicine/clinic/{название}_{id}`
`yandex.ru/medicine/doctor/{название}_{id}` | `https://yandex.ru/medicine/clinic/opeka_13445109767` | ### Услуги и специалисты [#url-services] | `source_id` | Площадка | Формат ссылки | Пример | | ----------- | ------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | `304` | B17.ru | `b17.ru/{ник специалиста}` | `https://www.b17.ru/svetlana_guedova` | | `400` | Profi.ru | `profi.ru/profile/{ник}` | `https://profi.ru/profile/SidorenkoSV3/` | | `401` | Яндекс.Услуги | `uslugi.yandex.ru/profile/{ник}` | `https://uslugi.yandex.ru/profile/DaniilR-152511` | | `205` | Avito | `адрес страницы продавца с ?sellerId={sellerId}` | `https://www.avito.ru/brands/4390b5a759ee16a3f054904fe1d96187/all/transport?sellerId=96133ce69977bd69330485c589bf5451` | ### Справочники [#url-directories] | `source_id` | Площадка | Формат ссылки | Пример | | ----------- | ------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | | `201` | Zoon.ru | `zoon.ru/{город}/{рубрика}/{название}` | `https://zoon.ru/msk/medical/meditsinskij_tsentr_nikor-med_v_andreevke` | | `207` | Flamp | `{город}.flamp.ru/firm/{название}-{id}` | `https://moscow.flamp.ru/firm/aviator_sheremetevo_otel-4504127918577229` | | `200` | Yell.ru | `yell.ru/{город}/com/{название}_{id}` | `https://www.yell.ru/moscow/com/sauna-zabava_12088202` | | `202` | Otzovik | `otzovik.com/reviews/{объект}` | `https://otzovik.com/reviews/laboratoriya_invitro_russia` | | `203` | iRecommend.ru | `irecommend.ru/content/{объект}` | `https://irecommend.ru/content/gorod-sochi-rossiya` | | `204` | Т-Банк | `tbank.ru/reviews/company/{компания}/{id}` | `https://www.tbank.ru/reviews/company/kazanskaya-rivyera/105252` | | `208` | ВКонтакте | `vk.ru/{имя сообщества}`
`vk.ru/club{id}`
`vk.ru/reviews-{id}` | `https://vk.ru/helix_lab`
`https://vk.ru/reviews-20155592` | ## Что полезно знать [#notes] ### Площадку и формат мы определяем сами [#autodetect] * Указывать площадку при добавлении не нужно – она определяется по адресу. * Адрес приводится к каноническому виду автоматически: лишние сегменты и параметры отбрасываются при сохранении. Например `2gis.ru/anapa/inside/104152…/firm/70000001088796893/37.30,44.94/tab/reviews` сохранится как `2gis.ru/anapa/inside/104152…/firm/70000001088796893`. Чистить адрес перед вставкой не нужно. ### Одна площадка – одна ссылка в объекте [#one-link-per-source] * Вторая ссылка на ту же площадку внутри объекта вернёт ошибку `Only one … link allowed per group`. Несколько филиалов – это несколько объектов. * При добавлении списком каждая ссылка получает свой результат: неверная вернёт `error` с ожидаемым форматом, остальные добавятся. ### Обязательные части адреса [#required-parts] * **Google** – фрагмент `data=…!1s0x…:0x…`, это идентификатор места. Адреса `maps.google.com/?cid=…` и короткие адреса из строки поиска (`/maps/place/Fresh`, `/maps/search/?q=…`) его не содержат и отклоняются – в этом случае используйте кнопку «Поделиться». * **Avito** – `?sellerId=` с 32-символьным идентификатором продавца. Без него продавца не определить. * **Trip.com** – `?hotelId=`; языковой поддомен любой (`ru.`, `us.`, `www.`). * **ВКонтакте** – годится любая ссылка на сообщество: `vk.ru/helix_lab`, `vk.ru/club29330414` или сама страница отзывов `vk.ru/reviews-29330414`. Личная страница не подойдёт – отзывы бывают только у сообществ. ### Короткая ссылка «Поделиться» – тоже ссылка [#short-links] * Адреса `maps.app.goo.gl/…`, `yandex.ru/maps/-/…`, `go.2gis.com/…` принимаются как есть: система разворачивает их и сохраняет карточку, на которую они ведут. * Делитесь **карточкой организации**, а не точкой на карте: у ссылки на произвольную точку идентификатора места нет, и отзывы по ней собрать нельзя. ### Зеркала и разные формы одного адреса [#mirrors] * Страновые домены равнозначны: `yandex.com.tr`, `yandex.kz`, `2gis.kz`, `google.de` ведут на ту же карточку, и дубли не создаются. * У 2ГИС `/firm/` и `/geo/`, у Яндекса `/maps/org/` и `/profile/` – одно и то же место. Городские поддомены вроде `spb.napopravku.ru` работают наравне с основным доменом. * 2ГИС и Otello – одна площадка (`source_id: 3`): Otello это гостиничный раздел 2ГИС. ### Если ссылку не приняли [#rejected] * Это не карточка объекта, а поиск, список или главная страница города. * Потеряна обязательная часть адреса – `data=` у Google, `?sellerId=` у Avito, `?hotelId=` у Trip.com. * Короткая ссылка «Поделиться» просрочена или площадка не ответила: откройте её в браузере и вставьте адрес карточки, на которую она ведёт. * Площадка не поддерживается – актуальный список отдаёт `GET /v3/sources`. * Причина другая – обязательно . # Все методы (/methods) Весь API целиком, одной страницей. Адрес `https://api.rewio.ru`, префикс `/v3`, ключ в заголовке `X-API-Key` у каждого запроса. Название метода ведёт на его страницу с параметрами, полями ответа и живым примером. ## Отзывы и аналитика [#reviews] | Метод | Что делает | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | [`GET /v3/sources`](/sources/list) | Справочник площадок: `id`, машинное имя, шкала оценок, что площадка умеет. | | [`GET /v3/reviews`](/reviews/list) | Отзывы объекта или папки: фильтры по оценке, дате, площадке и тексту, сортировка, страницы. | | [`GET /v3/reviews/{review_id}`](/reviews/get) | Один отзыв по идентификатору – та же модель, что в ленте. | | [`GET /v3/reviews/sync`](/reviews/sync) | Поток изменений с курсором – чтобы держать у себя актуальную копию отзывов. | | [`GET /v3/analytics`](/analytics/summary) | Сводка по объекту или папке: средняя оценка, распределение, полнота и скорость ответов. | | [`GET /v3/analytics/timeseries`](/analytics/timeseries) | Те же метрики по дням, неделям или месяцам. | ## Объекты и площадки [#objects] Объект – ваш объект учёта (отель, клиника, филиал, врач). Ссылка – его страница на конкретной площадке. | Метод | Что делает | | ----------------------------------------------------------------- | -------------------------------------------------- | | [`POST /v3/objects`](/objects/create) | Создать объект, сразу со ссылками на площадки. | | [`GET /v3/objects`](/objects/list) | Список объектов со ссылками и состоянием сбора. | | [`GET /v3/objects/{object_id}`](/objects/get) | Один объект со всеми его ссылками. | | [`PUT /v3/objects/{object_id}`](/objects/update) | Переименовать объект, включить или выключить сбор. | | [`PUT /v3/objects`](/objects/toggle) | Массовый выключатель сразу для набора объектов. | | [`DELETE /v3/objects/{object_id}`](/objects/delete) | Удалить объект вместе с его ссылками. | | [`POST /v3/objects/{object_id}/links`](/links/add) | Подключить к объекту новые площадки. | | [`GET /v3/objects/{object_id}/links`](/links/list) | Ссылки объекта и состояние сбора по каждой. | | [`PUT /v3/objects/{object_id}/links/{link_id}`](/links/update) | Переименовать ссылку или остановить сбор по ней. | | [`DELETE /v3/objects/{object_id}/links/{link_id}`](/links/remove) | Отключить площадку от объекта. | ## Папки [#folders] Уровень выше: набор объектов, по которому можно спросить отзывы и аналитику одним параметром `folder_id`. | Метод | Что делает | | --------------------------------------------------- | --------------------------------------------- | | [`POST /v3/folders`](/folders/create) | Создать папку и положить в неё объекты. | | [`GET /v3/folders`](/folders/list) | Все папки с подпапками и составом. | | [`GET /v3/folders/{folder_id}`](/folders/get) | Одна папка со своими объектами и подпапками. | | [`PATCH /v3/folders/{folder_id}`](/folders/update) | Переименовать, перенести или заменить состав. | | [`DELETE /v3/folders/{folder_id}`](/folders/delete) | Удалить папку, не трогая объекты внутри. | ## Ответы на отзывы [#replies] Ответ публикуется под отзывом на самой площадке. Включается по запросу – напишите на ; нужен полный тариф и ключ `full`. Подробности – в руководстве [«Как отвечать на отзывы»](/guides/replies). | Метод | Что делает | | --------------------------------------------------------- | -------------------------------------------- | | [`PUT /v3/reviews/{review_id}/reply`](/replies/publish) | Опубликовать ответ или заменить уже стоящий. | | [`DELETE /v3/reviews/{review_id}/reply`](/replies/delete) | Удалить ваш ответ с площадки. | ## Вебхуки [#webhooks] | Метод | Что делает | | ------------------------------------------------------------ | --------------------------------------------------------- | | [`POST /v3/webhooks`](/webhooks/create) | Получать новые отзывы и ответы пушем на свой адрес. | | [`GET /v3/webhooks`](/webhooks/list) | Все вебхуки аккаунта и состояние доставки. | | [`PATCH /v3/webhooks/{webhook_id}`](/webhooks/update) | Поменять адрес, объекты и фильтры или поставить на паузу. | | [`DELETE /v3/webhooks/{webhook_id}`](/webhooks/delete) | Отключить доставку. | | [`POST /v3/webhooks/{webhook_id}/test`](/webhooks/test) | Пробное событие с настоящей подписью. | | [`GET /v3/webhooks/secret`](/webhooks/secret) | Ключ, которым подписаны все доставки аккаунта. | | [`POST /v3/webhooks/rotate-secret`](/webhooks/rotate-secret) | Заменить ключ подписи, не теряя доставок. | ## Для виджетов [#widgets] Скрыть неудачный отзыв и закрепить удачный. Действует на выдачу, а не на данные: исходные отзывы остаются как есть. | Метод | Что делает | | ------------------------------------------------------------------------- | ------------------------------------- | | [`POST /v3/objects/{object_id}/hidden-reviews`](/widgets/hidden-add) | Убрать отзывы из ленты этого объекта. | | [`GET /v3/objects/{object_id}/hidden-reviews`](/widgets/hidden-list) | Что сейчас скрыто. | | [`DELETE /v3/objects/{object_id}/hidden-reviews`](/widgets/hidden-remove) | Вернуть отзывы в ленту. | | [`POST /v3/objects/{object_id}/pinned-reviews`](/widgets/pinned-add) | Закрепить отзывы наверху списка. | | [`GET /v3/objects/{object_id}/pinned-reviews`](/widgets/pinned-list) | Что закреплено и в каком порядке. | | [`PUT /v3/objects/{object_id}/pinned-reviews`](/widgets/pinned-set) | Заменить список закреплённых целиком. | | [`DELETE /v3/objects/{object_id}/pinned-reviews`](/widgets/pinned-remove) | Открепить, оставив отзывы в ленте. | ## Дополнительно [#extra] | Метод | Что делает | | -------------------------------------------- | -------------------------------------------------------------------- | | [`POST /v3/support/message`](/extra/support) | Написать разработчику. Работает с любым ключом, включая `read_only`. | ## Без ключа [#public] | Метод | Что делает | | ---------------------------------------- | ------------------------------------------------------------------ | | [`GET /health`](/extra/health) | API на связи. | | [`GET /health/read`](/extra/health-read) | Чтение работает – методы отзывов и аналитики ответят. Иначе `503`. | Ключи и доступ описаны в [отдельном разделе](/access), формат ошибок – в [Ошибках](/errors), а что такое объект и ссылка – в [Модели данных](/data-model). # Обзор (/overview) Rewio собирает отзывы о ваших объектах: отелях, клиниках, ресторанах, врачах и специалистах. Отзывы с трёх десятков площадок приводятся к одному формату и отдаются через REST API. ## Первый запрос [#first-request] Прямо сейчас вы можете протестировать отзывы демо-объекта тестовым ключом. ```bash curl "https://api.rewio.ru/v3/reviews?object_id=20&limit=3" \ -H "X-API-Key: hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M" ``` ## Что на этом строят [#use-cases] * **Виджет отзывов** на сайте или в личном кабинете клиента. * **Дашборды и BI** – средняя оценка, распределение, тренды по месяцам; выгрузка в Power BI, Metabase или DataLens. * **Мониторинг репутации** – новые отзывы пушем, эскалация негатива, контроль скорости ответов. * **Отчёты по сети** – объекты складываются в [папки](/guides/folders), аналитика строится по папке целиком. * **Ответы на отзывы** – ответ публикуется под отзывом на площадке одним запросом. * **Отзывы в CRM** – карточка филиала или клиента с его отзывами и оценкой. * **Своя копия отзывов** – [синхронизация](/guides/sync) держит вашу базу в актуальном состоянии: поток изменений с курсором, включая пропажи отзывов с площадок. ## Правила, общие для всего API [#rules] | | | | ------ | ---------------------------------------------------------------------------------------------- | | Адрес | `https://api.rewio.ru` | | Версия | `/v3` | | Ключ | Заголовок `X-API-Key` в каждом запросе | | Формат | JSON. Списки – `{data, total, limit, offset, has_next}` или `{data}`, элементы всегда в `data` | | Оценки | Приведены к шкале 1–5, бывают дробными | | Время | UTC в ISO 8601, кроме `review_date`: это местное время площадки | | Ошибки | `{"detail": "…", "code": "…"}` | ## С чего начать [#start] # Быстрый старт (/quickstart) Попробуйте пробный запрос готовым ключом. Для создания своих объектов используйте ключ из [личного кабинета](https://app.rewio.ru). Тестовый ключ только на чтение. Боевой ключ (`full`/`read_only`) рекомендуем хранить только на своём сервере: `read_only` тоже раскрывает ваши данные на чтение. ### Проверьте связь [#check-connection] Два пробных запроса: доступность API и справочник площадок. Первый идёт без ключа. Пришёл JSON-ответ – ключ и сеть в порядке. ```bash # API на связи – ключ не нужен curl https://api.rewio.ru/health # площадки, с которых собираются отзывы curl https://api.rewio.ru/v3/sources \ -H "X-API-Key: hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M" ``` ```python import requests BASE = "https://api.rewio.ru/v3" HEADERS = {"X-API-Key": "hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M"} # API на связи – ключ не нужен health = requests.get("https://api.rewio.ru/health").json() print(health["status"]) # площадки, с которых собираются отзывы sources = requests.get(f"{BASE}/sources", headers=HEADERS).json() print(sources["data"][:3]) ``` ```javascript const BASE = "https://api.rewio.ru/v3"; const HEADERS = { "X-API-Key": "hrev_FaDGMKJEDDeCR5BCBgEg0aEjMogI7O7hOzE53YY4T1M" }; // API на связи – ключ не нужен const health = await (await fetch("https://api.rewio.ru/health")).json(); console.log(health.status); // площадки, с которых собираются отзывы const sources = await (await fetch(`${BASE}/sources`, { headers: HEADERS })).json(); console.log(sources.data.slice(0, 3)); ``` ```php ### Создайте объект [#create-object] Объект – ваша бизнес-сущность: отель, клиника, филиал, врач или специалист. Ссылки на площадки передаются при создании или отдельным методом [добавления ссылок](/links/add). Площадка определяется автоматически по ссылке. Для создания объекта используйте ключ из [личного кабинета](https://app.rewio.ru). ```bash curl -X POST https://api.rewio.ru/v3/objects \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" \ -H "Content-Type: application/json" \ -d '{ "name": "Мой отель", "links": [ {"url": "https://yandex.ru/maps/org/national/1020542995"}, {"url": "https://2gis.ru/moscow/firm/70000001006369779"} ] }' ``` ```python import requests BASE = "https://api.rewio.ru/v3" HEADERS = {"X-API-Key": "hrev_ВАШ_КЛЮЧ"} obj = requests.post(f"{BASE}/objects", headers=HEADERS, json={ "name": "Мой отель", "links": [ {"url": "https://yandex.ru/maps/org/national/1020542995"}, {"url": "https://2gis.ru/moscow/firm/70000001006369779"}, ], }).json() object_id = obj["id"] for result in obj["link_results"]: print(result["url"], result["error"] or f'ok, link_id={result["link_id"]}') ``` ```javascript const BASE = "https://api.rewio.ru/v3"; const HEADERS = { "X-API-Key": "hrev_ВАШ_КЛЮЧ", "Content-Type": "application/json", }; const res = await fetch(`${BASE}/objects`, { method: "POST", headers: HEADERS, body: JSON.stringify({ name: "Мой отель", links: [ { url: "https://yandex.ru/maps/org/national/1020542995" }, { url: "https://2gis.ru/moscow/firm/70000001006369779" }, ], }), }); const object = await res.json(); const objectId = object.id; console.log(object.link_results); ``` ```php 'Мой отель', 'links' => [ ['url' => 'https://yandex.ru/maps/org/national/1020542995'], ['url' => 'https://2gis.ru/moscow/firm/70000001006369779'], ], ], JSON_UNESCAPED_UNICODE); $ch = curl_init("$base/objects"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: $key", 'Content-Type: application/json']); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); $object = json_decode(curl_exec($ch), true); curl_close($ch); $objectId = $object['id']; print_r($object['link_results']); ``` Какой адрес принимает каждая площадка, смотрите в [Форматах ссылок](/link-formats). ### Дождитесь сбора [#wait-for-scrape] Сбор стартует автоматически после создания объекта и обычно занимает несколько минут. Состояние видно и у объекта целиком, и у каждой ссылки, в поле `scrape_status`: * `pending` – в очереди; * `in_progress` – идёт; * `success` – готово; * `partial` – собрались не все площадки; * `failed` – не получилось, причина в `scrape_error` у ссылки. ```bash # статус по всему объекту curl https://api.rewio.ru/v3/objects/20 \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" # или по каждой площадке отдельно curl https://api.rewio.ru/v3/objects/20/links \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` ```python import time def wait_for_scrape(object_id, timeout_min=10): """Опрашивает раз в 30 секунд, пока сбор не закончится.""" for _ in range(timeout_min * 2): obj = requests.get(f"{BASE}/objects/{object_id}", headers=HEADERS).json() if obj["scrape_status"] in ("success", "partial", "failed"): return obj time.sleep(30) return obj obj = wait_for_scrape(object_id) print(obj["scrape_status"], obj["last_scraped_at"]) ``` ```javascript const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); async function waitForScrape(objectId, timeoutMin = 10) { for (let i = 0; i < timeoutMin * 2; i++) { const res = await fetch(`${BASE}/objects/${objectId}`, { headers: HEADERS }); const obj = await res.json(); if (["success", "partial", "failed"].includes(obj.scrape_status)) return obj; await sleep(30_000); } } const scraped = await waitForScrape(objectId); console.log(scraped.scrape_status, scraped.last_scraped_at); ``` ```php Дальше объект обновляется сам, по расписанию. Чтобы узнавать о новых отзывах и ответах, не опрашивая нас, подпишитесь на [вебхуки](/guides/webhooks). ### Получайте отзывы или аналитику [#get-reviews] Получайте отзывы с помощью фильтров, агрегированную аналитику или аналитику по дням, неделям и месяцам. ```bash # отзывы: свежие сначала, только с текстом curl -G https://api.rewio.ru/v3/reviews \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" \ --data-urlencode "object_id=20" \ --data-urlencode "limit=20" \ --data-urlencode "has_text=true" # или аналитика: средняя оценка, распределение, ответы организации curl "https://api.rewio.ru/v3/analytics?object_id=20" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` ```python # отзывы: свежие сначала, только с текстом reviews = requests.get(f"{BASE}/reviews", headers=HEADERS, params={ "object_id": object_id, "limit": 20, "has_text": True, }).json() print(f'{reviews["total"]} отзывов подходит под фильтры') # или аналитика: средняя оценка, распределение, ответы организации stats = requests.get(f"{BASE}/analytics", headers=HEADERS, params={"object_id": object_id}).json() summary = stats["summary"] print(summary["average_rating"], summary["rating_distribution"]) print("негатив без ответа:", summary["reply"]["unanswered_negative_count"]) ``` ```javascript // отзывы: свежие сначала, только с текстом const q = new URLSearchParams({ object_id: objectId, limit: 20, has_text: true }); const reviews = await (await fetch(`${BASE}/reviews?${q}`, { headers: HEADERS })).json(); console.log(reviews.total, reviews.data); // или аналитика: средняя оценка, распределение, ответы организации const stats = await ( await fetch(`${BASE}/analytics?object_id=${objectId}`, { headers: HEADERS }) ).json(); console.log(stats.summary.average_rating, stats.summary.rating_distribution); ``` ```php Отзывы приходят страницей: сами записи в `data`, а `total` и `has_next` говорят, сколько подходит под фильтры и есть ли что дальше. Все фильтры отзывов и все поля аналитики описаны в справочнике: [отзывы](/reviews/list), [аналитика](/analytics/summary). ## Дальше [#next] # OpenAPI, Postman, Swagger (/tools) Все методы можно открыть в интерактивном просмотрщике [Swagger](https://api.rewio.ru/v3/scalar). Там они не только описаны, но и вызываются прямо в окне браузера. Машиночитаемое описание API – OpenAPI 3.1: ``` https://api.rewio.ru/v3/openapi.json ``` Это источник истины: если ответ API расходится с документацией, верен он. ## Postman [#postman] **Import → Link**, вставьте адрес спецификации. Затем задайте в окружении переменную с заголовком `X-API-Key`, и коллекция готова к вызовам. ## Свой клиент [#own-client] Типизированный клиент генерируется из той же спецификации, например [openapi-generator](https://openapi-generator.tech/): ```bash # Python openapi-generator-cli generate \ -i https://api.rewio.ru/v3/openapi.json \ -g python -o ./rewio-client-python # TypeScript openapi-generator-cli generate \ -i https://api.rewio.ru/v3/openapi.json \ -g typescript-fetch -o ./rewio-client-ts ``` ## Документация для AI-агентов [#ai-docs] Кроме спецификации есть текстовые версии документации, которые агент выкачивает сам: [`llms.txt`](https://docs.rewio.ru/llms.txt) – карта разделов, а [`llms-full.txt`](https://docs.rewio.ru/llms-full.txt) – всё одним файлом. Готовый промпт для агента есть на странице [Интеграция через AI](/ai). # Динамика оценки (/analytics/ratings-history) Ряд изменений оценки по каждой ссылке. Текущее значение отдельно – на странице [Оценка на площадках](/reviews/ratings). Новое значение оценки записывается только в том случае, если оно изменилось. Необходимо указать либо объект, либо папку. ## GET https://api.rewio.ru/v3/ratings/history Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `measured_from · measured_to` (дата, query, может быть null) – Границы по дате замера, включительно. Названный в верхней границе день входит целиком. Не переданы – вся история. - `object_id · folder_id` (число, query, может быть null) – Объект или папка целиком. В запросе должно быть ровно одно из двух. - `link_ids · source_ids` (список чисел, query, по умолчанию пусто) – Ограничить выдачу конкретными ссылками объекта или площадками. Пусто – без ограничения. ### Ответ 200 - `data` (список объектов, обязательный) – По строке на каждую ссылку, у которой есть история. - `data[].link_id` (число, обязательный) – Ссылка, к которой относится ряд. - `data[].source_id` (число, обязательный) – Площадка, на которой показана оценка. - `data[].points` (список объектов, обязательный) – Точки ряда, свежая первой. - `data[].points[].rating` (число, может быть null) – Какой стала оценка, шкала 1–5. - `data[].points[].rating_count` (число, может быть null) – Сколько оценок её сформировали, вместе с оставленными без текста. - `data[].points[].review_count` (число, может быть null) – Сколько из этих оценок – отзывы с текстом, по данным самой площадки. - `data[].points[].measured_at` (дата и время, обязательный) – Когда мы последний раз видели это значение. ### Пример ответа ```json { "data": [ { "link_id": 794, "source_id": 1, "points": [ { "rating": 4.9, "rating_count": 966, "review_count": 286, "measured_at": "2026-08-27T05:21:23" }, { "rating": 4.8, "rating_count": 941, "review_count": 279, "measured_at": "2026-08-23T05:19:44" } ] }, { "link_id": 823, "source_id": 3, "points": [ { "rating": 4.8, "rating_count": 237, "review_count": 193, "measured_at": "2026-08-27T05:21:40" } ] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Сводная аналитика (/analytics/summary) Итоги по отзывам за период: средняя оценка, распределение по звёздам и то, как отвечали на отзывы – целиком и в разбивке по площадкам. Считать можно по одному объекту или по папке целиком: укажите ровно одно – `object_id` или `folder_id`. ## GET https://api.rewio.ru/v3/analytics Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, query, может быть null) – Папка целиком: все её объекты и подпапки. Вместе с `object_id` не передаётся. - `object_id` (число, query, может быть null) – Объект, по которому считать. - `source_ids` (список чисел, query, по умолчанию пусто) – Считать только по этим площадкам. Пусто – по всем площадкам объекта. - `published_from` (дата, query, может быть null) – Начало периода по дате публикации отзыва. По умолчанию `2000-01-01`. - `published_to` (дата, query, может быть null) – Конец периода по дате публикации. По умолчанию сегодня. - `min_rating` (число, query, 0–5, по умолчанию 1) – Учитывать отзывы с оценкой не ниже указанной. - `max_rating` (число, query, 1–5, по умолчанию 5) – Учитывать отзывы с оценкой не выше указанной. ### Ответ 200 - `meta` (объект, обязательный) – Что именно посчитано: фильтры в том виде, в котором применились. - `meta.object_id` (число, может быть null) – Объект, по которому посчитано. В папочном режиме пусто. - `meta.folder_id` (число, может быть null) – Папка, если считали по папке. - `meta.object_ids` (список чисел, обязательный) – Все объекты, попавшие в расчёт. В папочном режиме это состав папки вместе с подпапками. - `meta.published_from` (дата, обязательный) – Начало периода, которое применилось. - `meta.published_to` (дата, обязательный) – Конец периода, который применился. - `meta.source_ids` (список чисел, обязательный) – Площадки, которые применились. Пустой список – все площадки объекта. - `meta.generated_at` (дата и время, обязательный) – Когда посчитано. - `summary` (объект, обязательный) – Итоги за период. - `summary.review_count` (число, обязательный) – Сколько всего отзывов за период. - `summary.average_rating` (число, может быть null) – Средняя оценка по шкале 1–5, до двух знаков. - `summary.reviews_with_text` (число, может быть null) – Сколько отзывов с текстом. - `summary.reviews_with_images` (число, может быть null) – Сколько отзывов с фотографиями. - `summary.rating_distribution` (объект, может быть null) – Сколько отзывов на каждую оценку. Ключи от `1` до `5`. - `summary.reply` (объект, может быть null) – Как отвечали на отзывы за период. - `summary.reply.reviews_with_reply` (число, обязательный) – Сколько отзывов получили ответ организации. - `summary.reply.unanswered_negative_count` (число, обязательный) – Сколько отзывов с оценкой 1–2 остались без ответа. - `summary.reply.reply_by_rating` (объект, может быть null) – Сколько ответов дано на отзывы каждой оценки. - `summary.reply.last_reply_date` (дата, может быть null) – Когда организация отвечала в последний раз. - `by_source` (список объектов, обязательный) – То же самое, но по каждой площадке отдельно. - `by_source[].source_id` (число, обязательный) – Идентификатор площадки. - `by_source[].source_name` (строка, обязательный) – Название площадки. - `by_source[].review_count` (число, обязательный) – Сколько отзывов с этой площадки за период. - `by_source[].average_rating` (число, может быть null) – Средняя оценка по площадке. - `by_source[].reviews_with_reply` (число, может быть null) – Сколько отзывов с ответом организации. - `by_source[].reviews_with_text` (число, может быть null) – Сколько отзывов с текстом. - `by_source[].reviews_with_images` (число, может быть null) – Сколько отзывов с фотографиями. - `by_source[].rating_distribution` (объект, может быть null) – Распределение отзывов площадки по оценкам. - `by_source[].reply_distribution` (объект, может быть null) – Распределение ответов организации по оценке отзыва. - `by_source[].latest_review_date` (дата, может быть null) – Дата самого свежего отзыва с этой площадки. - `access` (объект, может быть null) – Ограничение выдачи, если показали не всё. - `access.reason` (строка, обязательный) – Почему выдача ограничена. `trial` — пробный доступ, `manual` — ограничение, согласованное по вашему договору. - `access.limit_per_link` (число, обязательный) – Сколько последних отзывов показывается по КАЖДОЙ ссылке (площадке объекта). - `access.hidden_total` (число, обязательный) – Сколько отзывов уже собрано сверх показанных. Считается по всему архиву и не зависит от фильтров запроса. - `access.message` (строка, обязательный) – Готовая формулировка для показа человеку. ### Пример ответа ```json { "meta": { "object_id": 20, "folder_id": null, "object_ids": [ 20 ], "published_from": "2000-01-01", "published_to": "2026-08-25", "source_ids": [ 1, 2, 3, 104, 105, 106, 108 ], "generated_at": "2026-08-25T05:43:00.078703Z" }, "summary": { "review_count": 5838, "average_rating": 4.51, "reviews_with_text": 3929, "reviews_with_images": 718, "rating_distribution": { "1": 254, "2": 133, "3": 358, "4": 964, "5": 4127 }, "reply": { "reviews_with_reply": 1327, "unanswered_negative_count": 287, "reply_by_rating": { "1": 65, "2": 35, "3": 104, "4": 192, "5": 931 }, "last_reply_date": "2026-08-20" } }, "by_source": [ { "source_id": 2, "source_name": "Google Maps", "review_count": 3301, "average_rating": 4.52, "reviews_with_reply": 0, "reviews_with_text": 1727, "reviews_with_images": 207, "rating_distribution": { "1": 149, "2": 70, "3": 165, "4": 457, "5": 2460 }, "reply_distribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 }, "latest_review_date": "2026-08-24" }, { "source_id": 1, "source_name": "Яндекс.Карты", "review_count": 1092, "average_rating": 4.48, "reviews_with_reply": 1043, "reviews_with_text": 1092, "reviews_with_images": 346, "rating_distribution": { "1": 56, "2": 30, "3": 69, "4": 119, "5": 818 }, "reply_distribution": { "1": 51, "2": 26, "3": 64, "4": 115, "5": 787 }, "latest_review_date": "2026-08-23" }, { "source_id": 106, "source_name": "Островок", "review_count": 698, "average_rating": 4.54, "reviews_with_reply": 159, "reviews_with_text": 473, "reviews_with_images": 63, "rating_distribution": { "1": 7, "2": 15, "3": 87, "4": 303, "5": 286 }, "reply_distribution": { "1": 2, "2": 5, "3": 33, "4": 71, "5": 48 }, "latest_review_date": "2026-08-24" }, { "source_id": 3, "source_name": "2ГИС", "review_count": 442, "average_rating": 4.47, "reviews_with_reply": 125, "reviews_with_text": 442, "reviews_with_images": 51, "rating_distribution": { "1": 29, "2": 11, "3": 21, "4": 43, "5": 338 }, "reply_distribution": { "1": 12, "2": 4, "3": 7, "4": 6, "5": 96 }, "latest_review_date": "2026-08-16" }, { "source_id": 104, "source_name": "Яндекс.Путешествия", "review_count": 251, "average_rating": 4.56, "reviews_with_reply": 0, "reviews_with_text": 150, "reviews_with_images": 39, "rating_distribution": { "1": 10, "2": 6, "3": 13, "4": 25, "5": 195 }, "reply_distribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 }, "latest_review_date": "2026-08-25" }, { "source_id": 108, "source_name": "TopHotels", "review_count": 32, "average_rating": 4.32, "reviews_with_reply": 0, "reviews_with_text": 28, "reviews_with_images": 12, "rating_distribution": { "1": 3, "2": 1, "3": 2, "4": 9, "5": 17 }, "reply_distribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 }, "latest_review_date": "2025-06-11" }, { "source_id": 105, "source_name": "101Hotels", "review_count": 22, "average_rating": 4.76, "reviews_with_reply": 0, "reviews_with_text": 17, "reviews_with_images": 0, "rating_distribution": { "1": 0, "2": 0, "3": 1, "4": 8, "5": 13 }, "reply_distribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0 }, "latest_review_date": "2026-05-06" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Динамика по периодам (/analytics/timeseries) Те же метрики, что и в сводке, разложенные по дням, неделям или месяцам. Ряд начинается с первого целого интервала. При шаге в месяц и `published_from=2026-05-06` май в ряд не попадёт совсем – чтобы увидеть его, начните период с первого числа. ## GET https://api.rewio.ru/v3/analytics/timeseries Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, query, может быть null) – Папка целиком: все её объекты и подпапки. Вместе с `object_id` не передаётся. - `object_id` (число, query, может быть null) – Объект, по которому строить ряд. - `source_ids` (список чисел, query, по умолчанию пусто) – Отдельный ряд на каждую из этих площадок. По умолчанию `0`: общий ряд по всем. - `granularity` (строка, query, day / week / month, по умолчанию «month») – Шаг ряда: по дням, неделям или месяцам. - `published_from` (дата, query, может быть null) – Начало периода по дате публикации отзыва. По умолчанию 90 дней назад. - `published_to` (дата, query, может быть null) – Конец периода по дате публикации. По умолчанию сегодня. - `min_rating` (число, query, 0–5, по умолчанию 1) – Учитывать отзывы с оценкой не ниже указанной. - `max_rating` (число, query, 1–5, по умолчанию 5) – Учитывать отзывы с оценкой не выше указанной. ### Ответ 200 - `meta` (объект, обязательный) – Что именно посчитано: фильтры в том виде, в котором применились. - `meta.object_id` (число, может быть null) – Объект, по которому посчитано. В папочном режиме пусто. - `meta.folder_id` (число, может быть null) – Папка, если считали по папке. - `meta.object_ids` (список чисел, обязательный) – Все объекты, попавшие в расчёт. - `meta.published_from` (дата, обязательный) – Начало периода, которое применилось. - `meta.published_to` (дата, обязательный) – Конец периода, который применился. - `meta.source_ids` (список чисел, обязательный) – Площадки, которые применились. - `meta.generated_at` (дата и время, обязательный) – Когда посчитано. - `meta.granularity` (строка, обязательный) – Шаг ряда, который применился. - `series` (список объектов, обязательный) – Ряды, по одному на каждую запрошенную площадку. - `series[].source_id` (число, обязательный) – Площадка ряда. `0` – общий ряд по всем площадкам. - `series[].source_name` (строка, обязательный) – Название площадки. У общего ряда это «Все источники». - `series[].points` (список объектов, обязательный) – Точки ряда по возрастанию времени. - `series[].points[].period` (строка, обязательный) – Метка интервала: `2026-08-04` для дня, `2026-W32` для недели, `2026-08` для месяца. - `series[].points[].review_count` (число, обязательный) – Сколько отзывов пришло за интервал. - `series[].points[].average_rating` (число, может быть null) – Средняя оценка за интервал. - `series[].points[].reply_count` (число, может быть null) – Сколько отзывов получили ответ организации. - `series[].points[].reviews_with_text` (число, может быть null) – Сколько отзывов с текстом. - `series[].points[].reviews_with_images` (число, может быть null) – Сколько отзывов с фотографиями. - `series[].points[].rating_distribution` (объект, может быть null) – Распределение отзывов интервала по оценкам. - `series[].points[].reply_distribution` (объект, может быть null) – Распределение ответов организации по оценке отзыва. - `access` (объект, может быть null) – Ограничение выдачи, если показали не всё. - `access.reason` (строка, обязательный) – Почему выдача ограничена. `trial` — пробный доступ, `manual` — ограничение, согласованное по вашему договору. - `access.limit_per_link` (число, обязательный) – Сколько последних отзывов показывается по КАЖДОЙ ссылке (площадке объекта). - `access.hidden_total` (число, обязательный) – Сколько отзывов уже собрано сверх показанных. Считается по всему архиву и не зависит от фильтров запроса. - `access.message` (строка, обязательный) – Готовая формулировка для показа человеку. ### Пример ответа ```json { "meta": { "object_id": 20, "folder_id": null, "object_ids": [ 20 ], "published_from": "2026-05-01", "published_to": "2026-08-01", "source_ids": [ 0 ], "generated_at": "2026-08-25T05:52:21.664180Z", "granularity": "month" }, "series": [ { "source_id": 0, "source_name": "Все источники", "points": [ { "period": "2026-05", "review_count": 69, "average_rating": 4.47, "reply_count": 43, "reviews_with_text": 51, "reviews_with_images": 7, "rating_distribution": { "1": 5, "2": 0, "3": 3, "4": 17, "5": 44 }, "reply_distribution": { "1": 4, "2": 0, "3": 1, "4": 9, "5": 29 } }, { "period": "2026-06", "review_count": 87, "average_rating": 4.28, "reply_count": 48, "reviews_with_text": 72, "reviews_with_images": 11, "rating_distribution": { "1": 4, "2": 3, "3": 15, "4": 20, "5": 45 }, "reply_distribution": { "1": 3, "2": 2, "3": 6, "4": 7, "5": 30 } }, { "period": "2026-07", "review_count": 71, "average_rating": 4.42, "reply_count": 47, "reviews_with_text": 54, "reviews_with_images": 14, "rating_distribution": { "1": 5, "2": 2, "3": 5, "4": 13, "5": 46 }, "reply_distribution": { "1": 3, "2": 0, "3": 4, "4": 8, "5": 32 } }, { "period": "2026-08", "review_count": 0, "average_rating": null, "reply_count": null, "reviews_with_text": null, "reviews_with_images": null, "rating_distribution": null, "reply_distribution": null } ] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Создать папку (/folders/create) Папка объединяет объекты, чтобы спрашивать отзывы и аналитику сразу по всем: `GET /v3/reviews?folder_id=…` отдаёт единую ленту по всем объектам папки и её подпапок. Глубина – два уровня: папка → подпапка → объекты. Один объект может лежать сразу в нескольких папках. Объект, который положить не удалось, создать папку не мешает: он не попадёт в состав, а его идентификатор вернётся в `ignored_object_ids`. ## POST https://api.rewio.ru/v3/folders Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `Idempotency-Key` (строка, header, может быть null) – Свой ключ запроса. Повтор с тем же ключом не создаст вторую папку. ### Тело запроса - `name` (строка, обязательный) – Название папки, 1–255 символов. - `parent_folder_id` (число, может быть null) – Положить папку внутрь другой. Не передано – папка окажется в корне. - `object_ids` (список чисел, может быть null) – Объекты, которые сразу положить в папку, до 200. ### Пример запроса ```json { "name": "Москва", "object_ids": [ 20, 21 ] } ``` ### Ответ 201 - `id` (число, обязательный) – Идентификатор созданной папки. - `user_id` (число, обязательный) – Владелец папки. - `name` (строка, обязательный) – Название папки. - `created_at` (дата и время, обязательный) – Когда папка создана. - `parent_folder_id` (число, может быть null) – Папка-родитель. Пусто – папка лежит в корне. - `objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в этой папке. - `objects[].id` (число, обязательный) – Идентификатор объекта. - `objects[].name` (строка, обязательный) – Название объекта. - `subfolders` (список объектов, по умолчанию пусто) – Подпапки этой папки. У новой папки список пустой. - `subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `ignored_object_ids` (список чисел) – Идентификаторы из `object_ids`, которые в состав не попали: чужие, удалённые или несуществующие. ### Пример ответа ```json { "id": 12, "user_id": 6, "name": "Москва", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" } ], "subfolders": [], "ignored_object_ids": [] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Удалить папку (/folders/delete) Удаляет только саму папку. Объекты внутри остаются жить и продолжают собирать отзывы. Если внутри есть подпапки, удаление не пройдёт – сначала перенесите или удалите их. ## DELETE https://api.rewio.ru/v3/folders/{folder_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, path, обязательный) – Папка, которую нужно удалить. ### Ответ 200 - `id` (число, обязательный) – Идентификатор удалённой папки. - `name` (строка, обязательный) – Название удалённой папки. ### Пример ответа ```json { "id": 13, "name": "Центр" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Получить папку (/folders/get) Одна ветка дерева: сама папка и её подпапки со своим составом. Запросить можно и подпапку – придёт она сама с пустым `subfolders`. ## GET https://api.rewio.ru/v3/folders/{folder_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, path, обязательный) – Папка, которую нужно получить. ### Ответ 200 - `id` (число, обязательный) – Идентификатор папки. - `user_id` (число, обязательный) – Владелец папки. - `name` (строка, обязательный) – Название папки. - `created_at` (дата и время, обязательный) – Когда папка создана. - `parent_folder_id` (число, может быть null) – Папка-родитель. Пусто – папка лежит в корне. - `objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в этой папке, без объектов подпапок. - `objects[].id` (число, обязательный) – Идентификатор объекта. - `objects[].name` (строка, обязательный) – Название объекта. - `subfolders` (список объектов, по умолчанию пусто) – Подпапки этой папки, по названию по алфавиту. - `subfolders[].id` (число, обязательный) – Идентификатор подпапки. - `subfolders[].user_id` (число, обязательный) – Владелец подпапки. - `subfolders[].name` (строка, обязательный) – Название подпапки. - `subfolders[].created_at` (дата и время, обязательный) – Когда подпапка создана. - `subfolders[].parent_folder_id` (число, может быть null) – Папка-родитель. - `subfolders[].objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в подпапке. - `subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders` (список объектов, по умолчанию пусто) – Всегда пусто: глубина ограничена двумя уровнями. - `subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. ### Пример ответа ```json { "id": 12, "user_id": 6, "name": "Москва", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" } ], "subfolders": [ { "id": 13, "user_id": 6, "name": "Центр", "created_at": "2026-07-28T16:52:11", "parent_folder_id": 12, "objects": [ { "id": 22, "name": "Балчуг" } ], "subfolders": [] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Список папок (/folders/list) Всё дерево папок одним запросом: в `data` – корневые папки, подпапки лежат внутри своего родителя. Состав у каждой папки свой: объекты подпапки не входят в состав родителя, хотя в выдачу по его `folder_id` попадают. ## GET https://api.rewio.ru/v3/folders Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `data` (список объектов, обязательный) – Корневые папки, по названию по алфавиту. Пагинации нет. - `data[].id` (число, обязательный) – Идентификатор папки. - `data[].user_id` (число, обязательный) – Владелец папки. - `data[].name` (строка, обязательный) – Название папки. - `data[].created_at` (дата и время, обязательный) – Когда папка создана. - `data[].parent_folder_id` (число, может быть null) – Папка-родитель. Пусто – папка лежит в корне. - `data[].objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в этой папке, без объектов подпапок. - `data[].objects[].id` (число, обязательный) – Идентификатор объекта. - `data[].objects[].name` (строка, обязательный) – Название объекта. - `data[].subfolders` (список объектов, по умолчанию пусто) – Подпапки этой папки, по названию по алфавиту. - `data[].subfolders[].id` (число, обязательный) – Идентификатор подпапки. - `data[].subfolders[].user_id` (число, обязательный) – Владелец подпапки. - `data[].subfolders[].name` (строка, обязательный) – Название подпапки. - `data[].subfolders[].created_at` (дата и время, обязательный) – Когда подпапка создана. - `data[].subfolders[].parent_folder_id` (число, может быть null) – Папка-родитель. - `data[].subfolders[].objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в подпапке. - `data[].subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `data[].subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `data[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Всегда пусто: глубина ограничена двумя уровнями. - `data[].subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `data[].subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `data[].subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `data[].subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `data[].subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `data[].subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `data[].subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. ### Пример ответа ```json { "data": [ { "id": 12, "user_id": 6, "name": "Москва", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" } ], "subfolders": [ { "id": 13, "user_id": 6, "name": "Центр", "created_at": "2026-07-28T16:52:11", "parent_folder_id": 12, "objects": [ { "id": 22, "name": "Балчуг" } ], "subfolders": [] } ] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Изменить папку (/folders/update) Переименовывает, переносит и меняет состав папки за один вызов. Меняется только то, что передано. `object_ids` заменяет состав целиком, а не дополняет его. Чтобы добавить один объект, передайте её вместе с теми, что уже лежат в папке. Объект, который положить не удалось, остальной состав не отменяет: он не попадёт в папку, а его идентификатор вернётся в `ignored_object_ids`. ## PATCH https://api.rewio.ru/v3/folders/{folder_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, path, обязательный) – Папка, которую нужно изменить. ### Тело запроса - `name` (строка, может быть null) – Новое название, 1–255 символов. Не передано – остаётся прежним. - `parent_folder_id` (число, может быть null) – Перенести папку внутрь другой. `null` – вынести в корень. Не передано – остаётся где была. - `object_ids` (список чисел, может быть null) – Новый состав папки целиком. Пустой список очищает состав. ### Пример запроса ```json { "name": "Москва и область", "object_ids": [ 20, 21, 22, 99 ] } ``` ### Ответ 200 - `id` (число, обязательный) – Идентификатор папки. - `user_id` (число, обязательный) – Владелец папки. - `name` (строка, обязательный) – Название папки. - `created_at` (дата и время, обязательный) – Когда папка создана. - `parent_folder_id` (число, может быть null) – Папка-родитель. Пусто – папка лежит в корне. - `objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в этой папке. - `objects[].id` (число, обязательный) – Идентификатор объекта. - `objects[].name` (строка, обязательный) – Название объекта. - `subfolders` (список объектов, по умолчанию пусто) – Подпапки этой папки, по названию по алфавиту. - `subfolders[].id` (число, обязательный) – Идентификатор подпапки. - `subfolders[].user_id` (число, обязательный) – Владелец подпапки. - `subfolders[].name` (строка, обязательный) – Название подпапки. - `subfolders[].created_at` (дата и время, обязательный) – Когда подпапка создана. - `subfolders[].parent_folder_id` (число, может быть null) – Папка-родитель. - `subfolders[].objects` (список объектов, по умолчанию пусто) – Объекты, лежащие непосредственно в подпапке. - `subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders` (список объектов, по умолчанию пусто) – Всегда пусто: глубина ограничена двумя уровнями. - `subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].objects[].id` (число, обязательный) – Идентификатор объекта. - `subfolders[].subfolders[].objects[].name` (строка, обязательный) – Название объекта. - `subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].id` (число, обязательный) – Идентификатор папки. - `subfolders[].subfolders[].subfolders[].user_id` (число, обязательный) – Владелец папки. - `subfolders[].subfolders[].subfolders[].name` (строка, обязательный) – Название папки. - `subfolders[].subfolders[].subfolders[].created_at` (дата и время, обязательный) – Момент создания папки (UTC, ISO 8601). - `subfolders[].subfolders[].subfolders[].parent_folder_id` (число, может быть null) – Родительская папка; `null` у папки верхнего уровня. - `subfolders[].subfolders[].subfolders[].objects` (список объектов, по умолчанию пусто) – Собственный состав папки — объекты с названиями. - `subfolders[].subfolders[].subfolders[].subfolders` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `ignored_object_ids` (список чисел) – Идентификаторы из `object_ids`, которые в состав не попали: чужие, удалённые или несуществующие. ### Пример ответа ```json { "id": 12, "user_id": 6, "name": "Москва и область", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" }, { "id": 22, "name": "Балчуг" } ], "subfolders": [ { "id": 13, "user_id": 6, "name": "Центр", "created_at": "2026-07-28T16:52:11", "parent_folder_id": 12, "objects": [ { "id": 22, "name": "Балчуг" } ], "subfolders": [] } ], "ignored_object_ids": [ 99 ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Как считать аналитику (/guides/analytics) Аналитика отвечает на вопросы про массив отзывов, не заставляя вас его выкачивать: «какой сейчас средний балл», «сколько негатива осталось без ответа», «где хуже всего», «растём мы или падаем». Считаем мы, вы получаете готовые числа. Методов два, и различаются они не набором метрик, а срезом: | Вопрос | Метод | | --------------------------------------------------- | ------------------------------------------------------------------ | | Как обстоят дела **сейчас**, за период целиком | [Сводка](/analytics/summary) – `GET /v3/analytics` | | Как это **менялось** – по дням, неделям или месяцам | [Динамика](/analytics/timeseries) – `GET /v3/analytics/timeseries` | ## Что задаёт расчёт [#parameters] Оба метода принимают одно и то же. **Адресат – ровно один.** `object_id` для объекта либо `folder_id` для [папки](/guides/folders) целиком; оба сразу – `400 object_and_folder_conflict`, ни одного – `400 object_or_folder_required`. В папке считается по всем её объектам и объектам подпапок, а ссылка, попавшая в несколько объектов одной папки, учитывается один раз: метрики не удваиваются. **Период – по дате публикации отзыва** (`published_from` / `published_to`, включительно). Это `review_date`, то есть когда отзыв появился на площадке, а не когда мы его забрали. Умолчания у методов разные: сводка без границ считает всю историю, ряд – последние 90 дней. **Фильтры** – `source_ids` (только эти площадки) и `min_rating` / `max_rating` (только эта полоса оценок). Оба сужают массив до расчёта, а не после него. ## Сводка [#summary] ```bash curl "https://api.rewio.ru/v3/analytics?object_id=20" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` Ответ – три блока: * **`meta`** – что фактически посчитано: список объектов, реальные границы периода, применённые площадки, момент расчёта. Читать его стоит всегда: именно здесь видно, какой период подставился по умолчанию. * **`summary`** – общие числа за период: `review_count`, `average_rating` (шкала 1–5), `rating_distribution`, `reviews_with_text`, `reviews_with_images` и блок `reply`. * **`by_source`** – те же числа по каждой площадке отдельно. В папочном режиме одна площадка разных объектов схлопывается в одну строку с суммой. Блок `reply` – это про работу с отзывами, а не про сами отзывы: `reviews_with_reply` – сколько отвечено, `unanswered_negative_count` – сколько низких оценок осталось без ответа, `reply_by_rating` – на какие оценки отвечают, `last_reply_date` – когда отвечали в последний раз. Отсюда собираются типовые показатели: | Что нужно | Как получить | | ------------------------- | ----------------------------------------------------------- | | Текущий рейтинг | `summary.average_rating` | | Доля отвеченных | `summary.reply.reviews_with_reply` / `summary.review_count` | | Очередь на ответ | `summary.reply.unanswered_negative_count` | | Какая площадка тянет вниз | сравнить `average_rating` в строках `by_source` | | Где отзывы вообще есть | `review_count` в строках `by_source` | ## Динамика [#dynamics] ```bash curl "https://api.rewio.ru/v3/analytics/timeseries?object_id=20&granularity=month" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` `granularity` – шаг ряда: `day`, `week` или `month`. Ответ – `series`: по ряду на каждую площадку плюс агрегированный ряд с `source_id: 0` («Все источники»). Точки лежат в `points`, в хронологическом порядке; в каждой – метка периода `period`, `review_count`, `average_rating` и распределения. Средняя оценка в точке считается по отзывам этого интервала, а не накопительно: это не «рейтинг на дату», а «как оценивали в этом месяце». Накопительный рейтинг даёт сводка. Без явных границ ряд строится за последние 90 дней, а не за всю историю. И ряд начинается с первого целого интервала: при шаге в месяц и `published_from=2026-05-06` мая в ряду не будет совсем; ставьте начало периода на первое число. ```python import requests BASE = "https://api.rewio.ru/v3" HEADERS = {"X-API-Key": "hrev_ВАШ_КЛЮЧ"} r = requests.get(f"{BASE}/analytics/timeseries", headers=HEADERS, params={ "object_id": 20, "granularity": "month", "published_from": "2025-08-01", "published_to": "2026-08-01", }) for series in r.json()["series"]: print(series["source_name"]) for point in series["points"]: print(f" {point['period']}: {point['average_rating']} ({point['review_count']} отз.)") ``` ## Что в расчёт не входит [#exclusions] * **Скрытые и закреплённые отзывы аналитику не двигают.** [Виджетные настройки](/guides/widgets) оформляют показ, а не данные: скрыли отзыв с единицей – он пропал из ленты, а средний балл остался прежним. Балл, согласованный с показанным, считайте сами по выдаче. * **Выключенные объекты и ссылки данных не дают.** Внутри папки такой объект молча отсутствует, прямой запрос по нему отвечает `404`. Все параметры и все поля ответа – в справочнике: [сводка](/analytics/summary), [динамика](/analytics/timeseries). # Как работать с папками (/guides/folders) Папка объединяет объекты, чтобы спрашивать данные сразу по всему набору. Не нужно запрашивать объекты по одному и складывать результаты у себя: положите их в папку и спрашивайте данные по ней целиком. ```bash curl "https://api.rewio.ru/v3/reviews?folder_id=7&limit=50" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" curl "https://api.rewio.ru/v3/analytics?folder_id=7" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` ## Как устроено [#how-it-works] ``` Папка «Сеть Север» (folder_id: 7) ├── Объект «Гранд Отель» → ссылки → отзывы… ├── Объект «Приморская» → ссылки → отзывы… └── Подпапка «Москва» (folder_id: 12) ├── Объект «Тверская» → ссылки → отзывы… └── Объект «Арбат» → ссылки → отзывы… ``` * **Максимальная глубина – два уровня.** Папка → подпапка → объекты. Попытка вложить подпапку в подпапку – `400 folder_depth_exceeded`. * **У подпапки один родитель**, а **объект может лежать в скольких угодно папках** – например, и в «Сеть Север», и в «Премиум-сегмент». * Запрос по родительской папке возвращает **объединение**: её собственные объекты плюс объекты всех её подпапок. Ссылка, попавшая в несколько объектов одной папки, учитывается **один раз**: ни отзывы, ни метрики не удваиваются. * Папки **не тарифицируются**: место в лимите занимают объекты. Ограничение одно – не больше 1000 живых папок на аккаунт. ## Управление папками [#managing] Пять методов. Для чтения хватит ключа `read_only`, для остальных нужен `full`. | Метод | Что делает | | -------------------------------- | ------------------------------------------------------------- | | `POST /v3/folders` | Создать – сразу с составом и, если нужно, внутри другой папки | | `GET /v3/folders` | Все папки с подпапками и объектами в них | | `GET /v3/folders/{folder_id}` | Одна папка со своими объектами и подпапками | | `PATCH /v3/folders/{folder_id}` | Переименовать, перенести и сменить состав одним вызовом | | `DELETE /v3/folders/{folder_id}` | Удалить папку. Объекты внутри остаются | `GET /v3/folders` отдаёт дерево целиком: в `data` – корневые папки, подпапки лежат внутри своего родителя в поле `subfolders`. Порядок и там, и там: по названию, при совпадении – по `id`; сортировка регистронезависимая. ```json { "data": [ { "id": 7, "user_id": 42, "name": "Сеть Север", "created_at": "2026-07-28T09:14:02", "parent_folder_id": null, "objects": [{ "id": 20, "name": "Гранд Отель" }], "subfolders": [ { "id": 12, "user_id": 42, "name": "Москва", "created_at": "2026-07-28T09:20:41", "parent_folder_id": 7, "objects": [{ "id": 31, "name": "Тверская" }], "subfolders": [] } ] } ] } ``` Состав у каждой папки свой: объекты подпапки в `objects` родителя не попадают, хотя в выдачу по его `folder_id` войдут. Нужна одна ветка вместо всего дерева, запросите `GET /v3/folders/{folder_id}`; для подпапки он вернёт её саму с пустым `subfolders`. `object_ids` в `POST` и `PATCH` – это **полная замена** состава, а не добавление. Прислали `[3, 4]` – состав стал ровно `[3, 4]`. Прислали `[]` – состав очищен. Не передали поле вовсе – состав не тронут. Объект, которого у вас нет (чужой, удалённый или несуществующий), остальной состав не отменяет. Он просто не попадёт в папку, а его идентификатор вернётся в `ignored_object_ids`. На вход идут идентификаторы (`object_ids`), а в ответе состав приходит объектами с названиями (`objects`), чтобы нарисовать дерево, не запрашивая объекты отдельно. Повторный `POST` с тем же заголовком `Idempotency-Key` вернёт ту же папку и не создаст вторую. Названия папок не обязаны быть уникальными, так что на таймауте клиента это единственная защита от дубля. Удалить папку с **живыми** подпапками нельзя – `409 folder_not_empty`: сначала удалите или перенесите их. Удалённая подпапка удалению родителя не мешает. ## Что попадает в выдачу [#contents] Состав папки и то, что реально вернётся, – не одно и то же: * **Выключенный объект** (`is_active=false`) остаётся виден в составе через `GET /v3/folders`, но отзывов и аналитики не даёт. Прямой запрос по такому объекту отвечает `404`, а внутри папки он молча отсутствует. * **Удалённый объект** исчезает и из состава, и из выдачи. * **Выключенная ссылка** внутри живого объекта данных не даёт. Если папка вернула пусто, проверьте состав через `GET /v3/folders`, а затем `is_active` у объектов и ссылок. ## Адресация: ровно один из двух [#addressing] `object_id` и `folder_id` взаимоисключимы на `GET /v3/reviews`, `GET /v3/analytics` и `GET /v3/analytics/timeseries`: | Что прислали | Ответ | | ------------------ | ------------------------------- | | только `object_id` | данные по одному объекту | | только `folder_id` | данные по всей папке | | оба сразу | `400 group_and_folder_conflict` | | ни одного | `400 group_or_folder_required` | `link_ids` и `source_ids` фильтруют **внутри** состава папки. В аналитике `by_source` схлопывает одну площадку разных объектов в одну строку с суммой, а `meta` показывает фактический состав, попавший в расчёт: ```json { "meta": { "object_id": null, "folder_id": 7, "object_ids": [20, 21, 34], "published_from": "2000-01-01", "published_to": "2026-07-28", "source_ids": [1, 3], "generated_at": "2026-07-28T09:20:11Z" } } ``` Поле `meta.object_id` присутствует всегда: в папочном режиме оно приходит `null`, а не пропадает. # Как отвечать на отзывы (/guides/replies) Ответ, отправленный через Rewio, появляется под отзывом на самой площадке, от лица вашей организации. ```bash curl -X PUT https://api.rewio.ru/v3/reviews/143046/reply \ -H "X-API-Key: hrev_ВАШ_FULL_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"text": "Спасибо за отзыв! Рады, что всё понравилось."}' # -> 202 { "text": "Спасибо за отзыв! …", "status": "pending", … } ``` ## Что нужно до первого ответа [#requirements] Три условия, все обязательные: | | | | ----------- | ----------------------------------------------------------------------------------------------------------- | | Тариф | Полный. На остальных публикация отвечает `402` с кодом `reply_requires_upgrade`. | | Подключение | Площадка должна пустить нас отвечать за вас. Делается на её стороне, один раз на объект – как именно, ниже. | | Ключ | Для публикации и удаления необходим скоуп `full`. Ключ на чтение получит `403`. | Для подключения новой площадки напишите на . ## Где это работает [#platforms] Сейчас на трёх площадках: | Площадка | Опубликовать | Заменить текст | Удалить | | ------------ | ------------ | -------------- | ------- | | Яндекс.Карты | да | да | да | | 2ГИС | да | **нет** | да | | ПроДокторов | да | **нет** | **нет** | В 2ГИС площадка не разрешает переписывать опубликованный ответ: попытка вернёт `409` с кодом `reply_edit_not_supported`. Чтобы поменять текст, [удалите ответ](/replies/delete) и опубликуйте заново. На ПроДокторов ответ публикует клиника, и площадка не даёт ни переписать, ни удалить опубликованный ответ (`reply_edit_not_supported` / `reply_delete_not_supported`). Ответ проходит модерацию площадки, поэтому появляется под отзывом не мгновенно. ## Как подключить площадки [#connect] Возможность отвечать выдаётся на стороне площадки: владелец организации добавляет нашу учётную запись в свой кабинет. Ниже – инструкции по подключению. Организация должна быть зарегистрирована в [Яндекс Бизнесе](https://business.yandex.ru/), доступ выдаёт её владелец. **1. Откройте «Доступы»** – раздел в левом меню кабинета. **2. Добавьте `review.answer@ya.ru` или свою почту с ролью «Представитель».**\ В случае собственной почты необходимо сообщить нам данные для входа.\ Рекомендуем завести для этого отдельную учётную запись. Яндекс Бизнес – раздел «Доступы» и карточка добавления представителя Карточка организации должна быть подтверждена в [2ГИС для бизнеса](https://business.2gis.ru/), приглашение отправляет её владелец. **1. Откройте «Управление доступом»** – пункт в меню аккаунта, справа сверху. **2. Пригласите `review.answer@ya.ru` или свою почту.**\ В случае собственной почты необходимо сообщить нам данные для входа.\ Рекомендуем завести для этого отдельную учётную запись. 2ГИС для бизнеса – «Управление доступом» и приглашение пользователя Доступ выдаётся через мультилогин – [как его настроить](https://help.prodoctorov.ru/nastroyka-multilogina/). **1. Добавьте `review.answer@ya.ru` или свою почту в мультилогин клиники.** **2. Выдайте этой учётной записи права на работу с отзывами.**\ В случае собственной почты необходимо сообщить нам данные для входа.\ Рекомендуем завести для этого отдельную учётную запись. ## Ответить, заменить, удалить [#publish-edit-delete] Ответ у отзыва ровно один, поэтому и метод один: [`PUT`](/replies/publish). Первый вызов публикует, повторный с новым текстом – заменяет. Повтор с тем же текстом ничего не ломает: это не дубль и не ошибка. [`DELETE`](/replies/delete) удаляет ваш ответ с площадки. Удалить можно только свой: ответ, опубликованный не через нас, методу не виден. {/* Скрыто по решению владельца 24.08.2026: три раздела ниже не показываются на портале. Текст сохранён — снять комментарий, когда решим показывать их снова. ## Что происходит с ответом У ответа есть состояние – `status` в ответе на запрос: | `status` | Что значит | |---|---| | `pending` | Мы приняли текст, ответ ждёт публикации. | | `publishing` | Запрос к площадке в полёте. | | `published` | Площадка приняла ответ. | | `failed` | Опубликовать не удалось. | | `deleted` | Ответ удалён с площадки. | `PUT` и `DELETE` возвращают состояние на момент приёма, а это всегда `pending`: новый текст начинает путь заново, даже если предыдущий ответ уже стоял на площадке. Что было дальше, показывает [`GET /v3/reviews/{review_id}/reply`](/replies/get) – по тому же адресу, отдельного идентификатора у ответа нет. ```bash curl https://api.rewio.ru/v3/reviews/143046/reply -H "X-API-Key: hrev_ВАШ_КЛЮЧ" # -> { "status": "published", "published_at": "…", "confirmed_at": "…", "error": null } ``` Чтение доступно и ключу на чтение, и не зависит от тарифа. Там же видна причина, если опубликовать не удалось: `status` станет `failed`, а в `error` придёт код. ## Как узнать, что ответ опубликован Опубликованный ответ виден там же, где живёт отзыв: - **В самом отзыве.** Заполняются `reply_text` и `reply_date` в [`GET /v3/reviews`](/reviews/list) – это подтверждение с площадки, а не наше обещание. - **Событием.** Если настроены [вебхуки](/guides/webhooks), приходит `replies.new`. Между `202` и появлением ответа на площадке проходит от нескольких секунд до нескольких минут. ## Если что-то пошло не так Отказы, которые видны сразу, приходят в ответе на запрос: тариф без ответов, площадка не поддерживает ответы, место под ответ занято другим аккаунтом, текст не прошёл проверку, доступ отозван. Каждый – со своим кодом, все они на странице [Ошибки](/errors). Дальше, при самой публикации, мешать может временное: наш доступ к площадке обновляется, площадка просит подождать, сорвалась сеть. Такие случаи мы отрабатываем сами, повторами, а результат виден в [состоянии ответа](/replies/get). Если ответ не появился, напишите на . */} # Как читать отзывы (/guides/reviews) Все отзывы читаются одним методом: `GET /v3/reviews`. Отзывы могут запрашиваться только по одному адресату: `object_id` – объект, `folder_id` – [папка целиком](/guides/folders). ```bash curl "https://api.rewio.ru/v3/reviews?object_id=20&limit=20" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` ## Страницы [#pagination] Окно задают `limit` (по умолчанию 100) и `offset`. `total` – сколько отзывов подходит под фильтры. `has_next` – есть ли следующая страница. Листайте, пока `has_next` не станет `false`: ```python import requests BASE = "https://api.rewio.ru/v3" HEADERS = {"X-API-Key": "hrev_ВАШ_КЛЮЧ"} def iter_reviews(object_id, **filters): offset, limit = 0, 100 while True: r = requests.get(f"{BASE}/reviews", headers=HEADERS, params={ "object_id": object_id, "limit": limit, "offset": offset, **filters, }) r.raise_for_status() page = r.json() yield from page["data"] if not page["has_next"]: break offset += limit for review in iter_reviews(20, min_rating=1, max_rating=3): print(review["rating"], review["author"]) ``` Так читают ленту целиком. Чтобы узнавать о новых отзывах и ответах, не опрашивая нас, подпишитесь на [вебхуки](/guides/webhooks) – мы сами пришлём событие. ## Альтернатива: обход курсором [#cursor] Если задача не «показать страницу», а перенести отзывы в свою базу и дальше держать её актуальной, листать `offset` не нужно. Для этого есть отдельный метод – поток изменений с курсором: он не теряет отзывы, если лента меняется прямо во время обхода, а на следующем проходе отдаёт только то, что изменилось. Как это устроено – в [Синхронизации данных](/guides/sync). ## Фильтры [#filters] Фильтры складываются: отзыв попадает в выдачу, если проходит все. | Параметр | Что делает | | --------------------------------------------------- | -------------------------------------------------------- | | `source_ids` | Только эти площадки. Параметр повторяемый. | | `link_ids` | Только эти ссылки внутри объекта. | | `min_rating` / `max_rating` | Диапазон оценки по шкале 1–5. | | `published_from` / `published_to` | Диапазон даты публикации. | | `has_text`, `has_images`, `has_videos`, `has_reply` | Наличие текста, фото, видео, ответа организации. | | `search` | Поиск подстроки в тексте, без морфологии и ранжирования. | Сортировка – `sort_by` (`date`, `rating` или `reply_date`) и `sort_order` (`desc` или `asc`). `reply_date` – дата ответа организации: `desc` показывает, на что отвечали последним, `asc` – самые давние ответы. Отзывы без ответа при этом уходят в конец списка в обоих направлениях; чтобы получить именно их, возьмите `has_reply=false`. Пример: негатив с фотографиями за квартал по двум площадкам. ```bash curl -G "https://api.rewio.ru/v3/reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" \ --data-urlencode "object_id=20" \ --data-urlencode "max_rating=3" \ --data-urlencode "has_images=true" \ --data-urlencode "published_from=2026-04-01" \ --data-urlencode "published_to=2026-06-30" \ --data-urlencode "source_ids=1" \ --data-urlencode "source_ids=2" ``` ## Даты отзыва [#dates] У отзыва две даты, и означают они разное: | Поле | Что означает | Зона | Чем фильтровать | | ------------- | ------------------------------------ | ---------------------- | --------------------------------- | | `review_date` | Когда отзыв опубликован на площадке. | Местное время площадки | `published_from` / `published_to` | | `created_at` | Когда отзыв впервые захвачен. | UTC | нельзя | Когда отзыв пропадает с площадки, мы помечаем его `is_deleted` и ставим `deleted_at` – момент, когда мы это заметили. Такие отзывы остаются у вас в истории, по умолчанию скрыты и возвращаются с `show_deleted`. Новые отзывы и ответы приходят [вебхуками](/guides/webhooks) – опрашивать нас для этого не нужно. Если у вас своя база и её надо держать в актуальном состоянии, это отдельная работа: [синхронизация](/guides/sync) – поток изменений с курсором, включая пропажи отзывов с площадок. ## Особые флаги [#flags] * `show_deleted` и `only_deleted` – показать отзывы, пропавшие с площадки. По умолчанию они скрыты. * `show_hidden` и `show_pinned` – вернуть [скрытые и закреплённые](/guides/widgets) отзывы вместе с их флагами. * `split_pros_cons` – разобрать слитый текст на «достоинства» и «недостатки» там, где площадка их разделяет. Каждый параметр и все поля ответа есть в [справочнике](/reviews/list). # Синхронизация данных (/guides/sync) Синхронизация нужна, когда отзывы живут не только у нас, но и в вашей базе: в CRM, в хранилище, в собственной аналитике. Одна ручка — [`GET /v3/reviews/sync`](/reviews/sync). Если своей базы нет, эта страница вам не нужна: показать отзывы на сайте умеет [лента](/guides/reviews), узнать о новом — [вебхук](/guides/webhooks). ## Цикл [#cycle] ```python cursor = db.load_cursor() # None при первом запуске params = {"cursor": cursor} if cursor else {"object_id": 20, "limit": 500} while True: page = httpx.get(f"{API}/reviews/sync", headers=H, params=params).json() for review in page["data"]: db.upsert_review(review) # склейка по review["id"] db.save_cursor(page["next_cursor"]) # ПОСЛЕ каждой страницы if not page["has_next"]: break params = {"cursor": page["next_cursor"]} ``` Первый прогон выгружает всю историю, следующие — только изменения. Отзывы мы собираем дважды в сутки, поэтому возвращаться чаще, чем раз в пару часов, смысла нет: между сборами поток отдаёт пустую страницу. Часового цикла хватает с запасом. ## Четыре правила [#rules] **1. Курсор хранится в базе, а не в памяти процесса.** В нём весь смысл: завтрашний запуск продолжает с той же точки, а не выкачивает всё заново. **2. Сохранять после каждой страницы.** Тогда обрыв связи стоит одной страницы, а не всего обхода. **3. В режиме `all` — UPSERT по `id`, не INSERT.** Изменённый отзыв приходит со старым `id`: новой строки мы не заводим, поэтому вставка даст дубли или ошибку уникальности. В режиме `new` достаточно INSERT — там ничего не приходит дважды. Потерять отзыв поток не может ни в том, ни в другом режиме, это его единственная твёрдая гарантия. **4. `next_cursor` приходит всегда** — и на последней странице, и на пустой. Признак «догнал» — это `has_next: false`, а не отсутствие курсора. ## Что приходит [#payload] Изменением считается: правка текста или оценки на площадке, появившийся или изменившийся ответ организации, изменившийся набор фотографий, пропажа отзыва с площадки (`is_deleted: true`) и его возврат. Пересбор сам по себе — не изменение: если на площадке ничего не поменялось, отзыв в поток не попадёт. | `mode` | Что приходит | Как класть к себе | | -------------------- | -------------------------- | ------------------------------------------------- | | `all` (по умолчанию) | новые отзывы и изменения | **UPSERT** по `id` | | `new` | только впервые появившиеся | **INSERT**: каждый приходит один раз за всю жизнь | Режим запечён в курсор — для второго режима заведите второй курсор. Отдельного режима «только изменения» нет, и он не нужен: когда вы догнали текущее состояние в режиме `all`, дальше в нём приходят как раз одни изменения — новых-то пока не появилось. ## Границы [#limits] * **Порядок задан режимом, и своего параметра сортировки у метода нет.** В `all` строки идут по времени последнего изменения отзыва, в `new` — по времени, когда мы его впервые захватили. Дата публикации на площадке (`review_date`) порядок не задаёт ни там, ни там: отзыв 2019 года, у которого вчера появился ответ, приедет в `all` вместе со вчерашними изменениями, а не в хвосте истории. Нужен свой порядок — стройте его у себя. * **Фильтров нет.** Отзыв, который правкой перестал подходить под фильтр, пришлось бы присылать событием «выбыл» — такого события не существует, поэтому любой фильтр сделал бы поток дырявым. Отбирайте у себя. * **Состав объекта поток не отслеживает.** Убрали ссылку или выключили объект — его отзывы просто перестанут приходить, отдельного события об этом не будет. Чистите у себя по `link_id`. Обратный случай: если ссылку вернули, её старые отзывы сами не приедут — курсор их уже прошёл. Чтобы забрать их снова, начните обход с нуля, без сохранённого курсора. * **Задержка несколько секунд.** Не запаздывание сбора, а защита: отзыв, который прямо сейчас записывается, иначе оказался бы позади вашего курсора и не пришёл бы никогда. ## Если курсор не принят [#cursor-rejected] `400 invalid_cursor` — курсор испорчен, изменён или выдан другому аккаунту: начните обход заново, без `cursor`. `400 cursor_mismatch` — вместе с курсором передан другой `object_id`, `folder_id` или `mode`: либо не передавайте их вовсе, либо передайте те же. Полный список параметров и полей — в [справочнике метода](/reviews/sync). # Как принимать вебхуки (/guides/webhooks) Укажите свой HTTPS-адрес, и Rewio будет присылать на него POST при появлении новых отзывов и ответов. Это замена опросу: узнать о новом отзыве в момент, когда он появился, а не когда вы в очередной раз спросили. На этом строят уведомления менеджеру о негативе, постановку задач на ответ, обновление карточки филиала в CRM и пересчёт витрины на сайте. Если же вам нужна не реакция на событие, а полная копия отзывов у себя, это [синхронизация](/guides/sync), а не вебхуки. Проверка подписи описана в [§3](#signature), все методы есть в [справочнике](/webhooks/list). ## 1. Создать вебхук [#create] ```bash curl -X POST https://api.rewio.ru/v3/webhooks \ -H "X-API-Key: hrev_ВАШ_FULL_КЛЮЧ" -H "Content-Type: application/json" \ -d '{ "target": "https://your-server.com/hooks/reviews", "event_types": ["reviews.new"], "object_ids": [10, 20], "bucket_window": "immediate", "filters": {} }' # -> { "id": 456, "target": "...", "is_active": true, ... } ``` * `target` **обязан быть HTTPS**; приватные / loopback / metadata-адреса отклоняются. * `object_ids` опущен или `null` – все ваши объекты; иначе только перечисленные. [Папки](/guides/folders) в вебхуках не поддерживаются: перечислите объекты явно. * Секрет в ответе не возвращается: он общий на аккаунт и берётся отдельно (см. §3). * Проверить доставку в любой момент: `POST /v3/webhooks/{id}/test`. ### Фильтры (`filters`) [#filters] Объект `filters` сужает, какие отзывы вызывают доставку. Поля объединяются по **И** – отзыв доставляется, только если проходит каждый заданный фильтр. Опустите поле (или весь объект), чтобы фильтр не действовал. ```json { "allowed_ratings": [1, 2, 3, 4, 5], "allowed_sources": ["yandex_maps"], "has_text": false, "has_images": false } ``` **`allowed_ratings`** – корзины оценок; отзыв проходит, если его корзина в списке: | корзина | что попадает | | ------- | ---------------------------------------------------------------------- | | `5` | rating == 5.0 | | `4` | 4.0 ≤ rating \< 5.0 | | `3` | 3.0 ≤ rating \< 4.0 | | `2` | 2.0 ≤ rating \< 3.0 | | `1` | 0.0 ≤ rating \< 2.0 | | `0` | **без числовой оценки** (текстовые площадки), только по явному запросу | Поле опущено – это то же самое, что `[1,2,3,4,5]`: приходят все отзывы с оценкой, без неоценённых. Чтобы получать и неоценённые, добавьте `0`. Примеры: `[1,2]` – только негатив, `[5]` – только идеальные, `[0,1,2,3,4,5]` – вообще всё. * **`allowed_sources`** – машинные имена площадок (поле `slug` в `GET /v3/sources`). Опущено или `null` – все. Регистр не важен. Имя не сверяется с живым списком: опечатка (`"yadnex_maps"`) молча ни с чем не совпадёт, ошибки не будет. * **`has_text`** – `true` доставляет только отзывы с непустым текстом. * **`has_images`** – `true` только с прикреплёнными фото. ## 2. Что вы получаете [#delivery] `POST` на ваш `target` с JSON-телом. Одна доставка несёт пачку отзывов, а не один отзыв. Разбирайте доставку по полю `event`: оно же дублируется в заголовке `X-Hrev-Event`. | `event` | Когда срабатывает | Тело | | --------------------- | ------------------------------------------------------------------ | ------------------------------------------------ | | `reviews.new` | при сборе появились новые отзывы | отзывы, сгруппированные по объектам | | `replies.new` | у отзыва **появился ответ** организации или отзыв пришёл уже с ним | та же форма; читайте `reply_text` и `reply_date` | | `scrape.run.finished` | сбор завершился. Приходит, даже если нового нет | только `finished_at` | `replies.new` срабатывает и на ответы, [опубликованные через нас](/guides/replies): для вас это подтверждение, что ответ дошёл до площадки. Подписывайтесь на любую комбинацию через `event_types`. `filters` применяются к `reviews.new` и `replies.new`. Событие `scrape.run.finished` их игнорирует: в нём нет отзывов. `bucket_window` действует на все три: | `bucket_window` | Доставка | | --------------- | ------------------------------------------------------------------------------------------------------------------------- | | `immediate` | один POST вскоре после каждого сбора. По умолчанию | | `daily_HOUR` | один ответ раз в сутки в конкретный час; `HOUR` = 0–23, время в UTC. Напр. `daily_9` = 09:00 UTC, `daily_0` = полночь UTC | Час дайджеста задаётся в UTC (как всё в системе), без ведущего нуля (`daily_9`, не `daily_09`). ### Заголовки [#headers] | Заголовок | Смысл | | -------------------- | ---------------------------------------------------------- | | `X-Hrev-Event` | тип события | | `X-Hrev-Delivery-Id` | **стабильный id доставки**, для идемпотентности | | `X-Hrev-Event-Id` | id первого отзыва в пачке (`0` для `scrape.run.finished`) | | `X-Hrev-Timestamp` | unix-секунды, участвуют в подписи | | `X-Hrev-Signature` | `sha256=` – одна или несколько через запятую (см. §3) | ### Тело `reviews.new` [#reviews-new] ```json { "schema_version": "3", "event": "reviews.new", "delivery_id": 456, "occurred_at": "2026-07-19T12:00:00", "objects": [ { "object_id": 20, "name": "Grand Hotel", "review_count": 2, "reviews": [ { "id": 78910, "external_review_id": "yandex_maps_abc", "source_id": 1, "source_slug": "yandex_maps", "rating": 4.5, "text": "Отличный отель ...", "author": "Иван П.", "review_date": "2026-07-19T00:00:00", "url": "https://yandex.ru/maps/org/1/reviews", "review_url": "https://yandex.ru/maps/org/1/reviews?reviews[publicId]=abc", "has_images": false, "reply_text": null, "reply_date": null } ] } ], "summary": { "review_count": 2, "by_source": {"yandex_maps": 2}, "average_rating": 4.5, "negative_rating_count": 0 }, "truncated": false } ``` * `rating` – по шкале **1–5**, может быть дробным (`4.5`). * Площадка приходит парой `source_id` + `source_slug` – теми же, что в [`GET /v3/sources`](/sources/list). * `reply_text` / `reply_date` несут ответ организации, если он есть (иначе `null`). * `truncated: true` – payload превысил лимит размера, детализация по отзывам опущена (`objects[].reviews` нет, но `summary` и `object_id`/`review_count` остаются). Дотяните детали через REST при необходимости. Форму тела выбирает подписка, а не запрос. Вебхук, созданный через `POST /v3/webhooks`, получает `schema_version: "3"` – он и описан здесь. Подписки, созданные раньше, через `/v2`, продолжают получать прежнее тело (`schema_version: "2"`, `groups[]` вместо `objects[]`, площадка одной строкой `source`) – ровно то, что получали до этого. ### Тело `replies.new` [#replies-new] Форма та же, что у `reviews.new`. В `objects[].reviews` приходят отзывы, которые только что получили ответ или пришли уже с ним, читайте `reply_text` и `reply_date`. Изменённый ответ повторно не доставляется, только впервые появившийся. ### Тело `scrape.run.finished` [#scrape-run-finished] Событие без отзывов: сообщает, что сбор завершился. Приходит раз за цикл каждому подписанному вебхуку, **даже если нового не найдено**. ```json { "schema_version": "3", "event": "scrape.run.finished", "delivery_id": 789, "occurred_at": "2026-07-19T13:00:00", "finished_at": "2026-07-19T13:00:00" } ``` ## 3. Проверка подписи (опционально) [#signature] Проверка подписи защищает от подделок: адрес `target` публичный, и без проверки кто угодно, узнав его, сможет прислать вам фейковые «новые отзывы». Формально она необязательна: без неё принимайте POST и отвечайте `2xx`. ### Секрет подписи, один на аккаунт [#secret] Все доставки со всех ваших вебхуков подписаны одним секретом аккаунта. Он виден всегда: ```bash curl https://api.rewio.ru/v3/webhooks/secret \ -H "X-API-Key: hrev_ВАШ_FULL_КЛЮЧ" # -> { "secret": "whsec_...", "rotated_at": null } ``` Нужен ключ со скоупом `full`: секрет позволяет подделывать подписи, поэтому ключу на чтение он не отдаётся. Секрет действует, пока вы не перевыпустите его сами (см. §4). ### Как проверять [#verify] Подписываются точные отправляемые байты, с префиксом-таймстампом: ``` signed = f"{X-Hrev-Timestamp}." + <сырые байты тела запроса> sig = HMAC_SHA256(secret, signed) # hex ``` **Проверяйте по сырому телу, до парсинга JSON**: повторная сериализация меняет байты и ломает подпись. ```python import hashlib, hmac, time def verify(headers, raw_body: bytes, secret: str) -> bool: ts = headers["X-Hrev-Timestamp"] # отбрасываем устаревшие / переигранные доставки (±5 мин) if abs(int(time.time()) - int(ts)) > 300: return False expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest() # при ротации заголовок может нести несколько подписей через запятую for part in headers["X-Hrev-Signature"].split(","): part = part.strip() if part.startswith("sha256=") and hmac.compare_digest(part[7:], expected): return True return False ``` ```javascript const crypto = require("crypto"); function verify(headers, rawBody, secret) { const ts = headers["x-hrev-timestamp"]; if (Math.abs(Math.floor(Date.now() / 1000) - Number(ts)) > 300) return false; const expected = crypto.createHmac("sha256", secret) .update(Buffer.concat([Buffer.from(ts + "."), rawBody])).digest("hex"); return headers["x-hrev-signature"].split(",").some((p) => { p = p.trim(); if (!p.startsWith("sha256=")) return false; const got = Buffer.from(p.slice(7)); const exp = Buffer.from(expected); // длины обязательно сверить до timingSafeEqual: на разной длине он бросает // RangeError, и приёмник упадёт 500-й вместо честного «подпись неверна» return got.length === exp.length && crypto.timingSafeEqual(got, exp); }); } ``` ## 4. Ротация секрета (без простоя) [#rotation] `POST /v3/webhooks/rotate-secret` перевыпускает секрет аккаунта и возвращает новый. Следующие 24 часа каждая доставка подписывается и новым, и предыдущим секретом; через запятую в `X-Hrev-Signature`. Проверка выше принимает любую из перечисленных подписей, поэтому обновить приёмник можно в любой момент этого окна. После 24 часов остаётся только новый. ```bash curl -X POST https://api.rewio.ru/v3/webhooks/rotate-secret \ -H "X-API-Key: hrev_ВАШ_FULL_КЛЮЧ" # -> { "secret": "whsec_...", "rotated_at": "2026-07-22T12:00:00" } ``` ## 5. Идемпотентность [#idempotency] Доставки приходят как минимум один раз: сбой между отправкой и учётом может переслать ту же доставку повторно. От этого защищают две вещи: * **Та же доставка всегда переиспользует `X-Hrev-Delivery-Id`** – дедупьте по нему: ```python if seen(delivery_id): # напр. Redis SET NX, TTL 24ч return 200 # уже обработано process(payload) mark_seen(delivery_id) ``` * Отзывы дедуплицируются на нашей стороне: в одной доставке отзыв не встретится дважды. Отвечайте `2xx` быстро, в пределах таймаута доставки. Тяжёлую работу выносите в фон. ### Что вернуть в ответе [#response] Подтверждение получения – это сам HTTP-статус: любой `2xx` означает «принято, больше не пересылать». Тело ответа не читается и не разбирается. Возвращайте короткий JSON вместо пустого ответа: явный `Content-Type` не даст фреймворку или прокси подсунуть HTML-страницу. Минимальный вариант: ``` HTTP/1.1 200 OK Content-Type: application/json {"ok": true} ``` Достаточно и `{}`: важен только код `2xx`. Любой не-2xx или таймаут считается недоставкой, и включаются повторы из §6. ## 6. Ретраи и обработка ошибок [#retries] | Ваш ответ | Результат | | ----------------------------------------------- | ----------------------------- | | `2xx` | успех | | `408`, `429`, `5xx`, таймаут, ошибка соединения | ретрай с backoff | | `3xx` и прочие `4xx` | постоянная ошибка, без ретрая | Лестница backoff: `30с → 1м → 2м → 5м → 10м → 15м`, дальше каждые **30м**. Всего до **30 попыток** за \~12 часов, после чего доставка уходит в `dead_letter`. **Подписка не отключается сама.** Сколько бы доставок ни сорвалось, канал продолжает работать: почините приёмник – события пойдут снова. На каждый 50-й провал подряд мы пишем владельцу аккаунта. Выключить и включить подписку вручную можно через `PATCH /v3/webhooks/{id}`. Чем больше попыток, тем выше шанс задвоенной доставки, поэтому дедупликация по `X-Hrev-Delivery-Id` (§5) обязательна. Если доставка так и не дошла, напишите нам – историю попыток по вашему вебхуку (статус, коды и тела ответов, времена) мы поднимем со своей стороны. # Как собрать виджет отзывов (/guides/widgets) Виджет показывает отзывы объекта на вашей странице. Управляют показом три инструмента: | Что нужно | Чем делается | | ------------------------------------------ | --------------------------------------- | | Закрепить отзыв наверху списка | [Закрепление](/widgets/pinned-set) | | Убрать отзыв из показа | [Скрытие](/widgets/hidden-add) | | Показать плюсы и минусы отдельными блоками | [`split_pros_cons`](/widgets/pros-cons) | Закрепление и скрытие действуют **внутри объекта** и не меняют собранные данные: в другом объекте тот же отзыв останется как был, на самой площадке не изменится ничего. ## Закрепить наверху [#pinned] Закреплённые отзывы образуют упорядоченный список, максимум 30 на объект. [Добавить в конец](/widgets/pinned-add) – `POST`, [задать порядок целиком](/widgets/pinned-set) – `PUT`: ```bash # добавить в конец curl -X POST "https://api.rewio.ru/v3/objects/20/pinned-reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"review_ids": [143046]}' # переставить: порядок в запросе становится порядком показа curl -X PUT "https://api.rewio.ru/v3/objects/20/pinned-reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"ordered_review_ids": [142391, 143046]}' ``` `PUT` – замена целиком: отзывы, которых нет в списке, открепляются. Место каждого приходит в `pin_position`, считая с нуля. ## Скрыть и вернуть [#hidden] ```bash # скрыть curl -X POST "https://api.rewio.ru/v3/objects/20/hidden-reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"review_ids": [143046, 142391]}' # вернуть в ленту curl -X DELETE "https://api.rewio.ru/v3/objects/20/hidden-reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"review_ids": [142391]}' ``` Скрытый отзыв пропадает из обычной ленты. Он остаётся доступен [списком скрытых](/widgets/hidden-list) и в обычной ленте с `show_hidden=true`, там у него приходит флаг `is_hidden`. За один запрос – до 200 идентификаторов. Скрытие снимает закрепление. Снятие скрытия его не возвращает – закрепите заново. ## Как собрать страницу [#page] В обычной ленте нет ни закреплённых, ни скрытых: `GET /v3/reviews` по умолчанию исключает и тех и других. Поэтому страница собирается двумя запросами, и дублей между ними не бывает – закреплённые сверху, за ними обычная лента. ```python import requests BASE = "https://api.rewio.ru/v3" HEADERS = {"X-API-Key": "hrev_ВАШ_КЛЮЧ"} OBJECT = 20 pinned = requests.get(f"{BASE}/objects/{OBJECT}/pinned-reviews", headers=HEADERS).json()["data"] feed = requests.get(f"{BASE}/reviews", headers=HEADERS, params={"object_id": OBJECT, "limit": 20}).json()["data"] for review in pinned + feed: # скрытые не придут ни там, ни там print(review["rating"], review["author"]) ``` Нужны закреплённые прямо в общей ленте – передайте `show_pinned=true`, и они придут вперемешку с остальными, с флагом `is_pinned`. Ключ API открывает все данные аккаунта, поэтому в браузерный код он не попадает: запрашивайте отзывы со своего бэкенда и отдавайте странице уже готовый ответ. Подробнее – в [Доступе](/access). ## Плюсы и минусы отдельными блоками [#pros-cons] Часть площадок спрашивает у автора достоинства и недостатки по отдельности. С `split_pros_cons=true` они приходят полями `pros` и `cons`, и показать их можно двумя колонками. Подробности и список площадок – на [отдельной странице](/widgets/pros-cons). ## Средний балл не зависит от показа [#rating] [Аналитика](/analytics/summary) считает **все** собранные отзывы объекта. Скрыли отзыв с единицей – он пропал из показа, но средний балл и распределение оценок не изменились. Это сделано намеренно: скрытие оформляет показ, а не правит данные. Если рядом с отзывами нужен балл, согласованный с показанными, считайте его сами по выдаче. ## В папках работает не всё [#folders] [Папочная лента](/guides/folders) применяет скрытие, но не закрепление. В ленте по папке закреплённый отзыв приходит обычной строкой, а флагов `is_pinned` и `is_hidden` там нет. Поэтому лента по папке из одного объекта может вернуть **больше** отзывов, чем лента по этому же объекту – ровно на число закреплённых. # Расширенная проверка (/extra/health-detailed) `GET /health/detailed` – проверка глубже двух предыдущих. Она смотрит не только на то, отвечает ли API, но и на то, в порядке ли всё, от чего он зависит. ```bash curl -i https://api.rewio.ru/health/detailed ``` Ключ не обязателен. ## Что она проверяет [#checks] Четыре вещи, и каждая проверяется по-настоящему, а не по факту «процесс запущен»: 1. **Хранилище данных** – выполняется запрос к базе. 2. **Кэш** – проверяется отклик. 3. **Фоновая обработка** – отвечают ли исполнители задач сбора. 4. **Регулярные задачи** – не замолчала ли работа по расписанию. Это отдельная проверка, потому что незапустившаяся задача не падает и другими способами не ловится. Состав проверок может меняться: читайте поле `status`, а не список под ним. ## Ответ и коды [#response] | Код | `status` | Что означает | | ----- | ---------- | ------------------------------------ | | `200` | `healthy` | Все проверки прошли. | | `503` | `degraded` | **Хотя бы одна** проверка не прошла. | Промежуточного состояния нет: одна незелёная проверка сразу даёт `503`, чтобы внешний мониторинг видел отказ, а не `200` с плохим телом внутри. ```json { "status": "degraded", "dependencies": { "…": { "status": "healthy" }, "…": { "status": "unhealthy" } } } ``` В `dependencies` каждая проверка отмечена `healthy` или `unhealthy`. Набор и названия проверок – наша внутренняя кухня: они меняются вместе с устройством сервиса, и завязываться на них не стоит. Ориентир один – поле `status` и код ответа. Текст ошибки в теле не показывается: он виден только администраторам сервиса. Для постоянного мониторинга берите [`/health/read`](/extra/health-read): он дешевле, отвечает на тот же вопрос «получу ли я сейчас данные» и не зависит от частей сервиса, которые к выдаче отношения не имеют. Расширенная проверка нужна, когда что-то уже сломалось и надо понять, насколько. # Проверка чтения данных (/extra/health-read) Проверка, которую стоит поставить в мониторинг. Отвечает `200`, если чтение данных работает – значит методы отзывов и аналитики ответят. Если нет – `503`. Ключ не нужен. ## GET https://api.rewio.ru/health/read Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 Тело ответа пустое. ### Пример ответа ```json { "status": "ready", "checks": { "mysql": "healthy" } } ``` ## Чем отличается от `/health` [#vs-health] [`/health`](/extra/health) говорит только «API на связи»: он ответит `200` и в тот момент, когда отзывы прочитать нельзя. Эта проверка идёт дальше и трогает сами данные, поэтому отвечает на вопрос, который вам действительно нужен, – «получу ли я сейчас отзывы». Метод поддерживает `HEAD` – если вашему мониторингу тело ответа не нужно. | Ответ | Что означает | | ---------------------------- | --------------------------------------------- | | `200`, `status: ready` | Читающие методы работают. | | `503`, `status: unavailable` | Данные сейчас не читаются. Ждать и повторять. | Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Доступность API (/extra/health) Самая дешёвая проверка: API на связи или нет. Ключ не нужен – заголовок `X-API-Key` метод не читает вовсе. Именно поэтому им удобно отделять проблему с сетью от проблемы с ключом. Молчит – дело в сети или на нашей стороне. Отвечает, а ваш следующий запрос с ключом даёт `401` – дело в ключе. ## GET https://api.rewio.ru/health Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 Тело ответа пустое. ### Пример ответа ```json { "status": "healthy", "app": "Review Aggregator", "environment": "production" } ``` ## Что в ответе [#response] | Поле | Что означает | | ------------- | --------------------------------------------------------------- | | `status` | Всегда `healthy`, если ответ вообще пришёл. | | `app` | Название сервиса. | | `environment` | Контур, который вам ответил. У `api.rewio.ru` это `production`. | Метод не проверяет ни данные, ни ваш доступ: он отвечает `200` и тогда, когда отзывы временно не читаются. Для мониторинга берите [проверку чтения](/extra/health-read) – она отвечает `503`, когда читающие методы недоступны. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Написать разработчику (/extra/support) Обращение к разработчику API: вопрос, ошибка в выдаче, просьба подключить площадку. Номер аккаунта, почту и тариф добавляем сами, по ключу, которым сделан запрос. Писать их в тексте не нужно – достаточно описать, что происходит. ## POST https://api.rewio.ru/v3/support/message Заголовок `X-API-Key` обязателен в каждом запросе. ### Тело запроса - `subject` (строка, обязательный) – О чём обращение, одной строкой. От 2 до 200 символов. - `message` (строка, обязательный) – Текст обращения. От 5 до 5000 символов. - `contact` (строка, может быть null) – Как с вами связаться, если почта аккаунта не подходит – телефон, телеграм, другой адрес. Необязательное поле. ### Пример запроса ```json { "subject": "Пустая выдача по объекту 20", "message": "Со вчерашнего дня GET /v3/reviews по объекту 20 возвращает total: 0, хотя на площадке отзывы есть. Ключ read_only, тот же запрос работал в понедельник.", "contact": "телеграм @petrov" } ``` ### Ответ 202 - `status` (строка, обязательный) – Всегда `accepted` – обращение принято. ### Пример ответа ```json { "status": "accepted" } ``` ## Что важно знать [#notes] **Работает с любым ключом.** В том числе с `read_only`: сообщить о поломке – не запись данных, и упереться в права доступа в такой момент неправильно. Из личного кабинета метод тоже доступен. **`contact` необязателен.** Без него мы отвечаем на почту аккаунта. Поле пригодится, если ключ общий на несколько человек или ответ нужен не на почту: тогда напишите в `contact`, как вас найти. **Ответ `202`, а не `200`.** Он означает «обращение принято», а не «на него уже ответили». Ответ приходит письмом. **Не больше 10 обращений в час** с одного аккаунта. Одиннадцатое получает `429` с кодом `rate_limited` – это защита от цикла в вашем коде, а не ограничение на общение. Если обращений действительно нужно больше, напишите об этом в первом. Если отправка временно недоступна, метод отвечает `503` с кодом `email_unavailable` – обращение при этом **не** сохранено, повторите позже. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Добавить ссылки (/links/add) Подключает к объекту новые площадки. Тело запроса – **массив ссылок**, без объекта-обёртки, до 200 за раз. Примеры адресов ссылок и где их взять – в [Форматах ссылок](/link-formats). Ссылка, которую не удалось добавить, не отменяет остальные: они добавятся, а по ней в `link_results` придёт причина отказа. На одну площадку в объекте приходится одна ссылка. ## POST https://api.rewio.ru/v3/objects/{object_id}/links Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в который добавляются ссылки. - `Idempotency-Key` (строка, header, может быть null) – Свой ключ запроса. Повтор с тем же ключом не добавит ссылки второй раз. ### Тело запроса - `[].url` (ссылка, обязательный) – Адрес страницы объекта на площадке, как он открывается в браузере. Площадку определим сами. - `[].is_active` (да/нет, по умолчанию да) – Собирать ли отзывы по этой ссылке. - `[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта, например «Филиал на Невском». ### Пример запроса ```json [ { "url": "https://2gis.ru/moscow/firm/70000001006369779", "link_name": "2ГИС" }, { "url": "https://www.tripadvisor.ru/Hotel_Review-g298484-d299118", "link_name": "Tripadvisor" } ] ``` ### Ответ 201 - `object_id` (число, обязательный) – Объект, в который добавлялись ссылки. - `link_results` (список объектов, обязательный) – Итог по каждой переданной ссылке, в том же порядке. - `link_results[].url` (строка, обязательный) – Адрес, к которому относится результат. - `link_results[].link_id` (число, может быть null) – Идентификатор созданной ссылки. Пусто, если добавить не удалось. - `link_results[].source_slug` (строка, может быть null) – Площадка, определённая по адресу. - `link_results[].link_name` (строка, может быть null) – Своё название ссылки, если его задавали. - `link_results[].error` (строка, может быть null) – Причина, по которой ссылку не удалось добавить. - `link_results[].error_code` (строка, может быть null) – Машинная причина отказа – по ней и стоит ветвиться: `source_not_detected`, `source_url_invalid`, `source_requires_upgrade`, `source_already_linked`, `link_already_added`. Пусто при успехе. ### Пример ответа ```json { "object_id": 20, "link_results": [ { "url": "https://2gis.ru/moscow/firm/70000001006369779", "link_id": 523, "source_slug": "2gis", "link_name": "2ГИС", "error": null }, { "url": "https://www.tripadvisor.ru/Hotel_Review-g298484-d299118", "link_id": null, "source_slug": null, "link_name": "Tripadvisor", "error": "Площадка по этому адресу не поддерживается" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Ссылки объекта (/links/list) Площадки, подключённые к объекту, и то, чем кончился последний сбор по каждой. ## GET https://api.rewio.ru/v3/objects/{object_id}/links Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, ссылки которого нужны. ### Ответ 200 - `data` (список объектов, обязательный) – Ссылки объекта. Пагинации нет: на одну площадку в объекте приходится одна ссылка. - `data[].id` (число, обязательный) – Идентификатор ссылки. - `data[].url` (строка, обязательный) – Адрес страницы объекта на площадке. - `data[].source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `data[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `data[].auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `data[].is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `data[].scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `data[].scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `data[].last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `data[].last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `data[].created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. ### Пример ответа ```json { "data": [ { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" }, { "id": 178, "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "source_id": 106, "link_name": "Островок Националь", "auto_name": "Ostrovok: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:04", "last_scraped_review_date": "2026-08-02T13:04:59", "created_at": "2026-02-23T17:32:06" }, { "id": 179, "url": "https://101hotels.com/opinions/hotel/moskva/gostinitsa_natsional.html", "source_id": 105, "link_name": "101hotels Националь", "auto_name": "101Hotels: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:20:05", "last_scraped_review_date": "2026-05-06T00:00:00", "created_at": "2026-02-23T17:33:18" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Удалить ссылку (/links/remove) Отключает площадку от объекта: ссылка удаляется, собранные по ней отзывы больше не отдаются. Чтобы остановить сбор, сохранив накопленные отзывы, [выключите ссылку](/links/update) через `is_active: false`. ## DELETE https://api.rewio.ru/v3/objects/{object_id}/links/{link_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, которому принадлежит ссылка. - `link_id` (число, path, обязательный) – Ссылка, которую нужно удалить. ### Ответ 200 - `message` (строка, обязательный) – Сообщение об итоге операции. - `object_id` (число, обязательный) – Объект, из которого удалена ссылка. - `link_id` (число, обязательный) – Идентификатор удалённой ссылки. ### Пример ответа ```json { "message": "Link removed from object", "object_id": 20, "link_id": 523 } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Обновить ссылку (/links/update) Меняет название ссылки внутри объекта и то, собирать ли по ней отзывы. Сам адрес поменять нельзя – для другой страницы добавьте новую ссылку. Выключенная ссылка (`is_active: false`) перестаёт обновляться, но уже собранные отзывы остаются в объекте. ## PUT https://api.rewio.ru/v3/objects/{object_id}/links/{link_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, которому принадлежит ссылка. - `link_id` (число, path, обязательный) – Ссылка, которую нужно изменить. ### Тело запроса - `link_name` (строка, может быть null) – Новое название ссылки внутри объекта. Не передано – остаётся прежним. - `is_active` (да/нет, может быть null) – Собирать ли отзывы по этой ссылке. Не передано – остаётся как было. ### Пример запроса ```json { "link_name": "Яндекс Карты — Националь", "is_active": true } ``` ### Ответ 200 - `id` (число, обязательный) – Идентификатор ссылки. - `url` (строка, обязательный) – Адрес страницы объекта на площадке. - `source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. ### Пример ответа ```json { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Карты — Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Создать объект (/objects/create) Объект – ваш объект: отель, клиника, филиал, врач или специалист. Ссылки на площадки передаются при создании или отдельным методом [добавления ссылок](/links/add). Ссылка, которую не удалось добавить, не отменяет остальные: они добавятся, а по ней в `link_results` придёт причина отказа. Какой адрес принимает каждая площадка, смотрите в [Форматах ссылок](/link-formats). ## POST https://api.rewio.ru/v3/objects Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `Idempotency-Key` (строка, header, может быть null) – Свой ключ запроса. Повтор с тем же ключом вернёт первый объект, а не создаст второй. ### Тело запроса - `name` (строка, обязательный) – Название объекта. Его видно в личном кабинете и в ответах API. - `links` (список объектов, может быть null) – Ссылки на страницы объекта на площадках. Можно не передавать и добавить позже. - `links[].url` (ссылка, обязательный) – Адрес страницы объекта на площадке, как он открывается в браузере. Площадку определим сами. - `links[].is_active` (да/нет, по умолчанию да) – Собирать ли отзывы по этой ссылке. - `links[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта, например «Филиал на Невском». ### Пример запроса ```json { "name": "Гостиница «Националь»", "links": [ { "url": "https://yandex.com/maps/org/national/1020542995", "link_name": "Яндекс Карты" }, { "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "link_name": "Островок" } ] } ``` ### Ответ 201 - `id` (число, обязательный) – Идентификатор созданного объекта. - `name` (строка, обязательный) – Название объекта. - `created_at` (дата и время, обязательный) – Когда объект создан. - `link_results` (список объектов, может быть null) – Итог по каждой переданной ссылке, в том же порядке. - `link_results[].url` (строка, обязательный) – Адрес, к которому относится результат. - `link_results[].link_id` (число, может быть null) – Идентификатор созданной ссылки. Пусто, если ссылку добавить не удалось. - `link_results[].source_slug` (строка, может быть null) – Площадка, определённая по адресу. - `link_results[].link_name` (строка, может быть null) – Своё название ссылки, если его задавали. - `link_results[].error` (строка, может быть null) – Причина, по которой ссылку не удалось добавить. - `link_results[].error_code` (строка, может быть null) – Машинная причина отказа — по ней и следует ветвиться: `source_not_detected`, `source_url_invalid`, `source_requires_upgrade`, `source_already_linked` (площадка в объекте может быть только одна), `link_already_added`. `null` при успехе. ### Пример ответа ```json { "name": "Гостиница «Националь»", "id": 218, "created_at": "2026-08-03T13:41:08", "link_results": [ { "url": "https://yandex.com/maps/org/national/1020542995", "link_id": 521, "source_slug": "yandex_maps", "link_name": "Яндекс Карты", "error": null }, { "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "link_id": 522, "source_slug": "ostrovok", "link_name": "Островок", "error": null } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Удалить объект (/objects/delete) Удаляет объект вместе со всеми его ссылками. Собранные отзывы по ней больше не отдаются. Чтобы убрать объект из выдачи на время, [выключите его](/objects/update) через `is_active: false`. ## DELETE https://api.rewio.ru/v3/objects/{object_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, который нужно удалить. ### Ответ 200 - `id` (число, обязательный) – Идентификатор удалённого объекта. - `name` (строка, обязательный) – Название удалённого объекта. ### Пример ответа ```json { "id": 218, "name": "Гостиница «Националь»" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Получить объект (/objects/get) Один объект со всеми его ссылками и состоянием сбора по каждой. ## GET https://api.rewio.ru/v3/objects/{object_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, который нужно получить. ### Ответ 200 - `id` (число, обязательный) – Идентификатор объекта. - `name` (строка, обязательный) – Название объекта. - `is_active` (да/нет, обязательный) – Включён ли объект. У выключенного сбор остановлен, отзывы и аналитика не отдаются. - `scrape_status` (строка, обязательный, pending / in_progress / success / partial / failed) – Итог последнего сбора по объекту: `success` – собрались все площадки, `partial` – часть, `failed` – ни одной, `in_progress` – сбор идёт, `pending` – собирать пока нечего. Выключенные ссылки не в счёт. - `last_scraped_at` (дата и время, может быть null) – Когда по объекту последний раз собирали отзывы: самая поздняя дата среди включённых ссылок. - `created_at` (дата и время, обязательный) – Когда объект создан. - `links` (список объектов, по умолчанию пусто) – Страницы объекта на площадках. - `links[].id` (число, обязательный) – Идентификатор ссылки. - `links[].url` (строка, обязательный) – Адрес страницы объекта на площадке. - `links[].source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `links[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `links[].auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `links[].is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `links[].scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `links[].scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `links[].last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `links[].last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `links[].created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. ### Пример ответа ```json { "id": 20, "name": "Националь", "is_active": true, "scrape_status": "success", "last_scraped_at": "2026-08-04T05:06:04", "created_at": "2026-02-23T17:29:38", "links": [ { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" }, { "id": 178, "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "source_id": 106, "link_name": "Островок Националь", "auto_name": "Ostrovok: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:04", "last_scraped_review_date": "2026-08-02T13:04:59", "created_at": "2026-02-23T17:32:06" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Список объектов (/objects/list) Ваши объекта вместе со ссылками на площадки – от новых к старым. ## GET https://api.rewio.ru/v3/objects Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `limit` (число, query, 1–1000, по умолчанию 100) – Сколько объектов вернуть за один запрос. - `offset` (число, query, не меньше 0, по умолчанию 0) – Сколько объектов пропустить с начала списка. ### Ответ 200 - `data` (список объектов, обязательный) – Объекты текущей страницы, от новых к старым. - `data[].id` (число, обязательный) – Идентификатор объекта. - `data[].name` (строка, обязательный) – Название объекта. - `data[].is_active` (да/нет, обязательный) – Включён ли объект. У выключенного сбор остановлен, отзывы и аналитика не отдаются. - `data[].scrape_status` (строка, обязательный, pending / in_progress / success / partial / failed) – Итог последнего сбора по объекту: `success` – собрались все площадки, `partial` – часть, `failed` – ни одной, `in_progress` – сбор идёт, `pending` – собирать пока нечего. Выключенные ссылки не в счёт. - `data[].last_scraped_at` (дата и время, может быть null) – Когда по объекту последний раз собирали отзывы: самая поздняя дата среди включённых ссылок. - `data[].created_at` (дата и время, обязательный) – Когда объект создан. - `data[].links` (список объектов, по умолчанию пусто) – Страницы объекта на площадках. - `data[].links[].id` (число, обязательный) – Идентификатор ссылки. - `data[].links[].url` (строка, обязательный) – Адрес страницы объекта на площадке. - `data[].links[].source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `data[].links[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `data[].links[].auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `data[].links[].is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `data[].links[].scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `data[].links[].scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `data[].links[].last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `data[].links[].last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `data[].links[].created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. - `total` (число, обязательный) – Сколько всего у вас объектов. - `limit` (число, обязательный) – Размер страницы, применённый к запросу. - `offset` (число, обязательный) – Смещение, применённое к запросу. - `has_next` (да/нет, обязательный) – Есть ли ещё объекта за текущей страницей. ### Пример ответа ```json { "data": [ { "id": 20, "name": "Националь", "is_active": true, "scrape_status": "success", "last_scraped_at": "2026-08-04T05:06:04", "created_at": "2026-02-23T17:29:38", "links": [ { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" }, { "id": 178, "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "source_id": 106, "link_name": "Островок Националь", "auto_name": "Ostrovok: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:04", "last_scraped_review_date": "2026-08-02T13:04:59", "created_at": "2026-02-23T17:32:06" } ] } ], "total": 14, "limit": 100, "offset": 0, "has_next": false } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Включить или выключить объекты (/objects/toggle) Включает или выключает до 200 объектов за один вызов. Переключается всё, что доступно: чужой, несуществующий или удалённый `object_id` молча пропускается, остальные объекта набора всё равно переключаются. В ответе – только те, что переключились. ## PUT https://api.rewio.ru/v3/objects Заголовок `X-API-Key` обязателен в каждом запросе. ### Тело запроса - `object_ids` (список чисел, обязательный) – Объекты, которые нужно переключить, от 1 до 200 за запрос. Повторы схлопываются. - `is_active` (да/нет, обязательный) – Куда переключить весь набор: `true` включить, `false` выключить. ### Пример запроса ```json { "object_ids": [ 20, 21 ], "is_active": false } ``` ### Ответ 200 - `data` (список объектов, обязательный) – Объекты после переключения. Пагинации нет. - `data[].id` (число, обязательный) – Идентификатор объекта. - `data[].name` (строка, обязательный) – Название объекта. - `data[].is_active` (да/нет, обязательный) – Включён ли объект. - `data[].scrape_status` (строка, обязательный, pending / in_progress / success / partial / failed) – Итог последнего сбора по объекту: `success` – собрались все площадки, `partial` – часть, `failed` – ни одной, `in_progress` – сбор идёт, `pending` – собирать пока нечего. Выключенные ссылки не в счёт. - `data[].last_scraped_at` (дата и время, может быть null) – Когда по объекту последний раз собирали отзывы: самая поздняя дата среди включённых ссылок. - `data[].created_at` (дата и время, обязательный) – Когда объект создан. - `data[].links` (список объектов, по умолчанию пусто) – Страницы объекта на площадках. - `data[].links[].id` (число, обязательный) – Идентификатор ссылки. - `data[].links[].url` (строка, обязательный) – Адрес страницы объекта на площадке. - `data[].links[].source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `data[].links[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `data[].links[].auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `data[].links[].is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `data[].links[].scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `data[].links[].scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `data[].links[].last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `data[].links[].last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `data[].links[].created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. ### Пример ответа ```json { "data": [ { "id": 20, "name": "Националь", "is_active": false, "scrape_status": "success", "last_scraped_at": "2026-08-04T05:06:04", "created_at": "2026-02-23T17:29:38", "links": [ { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" }, { "id": 178, "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "source_id": 106, "link_name": "Островок Националь", "auto_name": "Ostrovok: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:04", "last_scraped_review_date": "2026-08-02T13:04:59", "created_at": "2026-02-23T17:32:06" } ] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Обновить объект (/objects/update) Меняет название объекта и его выключатель. Передавайте только то, что нужно изменить. Выключенный объект (`is_active: false`) перестаёт отдавать отзывы и аналитику – на запросы по нему приходит 404, сбор по ссылкам останавливается. Сам объект остаётся: его видно в списке, можно переименовать и включить обратно. ## PUT https://api.rewio.ru/v3/objects/{object_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, который нужно изменить. ### Тело запроса - `name` (строка, может быть null) – Новое название, 1–255 символов. Не передано – остаётся прежним. - `is_active` (да/нет, может быть null) – Включить или выключить объект. Не передано – остаётся как было. ### Пример запроса ```json { "name": "Гостиница «Националь»" } ``` ### Ответ 200 - `id` (число, обязательный) – Идентификатор объекта. - `name` (строка, обязательный) – Название объекта. - `is_active` (да/нет, обязательный) – Включён ли объект. - `scrape_status` (строка, обязательный, pending / in_progress / success / partial / failed) – Итог последнего сбора по объекту: `success` – собрались все площадки, `partial` – часть, `failed` – ни одной, `in_progress` – сбор идёт, `pending` – собирать пока нечего. Выключенные ссылки не в счёт. - `last_scraped_at` (дата и время, может быть null) – Когда по объекту последний раз собирали отзывы: самая поздняя дата среди включённых ссылок. - `created_at` (дата и время, обязательный) – Когда объект создан. - `links` (список объектов, по умолчанию пусто) – Страницы объекта на площадках. - `links[].id` (число, обязательный) – Идентификатор ссылки. - `links[].url` (строка, обязательный) – Адрес страницы объекта на площадке. - `links[].source_id` (число, обязательный) – Площадка, к которой относится ссылка. - `links[].link_name` (строка, может быть null) – Своё название ссылки внутри объекта. - `links[].auto_name` (строка, может быть null) – Название, прочитанное с площадки, с её подписью впереди (`2ГИС: Кофейня Север`). Пока имя не прочитано, остаётся одна подпись. Своё `link_name` важнее. - `links[].is_active` (да/нет, обязательный) – Собираются ли отзывы по этой ссылке. - `links[].scrape_status` (строка, обязательный, pending / in_progress / success / failed) – Чем кончился последний сбор: `pending`, `in_progress`, `success` или `failed`. - `links[].scrape_error` (строка, может быть null) – Что помешало последнему сбору. - `links[].last_scraped_at` (дата и время, может быть null) – Когда по ссылке последний раз собирали отзывы. - `links[].last_scraped_review_date` (дата и время, может быть null) – Дата публикации самого свежего собранного отзыва. - `links[].created_at` (дата и время, обязательный) – Когда ссылка добавлена в объект. ### Пример ответа ```json { "id": 20, "name": "Гостиница «Националь»", "is_active": true, "scrape_status": "success", "last_scraped_at": "2026-08-04T05:06:04", "created_at": "2026-02-23T17:29:38", "links": [ { "id": 177, "url": "https://yandex.com/maps/org/national/1020542995", "source_id": 1, "link_name": "Яндекс Националь", "auto_name": "Яндекс.Карты: Националь", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:03", "last_scraped_review_date": "2026-08-03T09:42:39", "created_at": "2026-02-23T17:30:52" }, { "id": 178, "url": "https://ostrovok.ru/hotel/russia/moscow/mid7467340/gostinitsa_natsional_moskva", "source_id": 106, "link_name": "Островок Националь", "auto_name": "Ostrovok: Гостиница Националь Москва", "is_active": true, "scrape_status": "success", "scrape_error": null, "last_scraped_at": "2026-08-04T05:06:04", "last_scraped_review_date": "2026-08-02T13:04:59", "created_at": "2026-02-23T17:32:06" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Список площадок (/sources/list) Площадки, с которых Rewio собирает отзывы – Яндекс Карты, Google, 2ГИС и ещё почти три десятка сервисов. Идентификатор площадки подставляется в фильтры отзывов и аналитики. ## GET https://api.rewio.ru/v3/sources Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `data` (список объектов, обязательный) – Площадки. Пагинации нет: список возвращается целиком. - `data[].id` (число, обязательный) – Идентификатор площадки. Его подставляют в фильтр `source_ids` у отзывов и аналитики. - `data[].slug` (строка, обязательный) – Машинное имя площадки: латиница, не меняется. - `data[].name` (строка, обязательный) – Название площадки для интерфейса. - `data[].base_url` (строка, может быть null) – Домен площадки. Ссылки в объект принимаются только на него. - `data[].rating_scale` (число, может быть null) – Шкала оценок самой площадки: 5, 10 и так далее. В отзывах оценка уже приведена к 1–5. - `data[].supports_replies` (да/нет, обязательный) – Площадка позволяет организации отвечать на отзывы. - `data[].supports_images` (да/нет, обязательный) – К отзывам на площадке можно прикладывать фотографии. - `data[].can_publish_reply` (да/нет, обязательный) – Мы умеем публиковать ответы на этой площадке. Не то же самое, что `supports_replies`. - `data[].created_at` (дата и время, обязательный) – Когда площадка появилась в Rewio. ### Пример ответа ```json { "data": [ { "id": 1, "slug": "yandex_maps", "name": "Яндекс.Карты", "base_url": "https://yandex.ru/maps/", "rating_scale": 5, "supports_replies": true, "supports_images": true, "can_publish_reply": true, "created_at": "2026-02-08T18:33:17" }, { "id": 2, "slug": "google", "name": "Google Maps", "base_url": "https://www.google.com/maps", "rating_scale": 5, "supports_replies": true, "supports_images": true, "can_publish_reply": false, "created_at": "2026-02-23T05:51:28" }, { "id": 3, "slug": "2gis", "name": "2ГИС", "base_url": "https://2gis.ru/", "rating_scale": 5, "supports_replies": true, "supports_images": true, "can_publish_reply": true, "created_at": "2026-02-08T18:33:19" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Создать вебхук (/webhooks/create) Rewio отправляет события на ваш адрес, когда появляются новые отзывы. Каждая доставка подписана заголовком `X-Hrev-Signature`. Секрет общий на все вебхуки аккаунта – заберите его на [отдельной странице](/webhooks/secret). ## POST https://api.rewio.ru/v3/webhooks Заголовок `X-API-Key` обязателен в каждом запросе. ### Тело запроса - `target` (строка, обязательный) – Адрес, на который слать события. Только HTTPS. - `object_ids` (список чисел, может быть null) – Объекты, события которых доставлять. Не передано – все ваши объекты, включая будущие. - `event_types` (список строк, обязательный) – Какие события доставлять: `reviews.new`, `replies.new`, `scrape.run.finished`. - `bucket_window` (строка, по умолчанию «immediate») – Как часто доставлять: `immediate` – сразу после сбора, `daily_<час>` – сводкой в указанный час UTC (`daily_09`). - `filters` (объект) – Что доставлять, а что пропускать. Условия складываются: событие проходит, только если выполнены все. - `filters.allowed_ratings` (список чисел) – Доставлять только отзывы с этими оценками. Пусто – с любыми. - `filters.allowed_sources` (список строк, может быть null) – Доставлять только с этих площадок, машинными именами из справочника. Пусто – со всех. - `filters.has_text` (да/нет, по умолчанию нет) – Доставлять только отзывы с текстом. - `filters.has_images` (да/нет, по умолчанию нет) – Доставлять только отзывы с фотографиями. ### Пример запроса ```json { "target": "https://example.com/hooks/rewio", "object_ids": [ 20 ], "event_types": [ "reviews.new", "replies.new" ], "bucket_window": "immediate", "filters": { "allowed_ratings": [ 1, 2, 3 ], "has_text": true } } ``` ### Ответ 201 - `id` (число, обязательный) – Идентификатор созданного вебхука. - `target` (строка, обязательный) – Адрес, на который приходят события. - `object_ids` (список чисел, может быть null) – Объекты, события которых доставляются. - `event_types` (список строк, обязательный) – Какие события доставляются. - `bucket_window` (строка, обязательный) – Как часто доставляются. - `filters` (объект, обязательный) – Применённые фильтры доставки. - `filters.allowed_ratings` (список чисел) – Оценки, при которых доставлять. - `filters.allowed_sources` (список строк, может быть null) – Площадки, при которых доставлять. - `filters.has_text` (да/нет, по умолчанию нет) – Только отзывы с текстом. - `filters.has_images` (да/нет, по умолчанию нет) – Только отзывы с фотографиями. - `is_active` (да/нет, обязательный) – Включена ли доставка. - `failure_count` (число, обязательный) – Сколько неудачных доставок подряд. - `last_failure_at` (дата и время, может быть null) – Когда доставка не удалась в последний раз. - `created_at` (дата и время, обязательный) – Когда вебхук создан. - `updated_at` (дата и время, обязательный) – Когда его меняли в последний раз. ### Пример ответа ```json { "id": 41, "target": "https://example.com/hooks/rewio", "object_ids": [ 20 ], "event_types": [ "reviews.new", "replies.new" ], "bucket_window": "immediate", "filters": { "allowed_ratings": [ 1, 2, 3 ], "allowed_sources": null, "has_text": true, "has_images": false }, "is_active": true, "failure_count": 0, "last_failure_at": null, "created_at": "2026-08-01T09:14:02", "updated_at": "2026-08-01T09:14:02" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Удалить вебхук (/webhooks/delete) Удаляет вебхук. Доставка на его адрес прекращается сразу, история доставок пропадает вместе с ним. Чтобы приостановить доставку, не теряя настройки, вебхук проще выключить: `PATCH /v3/webhooks/{webhook_id}` с `is_active: false`. ## DELETE https://api.rewio.ru/v3/webhooks/{webhook_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `webhook_id` (число, path, обязательный) – Вебхук, который нужно удалить. ### Ответ 204 Тело ответа пустое. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Список вебхуков (/webhooks/list) Вебхуки аккаунта и состояние доставки по каждому. Секрет подписи здесь не приходит – он один на аккаунт и лежит на [своей странице](/webhooks/secret). ## GET https://api.rewio.ru/v3/webhooks Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `data` (список объектов, обязательный) – Вебхуки аккаунта. Пагинации нет. - `data[].id` (число, обязательный) – Идентификатор вебхука. - `data[].target` (строка, обязательный) – Адрес, на который приходят события. Только HTTPS. - `data[].object_ids` (список чисел, может быть null) – Объекты, события которых доставляются. Пусто – все ваши объекты. - `data[].event_types` (список строк, обязательный) – Какие события доставлять: `reviews.new`, `replies.new`, `scrape.run.finished`. - `data[].bucket_window` (строка, обязательный) – Как часто доставлять: `immediate` – сразу после сбора, `daily_<час>` – сводкой в указанный час UTC. - `data[].filters` (объект, обязательный) – Что доставлять, а что пропускать. Условия складываются: событие проходит, только если выполнены все. - `data[].filters.allowed_ratings` (список чисел) – Доставлять только отзывы с этими оценками. Пусто – с любыми. - `data[].filters.allowed_sources` (список строк, может быть null) – Доставлять только с этих площадок, машинными именами. Пусто – со всех. - `data[].filters.has_text` (да/нет, по умолчанию нет) – Доставлять только отзывы с текстом. - `data[].filters.has_images` (да/нет, по умолчанию нет) – Доставлять только отзывы с фотографиями. - `data[].is_active` (да/нет, обязательный) – Включена ли доставка. - `data[].failure_count` (число, обязательный) – Сколько неудачных доставок подряд. - `data[].last_failure_at` (дата и время, может быть null) – Когда доставка не удалась в последний раз. - `data[].created_at` (дата и время, обязательный) – Когда вебхук создан. - `data[].updated_at` (дата и время, обязательный) – Когда его меняли в последний раз. ### Пример ответа ```json { "data": [ { "id": 41, "target": "https://example.com/hooks/rewio", "object_ids": [ 20 ], "event_types": [ "reviews.new", "replies.new" ], "bucket_window": "immediate", "filters": { "allowed_ratings": [ 1, 2, 3 ], "allowed_sources": null, "has_text": true, "has_images": false }, "is_active": true, "failure_count": 0, "last_failure_at": null, "created_at": "2026-08-01T09:14:02", "updated_at": "2026-08-01T09:14:02" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Перевыпустить секрет (/webhooks/rotate-secret) Выдаёт новый секрет подписи для всего аккаунта. Старый работает ещё сутки: всё это время доставки подписываются обоими секретами. Обновите проверку подписи в течение этого окна. ## POST https://api.rewio.ru/v3/webhooks/rotate-secret Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `secret` (строка, обязательный) – Новый секрет подписи. - `rotated_at` (дата и время, может быть null) – Момент перевыпуска. От него считаются сутки, пока действует и старый секрет. ### Пример ответа ```json { "secret": "whsec_3Vn7Kp1Zs5Xq9Md2Gt6Yb4Wr8Ac0Ej2Hl4Nu6Rf8Ti1Ow3Pd5Km7Bz9Xv2Qs4", "rotated_at": "2026-08-04T07:31:12" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Секрет подписи (/webhooks/secret) Секрет, которым подписаны доставки. Он один на аккаунт, а не на вебхук, и виден всегда. Нужен ключ со scope `full`: ключом только на чтение секрет не получить. ## GET https://api.rewio.ru/v3/webhooks/secret Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `secret` (строка, обязательный) – Секрет подписи. Им проверяется заголовок `X-Hrev-Signature` на вашей стороне. - `rotated_at` (дата и время, может быть null) – Когда секрет перевыпускали в последний раз. Пусто – он ни разу не менялся. ### Пример ответа ```json { "secret": "whsec_8Qf2Lm4Rt6Yv9Bn3Kd5Wp7Zx1Cs0Hj2Ng4Mq6Tr8Uv1Ay3Ew5Ik7Ol9Pb2Xd4", "rotated_at": null } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Тестовая доставка (/webhooks/test) Отправляет на ваш адрес пробное событие с такой же подписью, как у настоящей доставки. Отправка асинхронная: ответ приходит сразу, а результат виден в состоянии вебхука – [список вебхуков](/webhooks/list). ## POST https://api.rewio.ru/v3/webhooks/{webhook_id}/test Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `webhook_id` (число, path, обязательный) – Вебхук, на который отправить пробное событие. ### Ответ 202 - `status` (строка, обязательный) – Состояние отправки. `queued` – доставка поставлена в очередь. - `test_id` (строка, обязательный) – Идентификатор пробной доставки. По нему её видно в истории доставок. ### Пример ответа ```json { "status": "queued", "test_id": "test_9Kd2mQx7ZpLr4Vn1" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Изменить вебхук (/webhooks/update) Меняет адрес, набор объектов, события и фильтры. Передавайте только то, что нужно изменить. `is_active: false` ставит доставку на паузу, сохраняя настройки – события за время паузы не накапливаются. ## PATCH https://api.rewio.ru/v3/webhooks/{webhook_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `webhook_id` (число, path, обязательный) – Вебхук, который нужно изменить. ### Тело запроса - `target` (строка, может быть null) – Новый адрес доставки. Только HTTPS. - `object_ids` (список чисел, может быть null) – Новый набор объектов. Пустой список – события всех ваших объектов. - `event_types` (список строк, может быть null) – Новый набор событий. - `bucket_window` (строка, может быть null) – Новая частота доставки: `immediate` или `daily_<час>`. - `filters` (объект, может быть null) – Новые фильтры доставки. Передаются целиком и заменяют прежние. - `filters.allowed_ratings` (список чисел) – Доставлять только отзывы с этими оценками. - `filters.allowed_sources` (список строк, может быть null) – Доставлять только с этих площадок. - `filters.has_text` (да/нет, по умолчанию нет) – Доставлять только отзывы с текстом. - `filters.has_images` (да/нет, по умолчанию нет) – Доставлять только отзывы с фотографиями. - `is_active` (да/нет, может быть null) – Включить доставку или поставить её на паузу. ### Пример запроса ```json { "is_active": false } ``` ### Ответ 200 - `id` (число, обязательный) – Идентификатор вебхука. - `target` (строка, обязательный) – Адрес, на который приходят события. - `object_ids` (список чисел, может быть null) – Объекты, события которых доставляются. - `event_types` (список строк, обязательный) – Какие события доставляются. - `bucket_window` (строка, обязательный) – Как часто доставляются. - `filters` (объект, обязательный) – Применённые фильтры доставки. - `filters.allowed_ratings` (список чисел) – Оценки, при которых доставлять. - `filters.allowed_sources` (список строк, может быть null) – Площадки, при которых доставлять. - `filters.has_text` (да/нет, по умолчанию нет) – Только отзывы с текстом. - `filters.has_images` (да/нет, по умолчанию нет) – Только отзывы с фотографиями. - `is_active` (да/нет, обязательный) – Включена ли доставка. - `failure_count` (число, обязательный) – Сколько неудачных доставок подряд. - `last_failure_at` (дата и время, может быть null) – Когда доставка не удалась в последний раз. - `created_at` (дата и время, обязательный) – Когда вебхук создан. - `updated_at` (дата и время, обязательный) – Когда его меняли в последний раз. ### Пример ответа ```json { "id": 41, "target": "https://example.com/hooks/rewio", "object_ids": [ 20 ], "event_types": [ "reviews.new", "replies.new" ], "bucket_window": "immediate", "filters": { "allowed_ratings": [ 1, 2, 3 ], "allowed_sources": null, "has_text": true, "has_images": false }, "is_active": false, "failure_count": 0, "last_failure_at": null, "created_at": "2026-08-01T09:14:02", "updated_at": "2026-08-04T07:22:40" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Скрыть отзывы (/widgets/hidden-add) Убирает отзывы из ленты объекта: они перестают приходить в [`GET /v3/reviews`](/reviews/list). Скрытие действует внутри объекта: в другом объекте тот же отзыв останется на месте. Сам отзыв остаётся доступен – в [списке скрытых](/widgets/hidden-list) и в обычной ленте с `show_hidden=true`. За один запрос – до 200 идентификаторов. Уже скрытый отзыв можно передать повторно, ошибки не будет. Скрытие **снимает закрепление**: если отзыв был закреплён, он открепляется, а остальные закреплённые сдвигаются вверх. Обратное [снятие скрытия](/widgets/hidden-remove) закрепление не возвращает – закрепите заново. Аналитика скрытые отзывы **продолжает считать**: `GET /v3/analytics` отдаёт средний балл и распределение оценок по всем собранным отзывам объекта. Скрытие – это оформление выдачи, а не правка данных. ## POST https://api.rewio.ru/v3/objects/{object_id}/hidden-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в котором скрываются отзывы. ### Тело запроса - `review_ids` (список чисел, обязательный) – Отзывы, которые нужно скрыть. ### Пример запроса ```json { "review_ids": [ 143046, 142391 ] } ``` ### Ответ 200 - `message` (строка, обязательный) – Сообщение об итоге операции. - `hidden_count` (число, обязательный) – Сколько отзывов скрыто в объекте после этой операции: всего, а не за вызов. ### Пример ответа ```json { "message": "Reviews hidden", "hidden_count": 2 } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Скрытые отзывы (/widgets/hidden-list) Отзывы, спрятанные в этом объекте – те, что не попадают в обычную ленту. Экран модерации строят на этой ручке: показать скрытое и дать [вернуть обратно](/widgets/hidden-remove). Скрытие действует внутри объекта: тот же отзыв в другом объекте останется видимым. Фильтры, сортировка и постраничная выдача устроены как в [общей ленте](/reviews/list), но список параметров короче – он весь ниже. В частности, разбора текста на достоинства и недостатки здесь нет: `split_pros_cons` эта ручка не принимает. ## GET https://api.rewio.ru/v3/objects/{object_id}/hidden-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, скрытые отзывы которого нужны. - `link_ids` (список чисел, query, по умолчанию пусто) – Только по этим ссылкам внутри объекта. Пусто – по всем. - `source_ids` (список чисел, query, по умолчанию пусто) – Только с этих площадок. Пусто – со всех. - `sort_by` (строка, query, review_date / rating / reply_date, по умолчанию «review_date») – По дате публикации, по оценке или по дате ответа организации (`reply_date`). - `sort_order` (строка, query, desc / asc, по умолчанию «desc») – `desc` – сначала новые (или высокие оценки), `asc` – наоборот. - `min_rating` (число, query, может быть null, 1–5) – Оценка не ниже указанной, по шкале 1–5. - `max_rating` (число, query, может быть null, 1–5) – Оценка не выше указанной. - `published_from` (дата, query, может быть null) – Отзывы, опубликованные не раньше этой даты. - `published_to` (дата, query, может быть null) – Отзывы, опубликованные не позже этой даты. Названный день входит в период целиком. - `has_images` (да/нет, query, может быть null) – `true` – только с изображениями, `false` – только без. - `has_text` (да/нет, query, может быть null) – `true` – только с текстом, `false` – только оценки без текста. - `has_reply` (да/нет, query, может быть null) – `true` – только с ответом организации, `false` – только без ответа. - `search` (строка, query, может быть null) – Поиск подстроки в тексте отзыва, без учёта регистра. - `limit` (число, query, 1–1000, по умолчанию 100) – Сколько отзывов вернуть за один запрос. - `offset` (число, query, не меньше 0, по умолчанию 0) – Сколько отзывов пропустить с начала выборки. - `show_deleted` (да/нет, query, по умолчанию нет) – Добавить к выдаче отзывы, пропавшие с площадки. - `only_deleted` (да/нет, query, по умолчанию нет) – Только пропавшие с площадки отзывы. ### Ответ 200 - `data` (список объектов, обязательный) – Скрытые отзывы текущей страницы. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_hidden` (да/нет, по умолчанию нет) – Всегда `true`: здесь только скрытые. - `total` (число, обязательный) – Сколько отзывов скрыто в этом объекте. - `limit` (число, обязательный) – Размер страницы, применённый к запросу. - `offset` (число, обязательный) – Смещение, применённое к запросу. - `has_next` (да/нет, обязательный) – Есть ли ещё отзывы за текущей страницей. ### Пример ответа ```json { "data": [ { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [], "is_hidden": true } ], "total": 1, "limit": 100, "offset": 0, "has_next": false } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Вернуть отзывы в ленту (/widgets/hidden-remove) Снимает скрытие: отзывы снова приходят в ленту объекта. За один запрос – до 200 идентификаторов. Отзыв, который не был скрыт, пропускается без ошибки. Закрепление, снятое при скрытии, само не возвращается – [закрепите заново](/widgets/pinned-add). ## DELETE https://api.rewio.ru/v3/objects/{object_id}/hidden-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в котором снимается скрытие. ### Тело запроса - `review_ids` (список чисел, обязательный) – Отзывы, которые нужно вернуть в ленту. ### Пример запроса ```json { "review_ids": [ 142391 ] } ``` ### Ответ 200 - `message` (строка, обязательный) – Сообщение об итоге операции. - `hidden_count` (число, обязательный) – Сколько отзывов осталось скрыто в объекте после этой операции. ### Пример ответа ```json { "message": "Reviews unhidden", "hidden_count": 1 } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Закрепить отзывы (/widgets/pinned-add) Поднимает отзывы в начало выдачи, добавляя их в конец списка закреплённых. Уже закреплённые отзывы второй раз не добавляются и своё место не теряют. Чтобы задать порядок целиком, используйте [`PUT`](/widgets/pinned-set). Закрепить можно **не больше 30 отзывов на объект**. Запрос, после которого их стало бы больше, отклоняется целиком – `400 pinned_limit_exceeded`. В ответ приходит весь список закреплённых после операции, в порядке показа. ## POST https://api.rewio.ru/v3/objects/{object_id}/pinned-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в котором закрепляются отзывы. ### Тело запроса - `review_ids` (список чисел, обязательный) – Отзывы, которые нужно закрепить. ### Пример запроса ```json { "review_ids": [ 143046 ] } ``` ### Ответ 200 - `data` (список объектов, обязательный) – Все закреплённые отзывы объекта после операции, в их порядке. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_pinned` (да/нет, по умолчанию нет) – Всегда `true`. - `data[].pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. ### Пример ответа ```json { "data": [ { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [], "is_pinned": true, "pin_position": 0 } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Закреплённые отзывы (/widgets/pinned-list) Отзывы, поднятые в начало выдачи, в том порядке, в котором их закрепили. Этим порядком и собирают верх страницы: закреплённые берут отсюда, остальное – [общей лентой](/reviews/list). Без `sort_by` порядок в ответе – порядок закрепления. Передали `sort_by` – закреплённые пересортируются по дате, оценке или дате ответа, а `pin_position` останется прежним. Закрепление работает внутри объекта: в папочной ленте (`folder_id`) оно не применяется, и такие отзывы приходят обычными строками. ## GET https://api.rewio.ru/v3/objects/{object_id}/pinned-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, закреплённые отзывы которого нужны. - `link_ids` (список чисел, query, по умолчанию пусто) – Только по этим ссылкам внутри объекта. Пусто – по всем. - `source_ids` (список чисел, query, по умолчанию пусто) – Только с этих площадок. Пусто – со всех. - `sort_by` (строка, query, review_date / rating / reply_date, по умолчанию «review_date») – Дата публикации, оценка или дата ответа организации (`reply_date`). Не передано – сохраняется порядок закрепления. - `sort_order` (строка, query, desc / asc, по умолчанию «desc») – `desc` – сначала новые (или высокие оценки), `asc` – наоборот. - `min_rating` (число, query, может быть null, 1–5) – Оценка не ниже указанной, по шкале 1–5. - `max_rating` (число, query, может быть null, 1–5) – Оценка не выше указанной. - `published_from` (дата, query, может быть null) – Отзывы, опубликованные не раньше этой даты. - `published_to` (дата, query, может быть null) – Отзывы, опубликованные не позже этой даты. Названный день входит в период целиком. - `has_images` (да/нет, query, может быть null) – `true` – только с изображениями, `false` – только без. - `has_text` (да/нет, query, может быть null) – `true` – только с текстом, `false` – только оценки без текста. - `has_reply` (да/нет, query, может быть null) – `true` – только с ответом организации, `false` – только без ответа. - `search` (строка, query, может быть null) – Поиск подстроки в тексте отзыва, без учёта регистра. - `limit` (число, query, 1–1000, по умолчанию 100) – Сколько отзывов вернуть за один запрос. - `offset` (число, query, не меньше 0, по умолчанию 0) – Сколько отзывов пропустить с начала выборки. - `show_deleted` (да/нет, query, по умолчанию нет) – Добавить к выдаче отзывы, пропавшие с площадки. - `only_deleted` (да/нет, query, по умолчанию нет) – Только пропавшие с площадки отзывы. ### Ответ 200 - `data` (список объектов, обязательный) – Закреплённые отзывы в порядке закрепления. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_pinned` (да/нет, по умолчанию нет) – Всегда `true`: здесь только закреплённые. - `data[].pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. - `total` (число, обязательный) – Общее число элементов, подходящих под фильтры (без учёта limit/offset). - `limit` (число, обязательный) – Размер страницы, применённый к запросу. - `offset` (число, обязательный) – Смещение от начала выборки, применённое к запросу. - `has_next` (да/нет, обязательный) – Есть ли ещё элементы за пределами текущей страницы. ### Пример ответа ```json { "data": [ { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [], "is_pinned": true, "pin_position": 0 } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Открепить отзывы (/widgets/pinned-remove) Снимает закрепление: отзывы перестают висеть наверху, но остаются в обычной ленте объекта. Оставшиеся закреплённые сдвигаются вверх, их порядок между собой сохраняется, а `pin_position` пересчитывается без пропусков. В ответ приходит список закреплённых, оставшихся после операции. ## DELETE https://api.rewio.ru/v3/objects/{object_id}/pinned-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в котором снимается закрепление. ### Тело запроса - `review_ids` (список чисел, обязательный) – Отзывы, которые нужно открепить. ### Пример запроса ```json { "review_ids": [ 143046 ] } ``` ### Ответ 200 - `data` (список объектов, обязательный) – Закреплённые отзывы, оставшиеся после операции. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_pinned` (да/нет, по умолчанию нет) – Всегда `true`. - `data[].pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. ### Пример ответа ```json { "data": [] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Задать порядок закреплённых (/widgets/pinned-set) Задаёт список закреплённых целиком: порядок в запросе становится порядком в выдаче. Это замена, а не добавление – отзывы, которых нет в списке, открепляются, а пустой список снимает закрепление со всех. Первый в списке получает `pin_position: 0`, следующий – `1`, и так далее. Не больше 30 отзывов, без повторов: и то и другое – `400`. Так удобнее переставлять: вы присылаете желаемый итог, а не двигаете отзывы по одному. Два одновременных запроса к одному объекту выполняются по очереди, порядок не перемешается. ## PUT https://api.rewio.ru/v3/objects/{object_id}/pinned-reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, в котором задаётся порядок. ### Тело запроса - `ordered_review_ids` (список чисел, обязательный) – Закреплённые отзывы целиком, в нужном порядке. Первый в списке окажется первым в выдаче. ### Пример запроса ```json { "ordered_review_ids": [ 142391, 143046 ] } ``` ### Ответ 200 - `data` (список объектов, обязательный) – Закреплённые отзывы после операции, в заданном порядке. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_pinned` (да/нет, по умолчанию нет) – Всегда `true`. - `data[].pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. ### Пример ответа ```json { "data": [ { "id": 142391, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [], "is_pinned": true, "pin_position": 0 }, { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [], "is_pinned": true, "pin_position": 1 } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Достоинства и недостатки (/widgets/pros-cons) Часть площадок спрашивает у автора плюсы и минусы отдельными полями. Мы храним такой отзыв одним текстом – с подписями, по которым его можно разобрать обратно. Так он приходит по умолчанию, в поле `text`: ```text Что понравилось: Исторический отель в котором стоит хотя бы раз остановиться, конечно интерьер завораживает Что не понравилось: Не понравилась организация завтрака: маленький зал, много людей, не все официанты ориентированы на гостей. ``` ## Как получить разбор [#how-to-get] Параметр `split_pros_cons=true` у [`GET /v3/reviews`](/reviews/list): ```bash curl -G "https://api.rewio.ru/v3/reviews" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" \ --data-urlencode "object_id=20" \ --data-urlencode "split_pros_cons=true" ``` Подписанные блоки уезжают в отдельные поля `pros` и `cons`: ```json { "id": 268268, "author": "Tatiana", "rating": 4.8, "pros": "Исторический отель в котором стоит хотя бы раз остановиться, конечно интерьер завораживает", "cons": "Не понравилась организация завтрака: маленький зал, много людей, не все официанты ориентированы на гостей." } ``` Разобранные блоки **убираются из `text`**. Если у отзыва не было ничего, кроме плюсов и минусов, – как в примере выше, – поля `text` в ответе не будет вовсе. Виджет, который читает `text` не глядя, на таком отзыве покажет пустоту. Часть площадок к плюсам и минусам добавляет ещё и свободный текст. У таких отзывов он и остаётся в `text`, а `pros` и `cons` приходят рядом. ## На каких площадках это есть [#sources] Отзыв изначально разделён на площадках: **Островок**, **Суточно.ру**, **OneTwoTrip**, **Booking.com**, **Agoda**, **Otzovik**, **Авито**. На остальных отзыв – один текст, делить в нём нечего. С `split_pros_cons=true` такой отзыв придёт как обычно: весь текст в `text`, полей `pros` и `cons` нет. Отдельного признака в [справочнике площадок](/sources/list) для этого нет. Надёжный способ – проверять наличие полей у самого отзыва: ```python text = review.get("text") pros = review.get("pros") cons = review.get("cons") ``` ## Где параметра нет [#unsupported] `split_pros_cons` работает только в общей ленте отзывов. [Скрытые](/widgets/hidden-list) и [закреплённые](/widgets/pinned-list) отдаются слитым текстом: `pros` и `cons` там не приходят никогда. # Получить отзыв по id (/reviews/get) Один отзыв по его идентификатору. Ответ – ровно та же модель, что приходит элементом `data` в [ленте отзывов](/reviews/list). Метод нужен там, где идентификатор уже на руках, а объекта под ним нет: вебхук приносит `id` отзыва, а не объект; после публикации ответа проверить `reply_text` больше нечем. Достаточно ключа со скоупом `read_only`. ## GET https://api.rewio.ru/v3/reviews/{review_id} Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Идентификатор отзыва в Rewio – тот же `id`, что в ленте отзывов и в событии вебхука. ### Ответ 200 - `id` (число, обязательный) – Идентификатор отзыва в Rewio. - `link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `text` (строка, может быть null) – Текст отзыва. - `review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `reply_text` (строка, может быть null) – Ответ организации на отзыв. - `reply_date` (дата и время, может быть null) – Когда организация ответила. - `has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `is_hidden` (да/нет, по умолчанию нет) – Отзыв скрыт в объекте. - `is_pinned` (да/нет, по умолчанию нет) – Отзыв закреплён в объекте. - `pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. - `pros` (строка, может быть null) – Блок «достоинства». - `cons` (строка, может быть null) – Блок «недостатки». ### Пример ответа ```json { "id": 918342, "link_id": 57, "source_id": 1, "author": "Марина К.", "text": "Номер чистый, завтрак хороший. Заселили раньше времени, спасибо.", "review_date": "2026-08-14T09:41:00", "rating_original": 9, "rating": 4.5, "review_url": "https://yandex.ru/maps/org/12345/reviews/?reviews%5BpublicId%5D=abc123", "reply_text": "Спасибо за отзыв! Ждём вас снова.", "reply_date": "2026-08-15T07:12:00", "has_images": false, "images": [], "has_videos": false, "videos": [] } ``` ## Чего в ответе не будет [#not-included] Отзыв **чужого аккаунта** и отзыв, **которого не существует**, отвечают одинаково – `404` с кодом `not_found`. Ответы намеренно неразличимы: иначе перебор идентификаторов рассказывал бы о чужих данных. Видимость та же, что у ленты по умолчанию: * отзыв, **пропавший с площадки**, по идентификатору не отдаётся; * отзыв, **скрытый** в объекте, тоже не отдаётся; * когда глубина выдачи ограничена (блок `access` в ленте), здесь действует тот же потолок видимости – отзыв старше этого потолка отвечает `404`. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Получить отзывы (/reviews/list) Отзывы одного объекта или всей папки – с фильтрами, сортировкой и постраничной выдачей. Объект или папку указывают ровно одну: либо `object_id`, либо `folder_id`. ## GET https://api.rewio.ru/v3/reviews Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id · folder_id` (число, query, может быть null) – Объект или папка целиком. В запросе должно быть ровно одно из двух. - `link_ids · source_ids` (список чисел, query, по умолчанию пусто) – Ограничить выдачу конкретными ссылками объекта или площадками. Пусто – без ограничения. - `sort_by · sort_order` (строка, query, review_date / rating / reply_date, по умолчанию «review_date», desc / asc, по умолчанию «desc») – Поле и направление сортировки: дата публикации, оценка или дата ответа организации (`reply_date`). При сортировке по `reply_date` отзывы без ответа всегда в конце. - `min_rating · max_rating` (число, query, может быть null, 0–5, 1–5) – Границы оценки по шкале 1–5, включительно. - `published_from · published_to` (дата, query, может быть null) – Границы даты публикации, включительно. Названный в верхней границе день входит в период целиком. - `has_images · has_videos` (да/нет, query, может быть null) – Наличие фотографий и видео. `true` – только с ними, `false` – только без. - `has_text · has_reply` (да/нет, query, может быть null) – Наличие текста отзыва и ответа организации. `true` – только с ними, `false` – только без. - `search` (строка, query, может быть null) – Поиск подстроки в тексте отзыва, без учёта регистра. Запрос короче двух символов игнорируется. - `limit · offset` (число, query, 1–1000, по умолчанию 100, не меньше 0, по умолчанию 0) – Сколько отзывов вернуть за запрос и сколько пропустить с начала выборки. - `show_deleted · only_deleted` (да/нет, query, по умолчанию нет) – Отзывы, пропавшие с площадки: добавить их к выдаче или оставить только их. - `show_hidden · show_pinned` (да/нет, query, по умолчанию нет) – Показывать отзывы, скрытые или закреплённые в этом объекте. По умолчанию лента не отдаёт ни тех, ни других – [как это устроено](/guides/widgets). - `split_pros_cons` (да/нет, query, по умолчанию нет) – Разбирать слитый текст на «достоинства» и «недостатки»: часть площадок отдаёт их одной строкой. Разобранные блоки убираются из `text` – [подробнее](/widgets/pros-cons). ### Ответ 200 - `data` (список объектов, обязательный) – Отзывы текущей страницы. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – Адрес с плейсхолдером `{size}`, в таком виде его отдаёт площадка. - `data[].images[].preview` (строка, может быть null) – Уменьшенная версия для списков и сеток. - `data[].images[].image` (строка, может быть null) – Полноразмерная версия для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – `embed` – плеер площадки, `file` – прямой файл, `hls` – поток. - `data[].videos[].video_url` (строка, может быть null) – Адрес видео или плеера, смотря какой `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – Кадр-заставка. - `data[].videos[].width` (число, может быть null) – Ширина в пикселях, если площадка её сообщает. - `data[].videos[].height` (число, может быть null) – Высота в пикселях, если площадка её сообщает. - `data[].videos[].duration_ms` (число, может быть null) – Длительность в миллисекундах, если площадка её сообщает. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_hidden` (да/нет, по умолчанию нет) – Отзыв скрыт в этом объекте. Приходит только при `show_hidden=true`. - `data[].is_pinned` (да/нет, по умолчанию нет) – Отзыв закреплён в этом объекте. Приходит только при `show_pinned=true`. - `data[].pin_position` (число, может быть null) – Место отзыва среди закреплённых, считая с нуля. - `data[].pros` (строка, может быть null) – Блок «достоинства». Приходит только при `split_pros_cons=true`. - `data[].cons` (строка, может быть null) – Блок «недостатки». Приходит только при `split_pros_cons=true`. - `total` (число, обязательный) – Сколько отзывов подходит под фильтры, без учёта `limit`. - `limit` (число, обязательный) – Размер страницы, применённый к запросу. - `offset` (число, обязательный) – Смещение, применённое к запросу. - `has_next` (да/нет, обязательный) – Есть ли ещё отзывы за текущей страницей. - `access` (объект, может быть null) – Ограничение выдачи. Приходит только когда показали не всё. - `access.reason` (строка, обязательный) – Почему выдача ограничена. `trial` — пробный доступ, `manual` — ограничение, согласованное по вашему договору. - `access.limit_per_link` (число, обязательный) – Сколько последних отзывов показывается по КАЖДОЙ ссылке (площадке объекта). - `access.hidden_total` (число, обязательный) – Сколько отзывов уже собрано сверх показанных. Считается по всему архиву и не зависит от фильтров запроса. - `access.message` (строка, обязательный) – Готовая формулировка для показа человеку. - `collecting` (объект, может быть null) – Первого сбора по части площадок объекта ещё не было. Приходит только пока это так. - `collecting.link_count` (число, обязательный) – Сколько площадок участвует в выдаче. - `collecting.links_collecting` (число, обязательный) – По скольким из них сбор идёт прямо сейчас. - `collecting.links_failed` (число, обязательный) – По скольким из них первый сбор не удался. - `collecting.message` (строка, обязательный) – Готовая формулировка на английском. ### Пример ответа ```json { "data": [ { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [] } ], "total": 397, "limit": 1, "offset": 0, "has_next": true } ``` ## Пустая выдача сразу после создания объекта [#empty-after-create] Сбор по новой площадке занимает от нескольких секунд до нескольких минут, и всё это время отзывов по ней ещё нет. Чтобы пустую страницу не пришлось трактовать наугад, в ответе появляется блок `collecting`: ```json { "collecting": { "link_count": 2, "links_collecting": 1, "links_failed": 0, "message": "First collection is still running for 1 of 2 platforms — reviews appear here as soon as it finishes." }, "total": 0, "limit": 100, "offset": 0, "has_next": false, "data": [] } ``` Блок приходит **только пока по какой-то площадке не было ни одного успешного сбора**. Как только сбор прошёл, ключ пропадает навсегда — даже если отзывов у объекта не оказалось вовсе: пустая выдача без `collecting` означает, что мы всё собрали и отзывов нет. Если `links_failed` больше нуля, первый сбор по этим площадкам не удался; подробности — в полях `scrape_status` и `scrape_error` у ссылок объекта ([Получить объект](/objects/get)). Ждать готовности удобнее по объекту, а не по отзывам: `scrape_status` объекта меняется на `success`, `partial` или `failed`, когда сбор закончен — готовый цикл ожидания есть в [Быстром старте](/quickstart). Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Оценка на площадках (/reviews/ratings) Оценка объекта – числовые значения рейтинга, выбранные пользователями. Отзыв – оценка с текстом. Необходимо указать либо объект, либо папку. Чтобы отслеживать динамику оценки, воспользуйтесь методом [Динамика оценки](/analytics/ratings-history). ## GET https://api.rewio.ru/v3/ratings Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id · folder_id` (число, query, может быть null) – Объект или папка целиком. В запросе должно быть ровно одно из двух. - `link_ids · source_ids` (список чисел, query, по умолчанию пусто) – Ограничить выдачу конкретными ссылками объекта или площадками. Пусто – без ограничения. ### Ответ 200 - `data` (список объектов, обязательный) – По строке на каждую ссылку, у которой есть замер. - `data[].link_id` (число, обязательный) – Ссылка, к которой относится оценка. - `data[].source_id` (число, обязательный) – Площадка, на которой она показана. - `data[].rating` (число, может быть null) – Оценка объекта на площадке, шкала 1–5. - `data[].rating_count` (число, может быть null) – Сколько оценок её сформировали, вместе с оставленными без текста. - `data[].review_count` (число, может быть null) – Сколько из этих оценок – отзывы с текстом, по данным самой площадки. - `data[].measured_at` (дата и время, обязательный) – Когда мы последний раз сверялись с площадкой и видели это значение. ### Пример ответа ```json { "data": [ { "link_id": 794, "source_id": 1, "rating": 4.9, "rating_count": 966, "review_count": 286, "measured_at": "2026-08-27T05:21:23" }, { "link_id": 823, "source_id": 3, "rating": 4.8, "rating_count": 237, "review_count": 193, "measured_at": "2026-08-27T05:21:40" }, { "link_id": 830, "source_id": 3, "rating": 4.8, "rating_count": 21, "review_count": 17, "measured_at": "2026-08-27T05:21:48" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Синхронизация отзывов (/reviews/sync) Поток изменений: отзывы, которые появились или изменились у нас после точки, на которой вы остановились. Нужен там, где у вас своя база и её надо держать в актуальном состоянии. Обычная [лента отзывов](/reviews/list) отвечает на вопрос «покажи», синхронизация — на вопрос «догони, ничего не потеряв». Поэтому здесь нет ни фильтров, ни сортировки, ни `offset`. ## GET https://api.rewio.ru/v3/reviews/sync Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `cursor` (строка, query, может быть null) – Курсор из `next_cursor` предыдущего ответа. С ним остальные параметры можно не передавать. - `mode` (строка, query, может быть null) – Что присылать: `all` — новые и изменения, `new` — только впервые появившиеся отзывы. - `limit` (число, query, может быть null, 1–1000) – Размер страницы, 1–1000. Запекается в курсор, дальше его можно не повторять. - `object_id · folder_id` (число, query, может быть null) – Объект или папка целиком. В запросе должно быть ровно одно из двух — но только на первом запросе, дальше адресат едет внутри курсора. ### Ответ 200 - `data` (список объектов, обязательный) – Отзывы, изменившиеся после вашей позиции. - `data[].id` (число, обязательный) – Идентификатор отзыва в Rewio. По нему и склеивайте у себя. - `data[].link_id` (число, обязательный) – Ссылка, с которой собран отзыв. - `data[].source_id` (число, обязательный) – Площадка, с которой собран отзыв. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, по времени площадки. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].has_images` (да/нет, обязательный) – Есть ли у отзыва изображения. - `data[].images` (список объектов, по умолчанию пусто) – Изображения отзыва. - `data[].images[].template_url` (строка, обязательный) – URL изображения на CDN площадки в исходном виде. У части площадок содержит шаблон размера (`{size}` или `{width}`/`{height}`) и потому не предназначен для прямой вставки — для показа берите `preview` или `image`. - `data[].images[].preview` (строка, может быть null) – Готовый URL уменьшенной версии (превью) для списков и сеток. - `data[].images[].image` (строка, может быть null) – Готовый URL полноразмерной версии для просмотра. - `data[].has_videos` (да/нет, по умолчанию нет) – Есть ли у отзыва видео. - `data[].videos` (список объектов, по умолчанию пусто) – Видео отзыва. - `data[].videos[].kind` (строка, обязательный, embed / file / hls) – Тип вложения: `embed` — встраиваемый плеер площадки (открывать в sandbox-iframe), `file` — прямая ссылка на видеофайл, `hls` — HLS-поток (`.m3u8`). - `data[].videos[].video_url` (строка, может быть null) – URL видео или встраиваемого плеера в зависимости от `kind`. - `data[].videos[].thumbnail` (строка, может быть null) – URL кадра-заставки (превью) видео. - `data[].videos[].width` (число, может быть null) – Ширина видео в пикселях, если известна. - `data[].videos[].height` (число, может быть null) – Высота видео в пикселях, если известна. - `data[].videos[].duration_ms` (число, может быть null) – Длительность видео в миллисекундах, если известна. - `data[].is_deleted` (да/нет, по умолчанию нет) – Отзыв пропал с площадки. В синхронизации такие приходят всегда. - `data[].deleted_at` (дата и время, может быть null) – Когда мы заметили пропажу. - `data[].is_hidden` (да/нет, по умолчанию нет) – Отзыв скрыт в рамках объекта (приходит только когда `true`). - `data[].is_pinned` (да/нет, по умолчанию нет) – Отзыв закреплён в рамках объекта (приходит только когда `true`). - `data[].pin_position` (число, может быть null) – Позиция закреплённого отзыва: меньше — выше. - `data[].pros` (строка, может быть null) – Блок «достоинства» (только при `split_pros_cons=true`). - `data[].cons` (строка, может быть null) – Блок «недостатки» (только при `split_pros_cons=true`). - `next_cursor` (строка, обязательный) – Позиция, с которой продолжить. Приходит всегда — сохраните её у себя. - `has_next` (да/нет, обязательный) – Есть ли ещё изменения прямо сейчас. - `access` (объект, может быть null) – Ограничение глубины выдачи. Приходит, только пока оно действует. - `access.reason` (строка, обязательный) – Почему выдача ограничена. `trial` — пробный доступ, `manual` — ограничение, согласованное по вашему договору. - `access.limit_per_link` (число, обязательный) – Сколько последних отзывов показывается по КАЖДОЙ ссылке (площадке объекта). - `access.hidden_total` (число, обязательный) – Сколько отзывов уже собрано сверх показанных. Считается по всему архиву и не зависит от фильтров запроса. - `access.message` (строка, обязательный) – Готовая формулировка для показа человеку. ### Пример ответа ```json { "data": [ { "id": 143046, "link_id": 177, "source_id": 1, "author": "Сергей", "text": "Замечательно. Приеду ещё. ", "review_date": "2026-07-21T18:07:03", "rating_original": "5", "rating": 5, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "reply_text": "Уважаемый Гость,\nБлагодарим Вас за визит в гостиницу «Националь» и высокую оценку нашего обслуживания. Ждем Вас снова!\nС наилучшими пожеланиями,\t\nЕлена Позолотина\nДиректор по операционной деятельности.\n", "reply_date": "2026-07-23T13:27:07", "has_images": true, "images": [ { "template_url": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/M", "image": "https://avatars.mds.yandex.net/get-altay/17743308/2a0000019f85dc34d7ee3b24b4b9ec82bdbd/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/M", "image": "https://avatars.mds.yandex.net/get-altay/18473509/2a0000019f85dc42d3b7bbf4e10e375c612e/XXXL" }, { "template_url": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/{size}", "preview": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/M", "image": "https://avatars.mds.yandex.net/get-altay/20191917/2a0000019f85dc255b9c227cfbc55fc57724/XXXL" } ], "has_videos": false, "videos": [] }, { "id": 143051, "link_id": 177, "source_id": 1, "author": "Марина", "text": "Номер не соответствовал описанию.", "review_date": "2026-07-19T09:14:00", "rating_original": "2", "rating": 2, "review_url": "https://yandex.ru/maps/org/1020542995/reviews?reviews[publicId]=u182gzp1r9rg4urew906ky9dd0", "has_images": false, "images": [], "has_videos": false, "videos": [], "is_deleted": true, "deleted_at": "2026-08-23T04:12:07" } ], "next_cursor": "eyJhIjoiMjAyNi0wOC0yM1QxNDowMzoxMSIsImQiOjE0MzA1MSwiaSI6MjAsImwiOjEwMCwibSI6ImFsbCIsInQiOiJnIiwidSI6MzAsInYiOjF9.k3Qw9x0nJ8Zr5wQfB2vLZA", "has_next": true } ``` ## Как это работает [#how-it-works] Первый запрос — с адресом объекта, дальше достаточно одного `cursor`: ``` GET /v3/reviews/sync?object_id=20&limit=200 → 200 отзывов, next_cursor: "eyJ…", has_next: true GET /v3/reviews/sync?cursor=eyJ… → следующие 200, next_cursor: "eyJ…", has_next: true … → has_next: false — вы догнали текущее состояние ``` Сохраните последний `next_cursor` у себя и вернитесь с ним завтра — придёт только то, что изменилось за сутки. ```python cursor = load_cursor() # None при первом запуске params = {"cursor": cursor} if cursor else {"object_id": 20, "limit": 200} while True: page = get("/v3/reviews/sync", params=params).json() for review in page["data"]: upsert(review) # склейка по review["id"] cursor = page["next_cursor"] save_cursor(cursor) # сохраняем ПОСЛЕ каждой страницы if not page["has_next"]: break params = {"cursor": cursor} ``` Курсор — это закладка, а не сохранённая выдача: он не устаревает и его можно хранить сколько угодно. Обрыв связи стоит одной страницы, а не всего обхода. Внутрь заглядывать не нужно и не получится — устройство курсора мы оставляем за собой, чтобы менять его, не ломая вашу интеграцию. ## Один отзыв может прийти дважды [#duplicates] Если отзыв изменится, пока вы читаете страницы, он придёт ещё раз — уже с новым содержимым и **с тем же `id`**: новой строки мы не заводим. Поэтому в режиме `all` кладите к себе **UPSERT по `id`**, а не INSERT — иначе дубли или ошибка уникальности. В режиме `new` достаточно INSERT: там ничего не приходит дважды. Потерять отзыв поток не может: это и есть его единственная твёрдая гарантия. ## Что считается изменением [#what-counts-as-change] Правка текста или оценки на площадке, появившийся или изменившийся ответ организации, изменившийся набор фотографий и видео, пропажа отзыва с площадки (`is_deleted: true`) и обратное восстановление. Пересбор сам по себе изменением не считается: если на площадке ничего не поменялось, отзыв в поток не попадёт. ## Два режима [#modes] | `mode` | Что приходит | Повторы | Как класть к себе | | -------------------- | --------------------------------- | -------- | ------------------ | | `all` (по умолчанию) | новые отзывы и изменения | возможны | **UPSERT** по `id` | | `new` | только впервые появившиеся отзывы | нет | **INSERT** | Режим запекается в курсор: курсор одного режима не подходит другому — у них разные оси. Если нужны оба потока сразу, держите два курсора, это нормально. `mode=new` удобен, когда отзывы уходят в CRM или в оповещения: правки и пропажи вас не интересуют, апсерт не нужен, каждая строка приходит ровно один раз. ## Первый обход — всегда с начала истории [#first-pass] Переключателя «начать с сегодняшнего дня» нет: первый запрос отдаёт самые давние записи, и обход идёт до конца. Синхронизация — это сперва полная копия, потом приращения. Если полная копия вам не нужна и интересны только новые отзывы по мере появления, это не эта ручка, а [вебхуки](/guides/webhooks): они и присылают только новое, без архива. ## Свежесть [#freshness] Изменения появляются в потоке с задержкой в несколько секунд. Это не запаздывание сбора, а защита от потери: отзыв, который в этот момент записывается, иначе оказался бы позади вашего курсора и не пришёл бы никогда. Опрашивать чаще раза в минуту смысла нет — отзывы на площадках так быстро не появляются. Практичный режим для актуальной копии: раз в 5–15 минут. ## Границы [#limits] * **Синхронизация не следит за составом объекта.** Убрали ссылку из объекта, выключили объект или перенесли его — отзывы по нему просто перестанут приходить, отдельного события об этом не будет. Такие строки чистите у себя по `link_id`. Если ссылку потом вернули, её старые отзывы заново не поедут: курсор идёт по времени изменения, а возврат ссылки ничего в отзывах не меняет. Начните для этого объекта обход с нуля, без сохранённого курсора. * **Скрытые и закреплённые отзывы** приходят обычными строками, без флагов `is_hidden` и `is_pinned`: скрытие и закрепление — настройка витрины объекта, а не свойство отзыва, и в поток изменений они не попадают. * **Ограниченная выдача** работает здесь ровно так же, как в ленте: не больше `access.limit_per_link` последних отзывов на каждую площадку объекта (на пробном доступе — 20), и в ответе появляется блок `access`. Пропажи отзывов, оставшихся за этой границей, в поток не попадают. ## Ошибки курсора [#cursor-errors] | Статус | `code` | Когда | | ------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400` | `invalid_cursor` | Курсор не читается: испорчен, изменён или выдан другому аккаунту. Начните обход заново, без `cursor`. | | `400` | `cursor_mismatch` | Вместе с курсором передан `object_id`, `folder_id` или `mode`, не совпадающий с тем, для которого курсор выдан. Либо не передавайте их, либо передайте те же. | Остальные коды общие для всего API и описаны на странице [Ошибки](/errors). # Удалить ответ (/replies/delete) Удаляет ваш ответ с площадки. Удалить можно только свой ответ: тот, что опубликован не через нас, методу не виден. Удаление асинхронное, как и публикация: `202` означает, что мы приняли задачу. Когда площадка её выполнит, поле `reply_text` у [отзыва](/reviews/list) опустеет. Удалять умеют не все площадки. Там, где ответ удалить нельзя, приходит `409` с кодом `reply_delete_not_supported` – в таком случае замените текст [публикацией](/replies/publish). ## DELETE https://api.rewio.ru/v3/reviews/{review_id}/reply Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, ответ на который нужно удалить. ### Ответ 202 - `text` (строка, обязательный) – Пустая строка. Она и означает, что ответ удалён. - `status` (строка, обязательный, pending / publishing / published / failed / deleted) – Состояние вашего ответа: `pending` – принят и ждёт публикации, `publishing` – запрос к площадке в полёте, `published` – площадка приняла, `failed` – опубликовать не удалось, `deleted` – ответ удалён. В ответе на этот запрос всегда `pending`: публикация асинхронная. Что ответ действительно стоит на площадке, видно по полям `reply_text` и `reply_date` самого [отзыва](/reviews/list) и по событию `replies.new`. - `updated_at` (дата и время, обязательный) – Когда мы приняли задачу. ### Пример ответа ```json { "text": "", "status": "pending", "updated_at": "2026-08-16T10:20:41" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). Отказы, свойственные именно ответам, собраны там в отдельной таблице. # Опубликовать ответ (/replies/publish) Публикует ваш ответ под отзывом на самой площадке или заменяет уже стоящий. Ответ на отзыв ровно один, поэтому повторный запрос с тем же текстом – не дубль и не ошибка. Нужен ключ со скоупом `full`, полный тариф и подключённая площадка. Что для этого сделать – в руководстве [«Как отвечать на отзывы»](/guides/replies). Публикация асинхронная: `202` означает, что мы приняли задачу. Опубликованный ответ появляется в самом отзыве, в поле `reply_text` [метода отзывов](/reviews/list), и приходит событием `replies.new`, если у вас настроены [вебхуки](/guides/webhooks). ## PUT https://api.rewio.ru/v3/reviews/{review_id}/reply Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, на который отвечаете. ### Тело запроса - `text` (строка, обязательный) – Текст ответа. Пустым он не бывает: чтобы убрать ответ, есть [удаление](/replies/delete). ### Пример запроса ```json { "text": "Спасибо за отзыв! Рады, что всё понравилось — ждём вас снова." } ``` ### Ответ 202 - `text` (строка, обязательный) – Текст, который мы приняли в работу. - `status` (строка, обязательный, pending / publishing / published / failed / deleted) – Состояние вашего ответа: `pending` – принят и ждёт публикации, `publishing` – запрос к площадке в полёте, `published` – площадка приняла, `failed` – опубликовать не удалось, `deleted` – ответ удалён. В ответе на этот запрос всегда `pending`: публикация асинхронная. Что ответ действительно стоит на площадке, видно по полям `reply_text` и `reply_date` самого [отзыва](/reviews/list) и по событию `replies.new`. - `updated_at` (дата и время, обязательный) – Когда мы приняли задачу. ### Пример ответа ```json { "text": "Спасибо за отзыв! Рады, что всё понравилось — ждём вас снова.", "status": "pending", "updated_at": "2026-08-16T10:12:03" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). Отказы, свойственные именно ответам, собраны там в отдельной таблице.