Отзывы

Синхронизация отзывов

Доступ для AI:

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

Обычная лента отзывов отвечает на вопрос «покажи», синхронизация — на вопрос «догони, ничего не потеряв». Поэтому здесь нет ни фильтров, ни сортировки, ни offset.

GET
/v3/reviews/sync

Параметры

cursorстрока

Курсор из next_cursor предыдущего ответа. С ним остальные параметры можно не передавать.

modeстрока

Что присылать: all — новые и изменения, new — только впервые появившиеся отзывы.

limitчисло1–1000

Размер страницы, 1–1000. Запекается в курсор, дальше его можно не повторять.

object_id · folder_idчисло

Объект или папка целиком. В запросе должно быть ровно одно из двух — но только на первом запросе, дальше адресат едет внутри курсора.

Ответ

dataсписок объектов

Отзывы, изменившиеся после вашей позиции.

data[].idчисло

Идентификатор отзыва в Rewio. По нему и склеивайте у себя.

data[].link_idчисло

Ссылка, с которой собран отзыв.

data[].source_idчисло

Площадка, с которой собран отзыв.

data[].authorстрокаможет быть пустым

Имя автора так, как его показывает площадка. Фамилии маскируются.

data[].textстрокаможет быть пустым

Текст отзыва.

data[].review_dateдата и времяможет быть пустым

Когда отзыв опубликован, по времени площадки.

data[].rating_originalстрокаможет быть пустым

Оценка в шкале самой площадки, как есть.

data[].ratingчисломожет быть пустым

Та же оценка, приведённая к шкале 1–5.

data[].review_urlстрокаможет быть пустым

Прямая ссылка на отзыв на площадке.

data[].reply_textстрокаможет быть пустым

Ответ организации на отзыв.

data[].reply_dateдата и времяможет быть пустым

Когда организация ответила.

data[].is_deletedда/нет

Отзыв пропал с площадки. В синхронизации такие приходят всегда.

data[].is_hiddenда/нет

Отзыв скрыт в рамках объекта (приходит только когда true).

data[].is_pinnedда/нет

Отзыв закреплён в рамках объекта (приходит только когда true).

data[].pin_positionчисломожет быть пустым

Позиция закреплённого отзыва: меньше — выше.

data[].prosстрокаможет быть пустым

Блок «достоинства» (только при split_pros_cons=true).

data[].consстрокаможет быть пустым

Блок «недостатки» (только при split_pros_cons=true).

next_cursorстрока

Позиция, с которой продолжить. Приходит всегда — сохраните её у себя.

has_nextда/нет

Есть ли ещё изменения прямо сейчас.

accessобъектможет быть пустым

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

access.reasonстрока

Почему выдача ограничена. trial — пробный доступ, manual — ограничение, согласованное по вашему договору.

access.limit_per_linkчисло

Сколько последних отзывов показывается по КАЖДОЙ ссылке (площадке объекта).

access.hidden_totalчисло

Сколько отзывов уже собрано сверх показанных. Считается по всему архиву и не зависит от фильтров запроса.

access.messageстрока

Готовая формулировка для показа человеку.

Ещё 14 полей – реже нужны
data[].has_imagesда/нет

Есть ли у отзыва изображения.

data[].imagesсписок объектов

Изображения отзыва.

data[].images[].template_urlстрока

URL изображения на CDN площадки в исходном виде. У части площадок содержит шаблон размера ({size} или {width}/{height}) и потому не предназначен для прямой вставки — для показа берите preview или image.

data[].images[].previewстрокаможет быть пустым

Готовый URL уменьшенной версии (превью) для списков и сеток.

data[].images[].imageстрокаможет быть пустым

Готовый URL полноразмерной версии для просмотра.

data[].has_videosда/нет

Есть ли у отзыва видео.

data[].videosсписок объектов

Видео отзыва.

data[].videos[].kindстрокаembed / file / hls

Тип вложения: embed — встраиваемый плеер площадки (открывать в sandbox-iframe), file — прямая ссылка на видеофайл, hls — HLS-поток (.m3u8).

data[].videos[].video_urlстрокаможет быть пустым

URL видео или встраиваемого плеера в зависимости от kind.

data[].videos[].thumbnailстрокаможет быть пустым

