Документация API v2. Версия заморожена и продолжает работать; актуальная — на главной. Что изменилось: переход с v2 на v3.
Руководства

Синхронизация данных

Доступ для AI:

Синхронизация нужна, когда отзывы живут не только у нас, но и в вашей базе: в CRM, в хранилище, в собственной аналитике. Одна ручка — GET /v2/reviews/sync.

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

Цикл

cursor = db.load_cursor()                       # None при первом запуске
params = {"cursor": cursor} if cursor else {"group_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"]}

Первый прогон выгружает всю историю, следующие — только изменения. Возвращайтесь с сохранённым курсором раз в 5–15 минут.

Четыре правила

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

2. Сохранять после каждой страницы. Тогда обрыв связи стоит одной страницы, а не всего обхода.

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

4. next_cursor приходит всегда — и на последней странице, и на пустой. Признак «догнал» — это has_next: false, а не отсутствие курсора.

Что приходит

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

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

Режим запечён в курсор — для второго режима заведите второй курсор.

Отдельного режима «только изменения» нет, и он не нужен: когда вы догнали текущее состояние в режиме all, дальше в нём приходят как раз одни изменения — новых-то пока не появилось.

Границы

  • Порядок — по времени изменения, не по дате отзыва. Отзыв 2019 года, у которого вчера появился ответ, придёт после вчерашнего. Сортировать нечем и незачем: это поток, а не витрина.
  • Фильтров нет. Отзыв, который правкой перестал подходить под фильтр, пришлось бы присылать событием «выбыл» — такого события не существует, поэтому любой фильтр сделал бы поток дырявым. Отбирайте у себя.
  • Состав объекта не отслеживается. Убрали ссылку или выключили объект — отзывы по нему просто перестанут приходить, события об этом не будет. Чистите у себя по link_id. Обратный случай тоже стоит держать в голове: если ссылку вернули, её старые отзывы заново потоком не поедут — курсор их давно прошёл. После возврата ссылки начните обход с нуля, без сохранённого курсора.
  • Скрытые и закреплённые приходят обычными строками: это настройка витрины, а не свойство отзыва.
  • Задержка несколько секунд. Не запаздывание сбора, а защита: отзыв, который прямо сейчас записывается, иначе оказался бы позади вашего курсора и не пришёл бы никогда.

Если курсор не принят

400 invalid_cursor — курсор испорчен, изменён или выдан другому аккаунту: начните обход заново, без cursor. 400 cursor_mismatch — вместе с курсором передан другой group_id, folder_id или mode: либо не передавайте их вовсе, либо передайте те же.

Полный список параметров и полей — в справочнике метода.

On this page