# Ключи и доступ (/access) Ключ передаётся в заголовке `X-API-Key` каждого запроса (кроме `GET /health` и `GET /health/read`): ```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 самых свежих **по каждой ссылке** | Все собранные | | Ответов и жалоб на отзывы | 3 ответа и 3 жалобы **на каждую площадку** | Без ограничений на тарифе «Полный» | | [Дополнительных сборов отзывов](/refresh/rules) | 5 **на аккаунт** | Раз в сутки для каждого объекта на тарифе «Полный» | Отзывы при этом собираются полностью, ограничена только выдача. Оплата открывает накопленное сразу, пересобирать ничего не нужно. Пока выдача ограничена, ответ методов отзывов, аналитики и синхронизации содержит блок `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/v3/openapi.json`](https://api.rewio.ru/v3/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 со ссылками на разделы документации. Недостающее агент найдёт в документации или напишет в поддержку. ## Где взять ключ и как его передать [#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`. | | Как узнать, что появилось новое? | Вебхук `reviews.new` или `GET /v3/reviews/sync` с курсором, без опроса в цикле. | | Чем `review_date` отличается от `created_at`? | Публикация на площадке против захвата у нас. Оба в UTC; `review_date` – где это возможно, иначе как на площадке. | | Пользователь просит «четвёрки» – какой фильтр? | `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/{review_id}/reply`. | | Что передать в жалобе на отзыв? | То, что просит `form` из `GET /v3/reviews/{review_id}/complaints`: `category` при `form.category = required`, `text` по `form.text`. | | Откуда берётся формат ссылки? | Из раздела [«Где взять ссылку»](/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` и собирается с площадки как есть, кем бы он ни был написан. Ответ, опубликованный [через Rewio](/guides/replies), занимает то же место на площадке: после публикации он приходит в тех же `reply_text` и `reply_date`. Ответ у отзыва ровно один, и место под него на площадке одно. ## Оценки приведены к 1–5 [#ratings] Площадки считают по-разному: пять баллов, десять, сто, «палец вверх». Rewio приводит всё к шкале 1–5. Это поле `rating`, оно может быть дробным. Исходная оценка площадки остаётся рядом, в `rating_original`. У площадок без числовой оценки `rating` = `null`. ## Площадки [#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` | `access_suspended` | Доступ к API приостановлен: отклоняются все запросы, кроме `DELETE`. | | `402` | `access_expired` | Оплаченный период закончился: работают чтение и `DELETE`, остальная запись отклоняется. | | `403` | `forbidden` | Не хватает прав: запись ключом `read_only`. | | `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`. ## Дополнительный сбор отзывов [#refresh] | Статус | `code` | Когда | | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `402` | `refresh_requires_upgrade` | Дополнительный сбор отзывов входит в тариф «Полный». | | `402` | `refresh_trial_exhausted` | Все 5 дополнительных сборов пробного периода использованы. На тарифе «Полный» дополнительный сбор доступен раз в сутки для каждого объекта. | | `409` | `refresh_in_progress` | Сбор по объекту уже идёт. Итог – в [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state). | | `409` | `refresh_nothing_to_scrape` | У объекта нет ссылок, которые можно собрать. | | `429` | `refresh_limited` | Дополнительный сбор по объекту был меньше суток назад, собирать ещё раз нечего. `Retry-After` – секунд до следующего сбора. | ## Синхронизация отзывов [#sync] | Статус | `code` | Когда | | ------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `400` | `invalid_cursor` | Курсор не читается: испорчен, изменён или выдан другому аккаунту. Начните обход заново, без `cursor` – [как это работает](/reviews/sync). | | `400` | `cursor_mismatch` | Вместе с курсором передан `object_id`, `folder_id` или `mode`, не совпадающий с тем, для которого курсор выдан. | ## Ответы на отзывы [#replies] | Статус | `code` | Когда | | ------ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `402` | `reply_requires_upgrade` | Публикация ответов и «Пропустить» входят в тариф «Полный». Удалить уже опубликованный ответ можно на любом тарифе. | | `402` | `reply_trial_quota_exhausted` | Пробный доступ включает три ответа на каждую площадку, и они израсходованы. Лимит снимает переход на «Полный». | | `403` | `reply_card_not_yours` | Объект не закреплён за вашим аккаунтом. Мы отвечаем от имени организации, поэтому публикуем только там, где подтверждено, что объект ваш. Чтобы подтвердить, напишите в поддержку. | | `403` | `reply_access_revoked` | Площадка не даёт нам отвечать по этой ссылке: доступ был, но его отозвали. Что сделать, написано в `detail`. | | `404` | `reply_not_found` | Ответа нет. Для `GET /reply` – нет ответа через нас (написанный не через нас виден как `reply_text` отзыва); для `DELETE` – на отзыве нет никакого ответа. | | `409` | `reply_not_supported` | На этой площадке мы пока не публикуем ответы. Смотрите `can_publish_reply` в `GET /v3/sources`. | | `409` | `reply_not_replyable` | Отзыв не нативен для площадки: она показывает его в своей ленте, но собран он с другой (`provider` ≠ `source_slug`: `tbank`, `booking`, `tripadvisor`, …). Ответить на него через эту площадку нельзя. | | `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`. Если ответ не появился, причина обычно одна из этих: | Причина | Что происходит | | -------------------------------------- | ---------------------------------------- | | Наш доступ к площадке обновляется | Ничего делать не нужно, ответ уйдёт сам. | | Площадка просит подождать | Повтор произойдёт автоматически. | | Сеть или сбой на стороне площадки | Повторим сами, до трёх раз. | | Из ссылки не выводится объект площадки | Проверьте адрес ссылки в объекте. | | Площадка отклонила текст | Измените текст и отправьте снова. | Ответ не появился – напишите на . ## Жалобы на отзывы [#complaints] | Статус | `code` | Когда | | ------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `402` | `complaint_requires_upgrade` | Жалобы входят в тариф «Полный». | | `402` | `complaint_trial_quota_exhausted` | Пробный доступ включает три жалобы на каждую площадку, и они израсходованы. | | `403` | `complaint_access_missing` | На этой карточке у вас не подключены ответы – а жалобы живут там же. | | `403` | `complaint_card_not_yours` | Объект не закреплён за вашим аккаунтом. Чтобы подтвердить, напишите в поддержку. | | `409` | `complaint_not_supported` | На этой площадке мы не подаём жалобы. Смотрите `can_file_complaint` в `GET /v3/sources`. | | `409` | `complaint_not_replyable` | Отзыв собран с другой площадки (`provider` ≠ `source_slug`): жаловаться на него нужно там. | | `409` | `complaint_already_filed` | На отзыв уже подана жалоба, а площадка принимает одну (Яндекс). | | `409` | `complaint_pending_review` | Прежняя жалоба ещё на рассмотрении (2ГИС). | | `409` | `complaint_cooldown` | Повторно – не чаще раза в трое суток (Google). Когда можно, говорит заголовок `Retry-After` и `retry_at` в [форме](/complaints/get). | | `409` | `complaint_in_progress` | Жалоба на этот отзыв сейчас отправляется. | | `422` | `complaint_category_invalid` | Нет `category` или код не из `form.categories`. | | `422` | `complaint_text_required` | Площадка принимает жалобу текстом, а `text` пуст. | | `422` | `complaint_text_too_long` | `text` длиннее `form.max_length`. | | `422` | `complaint_text_invalid` | В `text` управляющие символы. | | `503` | `complaint_source_paused` | Подача жалоб на площадке временно приостановлена: у площадки сбой. | Если жалоба не подана уже после `202`, у неё `status: failed` и `error.code` из того же словаря: * за время отправки что-то изменилось – `complaint_requires_upgrade`, `complaint_trial_quota_exhausted`, `complaint_access_missing`, `complaint_access_revoked` (доступ к площадке отозван), `complaint_card_not_yours`, `complaint_source_paused`, `complaint_already_filed`; * отзыв или площадка – `complaint_not_replyable` (отзыва больше нет на площадке), `complaint_target_unresolved` (не нашли отзыв на площадке), `complaint_not_supported`; * площадка не приняла – `complaint_rejected_by_platform`; * не удалось за сутки – `complaint_session_expired`, `complaint_rate_limited` или `complaint_transport_failed`. ## Как обрабатывать [#handling] * Повторяйте `429` и `5xx` с нарастающей задержкой. Исключение – `429 refresh_limited`: раньше `Retry-After` дополнительный сбор по объекту не запустится. Остальные `4xx` не повторяйте без исправления запроса; исключения – `409 idempotency_in_progress` и `409 reply_in_progress`, их повторяют с задержкой. * Логируйте `code` вместе с `detail`: по коду мы быстрее поймём, что случилось. * При добавлении ссылок отказ приходит по каждой ссылке отдельно: текст в `error`, машинная причина в `error_code`. Негодная ссылка не отменяет остальные – они добавятся. Форматы адресов смотрите в разделе [«Форматы ссылок»](/link-formats#url-formats). Примеры: ```json // 401 – ключ не передан { "detail": "API key required. Provide X-API-Key header.", "code": "unauthorized" } // 403 – запись ключом на чтение { "detail": "This operation requires full access. Your API key has read-only access.", "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 – страница объекта Откройте страницу клиники, салона, врача или мастера – подойдёт и вкладка «Отзывы». Собираем отзывы, оставленные на самом Клеосе. Откройте карточку организации и скопируйте адрес из строки браузера. Клеос – страница объекта Откройте страницу клиники или врача – подойдёт и вкладка «Отзывы». У клиники собираем все её отзывы, вместе с отзывами о её врачах. Откройте карточку организации и скопируйте адрес из строки браузера. 32top – страница объекта ## Услуги и специалисты [#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` | | `306` | 103.kz | `{организация}.103.kz`
`103.kz/spec/{id}-{врач}` | `https://emirmed-nii.103.kz/`
`https://www.103.kz/spec/6212-murathanova/` | | `210` | Клеос | `kleos.ru/{раздел}/{название}`
`kleos.ru/{город}/{раздел}/{название}` | `https://www.kleos.ru/cosmetic/klinika-hfe/`
`https://www.kleos.ru/spb/meditsina/56229-stomatologiya-faktor-ulybki/` | | `307` | 32top | `32top.ru/clinics/{id}`
`32top.ru/{город}/clinics/{id}`
`32top.ru/dr/{id}-{врач}` | `https://www.32top.ru/clinics/15124/`
`https://www.32top.ru/dr/9356-arzumanov-amayak-arkadevich/` | ### Услуги и специалисты [#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` | | `209` | ВсеОтзывы | `vseotzyvy.ru/otzyvy/{название}-{id}` | `https://vseotzyvy.ru/otzyvy/sputnikovoe-televidenie-trikolor-13537` | ## Что полезно знать [#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 или 64 шестнадцатеричных символа). Без него продавца не определить. * **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) | Те же метрики по дням, неделям или месяцам. | | [`GET /v3/ratings`](/reviews/ratings) | Оценка объекта на каждой площадке и число оценок. | | [`GET /v3/ratings/history`](/analytics/ratings-history) | Как менялась оценка объекта на площадках. | ## Объекты и ссылки [#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) | Удалить папку, не трогая объекты внутри. | ## Дополнительный сбор отзывов [#refresh] Сбор новых отзывов вне расписания – раз в сутки на объект, тариф «Полный». Правила – на странице [«Как работает дополнительный сбор отзывов»](/refresh/rules). | Метод | Что делает | | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | [`POST /v3/objects/{object_id}/refresh`](/refresh/object) | Запустить сбор по объекту: новые отзывы со всех площадок или ещё раз с площадок, где не получилось. | | [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state) | Можно ли запустить сбор сейчас, когда снова и итог по каждой площадке. | | [`GET /v3/objects/refresh`](/refresh/list) | То же состояние по всем объектам аккаунта. | | [`POST /v3/folders/{folder_id}/refresh`](/refresh/folder) | Запустить сбор по всем объектам папки и её подпапок. | | [`GET /v3/folders/{folder_id}/refresh`](/refresh/folder-state) | Состояние сбора по каждому объекту папки. | ## Ответы на отзывы [#replies] Ответ публикуется под отзывом на самой площадке. Включается по запросу – напишите на ; нужен ключ `full` и тариф «Полный» (на пробном доступе – три ответа на площадку). Подробности – в руководстве [«Как отвечать на отзывы»](/guides/replies). | Метод | Что делает | | --------------------------------------------------------- | ----------------------------------------------------------- | | [`PUT /v3/reviews/{review_id}/reply`](/replies/publish) | Опубликовать ответ или заменить уже стоящий. | | [`GET /v3/reviews/{review_id}/reply`](/replies/get) | Состояние ответа: отправлен, принят площадкой, опубликован. | | [`DELETE /v3/reviews/{review_id}/reply`](/replies/delete) | Удалить ваш ответ с площадки. | ## Жалобы на отзывы [#complaints] Жалоба подаётся на самой площадке от имени организации – там, где у вас подключены ответы. Форма у каждой площадки своя: Яндекс – текст, 2ГИС – категория и текст, Google – категория. Нужен ключ `full` и тариф «Полный» (на пробном доступе – три жалобы на площадку). | Метод | Что делает | | ------------------------------------------------------------- | --------------------------------------------------------- | | [`GET /v3/reviews/{review_id}/complaints`](/complaints/get) | Форма площадки, жалобы на отзыв и можно ли подать сейчас. | | [`POST /v3/reviews/{review_id}/complaints`](/complaints/file) | Пожаловаться на отзыв. | | [`GET /v3/complaints`](/complaints/list) | Ваши жалобы вместе с отзывами – по статусу. | ## Вебхуки [#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) | Выпустить новый секрет подписи. 24 часа доставки подписываются и новым, и старым секретом. | ## Для виджетов [#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), аналитика строится по папке целиком. * **Ответы на отзывы** – ответ публикуется под отзывом на площадке одним запросом. * **Жалобы на отзывы** – жалоба уходит в форму Яндекс Карт, 2ГИС или Google от имени организации, итог виден в API. * **Отзывы в 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. Время площадки приводится к UTC, где это возможно, иначе отдаётся как на площадке | | Ошибки | `{"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#url-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 Дальше отзывы объекта собираются по расписанию. Чтобы получать новые отзывы и ответы без опроса API, подпишитесь на [вебхуки](/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) Все методы можно открыть в интерактивном просмотрщике [Scalar](https://api.rewio.ru/v3/scalar) (или [Swagger UI](https://api.rewio.ru/v3/docs)) и вызвать прямо из браузера. Машиночитаемое описание API – OpenAPI 3.1: ``` https://api.rewio.ru/v3/openapi.json ``` Спецификация – источник истины: если документация расходится со спецификацией, верна спецификация. ## Postman [#postman] **Import → Link**, вставьте адрес спецификации. Затем задайте в окружении переменную `apiKey` со значением вашего ключа: импорт уже подставил её в заголовок `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) – всё одним файлом. Готовый Skill для агента – на странице [Интеграция через AI](/ai). # Пожаловаться на отзыв (/complaints/file) Подаёт жалобу на отзыв на самой площадке – от имени организации, той же учёткой, что публикует ответы на этой карточке. Что передать, говорит [форма](/complaints/get): Яндекс – только `text`, 2ГИС – `category` и `text`, Google – только `category`. Подача асинхронная: `202` означает, что мы приняли жалобу. Её дальнейшую судьбу показывают [форма и жалобы на отзыв](/complaints/get) и [список жалоб](/complaints/list). **Итог.** Яндекс и Google итога не сообщают, поэтому через 7 дней (Яндекс) и 5 дней (Google) после подачи мы смотрим отзыв на площадке: стоит – `rejected`, удалён – `accepted`. 2ГИС отмечает рассмотренные жалобы сам – тогда смотрим так же; если 2ГИС молчит 14 дней, тоже. Нужен ключ со скоупом `full` и тариф «Полный»; в пробном периоде – три жалобы на площадку. Жалобы есть только на карточках, где у вас подключены ответы. ## POST https://api.rewio.ru/v3/reviews/{review_id}/complaints Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, на который жалуетесь. ### Тело запроса - `category` (строка, может быть null) – Код категории из `form.categories` – если [форма](/complaints/get) говорит `category: required`. Иначе не передавайте. - `text` (строка, по умолчанию «») – Текст жалобы – по `form.text`: обязателен при `required`, по желанию при `optional`, не передаётся при `none`. ### Пример запроса ```json { "category": "no_client", "text": "Гостя с таким именем в эти даты не было." } ``` ### Ответ 202 - `id` (число, обязательный) – Идентификатор жалобы. - `review_id` (число, обязательный) – Отзыв, на который она подана. - `status` (строка, может быть null, pending / accepted / rejected / failed) – В ответе на этот запрос всегда `null`: жалоба принята, площадке ещё не передана. Дальше – `pending` (на рассмотрении), `accepted` (отзыв удалён), `rejected` (отзыв остался) или `failed` (не подана, причина в `error`). - `origin` (строка, обязательный, rewio / platform) – `rewio` – подана через Rewio. - `category` (объект, может быть null) – Категория, если площадка её спрашивает. - `category.code` (строка, обязательный) – Код, который передаётся в `category`. - `category.label` (строка, обязательный) – Как категорию называет площадка. - `category.description` (строка, может быть null) – Что она значит. - `text` (строка, обязательный) – Текст жалобы. - `author` (строка, может быть null) – Кто подал, как его называет площадка (`origin = platform`). - `submitted_at` (дата и время, обязательный) – Когда подана. - `resolved_at` (дата и время, может быть null) – Когда стал известен итог. В ответе на этот запрос – `null`. - `updated_at` (дата и время, обязательный) – Когда запись менялась в последний раз. - `error` (объект, может быть null) – Почему не подана. В ответе на этот запрос – `null`. - `error.code` (строка, обязательный) – Машинный код: `complaint_already_filed` – на отзыв уже подана жалоба (Яндекс принимает одну); `complaint_requires_upgrade`, `complaint_trial_quota_exhausted` – тариф; `complaint_access_missing`, `complaint_access_revoked`, `complaint_card_not_yours` – карточка не подключена; `complaint_not_replyable` – отзыв удалён или пришёл с другой площадки; `complaint_target_unresolved` – отзыв не нашли на площадке; `complaint_not_supported` – на площадке жалобы не подаются; `complaint_source_paused` – подача на площадке приостановлена; `complaint_rejected_by_platform` – площадка не приняла жалобу; `complaint_session_expired`, `complaint_rate_limited`, `complaint_transport_failed` – не удалось за сутки. - `error.message` (строка, по умолчанию «») – Пояснение для человека. ### Пример ответа ```json { "id": 213, "review_id": 539486, "status": null, "origin": "rewio", "category": { "code": "no_client", "label": "Такого клиента у нас не было", "description": "2ГИС запросит у автора подтверждение визита или покупки. Без него отзыв перенесут в «Неподтверждённые», и он перестанет влиять на рейтинг." }, "text": "Гостя с таким именем в эти даты не было.", "author": null, "submitted_at": "2026-10-29T18:02:11", "resolved_at": null, "updated_at": "2026-10-29T18:02:11", "error": null } ``` Коды ошибок описаны на странице [Ошибки](/errors#complaints). # Форма и жалобы на отзыв (/complaints/get) Отзыв называете вы, форму говорим мы: у каждой площадки она своя. Начните с этого метода, затем передайте в [подаче жалобы](/complaints/file) ровно то, что просит `form`. | Площадка | `form.category` | `form.text` | Повторная жалоба | | -------- | --------------- | ----------- | ------------------------------------------------------------ | | Яндекс | `none` | `required` | нельзя: на отзыв принимается одна жалоба, кто бы её ни подал | | 2ГИС | `required` | `required` | когда 2ГИС рассмотрел прежнюю | | Google | `required` | `none` | не чаще раза в трое суток – это наше правило | ## Категории [#categories] **2ГИС** – категория уходит первой фразой текста жалобы. | `code` | Как называет 2ГИС | Что значит | | ------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `no_client` | Такого клиента у нас не было | 2ГИС запросит у автора подтверждение визита или покупки. Без него отзыв перенесут в «Неподтверждённые», и он перестанет влиять на рейтинг. | | `offensive` | В отзыве оскорбления/мат | Мат, оскорбления или обвинения без оснований. | | `hearsay` | Отзыв написан с чужих слов | Автор пишет не о своём опыте, а об услуге, оказанной другому человеку. | | `ex_employee` | Отзыв бывшего работника | Отзыв оставил бывший сотрудник, а не клиент. | | `refused` | Клиент сам отказался от покупки | Автор сам отказался от покупки или услуги – из-за цены, условий или сроков – и клиентом не был. | | `other` | Нарушены другие правила | Реклама, спам, личные данные, отзыв не об этой компании и другие нарушения правил 2ГИС. | **Google** – только тема, без текста. | `code` | Как называет Google | Что значит | | ------ | --------------------------------- | -------------------------------------------------------------------------------------------------- | | `1` | Не по теме | Отзыв не имеет отношения к этой компании. | | `2` | Спам | Отзыв оставлен ботом, отправлен с поддельного аккаунта или содержит рекламу. | | `3` | Конфликт интересов | Отзыв оставлен пользователем, который связан с этой компанией или её конкурентом. | | `4` | Грубая речь | Отзыв содержит ненормативную лексику, призывы к насилию или другие противозаконные материалы. | | `6` | Издевательство или домогательство | Отзыв демонстрирует агрессию в отношении конкретного человека. | | `7` | Дискриминационные высказывания | Отзыв содержит оскорбительные или дискриминационные высказывания о человеке или социальной группе. | | `8` | Личные данные | Отзыв содержит личную информацию, такую как адрес или номер телефона. | **Яндекс** категорий не спрашивает: жалоба – это текст. Жалобы есть только на карточках, где у вас подключены ответы на отзывы; на остальных метод отвечает `403 complaint_access_missing`. Чтение доступно ключу со скоупом `read_only`. ## GET https://api.rewio.ru/v3/reviews/{review_id}/complaints Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, на который хотите пожаловаться. ### Ответ 200 - `data` (список объектов, обязательный) – Жалобы на этот отзыв, новые сверху: ваши (`origin: rewio`) и поданные в кабинете площадки (`origin: platform`). - `data[].id` (число, обязательный) – Идентификатор жалобы. - `data[].review_id` (число, обязательный) – Отзыв, на который она подана. - `data[].status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался (2ГИС отметил жалобу рассмотренной или молчит 14 дней, у Яндекса прошло 7 дней, у Google – 5); `failed` – не подана, причина в `error`. - `data[].origin` (строка, обязательный, rewio / platform) – `rewio` – подана через Rewio; `platform` – подана в кабинете площадки, мы нашли её там. - `data[].category` (объект, может быть null) – Категория, если площадка их спрашивает. - `data[].category.code` (строка, обязательный) – Код, который передаётся в `category`. - `data[].category.label` (строка, обязательный) – Как категорию называет площадка. - `data[].category.description` (строка, может быть null) – Что она значит. - `data[].text` (строка, обязательный) – Текст жалобы. Пустой там, где площадка текста не принимает (Google). - `data[].author` (строка, может быть null) – Кто подал, как его называет площадка (`origin = platform`). - `data[].submitted_at` (дата и время, обязательный) – Когда подана (UTC, ISO 8601). - `data[].resolved_at` (дата и время, может быть null) – Когда стал известен итог – `accepted` или `rejected` (UTC, ISO 8601). - `data[].updated_at` (дата и время, обязательный) – Когда запись менялась в последний раз (UTC, ISO 8601). - `data[].error` (объект, может быть null) – Почему не подана (`status = failed`). - `data[].error.code` (строка, обязательный) – Машинный код: `complaint_already_filed` – на отзыв уже подана жалоба (Яндекс принимает одну); `complaint_requires_upgrade`, `complaint_trial_quota_exhausted` – тариф; `complaint_access_missing`, `complaint_access_revoked`, `complaint_card_not_yours` – карточка не подключена; `complaint_not_replyable` – отзыв удалён или пришёл с другой площадки; `complaint_target_unresolved` – отзыв не нашли на площадке; `complaint_not_supported` – на площадке жалобы не подаются; `complaint_source_paused` – подача на площадке приостановлена; `complaint_rejected_by_platform` – площадка не приняла жалобу; `complaint_session_expired`, `complaint_rate_limited`, `complaint_transport_failed` – не удалось за сутки. - `data[].error.message` (строка, по умолчанию «») – Пояснение для человека. - `can_file` (да/нет, обязательный) – Можно ли подать жалобу сейчас. - `reason_code` (строка, может быть null, already_filed / pending_review / cooldown / in_progress / requires_upgrade / trial_quota_exhausted / source_paused / not_replyable) – Почему нельзя: `already_filed`, `pending_review`, `cooldown`, `in_progress`, `requires_upgrade`, `trial_quota_exhausted`, `source_paused`, `not_replyable`. `null`, если можно. - `reason` (строка, может быть null) – То же готовой фразой для человека. - `retry_at` (дата и время, может быть null) – С какого момента можно подать снова – только при `cooldown`. - `form` (объект, обязательный) – Что передать в [подаче жалобы](/complaints/file) на площадке этого отзыва. - `form.category` (строка, обязательный, required / none) – `required` – передайте `category`, код из `form.categories`; `none` – у площадки категорий нет, `category` не передавайте. - `form.categories` (список объектов, обязательный) – Категории площадки – её же словами: `code` (что передать), `label` (как называет площадка), `description` (что значит). - `form.categories[].code` (строка, обязательный) – Код, который передаётся в `category`. - `form.categories[].label` (строка, обязательный) – Как категорию называет площадка. - `form.categories[].description` (строка, может быть null) – Что она значит. - `form.text` (строка, обязательный, required / optional / none) – `required` – передайте `text`; `optional` – по желанию; `none` – площадка текста не принимает, `text` не передавайте. - `form.max_length` (число, обязательный) – Наибольшая длина `text`. - `form.review_period` (строка, может быть null) – Сколько площадка рассматривает жалобу. ### Пример ответа ```json { "data": [ { "id": 212, "review_id": 539486, "status": "pending", "origin": "rewio", "category": { "code": "other", "label": "Нарушены другие правила", "description": "Реклама, спам, личные данные, отзыв не об этой компании и другие нарушения правил 2ГИС." }, "text": "Автор не был у нас: в CRM нет визита с этим авто.", "author": null, "submitted_at": "2026-10-29T17:54:45", "resolved_at": null, "updated_at": "2026-10-29T17:54:46", "error": null } ], "can_file": false, "reason_code": "pending_review", "reason": "Пока прежняя жалоба на рассмотрении, новую подать нельзя.", "retry_at": null, "form": { "category": "required", "categories": [ { "code": "no_client", "label": "Такого клиента у нас не было", "description": "2ГИС запросит у автора подтверждение визита или покупки. Без него отзыв перенесут в «Неподтверждённые», и он перестанет влиять на рейтинг." }, { "code": "offensive", "label": "В отзыве оскорбления/мат", "description": "Мат, оскорбления или обвинения без оснований." } ], "text": "required", "max_length": 2000, "review_period": "2ГИС рассматривает жалобы до 5 дней." } } ``` Коды ошибок описаны на странице [Ошибки](/errors#complaints). # Ваши жалобы (/complaints/list) Жалобы, поданные через Rewio на отзывы ваших объектов. `status` выбирает группу: `pending` – на рассмотрении (в том числе ещё отправляемые), `accepted` – отзыв удалён, `rejected` – отзыв остался, `failed` – не поданы; можно несколько сразу: `status=rejected&status=failed`. `object_id` и `source_ids` сужают выдачу. Жалобы, поданные в кабинете площадки, здесь не показываются – они видны в [форме и жалобах на отзыв](/complaints/get) у своего отзыва. ## GET https://api.rewio.ru/v3/complaints Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `status` (список строк, query, по умолчанию ["pending"]) – `pending` – на рассмотрении, в том числе ещё отправляемые (`status: null`); `accepted` – отзыв удалён; `rejected` – отзыв остался; `failed` – не поданы. Можно несколько: `status=rejected&status=failed`. - `source_ids` (список чисел, query, по умолчанию пусто) – Фильтр по площадкам: id из `GET /v3/sources`. - `limit` (число, query, 1–100, по умолчанию 20) – Размер страницы (1–100). - `offset` (число, query, не меньше 0, по умолчанию 0) – Смещение. - `object_id` (число, query, может быть null) – Идентификатор объекта. Взаимоисключим с `folder_id` – в запросе может быть только один из двух. ### Ответ 200 - `data` (список объектов, обязательный) – Жалобы, новые сверху. - `data[].complaint` (объект, обязательный) – Жалоба – как в [подаче](/complaints/file). - `data[].complaint.id` (число, обязательный) – Идентификатор жалобы. - `data[].complaint.review_id` (число, обязательный) – Отзыв, на который она подана. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался (2ГИС отметил жалобу рассмотренной или молчит 14 дней, у Яндекса прошло 7 дней, у Google – 5); `failed` – не подана, причина в `error`. - `data[].complaint.origin` (строка, обязательный, rewio / platform) – `rewio` – подана через Rewio; `platform` – подана в кабинете площадки, мы нашли её там. - `data[].complaint.category` (объект, может быть null) – Категория, если площадка их спрашивает. - `data[].complaint.category.code` (строка, обязательный) – Код, который передаётся в `category`. - `data[].complaint.category.label` (строка, обязательный) – Как категорию называет площадка. - `data[].complaint.category.description` (строка, может быть null) – Что она значит. - `data[].complaint.text` (строка, обязательный) – Текст жалобы. Пустой там, где площадка текста не принимает (Google). - `data[].complaint.author` (строка, может быть null) – Кто подал, как его называет площадка (`origin = platform`). - `data[].complaint.submitted_at` (дата и время, обязательный) – Когда подана (UTC, ISO 8601). - `data[].complaint.resolved_at` (дата и время, может быть null) – Когда стал известен итог – `accepted` или `rejected` (UTC, ISO 8601). - `data[].complaint.updated_at` (дата и время, обязательный) – Когда запись менялась в последний раз (UTC, ISO 8601). - `data[].complaint.error` (объект, может быть null) – Почему не подана (`status = failed`). - `data[].complaint.error.code` (строка, обязательный) – Машинный код: `complaint_already_filed` – на отзыв уже подана жалоба (Яндекс принимает одну); `complaint_requires_upgrade`, `complaint_trial_quota_exhausted` – тариф; `complaint_access_missing`, `complaint_access_revoked`, `complaint_card_not_yours` – карточка не подключена; `complaint_not_replyable` – отзыв удалён или пришёл с другой площадки; `complaint_target_unresolved` – отзыв не нашли на площадке; `complaint_not_supported` – на площадке жалобы не подаются; `complaint_source_paused` – подача на площадке приостановлена; `complaint_rejected_by_platform` – площадка не приняла жалобу; `complaint_session_expired`, `complaint_rate_limited`, `complaint_transport_failed` – не удалось за сутки. - `data[].complaint.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].review` (объект, обязательный) – Отзыв – как в [получении отзывов](/reviews/list). У принятой жалобы он уже удалён с площадки. - `data[].review.id` (число, обязательный) – Идентификатор отзыва в сервисе. - `data[].review.link_id` (число, обязательный) – Идентификатор ссылки (страницы объекта на площадке). - `data[].review.source_id` (число, обязательный) – Идентификатор площадки, с которой собран отзыв. - `data[].review.source_slug` (строка, может быть null) – Слаг площадки, с которой собран отзыв (`2gis`, `google`, `yandex_maps`). Отвечать можно, если он совпадает с `provider` отзыва. - `data[].review.author` (строка, может быть null) – Имя автора; `null`, если анонимен. - `data[].review.text` (строка, может быть null) – Текст отзыва; `null`, если отзыв без текста. - `data[].review.review_date` (дата и время, может быть null) – Дата и время публикации отзыва. Приводится к UTC везде, где это возможно; в противном случае – время, как его показывает площадка. ISO 8601 без таймзоны. - `data[].review.rating_original` (строка, может быть null) – Исходная оценка в шкале площадки. - `data[].review.rating` (число, может быть null) – Оценка, приведённая к единой шкале 1–5. `null`, если оценки нет. - `data[].review.review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. `null`, если недоступна. - `data[].review.reply_text` (строка, может быть null) – Текст официального ответа организации. `null`, если ответа нет. - `data[].review.reply_date` (дата и время, может быть null) – Дата и время ответа организации (ISO 8601). Приводится к UTC, где это возможно. - `data[].review.provider` (строка, может быть null) – Площадка-источник самого отзыва внутри `source` (слаг в нижнем регистре). Многие площадки показывают в ленте отзывы других: 2ГИС – `booking`/`tbank`/`flamp`/…, Google – `tripadvisor`. У нативного отзыва совпадает со слагом площадки (`2gis`, `google`), и только на такой отзыв можно опубликовать ответ через эту площадку – на остальные вернётся `409 reply_not_replyable`. - `data[].review.is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `data[].review.has_images` (да/нет, обязательный) – Признак наличия изображений в отзыве. - `data[].review.images` (список объектов, по умолчанию пусто) – Список изображений отзыва. - `data[].review.images[].template_url` (строка, обязательный) – URL изображения на CDN площадки в исходном виде. У части площадок содержит шаблон размера (`{size}` или `{width}`/`{height}`) и потому не предназначен для прямой вставки – для показа берите `preview` или `image`. - `data[].review.images[].preview` (строка, может быть null) – Готовый URL уменьшенной версии (превью) для списков и сеток. - `data[].review.images[].image` (строка, может быть null) – Готовый URL полноразмерной версии для просмотра. - `data[].review.has_videos` (да/нет, по умолчанию нет) – Признак наличия видео в отзыве. - `data[].review.videos` (список объектов, по умолчанию пусто) – Список видеовложений отзыва. - `data[].review.videos[].kind` (строка, обязательный, embed / file / hls) – Тип вложения: `embed` – встраиваемый плеер площадки (открывать в sandbox-iframe), `file` – прямая ссылка на видеофайл, `hls` – HLS-поток (`.m3u8`). - `data[].review.videos[].video_url` (строка, может быть null) – URL видео или встраиваемого плеера в зависимости от `kind`. - `data[].review.videos[].thumbnail` (строка, может быть null) – URL кадра-заставки (превью) видео. - `data[].review.videos[].width` (число, может быть null) – Ширина видео в пикселях, если известна. - `data[].review.videos[].height` (число, может быть null) – Высота видео в пикселях, если известна. - `data[].review.videos[].duration_ms` (число, может быть null) – Длительность видео в миллисекундах, если известна. - `data[].review.is_deleted` (да/нет, по умолчанию нет) – Отзыв обнаружен удалённым на площадке (приходит только когда `true`). - `data[].review.deleted_at` (дата и время, может быть null) – Момент обнаружения удаления (UTC, ISO 8601). - `data[].review.is_hidden` (да/нет, по умолчанию нет) – Отзыв скрыт в рамках объекта (приходит только когда `true`). - `data[].review.is_pinned` (да/нет, по умолчанию нет) – Отзыв закреплён в рамках объекта (приходит только когда `true`). - `data[].review.pin_position` (число, может быть null) – Позиция закреплённого отзыва: меньше – выше. - `data[].review.pros` (строка, может быть null) – Блок «достоинства» (только при `split_pros_cons=true`). - `data[].review.cons` (строка, может быть null) – Блок «недостатки» (только при `split_pros_cons=true`). - `data[].review.our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].review.our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].review.our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].review.our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].review.our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].review.our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].review.our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].review.is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].review.complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].review.complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].review.complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].review.complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. - `total` (число, обязательный) – Общее число элементов, подходящих под фильтры (без учёта limit/offset). - `limit` (число, обязательный) – Размер страницы, применённый к запросу. - `offset` (число, обязательный) – Смещение от начала выборки, применённое к запросу. - `has_next` (да/нет, обязательный) – Есть ли ещё элементы за пределами текущей страницы. ### Пример ответа ```json { "data": [ { "complaint": { "id": 213, "review_id": 539486, "status": "pending", "origin": "rewio", "category": { "code": "no_client", "label": "Такого клиента у нас не было", "description": "2ГИС запросит у автора подтверждение визита или покупки. Без него отзыв перенесут в «Неподтверждённые», и он перестанет влиять на рейтинг." }, "text": "Гостя с таким именем в эти даты не было.", "author": null, "submitted_at": "2026-10-29T18:02:11", "resolved_at": null, "updated_at": "2026-10-29T18:02:11", "error": null }, "review": { "id": 539486, "object_id": 20, "link_id": 2001, "source_id": 3, "source_slug": "2gis", "author": "Олег", "rating": 2, "text": "Долго ждал, мастер грубил.", "review_date": "2026-09-28T10:00:00", "reply_text": null, "review_url": "https://2gis.ru/reviews/539486" } } ], "total": 1, "limit": 20, "offset": 0, "has_next": false } ``` # Расширенная проверка (/extra/health-detailed) `GET /health/detailed` – проверка глубже, чем [`/health`](/extra/health) и [`/health/read`](/extra/health-read). Она смотрит не только на то, отвечает ли 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). # Создать папку (/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` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `ignored_object_ids` (список чисел) – Идентификаторы из `object_ids`, которые в состав не попали: чужие, удалённые или несуществующие. ### Пример ответа ```json { "id": 12, "user_id": 48213, "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) Удаляет только саму папку. Объекты из папки не удаляются, сбор по ним продолжается. Если внутри есть подпапки, запрос отклоняется с `409 folder_not_empty` – сначала перенесите или удалите их. ## 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` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. ### Пример ответа ```json { "id": 12, "user_id": 48213, "name": "Москва", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" } ], "subfolders": [ { "id": 13, "user_id": 48213, "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` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `data[].subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `data[].subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `data[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `data[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `data[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `data[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. ### Пример ответа ```json { "data": [ { "id": 12, "user_id": 48213, "name": "Москва", "created_at": "2026-07-28T16:50:24", "parent_folder_id": null, "objects": [ { "id": 20, "name": "Националь" }, { "id": 21, "name": "Метрополь" } ], "subfolders": [ { "id": 13, "user_id": 48213, "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` (список объектов, по умолчанию пусто) – Подпапки со своим составом. - `subfolders[].subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `subfolders[].review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `subfolders[].is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `review_count` (число, может быть null) – Сколько отзывов в ленте папки (`GET /v3/reviews?folder_id=`): объекты папки и её подпапок, отзыв общей для двух объектов ссылки считается один раз. - `is_demo` (да/нет, по умолчанию нет) – Папка примеров, которую кабинет кладёт новому клиенту. - `ignored_object_ids` (список чисел) – Идентификаторы из `object_ids`, которые в состав не попали: чужие, удалённые или несуществующие. ### Пример ответа ```json { "id": 12, "user_id": 48213, "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": 48213, "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_ВАШ_КЛЮЧ" ``` Ответ – три блока (и `access`, если тариф ограничил выдачу): * **`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` (по умолчанию `month`). Ответ – `series`. Без `source_ids` приходит один агрегированный ряд с `source_id: 0` («Все источники»); ряды по площадкам – только для перечисленных в `source_ids` (`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/complaints) Жалоба уходит на самой площадке от имени вашей организации – той же учёткой, что публикует [ответы](/guides/replies). Решение принимает площадка; мы подаём жалобу и следим за итогом. ## Два шага [#steps] **1. Узнать форму.** У каждой площадки она своя, и `GET` говорит, что передать: ```bash curl https://api.rewio.ru/v3/reviews/539486/complaints -H "X-API-Key: hrev_ВАШ_КЛЮЧ" # -> { "can_file": true, # "form": { "category": "required", "categories": [{ "code": "no_client", "label": "Такого клиента у нас не было", "description": "…" }, …], # "text": "required", "max_length": 2000, "review_period": "2ГИС рассматривает жалобы до 5 дней." }, # "data": [] } ``` * `form.category = required` – передайте `category`, код из `form.categories`; `none` – не передавайте. * `form.text = required` – передайте `text`; `optional` – по желанию; `none` – не передавайте. **2. Подать.** ```bash curl -X POST https://api.rewio.ru/v3/reviews/539486/complaints \ -H "X-API-Key: hrev_ВАШ_FULL_КЛЮЧ" -H "Content-Type: application/json" \ -d '{"category": "no_client", "text": "Гостя с таким именем в эти даты не было."}' # -> 202 { "id": 213, "review_id": 539486, "status": null, "origin": "rewio", … } ``` ## Площадки [#platforms] | Площадка | Что передать | Повторная жалоба | Когда известен итог | | ------------ | ------------------- | ------------------------------------------------ | ----------------------------------------------------------- | | Яндекс Карты | `text` | нельзя: на отзыв одна жалоба, кто бы её ни подал | через 7 дней после подачи | | 2ГИС | `category` и `text` | когда 2ГИС рассмотрел прежнюю | когда 2ГИС отметил жалобу рассмотренной (или через 14 дней) | | Google | `category` | не чаще раза в трое суток – наше правило | через 5 дней после подачи | Категории 2ГИС и Google с описанием – в [справочнике](/complaints/get#categories). ## Итог [#outcome] Яндекс и Google итога не сообщают, поэтому в назначенный день мы открываем отзыв на площадке: отзыв стоит – жалоба `rejected`, удалён – `accepted`. Если отзыв не открылся, пробуем следующие ночи. Статус жалобы показывают [форма и жалобы на отзыв](/complaints/get) и [список ваших жалоб](/complaints/list); в кабинете – раздел «Жалобы». ## Условия [#requirements] | | | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Тариф | «Полный» – без ограничений; на пробном доступе – **три жалобы на каждую площадку**, дальше `402 complaint_trial_quota_exhausted`; на остальных тарифах – `402 complaint_requires_upgrade`. | | Подключение | Жалобы живут там же, где ответы: на карточке должны быть подключены [ответы](/guides/replies#requirements). Иначе – `403 complaint_access_missing`. | | Ключ | Для подачи нужен скоуп `full`; посмотреть форму и жалобы можно ключом `read_only`. | Все отказы и их коды – на странице [Ошибки](/errors#complaints). # Как работать с папками (/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 неудалённых папок на аккаунт (`403 folder_limit_reached`). ## Управление папками [#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": 48213, "name": "Сеть Север", "created_at": "2026-07-28T09:14:02", "parent_folder_id": null, "objects": [{ "id": 20, "name": "Гранд Отель" }], "subfolders": [ { "id": 12, "user_id": 48213, "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 object_and_folder_conflict` | | ни одного | `GET /v3/reviews` и `GET /v3/analytics` – данные по всем включённым объектам аккаунта; `GET /v3/analytics/timeseries` – `400 object_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, появляется под отзывом на самой площадке, от лица вашей организации. На карточках с подключёнными ответами работают и [жалобы на отзывы](/guides/complaints). ```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": null, … } ``` ## Что нужно до первого ответа [#requirements] Четыре условия, все обязательные: | | | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Тариф | Полный – без ограничений. На пробном доступе даётся **три ответа на каждую площадку**; дальше `402` с кодом `reply_trial_quota_exhausted`. На остальных тарифах публикация отвечает `402` с кодом `reply_requires_upgrade`. | | Подключение | Площадка должна выдать нам доступ к ответам. Делается на её стороне, один раз на объект – как именно, ниже. | | Закрепление объекта | Объект должен быть закреплён за вашим аккаунтом на нашей стороне. Включаем мы, по обращению в поддержку. Без этого публикация отвечает `403` с кодом `reply_card_not_yours`. | | Ключ | Для публикации и удаления необходим скоуп `full`. Ключ на чтение получит `403`. | **Ответы включаются по запросу.** Напишите на – укажите площадку и объекты. Мы сверим, что доступ выдан именно вам, и закрепим объекты за вашим аккаунтом. Почему закрепление – отдельное условие: ответ появляется под отзывом **от имени организации**, а не от имени Rewio. Добавить чужую карточку в свои объекты может кто угодно – это штатная возможность, по ней работает аналитика конкурентов. Поэтому право отвечать мы подтверждаем отдельно от того, что объект заведён. Клиентам, которые отвечают **своей** учётной записью площадки, закрепление не нужно: площадка пустит их только туда, куда у этой учётной записи есть права. ## Где это работает [#platforms] Сейчас на четырёх площадках: | Площадка | Опубликовать | Заменить текст | Удалить | | ------------ | ------------ | -------------- | ------- | | Яндекс.Карты | да | да | да | | Google | да | да | да | | 2ГИС | да | да\* | да | | ПроДокторов | да | **нет** | **нет** | \* В 2ГИС площадка не разрешает переписывать опубликованный ответ. Поэтому при замене мы сами снимаем стоящий ответ и ставим на его место новый – для вас это тот же [`PUT`](/replies/publish). На ПроДокторов ответ публикует клиника, и площадка не даёт ни переписать, ни удалить опубликованный ответ (`reply_edit_not_supported` / `reply_delete_not_supported`). Ответ проходит модерацию площадки, поэтому появляется под отзывом не мгновенно. ## На какие отзывы можно отвечать [#replyable] Площадки показывают в своей ленте не только собственные отзывы, но и отзывы других площадок: 2ГИС – отзывы Booking, Т-Банка, Flamp; Google – отзывы Tripadvisor. Ответить на такой отзыв через кабинет площадки, которая его лишь отображает, нельзя. Источник самого отзыва виден в поле **`provider`** (слаг в нижнем регистре) у каждого отзыва в [`GET /reviews`](/reviews/list). Ответ пройдёт, только если **`provider` совпадает с `source_slug`** этого же отзыва (слаг площадки, с которой он собран, – отдаётся рядом с `source_id`). У нативного отзыва так и есть. На отзыв, чей `provider` иной (`tbank`, `booking`, `tripadvisor`, …), [`PUT`](/replies/publish) сразу вернёт `409` с кодом `reply_not_replyable`. Какие провайдеры вообще встречаются у площадки – в поле `providers` [списка площадок](/sources/list). ## Как подключить площадки [#connect] Возможность отвечать выдаётся на стороне площадки: владелец организации добавляет нашу учётную запись в свой кабинет. Ниже – инструкции по подключению. Организация должна быть зарегистрирована в [Яндекс Бизнесе](https://business.yandex.ru/), доступ выдаёт её владелец. **1. Откройте «Доступы»** – раздел в левом меню кабинета. **2. Добавьте `review.answer@ya.ru` или свою почту с ролью «Представитель».**\ В случае собственной почты необходимо сообщить нам данные для входа.\ Рекомендуем завести для этого отдельную учётную запись. Яндекс Бизнес – раздел «Доступы» и карточка добавления представителя Организация должна быть подтверждена в [Google Бизнес-профиле](https://business.google.com/), доступ выдаёт её владелец ([инструкция Google](https://support.google.com/business/community-guide/389329805/)). **1. Откройте настройки профиля.** В карточке компании нажмите на меню «⋮» и выберите «Настройки профиля компании». Google Бизнес-профиль – меню и пункт «Настройки профиля компании» **2. Перейдите в «Пользователи и доступ» и нажмите «Добавить».** Google Бизнес-профиль – раздел «Пользователи и доступ» и кнопка «Добавить» **3. Добавьте `review.answer@ya.ru` или свою почту с ролью «Менеджер», затем «Пригласить».**\ В случае собственной почты необходимо сообщить нам данные для входа.\ Рекомендуем завести для этого отдельную учётную запись. Google Бизнес-профиль – ввод почты и выбор роли «Менеджер» Карточка организации должна быть подтверждена в [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). Первый вызов публикует, повторный с новым текстом – заменяет. Повтор с тем же текстом ничего не ломает: это не дубль и не ошибка. [`PUT`](/replies/publish) и [`DELETE`](/replies/delete) работают с любым ответом организации на отзыве: и с вашим, и с поставленным не через Rewio – например, в кабинете площадки до подключения. Такой ответ виден как `reply_text` отзыва; заменить или удалить его можно теми же методами. ## Лента ответов [#feed] Кабинет строит раздел «Ответы» из того же [`GET /reviews`](/reviews/list), и вы можете собрать такую же ленту у себя: * `replyable=true` – только отзывы, на которые можно ответить через Rewio; * `reply_state` делит их на вкладки: `unanswered` – без ответа, `waiting` – ваш ответ ждёт публикации, `answered` – отвечено (вашим ответом или поставленным не через Rewio), `skipped` – пропущенные. У каждого отзыва в ленте – `our_reply` (ваш ответ через Rewio и его состояние), `is_skipped` и `complaint` (последняя жалоба). Отзыв, на который отвечать не будете, отметьте [«Пропустить»](/replies/skip); вернуть его – [`DELETE`](/replies/unskip). На тарифе без ответов `waiting` и `skipped` всегда пусты, `our_reply` и `complaint` – `null`. ## Что происходит с ответом [#status] Состояние ответа – `status` в [`GET /reply`](/replies/get). Оно говорит, что стоит **на карточке**: | `status` | Что значит | | ----------- | ------------------------------------------------------------------------------- | | `null` | Мы приняли текст, площадке ещё не передали. | | `pending` | Площадка приняла ответ, на карточке мы его ещё не видели. | | `published` | Ваш текст стоит на карточке. | | `deleted` | Вашего ответа на карточке нет: вы его сняли, или он пропал (причина в `error`). | | `failed` | Ответ не опубликован (причина в `error`). | `PUT` и `DELETE` возвращают состояние на момент приёма, а это всегда `null`: новый текст начинает путь заново, даже если предыдущий ответ уже стоял на площадке. Что было дальше, показывает [`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", "submitted_at": "2026-10-14T15:12:01", # "published_at": "2026-10-14T15:12:40", "error": null, … } ``` `submitted_at` – когда вы отправили этот текст, `published_at` – когда мы увидели его на карточке. Метод читает нашу запись и на площадку не ходит, поэтому опрашивать её можно сколько нужно. Чтение доступно и ключу на чтение и не зависит от тарифа. ## Как мы узнаём, что ответ на карточке [#confirm] Когда площадка приняла ответ, мы проверяем этот отзыв на площадке через 15 и 30 секунд, через 1, 2, 3, 5, 15 и 30 минут, через 1, 2 и 4 часа. Как только видим ваш текст, ставим `published`; обычно это первые минуты. Если за 4 часа текст так и не появился – `failed` с кодом `not_visible`. Так читаются Яндекс.Карты, 2ГИС и Google. На других площадках (ПроДокторов и прочие) отдельный отзыв так не прочитать, и ответ подтверждает сбор карточки; если за сутки сбор нашего текста не нашёл – тоже `failed` с `not_visible`. Сбор площадки меняет статус так же: нашёл ваш текст – `published`, даже если перед этим было `failed`. Если сбор под опубликованным ответом текста больше не видит, мы перечитываем отзыв, и если ответа действительно нет – `deleted` с причиной: | Код в `error` | Что случилось | | ---------------- | -------------------------------------------- | | `review_deleted` | Отзыва больше нет на площадке. | | `reply_missing` | Отзыв на месте, а ответа под ним нет. | | `reply_replaced` | Под отзывом теперь другой ответ организации. | Поля `reply_text` и `reply_date` самого отзыва в [`GET /reviews`](/reviews/list) по-прежнему заполняет сбор, поэтому `status: published` может прийти раньше, чем ваш текст появится в `reply_text`. Если настроены [вебхуки](/guides/webhooks), о появлении ответа в отзыве приходит `replies.new`. `reply_date` – это дата ответа, **как её показывает площадка** на момент последнего сбора, а не время вашего запроса. Площадки часто сохраняют исходную дату при перепубликации или редактировании ответа, поэтому опираться на `reply_date` как на «время последней публикации» нельзя – для этого есть `published_at` в [`GET /reply`](/replies/get): когда мы увидели ваш текст на карточке. ## Если что-то пошло не так [#errors] Отказы, которые видны сразу, приходят в ответе на запрос: тариф без ответов, площадка не поддерживает ответы, отзыв не нативен для площадки (`reply_not_replyable`), место под ответ занято другим аккаунтом, текст не прошёл проверку, доступ отозван. Каждый – со своим кодом, все они на странице [Ошибки](/errors). Дальше, при самой публикации, мешать может временное: наш доступ к площадке обновляется, площадка просит подождать, сорвалась сеть. В таких случаях мы автоматически повторяем запрос, а результат виден в [состоянии ответа](/replies/get) (`status: failed` и код в `error`). Если площадка приняла запрос, но ответ на карточке так и не появился, код – `not_visible`; если площадка приняла удаление, но ответ остался на карточке, – `not_taken_down`. Если ответ не появился, напишите на . # Как читать отзывы (/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` (`review_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` | Когда отзыв опубликован на площадке. | UTC, где это возможно; иначе – как на площадке | `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` повтор возможен после смены состава объекта (см. «Границы»), поэтому UPSERT по `id` надёжнее и здесь. Потерять отзыв поток не может ни в одном из режимов. **4. `next_cursor` приходит всегда** – и на последней странице, и на пустой. Признак «догнал» – это `has_next: false`, а не отсутствие курсора. ## Что приходит [#payload] Изменением считается: правка текста или оценки на площадке, появившийся или изменившийся ответ организации, изменившийся набор фотографий, пропажа отзыва с площадки (`is_deleted: true`) и его возврат. Пересбор сам по себе – не изменение: если на площадке ничего не поменялось, отзыв в поток не попадёт. | `mode` | Что приходит | Как класть к себе | | -------------------- | -------------------------- | --------------------------------------------------------------- | | `all` (по умолчанию) | новые отзывы и изменения | **UPSERT** по `id` | | `new` | только впервые появившиеся | **UPSERT** по `id`: повтор возможен после смены состава объекта | Режим зашит в курсор: для второго режима нужен отдельный курсор. Отдельного режима «только изменения» нет: после первого полного прохода режим `all` отдаёт только то, что появилось или изменилось с прошлого запроса. ## Границы [#limits] * **Порядок задан режимом, и своего параметра сортировки у метода нет.** В `all` строки идут по времени последнего изменения отзыва, в `new` – по времени, когда мы его впервые захватили. Дата публикации на площадке (`review_date`) порядок не задаёт ни там, ни там: отзыв 2019 года, у которого вчера появился ответ, придёт в `all` вместе со вчерашними изменениями, а не в хвосте истории. Нужен свой порядок – стройте его у себя. * **Фильтров нет.** Отзыв, который правкой перестал подходить под фильтр, пришлось бы присылать событием «выбыл» – такого события не существует, поэтому любой фильтр сделал бы поток дырявым. Отбирайте у себя. * **Состав объекта поток не отслеживает.** Убрали ссылку или выключили объект – его отзывы просто перестанут приходить, отдельного события об этом не будет. Чистите у себя по `link_id`. Любая смена состава – ссылку убрали, добавили или вернули, оплатили тариф после пробного периода – сбрасывает сохранённый курсор: поток проходит объект заново с начала истории. Уже полученные отзывы придут ещё раз, upsert по `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` | один POST раз в сутки в указанный час; `HOUR` = 0–23, время в UTC. Напр. `daily_9` = 09:00 UTC, `daily_0` = полночь 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` – тело превысило 50 КБ, и списки отзывов убраны (`objects[].reviews` нет; `summary`, `object_id`, `name` и `review_count` остаются). Отзывы целиком получите через [`GET /v3/reviews`](/reviews/list). Форма тела зависит от версии API, через которую создана подписка. Вебхук, созданный через `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` в пределах 10 секунд (таймаут доставки). Тяжёлую работу выносите в фон. ### Что вернуть в ответе [#response] Подтверждение получения – это сам HTTP-статус: любой `2xx` означает «принято, больше не пересылать». Тело ответа не разбирается. Тело может быть любым, например: ``` 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` там нет. Поэтому лента по папке из одного объекта может вернуть **больше** отзывов, чем лента по этому же объекту – ровно на число закреплённых. # Добавить ссылки (/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) – Итог по каждой переданной ссылке, в том же порядке. `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` (дата и время, обязательный) – Когда ссылка добавлена в объект. - `is_demo` (да/нет, по умолчанию нет) – Пример, который мы положили в кабинет при регистрации. Место в тарифе не занимает; исчезает с первым своим объектом или первой оплатой, удалить можно как обычный объект. - `review_count` (число, может быть null) – Сколько отзывов объекта доступно вам сейчас: по включённым ссылкам, без удалённых на площадке, в пробном периоде – в пределах его окна. Скрытые и закреплённые через API здесь не вычитаются, поэтому `total` у `GET /v3/reviews?object_id=…` может быть меньше на их число. Есть в списке объектов и в `GET /v3/objects/{object_id}`; в ответах на изменение – `null`. ### Пример ответа ```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` (дата и время, обязательный) – Когда ссылка добавлена в объект. - `data[].is_demo` (да/нет, по умолчанию нет) – Пример, который мы положили в кабинет при регистрации. Место в тарифе не занимает; исчезает с первым своим объектом или первой оплатой, удалить можно как обычный объект. - `data[].review_count` (число, может быть null) – Сколько отзывов объекта доступно вам сейчас: по включённым ссылкам, без удалённых на площадке, в пробном периоде – в пределах его окна. Скрытые и закреплённые через API здесь не вычитаются, поэтому `total` у `GET /v3/reviews?object_id=…` может быть меньше на их число. Есть в списке объектов и в `GET /v3/objects/{object_id}`; в ответах на изменение – `null`. - `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` (дата и время, обязательный) – Когда ссылка добавлена в объект. - `data[].is_demo` (да/нет, по умолчанию нет) – Пример, который мы положили в кабинет при регистрации. Место в тарифе не занимает; исчезает с первым своим объектом или первой оплатой, удалить можно как обычный объект. - `data[].review_count` (число, может быть null) – Сколько отзывов объекта доступно вам сейчас: по включённым ссылкам, без удалённых на площадке, в пробном периоде – в пределах его окна. Скрытые и закреплённые через API здесь не вычитаются, поэтому `total` у `GET /v3/reviews?object_id=…` может быть меньше на их число. Есть в списке объектов и в `GET /v3/objects/{object_id}`; в ответах на изменение – `null`. ### Пример ответа ```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` (дата и время, обязательный) – Когда ссылка добавлена в объект. - `is_demo` (да/нет, по умолчанию нет) – Пример, который мы положили в кабинет при регистрации. Место в тарифе не занимает; исчезает с первым своим объектом или первой оплатой, удалить можно как обычный объект. - `review_count` (число, может быть null) – Сколько отзывов объекта доступно вам сейчас: по включённым ссылкам, без удалённых на площадке, в пробном периоде – в пределах его окна. Скрытые и закреплённые через API здесь не вычитаются, поэтому `total` у `GET /v3/reviews?object_id=…` может быть меньше на их число. Есть в списке объектов и в `GET /v3/objects/{object_id}`; в ответах на изменение – `null`. ### Пример ответа ```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). # Состояние сбора по папке (/refresh/folder-state) Состояние дополнительного сбора по каждому объекту папки и её подпапок – поля те же, что у [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state). ## GET https://api.rewio.ru/v3/folders/{folder_id}/refresh Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, path, обязательный) – Папка, состояние объектов которой нужно. ### Ответ 200 - `data` (список объектов, обязательный) – Все элементы (пагинации нет). - `data[].object_id` (число, обязательный) – Объект. - `data[].is_allowed` (да/нет, обязательный) – Запустит ли `POST` сбор прямо сейчас. - `data[].code` (строка, может быть null) – Почему нельзя – тот же код, что вернёт `POST`: `refresh_requires_upgrade`, `refresh_trial_exhausted`, `refresh_in_progress`, `refresh_limited`, `refresh_nothing_to_scrape`. `null`, если можно. - `data[].mode` (строка, может быть null) – Что сделает `POST`: `full` – соберёт все включённые ссылки объекта, `retry` – только не собравшиеся в эти сутки. `null`, если нельзя. - `data[].is_running` (да/нет, обязательный) – Идёт ли дополнительный сбор. - `data[].is_retried` (да/нет, обязательный) – Повтор этих суток уже использован. - `data[].refreshed_at` (дата и время, может быть null) – Начало текущих суток объекта – последний сбор всех ссылок, UTC. - `data[].next_available_at` (дата и время, может быть null) – Когда снова будет доступен сбор всех ссылок, UTC. `null` – уже доступен. - `data[].retry_link_ids` (список чисел) – Ссылки, не собравшиеся в эти сутки, которым положен один повтор. - `data[].trial_left` (число, может быть null) – Сколько дополнительных сборов осталось в пробном периоде (всего 5). `null` – не пробный период. - `data[].links` (список объектов) – Итог дополнительных сборов этих суток по ссылкам; повтор перекрывает первый сбор по своим ссылкам. Пусто вне суток объекта. - `data[].links[].link_id` (число, обязательный) – Ссылка объекта. - `data[].links[].status` (строка, обязательный) – `running` – собирается, `success` – собрана, `failed` – не собралась. ### Пример ответа ```json { "data": [ { "object_id": 20, "is_allowed": true, "code": null, "mode": "retry", "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [ 178 ], "trial_left": null, "links": [ { "link_id": 177, "status": "success" }, { "link_id": 178, "status": "failed" }, { "link_id": 179, "status": "success" } ] }, { "object_id": 21, "is_allowed": false, "code": "refresh_limited", "mode": null, "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T09:12:00", "next_available_at": "2026-10-30T09:11:00", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 184, "status": "success" }, { "link_id": 185, "status": "success" } ] }, { "object_id": 22, "is_allowed": true, "code": null, "mode": "full", "is_running": false, "is_retried": false, "refreshed_at": null, "next_available_at": null, "retry_link_ids": [], "trial_left": null, "links": [] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Дополнительный сбор по папке (/refresh/folder) Сбор по папке собирает отзывы всех вложенных объектов, включая подпапки, – каждого по [правилам дополнительного сбора](/refresh/rules). Запускается всё, что можно прямо сейчас: первый сбор за сутки или повтор для площадок, где не получилось. Остальные объекты пропускаются без ошибки. В пробном периоде каждый запущенный объект тратит один из 5 дополнительных сборов. Если осталось меньше, чем объектов в папке, соберутся первые по порядку `object_id`. Ответ `202` – состояние каждого объекта папки и `started_object_ids`, объекты, по которым сбор запущен этим запросом. ## POST https://api.rewio.ru/v3/folders/{folder_id}/refresh Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `folder_id` (число, path, обязательный) – Папка, по объектам которой нужно собрать отзывы. ### Ответ 202 - `data` (список объектов, обязательный) – Состояние каждого объекта папки и её подпапок. - `data[].object_id` (число, обязательный) – Объект. - `data[].is_allowed` (да/нет, обязательный) – Запустит ли `POST` сбор прямо сейчас. - `data[].code` (строка, может быть null) – Почему нельзя – тот же код, что вернёт `POST`: `refresh_requires_upgrade`, `refresh_trial_exhausted`, `refresh_in_progress`, `refresh_limited`, `refresh_nothing_to_scrape`. `null`, если можно. - `data[].mode` (строка, может быть null) – Что сделает `POST`: `full` – соберёт все включённые ссылки объекта, `retry` – только не собравшиеся в эти сутки. `null`, если нельзя. - `data[].is_running` (да/нет, обязательный) – Идёт ли дополнительный сбор. - `data[].is_retried` (да/нет, обязательный) – Повтор этих суток уже использован. - `data[].refreshed_at` (дата и время, может быть null) – Начало текущих суток объекта – последний сбор всех ссылок, UTC. - `data[].next_available_at` (дата и время, может быть null) – Когда снова будет доступен сбор всех ссылок, UTC. `null` – уже доступен. - `data[].retry_link_ids` (список чисел) – Ссылки, не собравшиеся в эти сутки, которым положен один повтор. - `data[].trial_left` (число, может быть null) – Сколько дополнительных сборов осталось в пробном периоде (всего 5). `null` – не пробный период. - `data[].links` (список объектов) – Итог дополнительных сборов этих суток по ссылкам; повтор перекрывает первый сбор по своим ссылкам. Пусто вне суток объекта. - `data[].links[].link_id` (число, обязательный) – Ссылка объекта. - `data[].links[].status` (строка, обязательный) – `running` – собирается, `success` – собрана, `failed` – не собралась. - `started_object_ids` (список чисел, обязательный) – Объекты, по которым сбор запущен этим запросом. ### Пример ответа ```json { "data": [ { "object_id": 20, "is_allowed": false, "code": "refresh_in_progress", "mode": null, "is_running": true, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 177, "status": "running" }, { "link_id": 178, "status": "running" }, { "link_id": 179, "status": "running" } ] }, { "object_id": 21, "is_allowed": false, "code": "refresh_limited", "mode": null, "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T09:12:00", "next_available_at": "2026-10-30T09:11:00", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 184, "status": "success" }, { "link_id": 185, "status": "success" } ] }, { "object_id": 22, "is_allowed": false, "code": "refresh_in_progress", "mode": null, "is_running": true, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 190, "status": "running" } ] } ], "started_object_ids": [ 20, 22 ] } ``` Если не запущен ни один объект, приходит отказ с причиной, как у объекта: `402 refresh_requires_upgrade`, `402 refresh_trial_exhausted`, `409 refresh_in_progress`, `409 refresh_nothing_to_scrape`, `429 refresh_limited`. Остальные коды общие для всего API и описаны на странице [Ошибки](/errors). # Состояние сбора по всем объектам (/refresh/list) Состояние дополнительного сбора по каждому объекту аккаунта одним запросом – поля те же, что у [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state). Пагинации нет. ## GET https://api.rewio.ru/v3/objects/refresh Заголовок `X-API-Key` обязателен в каждом запросе. ### Ответ 200 - `data` (список объектов, обязательный) – Все элементы (пагинации нет). - `data[].object_id` (число, обязательный) – Объект. - `data[].is_allowed` (да/нет, обязательный) – Запустит ли `POST` сбор прямо сейчас. - `data[].code` (строка, может быть null) – Почему нельзя – тот же код, что вернёт `POST`: `refresh_requires_upgrade`, `refresh_trial_exhausted`, `refresh_in_progress`, `refresh_limited`, `refresh_nothing_to_scrape`. `null`, если можно. - `data[].mode` (строка, может быть null) – Что сделает `POST`: `full` – соберёт все включённые ссылки объекта, `retry` – только не собравшиеся в эти сутки. `null`, если нельзя. - `data[].is_running` (да/нет, обязательный) – Идёт ли дополнительный сбор. - `data[].is_retried` (да/нет, обязательный) – Повтор этих суток уже использован. - `data[].refreshed_at` (дата и время, может быть null) – Начало текущих суток объекта – последний сбор всех ссылок, UTC. - `data[].next_available_at` (дата и время, может быть null) – Когда снова будет доступен сбор всех ссылок, UTC. `null` – уже доступен. - `data[].retry_link_ids` (список чисел) – Ссылки, не собравшиеся в эти сутки, которым положен один повтор. - `data[].trial_left` (число, может быть null) – Сколько дополнительных сборов осталось в пробном периоде (всего 5). `null` – не пробный период. - `data[].links` (список объектов) – Итог дополнительных сборов этих суток по ссылкам; повтор перекрывает первый сбор по своим ссылкам. Пусто вне суток объекта. - `data[].links[].link_id` (число, обязательный) – Ссылка объекта. - `data[].links[].status` (строка, обязательный) – `running` – собирается, `success` – собрана, `failed` – не собралась. ### Пример ответа ```json { "data": [ { "object_id": 20, "is_allowed": true, "code": null, "mode": "retry", "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [ 178 ], "trial_left": null, "links": [ { "link_id": 177, "status": "success" }, { "link_id": 178, "status": "failed" }, { "link_id": 179, "status": "success" } ] }, { "object_id": 21, "is_allowed": false, "code": "refresh_limited", "mode": null, "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T09:12:00", "next_available_at": "2026-10-30T09:11:00", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 184, "status": "success" }, { "link_id": 185, "status": "success" } ] }, { "object_id": 22, "is_allowed": true, "code": null, "mode": "full", "is_running": false, "is_retried": false, "refreshed_at": null, "next_available_at": null, "retry_link_ids": [], "trial_left": null, "links": [] } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Состояние сбора по объекту (/refresh/object-state) Отвечает, что сделает [`POST`](/refresh/object) прямо сейчас, и показывает итог дополнительных сборов этих суток по каждой площадке. Пока идёт сбор, `is_running` – `true`, а площадки в `links` переходят из `running` в `success` или `failed`. ## GET https://api.rewio.ru/v3/objects/{object_id}/refresh Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, состояние которого нужно. ### Ответ 200 - `object_id` (число, обязательный) – Объект. - `is_allowed` (да/нет, обязательный) – Запустит ли `POST` сбор прямо сейчас. - `code` (строка, может быть null) – Почему нельзя – тот же код, что вернёт `POST`: `refresh_requires_upgrade`, `refresh_trial_exhausted`, `refresh_in_progress`, `refresh_limited`, `refresh_nothing_to_scrape`. `null`, если можно. - `mode` (строка, может быть null) – Что сделает `POST`: `full` – соберёт все включённые ссылки объекта, `retry` – только не собравшиеся в эти сутки. `null`, если нельзя. - `is_running` (да/нет, обязательный) – Идёт ли дополнительный сбор. - `is_retried` (да/нет, обязательный) – Повтор этих суток уже использован. - `refreshed_at` (дата и время, может быть null) – Начало текущих суток объекта – последний сбор всех ссылок, UTC. - `next_available_at` (дата и время, может быть null) – Когда снова будет доступен сбор всех ссылок, UTC. `null` – уже доступен. - `retry_link_ids` (список чисел) – Ссылки, не собравшиеся в эти сутки, которым положен один повтор. - `trial_left` (число, может быть null) – Сколько дополнительных сборов осталось в пробном периоде (всего 5). `null` – не пробный период. - `links` (список объектов) – Итог дополнительных сборов этих суток по ссылкам; повтор перекрывает первый сбор по своим ссылкам. Пусто вне суток объекта. - `links[].link_id` (число, обязательный) – Ссылка объекта. - `links[].status` (строка, обязательный) – `running` – собирается, `success` – собрана, `failed` – не собралась. ### Пример ответа ```json { "object_id": 20, "is_allowed": true, "code": null, "mode": "retry", "is_running": false, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [ 178 ], "trial_left": null, "links": [ { "link_id": 177, "status": "success" }, { "link_id": 178, "status": "failed" }, { "link_id": 179, "status": "success" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Дополнительный сбор по объекту (/refresh/object) Собирает новые отзывы со всех площадок объекта вне очереди. Ответ `202` приходит сразу, сбор идёт в фоне – обычно несколько минут. Если в эти сутки с части площадок собрать не получилось, этот же вызов соберёт ещё раз только с них (`mode: retry`) – один раз. Правила целиком – на странице [«Как работает дополнительный сбор отзывов»](/refresh/rules). ## POST https://api.rewio.ru/v3/objects/{object_id}/refresh Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `object_id` (число, path, обязательный) – Объект, по которому нужно собрать отзывы. ### Ответ 202 - `object_id` (число, обязательный) – Объект. - `is_allowed` (да/нет, обязательный) – Запустит ли `POST` сбор прямо сейчас. - `code` (строка, может быть null) – Почему нельзя – тот же код, что вернёт `POST`: `refresh_requires_upgrade`, `refresh_trial_exhausted`, `refresh_in_progress`, `refresh_limited`, `refresh_nothing_to_scrape`. `null`, если можно. - `mode` (строка, может быть null) – Что сделает `POST`: `full` – соберёт все включённые ссылки объекта, `retry` – только не собравшиеся в эти сутки. `null`, если нельзя. - `is_running` (да/нет, обязательный) – Идёт ли дополнительный сбор. - `is_retried` (да/нет, обязательный) – Повтор этих суток уже использован. - `refreshed_at` (дата и время, может быть null) – Начало текущих суток объекта – последний сбор всех ссылок, UTC. - `next_available_at` (дата и время, может быть null) – Когда снова будет доступен сбор всех ссылок, UTC. `null` – уже доступен. - `retry_link_ids` (список чисел) – Ссылки, не собравшиеся в эти сутки, которым положен один повтор. - `trial_left` (число, может быть null) – Сколько дополнительных сборов осталось в пробном периоде (всего 5). `null` – не пробный период. - `links` (список объектов) – Итог дополнительных сборов этих суток по ссылкам; повтор перекрывает первый сбор по своим ссылкам. Пусто вне суток объекта. - `links[].link_id` (число, обязательный) – Ссылка объекта. - `links[].status` (строка, обязательный) – `running` – собирается, `success` – собрана, `failed` – не собралась. ### Пример ответа ```json { "object_id": 20, "is_allowed": false, "code": "refresh_in_progress", "mode": null, "is_running": true, "is_retried": false, "refreshed_at": "2026-10-29T15:35:36", "next_available_at": "2026-10-30T15:34:36", "retry_link_ids": [], "trial_left": null, "links": [ { "link_id": 177, "status": "running" }, { "link_id": 178, "status": "running" }, { "link_id": 179, "status": "running" } ] } ``` Отказы: `402 refresh_requires_upgrade`, `402 refresh_trial_exhausted`, `409 refresh_in_progress`, `409 refresh_nothing_to_scrape`, `429 refresh_limited` с заголовком `Retry-After`. Остальные коды общие для всего API и описаны на странице [Ошибки](/errors). # Как работает дополнительный сбор отзывов (/refresh/rules) Новые отзывы мы собираем сами, по расписанию. Если свежие отзывы нужны сразу, по объекту можно запустить дополнительный сбор: [`POST /v3/objects/{object_id}/refresh`](/refresh/object) соберёт новые отзывы со всех площадок объекта вне очереди. ```bash curl -X POST "https://api.rewio.ru/v3/objects/20/refresh" \ -H "X-API-Key: hrev_ВАШ_КЛЮЧ" ``` Ответ `202` приходит сразу, сбор идёт в фоне – обычно несколько минут. Новые отзывы появляются в [`GET /v3/reviews`](/reviews/list) по мере того, как собирается каждая площадка. Ход и итог – в [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state). Дополнительный сбор, как и сбор по расписанию, забирает только новое: отзывы, появившиеся после последнего собранного. ## Правила [#rules] | Правило | Как работает | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Раз в сутки на объект | Следующий дополнительный сбор по объекту – через 23 ч 59 мин после предыдущего, время в `next_available_at`. У каждого объекта свои сутки. | | Один повтор | Если с части площадок собрать не получилось, в те же сутки можно собрать ещё раз – следующий `POST` возьмёт только их (`mode: retry`). Площадка, с которой не получилось и при повторе, ждёт следующих суток. | | Тариф | На тарифе «Полный» дополнительный сбор доступен раз в сутки для каждого объекта. На других тарифах – `402 refresh_requires_upgrade`. | | Пробный период | 5 дополнительных сборов на аккаунт за весь пробный период, по любым объектам. Повтор для площадок, где не получилось, в счёт не идёт. | | Папка | [`POST /v3/folders/{folder_id}/refresh`](/refresh/folder): сбор по папке собирает отзывы всех вложенных объектов, включая подпапки, – каждого по тем же правилам. | ## Состояние объекта [#state] [`GET /v3/objects/{object_id}/refresh`](/refresh/object-state) отвечает, что сделает `POST` прямо сейчас: | `is_allowed` | `mode` / `code` | Что это значит | | ------------ | --------------------------- | ----------------------------------------------------------------------------------------------- | | `true` | `mode: full` | Можно запустить сбор: соберутся все площадки объекта. | | `true` | `mode: retry` | С части площадок собрать не получилось – можно собрать ещё раз только с них (`retry_link_ids`). | | `false` | `refresh_in_progress` | Сбор идёт. Итог по площадкам – в `links`. | | `false` | `refresh_limited` | Дополнительный сбор по объекту уже был в эти сутки. Когда снова – `next_available_at`. | | `false` | `refresh_requires_upgrade` | Дополнительный сбор не входит в тариф. | | `false` | `refresh_trial_exhausted` | Дополнительные сборы пробного периода закончились. | | `false` | `refresh_nothing_to_scrape` | У объекта нет ссылок, которые можно собрать. | `links` – итог дополнительных сборов этих суток по каждой площадке: `running` (собирается), `success` (собрано) или `failed` (не удалось собрать). Повтор перекрывает первый сбор по своим площадкам. Состояние всех объектов сразу – [`GET /v3/objects/refresh`](/refresh/list). ## Отказы [#errors] `POST` отвечает тем же кодом, что показан в `code` состояния: | Статус | `code` | Когда | | ------ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `402` | `refresh_requires_upgrade` | Дополнительный сбор входит в тариф «Полный». | | `402` | `refresh_trial_exhausted` | Все 5 дополнительных сборов пробного периода использованы. | | `409` | `refresh_in_progress` | Сбор по объекту уже идёт. | | `409` | `refresh_nothing_to_scrape` | У объекта нет ссылок, которые можно собрать. | | `429` | `refresh_limited` | Дополнительный сбор по объекту был меньше суток назад, собирать ещё раз нечего. Заголовок `Retry-After` – секунд до `next_available_at`. | # Удалить ответ (/replies/delete) Удаляет ответ организации с площадки – ваш или поставленный не через Rewio (он виден как `reply_text` [отзыва](/reviews/list)). Удаление асинхронное, как и публикация: `202` означает, что мы приняли задачу. Когда площадка её выполнит, статус ответа станет `deleted` – смотрите [состояние ответа](/replies/get). Удалять умеют не все площадки. Там, где ответ удалить нельзя, приходит `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` (строка, может быть null, pending / published / failed / deleted) – В ответе на этот запрос всегда `null`: текст принят, площадке ещё не передан. Дальше статус меняется на `pending` (площадка приняла), `published` (ваш текст на карточке), `deleted` или `failed` – смотрите [состояние ответа](/replies/get). - `updated_at` (дата и время, обязательный) – Когда мы приняли задачу. ### Пример ответа ```json { "text": "", "status": null, "updated_at": "2026-08-16T10:20:41" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). Отказы, свойственные именно ответам, собраны там в отдельной таблице. # Состояние ответа (/replies/get) Показывает, что с **вашим** ответом на карточке. После того как площадка приняла ответ, мы проверяем отзыв на площадке через 15 и 30 секунд, 1, 2, 3, 5, 15 и 30 минут, 1, 2 и 4 часа – и ставим `published`, как только видим ваш текст. Не увидели за 4 часа – `failed` с кодом `not_visible`. Сбор площадки обновляет статус так же. Подробно – в [руководстве по ответам](/guides/replies#confirm). Метод читает нашу запись и на площадку не ходит: опрашивать его можно сколько нужно. Ответ, который стоит на карточке, но опубликован не через нас, здесь не виден: его показывают поля `reply_text` и `reply_date` самого [отзыва](/reviews/list). Заменить или удалить его можно [`PUT`](/replies/publish) и [`DELETE`](/replies/delete). Чтение доступно ключу со скоупом `read_only` и не зависит от тарифа. Если ответа через нас на этом отзыве не было, метод отвечает `404` с кодом `reply_not_found`. ## GET https://api.rewio.ru/v3/reviews/{review_id}/reply Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, ответ на который вы отправляли. ### Ответ 200 - `status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели; `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет (сняли или пропал, причина в `error`); `failed` – не опубликован. - `submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст. - `published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке. `null`, пока не видели. - `error` (объект, может быть null) – Почему ответ не опубликован или пропал: `{code, message}` – `not_visible`, `not_taken_down`, `review_deleted`, `reply_missing`, `reply_replaced` или код отказа площадки. `null`, если причины нет. - `error.code` (строка, обязательный) – Машинный код ошибки публикации. - `error.message` (строка, по умолчанию «») – Пояснение для человека. - `updated_at` (дата и время, обязательный) – Когда запись об ответе менялась в последний раз. ### Пример ответа ```json { "status": "published", "submitted_at": "2026-10-14T15:12:01", "published_at": "2026-10-14T15:12:40", "error": null, "updated_at": "2026-10-14T15:12:40" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Опубликовать ответ (/replies/publish) Публикует ваш ответ под отзывом на самой площадке или заменяет уже стоящий. Ответ на отзыв ровно один, поэтому повторный запрос с тем же текстом – не дубль и не ошибка. Заменить можно любой стоящий ответ организации, в том числе поставленный не через Rewio. В 2ГИС, где площадка не даёт переписать ответ, мы снимаем стоящий и ставим новый. Нужен ключ со скоупом `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` (строка, может быть null, pending / published / failed / deleted) – В ответе на этот запрос всегда `null`: текст принят, площадке ещё не передан. Дальше статус меняется на `pending` (площадка приняла), `published` (ваш текст на карточке), `deleted` или `failed` – смотрите [состояние ответа](/replies/get). - `updated_at` (дата и время, обязательный) – Когда мы приняли задачу. ### Пример ответа ```json { "text": "Спасибо за отзыв! Рады, что всё понравилось — ждём вас снова.", "status": null, "updated_at": "2026-08-16T10:12:03" } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). Отказы, свойственные именно ответам, собраны там в отдельной таблице. # Пропустить отзыв (/replies/skip) Отмечает, что отвечать на отзыв вы не будете. Отзыв уходит из выборки `reply_state=unanswered` в `reply_state=skipped` [ленты отзывов](/reviews/list) и получает `is_skipped: true`. На площадку запрос не ходит: это ваша пометка в Rewio. `204` – отметка поставлена; `200` с телом `{"is_skipped": true}` – она уже стояла. Повтор не ошибка. Снять отметку – [`DELETE`](/replies/unskip). Нужен ключ со скоупом `full` и тариф с ответами («Полный» или пробный период). На тарифе без ответов приходит `402` с кодом `reply_requires_upgrade`. ## PUT https://api.rewio.ru/v3/reviews/{review_id}/skip Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, который вы пропускаете. ### Ответ 200 Тело ответа пустое. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Вернуть пропущенный отзыв (/replies/unskip) Снимает отметку [«Пропустить»](/replies/skip): отзыв возвращается в выборку `reply_state=unanswered` [ленты отзывов](/reviews/list), `is_skipped` становится `false`. Отметки не было – тоже `204`. Нужен ключ со скоупом `full` и тариф с ответами, иначе `402` с кодом `reply_requires_upgrade`. ## DELETE https://api.rewio.ru/v3/reviews/{review_id}/skip Заголовок `X-API-Key` обязателен в каждом запросе. ### Параметры - `review_id` (число, path, обязательный) – Отзыв, с которого снимается отметка. ### Ответ 204 Тело ответа пустое. Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Получить отзыв по 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` (число, обязательный) – Площадка, с которой собран отзыв. - `source_slug` (строка, может быть null) – Слаг площадки (`2gis`, `google`, `yandex_maps`). Отвечать можно, если совпадает с `provider` отзыва. - `author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `text` (строка, может быть null) – Текст отзыва. - `review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `reply_text` (строка, может быть null) – Ответ организации на отзыв. - `reply_date` (дата и время, может быть null) – Когда организация ответила. - `provider` (строка, может быть null) – Площадка, на которой отзыв написан изначально (слаг в нижнем регистре: `2gis`, `google`, `tbank`, `booking`, `tripadvisor`, …). У нативного отзыва совпадает с `source_slug` – только на такой отзыв можно опубликовать ответ. - `is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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) – Блок «недостатки». - `our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. ### Пример ответа ```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": [], "source_slug": "yandex_maps", "is_replyable": true, "our_reply": null, "is_skipped": false, "complaint": null } ``` ## Чего в ответе не будет [#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` обязателен в каждом запросе. ### Параметры - `replyable` (да/нет, query, может быть null) – `true` – только отзывы, на которые можно ответить через Rewio (`is_replyable: true`), `false` – все остальные. - `reply_state` (строка, query, может быть null, unanswered / waiting / answered / skipped) – Состояние ответа: `unanswered` – ответа нет, вашего в ожидании нет, отзыв не пропущен; `waiting` – ваш ответ отправлен и ещё не появился на карточке; `answered` – на карточке стоит ответ организации, ваш или поставленный не через Rewio; `skipped` – вы отметили отзыв [«Пропустить»](/replies/skip). На тарифе без ответов `waiting` и `skipped` всегда пусты. Просто «есть ли ответ на площадке» – `has_reply`. - `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) – Границы даты публикации, включительно. Названный в верхней границе день входит в период целиком. - `tz` (строка, query, может быть null) – Часовой пояс (IANA: `Europe/Moscow`, `Asia/Vladivostok`), в котором считаются дни `published_from` / `published_to`. Без параметра – UTC, неизвестный пояс – Москва. - `has_images · has_videos` (да/нет, query, может быть null) – Наличие фотографий и видео. `true` – только с ними, `false` – только без. - `has_media` (да/нет, query, может быть null) – Фото или видео: `true` – есть хотя бы одно из них, `false` – нет ни того, ни другого. - `has_rating` (да/нет, 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[].source_slug` (строка, может быть null) – Слаг площадки (`2gis`, `google`, `yandex_maps`). Отвечать можно, если совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка, на которой отзыв написан изначально (слаг в нижнем регистре: `2gis`, `google`, `tbank`, `booking`, `tripadvisor`, …). У нативного отзыва совпадает с `source_slug` – только на такой отзыв можно опубликовать ответ. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через Rewio: ответы на ссылке подключены, и отзыв родной для площадки. Приходит только на площадках, где Rewio публикует ответы. - `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`. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что [`GET /reply`](/replies/get). `null` – ответа через Rewio нет или тариф без ответов. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить». На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв – ваша или найденная на площадке. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. - `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": [], "source_slug": "yandex_maps", "is_replyable": true, "our_reply": null, "is_skipped": false, "complaint": null } ], "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[].source_slug` (строка, может быть null) – Слаг площадки (`2gis`, `google`, `yandex_maps`). Отвечать можно, если совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка, на которой отзыв написан изначально (слаг в нижнем регистре: `2gis`, `google`, `tbank`, `booking`, `tripadvisor`, …). У нативного отзыва совпадает с `source_slug` – только на такой отзыв можно опубликовать ответ. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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`). - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. - `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` повтор возможен после смены состава объекта (см. «Границы»), поэтому и здесь надёжнее UPSERT по `id`. Потерять отзыв поток не может: это и есть его единственная твёрдая гарантия. ## Что считается изменением [#what-counts-as-change] Правка текста или оценки на площадке, появившийся или изменившийся ответ организации, изменившийся набор фотографий и видео, пропажа отзыва с площадки (`is_deleted: true`) и обратное восстановление. Пересбор сам по себе изменением не считается: если на площадке ничего не поменялось, отзыв в поток не попадёт. ## Два режима [#modes] | `mode` | Что приходит | Повторы | Как класть к себе | | -------------------- | --------------------------------- | --------------------------- | ------------------ | | `all` (по умолчанию) | новые отзывы и изменения | возможны | **UPSERT** по `id` | | `new` | только впервые появившиеся отзывы | после смены состава объекта | **UPSERT** по `id` | Режим запекается в курсор: курсор одного режима не подходит другому – у них разные оси. Если нужны оба потока сразу, держите два курсора, это нормально. `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). # Список площадок (/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) – Основной адрес площадки. Ссылки принимаются и на её зеркала и короткие адреса – см. [Форматы ссылок](/link-formats). - `data[].rating_scale` (число, может быть null) – Шкала оценок самой площадки: 5, 10 и так далее. В отзывах оценка уже приведена к 1–5. - `data[].supports_replies` (да/нет, обязательный) – Площадка позволяет организации отвечать на отзывы. - `data[].supports_images` (да/нет, обязательный) – К отзывам на площадке можно прикладывать фотографии. - `data[].providers` (список строк) – Площадки-источники, чьи отзывы встречаются в ленте этой площадки (слаги в нижнем регистре; у отзыва – в поле `provider`). У большинства это только сам слаг; 2ГИС показывает ещё `booking`/`tbank`/`flamp`/…, Google – `tripadvisor`. Ответить можно только на отзыв, чей `provider` равен слагу этой площадки. - `data[].can_publish_reply` (да/нет, обязательный) – Rewio публикует ответы на этой площадке. Не то же самое, что `supports_replies`. - `data[].can_file_complaint` (да/нет, по умолчанию нет) – Rewio умеет подавать на этой площадке жалобы на отзывы (`/v3/reviews/{review_id}/complaints`). - `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, "can_file_complaint": 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, "can_file_complaint": true, "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, "can_file_complaint": true, "created_at": "2026-02-08T18:33:19" } ] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Создать вебхук (/webhooks/create) Rewio отправляет на ваш адрес события: новые отзывы (`reviews.new`), новые ответы (`replies.new`) и завершение сбора (`scrape.run.finished`). Каждая доставка подписана заголовком `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_9`). - `filters` (объект) – Что доставлять, а что пропускать. Условия складываются: событие проходит, только если выполнены все. - `filters.allowed_ratings` (список чисел) – Доставлять только отзывы с этими оценками, целые 0–5 (`0` – без оценки). По умолчанию `[1, 2, 3, 4, 5]`: отзывы без оценки не доставляются. Пустой список не принимается. - `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) – Объекты, события которых доставляются. `null` – все ваши объекты, включая будущие. - `data[].event_types` (список строк, обязательный) – Какие события доставлять: `reviews.new`, `replies.new`, `scrape.run.finished`. - `data[].bucket_window` (строка, обязательный) – Как часто доставлять: `immediate` – сразу после сбора, `daily_<час>` – сводкой в указанный час UTC. - `data[].filters` (объект, обязательный) – Что доставлять, а что пропускать. Условия складываются: событие проходит, только если выполнены все. - `data[].filters.allowed_ratings` (список чисел) – Доставлять только отзывы с этими оценками, целые 0–5 (`0` – без оценки). По умолчанию `[1, 2, 3, 4, 5]`: отзывы без оценки не доставляются. Пустой список не принимается. - `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) Секрет, которым подписаны доставки. Он один на аккаунт, а не на вебхук, и виден всегда. Нужен ключ `full`: ключом `read_only` секрет не получить. ## 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) Отправляет на ваш адрес пробное событие с такой же подписью, как у настоящей доставки. Отправка асинхронная: `202` значит, что доставка поставлена в очередь. Результат проверяйте по приёму на своей стороне: `failure_count` и `last_failure_at` пробная отправка не меняет. Для выключенного вебхука метод отвечает `409 webhook_inactive`. ## 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) – Новый набор объектов, от 1 до 200. Пустой список отклоняется (`422`); вернуть подписку на все объекты через `PATCH` нельзя – для этого создайте вебхук без `object_ids`. - `event_types` (список строк, может быть null) – Новый набор событий. - `bucket_window` (строка, может быть null) – Новая частота доставки: `immediate` или `daily_<час>`. - `filters` (объект, может быть null) – Новые фильтры доставки. Передаются целиком и заменяют прежние: поле, не переданное внутри `filters`, возвращается к умолчанию. - `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[].source_slug` (строка, может быть null) – Слаг площадки (`2gis`, `google`, `yandex_maps`). Отвечать можно, если совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка, на которой отзыв написан изначально (слаг в нижнем регистре). У нативного отзыва совпадает с `source_slug`. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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`: здесь только скрытые. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. - `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`. В одном запросе – не больше 30 идентификаторов. В ответ приходит весь список закреплённых после операции, в порядке показа. ## 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[].source_slug` (строка, может быть null) – Слаг площадки, с которой собран отзыв (`2gis`, `google`, `yandex_maps`). Отвечать можно, если он совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка-источник самого отзыва внутри `source` (слаг в нижнем регистре). Многие площадки показывают в ленте отзывы других: 2ГИС – `booking`/`tbank`/`flamp`/…, Google – `tripadvisor`. У нативного отзыва совпадает со слагом площадки (`2gis`, `google`), и только на такой отзыв можно опубликовать ответ через эту площадку – на остальные вернётся `409 reply_not_replyable`. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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) – Место отзыва среди закреплённых, считая с единицы. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. ### Пример ответа ```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": 1 } ] } ``` Коды ошибок общие для всего 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, может быть null, review_date / rating / reply_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[].source_slug` (строка, может быть null) – Слаг площадки (`2gis`, `google`, `yandex_maps`). Отвечать можно, если совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка, на которой отзыв написан изначально (слаг в нижнем регистре). У нативного отзыва совпадает с `source_slug`. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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) – Место отзыва среди закреплённых, считая с единицы. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. - `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": 1 } ] } ``` Коды ошибок общие для всего 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[].source_slug` (строка, может быть null) – Слаг площадки, с которой собран отзыв (`2gis`, `google`, `yandex_maps`). Отвечать можно, если он совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован: в UTC, если площадка позволяет пересчитать время, иначе – как показывает площадка. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка-источник самого отзыва внутри `source` (слаг в нижнем регистре). Многие площадки показывают в ленте отзывы других: 2ГИС – `booking`/`tbank`/`flamp`/…, Google – `tripadvisor`. У нативного отзыва совпадает со слагом площадки (`2gis`, `google`), и только на такой отзыв можно опубликовать ответ через эту площадку – на остальные вернётся `409 reply_not_replyable`. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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) – Место отзыва среди закреплённых, считая с единицы. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. ### Пример ответа ```json { "data": [] } ``` Коды ошибок общие для всего API и описаны на странице [Ошибки](/errors). # Задать порядок закреплённых (/widgets/pinned-set) Задаёт список закреплённых целиком: порядок в запросе становится порядком в выдаче. Это замена, а не добавление – отзывы, которых нет в списке, открепляются, а пустой список снимает закрепление со всех. Первый в списке получает `pin_position: 1`, следующий – `2`, и так далее. Не больше 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[].source_slug` (строка, может быть null) – Слаг площадки, с которой собран отзыв (`2gis`, `google`, `yandex_maps`). Отвечать можно, если он совпадает с `provider` отзыва. - `data[].author` (строка, может быть null) – Имя автора так, как его показывает площадка. Фамилии маскируются. - `data[].text` (строка, может быть null) – Текст отзыва. - `data[].review_date` (дата и время, может быть null) – Когда отзыв опубликован, в UTC, где это возможно. - `data[].rating_original` (строка, может быть null) – Оценка в шкале самой площадки, как есть. - `data[].rating` (число, может быть null) – Та же оценка, приведённая к шкале 1–5. - `data[].review_url` (строка, может быть null) – Прямая ссылка на отзыв на площадке. - `data[].reply_text` (строка, может быть null) – Ответ организации на отзыв. - `data[].reply_date` (дата и время, может быть null) – Когда организация ответила. - `data[].provider` (строка, может быть null) – Площадка-источник самого отзыва внутри `source` (слаг в нижнем регистре). Многие площадки показывают в ленте отзывы других: 2ГИС – `booking`/`tbank`/`flamp`/…, Google – `tripadvisor`. У нативного отзыва совпадает со слагом площадки (`2gis`, `google`), и только на такой отзыв можно опубликовать ответ через эту площадку – на остальные вернётся `409 reply_not_replyable`. - `data[].is_replyable` (да/нет, может быть null) – Можно ли ответить на отзыв через `PUT /v3/reviews/{review_id}/reply`. Приходит только на площадках, где Rewio публикует ответы (`can_publish_reply` в `GET /v3/sources`); на остальных ключа нет. `true` – ответы на ссылке подключены, и отзыв родной для площадки (`provider` пуст или равен `source_slug`). `false` – ответ вернёт ошибку: отзыв другой площадки (2ГИС показывает отзывы Netmonet, Booking, Т-Банка – `409 reply_not_replyable`) или ответы на ссылке не подключены. Тариф флаг не учитывает. - `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) – Место отзыва среди закреплённых, считая с единицы. - `data[].our_reply` (объект, может быть null) – Ваш ответ, отправленный через Rewio, и его состояние – то же, что в `GET /v3/reviews/{review_id}/reply`. `null` – ответа через Rewio нет или тариф без ответов. Ответ, поставленный не через Rewio, – в `reply_text`. - `data[].our_reply.status` (строка, может быть null, pending / published / failed / deleted) – Что с вашим ответом на карточке: `null` – отправлен, площадке ещё не передан; `pending` – площадка приняла, на карточке ещё не видели (проверяем через 15 с, 30 с, 1 мин … 4 ч); `published` – ваш текст стоит на карточке; `deleted` – вашего ответа на карточке нет: вы его удалили или он пропал (причина – в `error`); `failed` – не опубликован (почему – в `error`). - `data[].our_reply.text` (строка, обязательный) – Текст, который должен стоять на площадке. Пусто – ответ снимается. - `data[].our_reply.submitted_at` (дата и время, может быть null) – Когда вы отправили этот текст (UTC). - `data[].our_reply.published_at` (дата и время, может быть null) – Когда мы увидели ваш текст на карточке (UTC). - `data[].our_reply.updated_at` (дата и время, обязательный) – Когда ответ меняли в последний раз (UTC). - `data[].our_reply.error` (объект, может быть null) – Почему ответ не опубликован или пропал с карточки. - `data[].our_reply.error.code` (строка, обязательный) – Машинный код ошибки публикации. - `data[].our_reply.error.message` (строка, по умолчанию «») – Пояснение для человека. - `data[].is_skipped` (да/нет, по умолчанию нет) – Вы отметили отзыв «Пропустить» (`PUT /v3/reviews/{review_id}/skip`). На тарифе без ответов всегда `false`. - `data[].complaint` (объект, может быть null) – Последняя жалоба на отзыв. `null` – жалоб нет или тариф без жалоб. - `data[].complaint.status` (строка, может быть null, pending / accepted / rejected / failed) – `null` – отправляется на площадку; `pending` – на рассмотрении; `accepted` – отзыв удалён; `rejected` – отзыв остался. Подробно – `GET /v3/reviews/{review_id}/complaints`. - `data[].complaint.filed_at` (дата и время, может быть null) – Когда жалоба подана (UTC). - `data[].complaint.is_ours` (да/нет, обязательный) – `true` – подана через Rewio; `false` – найдена на площадке. ### Пример ответа ```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": 1 }, { "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": 2 } ] } ``` Коды ошибок общие для всего 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` там не приходят никогда. # Динамика оценки (/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) – Учитывать отзывы с оценкой не выше указанной. - `tz` (строка, query, может быть null) – Часовой пояс (IANA: `Europe/Moscow`, `Asia/Vladivostok`). Дни периода считаются в этом поясе; без параметра – в UTC, неизвестный пояс – Москва. ### Ответ 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` (число, обязательный) – Сколько отзывов с оценкой ниже 3 остались без ответа. - `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) Те же метрики, что и в сводке, разложенные по дням, неделям или месяцам. В ряд попадают только целые интервалы: неполные первый и последний отбрасываются, кроме текущих недели и месяца и недели на стыке годов. При шаге `day` обрезки нет. При шаге в месяц и `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) – Объект, по которому строить ряд. Нужен ровно один из `object_id` и `folder_id`: ряда по всему аккаунту нет. - `source_ids` (список чисел, query, по умолчанию пусто) – Отдельный ряд на каждую из этих площадок. По умолчанию `0`: общий ряд по всем. - `granularity` (строка, query, day / week / month, по умолчанию «month») – Шаг ряда: `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) – Учитывать отзывы с оценкой не выше указанной. - `tz` (строка, query, может быть null) – Часовой пояс (IANA: `Europe/Moscow`, `Asia/Vladivostok`). Дни периода и интервалы ряда считаются в этом поясе; без параметра – в UTC, неизвестный пояс – Москва. ### Ответ 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).