URL кадра-заставки (превью) видео.

data[].videos[].widthчисломожет быть пустым

Ширина видео в пикселях, если известна.

data[].videos[].heightчисломожет быть пустым

Высота видео в пикселях, если известна.

data[].videos[].duration_msчисломожет быть пустым

Длительность видео в миллисекундах, если известна.

data[].deleted_atдата и времяможет быть пустым

Когда мы заметили пропажу.

curl -X GET "https://example.com/v3/reviews/sync?object_id=20"
{  "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}

Как это работает

Первый запрос — с адресом объекта, дальше достаточно одного 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 у себя и вернитесь с ним завтра — придёт только то, что изменилось за сутки.

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}

Курсор — это закладка, а не сохранённая выдача: он не устаревает и его можно хранить сколько угодно. Обрыв связи стоит одной страницы, а не всего обхода. Внутрь заглядывать не нужно и не получится — устройство курсора мы оставляем за собой, чтобы менять его, не ломая вашу интеграцию.

Один отзыв может прийти дважды

Если отзыв изменится, пока вы читаете страницы, он придёт ещё раз — уже с новым содержимым и с тем же id: новой строки мы не заводим. Поэтому в режиме all кладите к себе UPSERT по id, а не INSERT — иначе дубли или ошибка уникальности. В режиме new достаточно INSERT: там ничего не приходит дважды.

Потерять отзыв поток не может: это и есть его единственная твёрдая гарантия.

Что считается изменением

Правка текста или оценки на площадке, появившийся или изменившийся ответ организации, изменившийся набор фотографий и видео, пропажа отзыва с площадки (is_deleted: true) и обратное восстановление. Пересбор сам по себе изменением не считается: если на площадке ничего не поменялось, отзыв в поток не попадёт.

Два режима

modeЧто приходитПовторыКак класть к себе
all (по умолчанию)новые отзывы и изменениявозможныUPSERT по id
newтолько впервые появившиеся отзывынетINSERT

Режим запекается в курсор: курсор одного режима не подходит другому — у них разные оси. Если нужны оба потока сразу, держите два курсора, это нормально.

mode=new удобен, когда отзывы уходят в CRM или в оповещения: правки и пропажи вас не интересуют, апсерт не нужен, каждая строка приходит ровно один раз.

Первый обход — всегда с начала истории

Переключателя «начать с сегодняшнего дня» нет: первый запрос отдаёт самые давние записи, и обход идёт до конца. Синхронизация — это сперва полная копия, потом приращения.

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

Свежесть

Изменения появляются в потоке с задержкой в несколько секунд. Это не запаздывание сбора, а защита от потери: отзыв, который в этот момент записывается, иначе оказался бы позади вашего курсора и не пришёл бы никогда.

Опрашивать чаще раза в минуту смысла нет — отзывы на площадках так быстро не появляются. Практичный режим для актуальной копии: раз в 5–15 минут.

Границы

  • Синхронизация не следит за составом объекта. Убрали ссылку из объекта, выключили объект или перенесли его — отзывы по нему просто перестанут приходить, отдельного события об этом не будет. Такие строки чистите у себя по link_id. Если ссылку потом вернули, её старые отзывы заново не поедут: курсор идёт по времени изменения, а возврат ссылки ничего в отзывах не меняет. Начните для этого объекта обход с нуля, без сохранённого курсора.
  • Скрытые и закреплённые отзывы приходят обычными строками, без флагов is_hidden и is_pinned: скрытие и закрепление — настройка витрины объекта, а не свойство отзыва, и в поток изменений они не попадают.
  • Ограниченная выдача работает здесь ровно так же, как в ленте: не больше access.limit_per_link последних отзывов на каждую площадку объекта (на пробном доступе — 20), и в ответе появляется блок access. Пропажи отзывов, оставшихся за этой границей, в поток не попадают.

Ошибки курсора

СтатусcodeКогда
400invalid_cursorКурсор не читается: испорчен, изменён или выдан другому аккаунту. Начните обход заново, без cursor.
400cursor_mismatchВместе с курсором передан object_id, folder_id или mode, не совпадающий с тем, для которого курсор выдан. Либо не передавайте их, либо передайте те же.

Остальные коды общие для всего API и описаны на странице Ошибки.