Перейти к содержимому
ReplAI
Разделы документации

Каталог на сайте

ReplAI Feed — формат фида каталога

JSON-контракт для передачи товаров, акций и информационных страниц агенту ReplAI. Подходит для любого стека.

Универсальный способ передать AI-агенту ReplAI товары, акции и информационные страницы вашего сайта. Один контракт для любого стека: PHP, Python, Node, 1С-выгрузка или скрипт по расписанию.

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

Ничего отправлять не нужно: вы отдаёте JSON по постоянному URL, а ReplAI сам забирает его каждые 30 минут. Cron на вашем хостинге не требуется.

  1. Настройте на сайте страницу, отдающую фид, — например https://мой-магазин.kg/replai-feed.json.
  2. В кабинете ReplAI: Агент → Интеграции → Фид каталога → Другой сайт — вставьте адрес в поле «Ссылка на фид вашего сайта» и нажмите «Сохранить URL».
  3. Нажмите «Забрать сейчас» — сразу увидите, сколько товаров и записей знаний загрузилось. Ошибка последнего забора тоже видна в кабинете.

Ответ трактуется как полный снимок (snapshot: true), если в JSON явно не указано иное.

Требования к URL: http(s), без логина/пароля в адресе, доступен из интернета (не localhost и не внутренний IP), без редиректов — давайте конечный адрес. Один ответ — до 25 МБ; каталог, который в этот размер не влезает, отдавайте страницами. Если фид «секретный», добавьте свой токен в query — мы сохраним адрес как есть.

Режим обновления

Рекомендуемый режим — полный снимок ("snapshot": true): отдавайте по URL весь актуальный каталог, всё пропавшее из снимка скрывается автоматически. Это же значение подставляется по умолчанию, если поля в ответе нет.

Частичная выдача ("snapshot": false) ничего не скрывает — она дополняет и обновляет то, что уже загружено. Нужна редко: например, пока каталог собирается по частям.

Большой каталог — страницы

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

Как это выглядит: к вашему адресу мы дописываем параметры и запрашиваем страницы одну за другой.

…/replai-feed.json?page=1&per_page=1000
…/replai-feed.json?page=2&per_page=1000&cursor=1000   ← cursor из прошлого ответа
…/replai-feed.json?page=3&per_page=1000&cursor=2000
Параметр запроса Что означает
page Номер страницы, начиная с 1
per_page Сколько товаров мы просим (сейчас 1000)
cursor Значение next_cursor из предыдущего ответа; на первой странице отсутствует

Ответ добавляет к обычному телу три поля:

{
  "snapshot": true,
  "page": 2,
  "has_more": true,
  "next_cursor": "2000",
  "products": [ "…1000 товаров…" ],
  "pages": []
}
Поле ответа Тип Описание
has_more bool true — есть ещё страницы, мы придём за следующей
next_cursor string ≤500 Что вернуть в cursor следующего запроса (например, id последнего товара)
page int Номер отданной страницы (необязательно)

Правила простые:

  • snapshot: true достаточно указать на первой странице — режим действует на весь обход.
  • promotions и pages отдавайте только на первой странице: повторять их на каждой незачем.
  • Отдавать страницы по курсору надёжнее, чем по смещению: пока идёт обход, каталог живёт своей жизнью, а сдвиг окна OFFSET терял бы товары. Курсор — любая ваша строка (обычно id последней позиции страницы), мы возвращаем её как есть.
  • Пока обход не дошёл до конца, ничего не скрывается: если мы не успели забрать каталог за один заход, снимок не применяется целиком — незабранное не будет принято за «пропало». Забор продолжится следующим циклом.
  • Потолок одного захода — 100 страниц по 1000 товаров и 10 минут.

Фид без has_more считается цельным — так работают все прежние интеграции, менять их не нужно.

Формат тела

{
  "snapshot": true,
  "generator": { "name": "my-shop-exporter", "version": "1.0.0" },
  "products": [
    {
      "external_id": "42-red-M",
      "name": "Куртка зимняя North",
      "price": "4500.00",
      "old_price": "6000.00",
      "special_until": "2026-08-15T23:59:59+06:00",
      "quantity": 7,
      "color": "красный",
      "size": "M",
      "description": "Мембрана 10K, утеплитель 200г.",
      "category": "Куртки",
      "is_active": true
    }
  ],
  "promotions": [
    {
      "external_id": "summer-sale",
      "title": "Летняя распродажа",
      "description": "Скидка 20% на всю обувь при заказе от 5000 сом.",
      "starts_at": "2026-07-20T00:00:00+06:00",
      "ends_at": "2026-08-10T23:59:59+06:00"
    }
  ],
  "pages": [
    {
      "external_id": "delivery",
      "title": "Доставка и оплата",
      "content": "Доставка по Бишкеку — бесплатно от 3000 сом...",
      "url": "https://myshop.kg/delivery"
    }
  ]
}

Все три секции опциональны — можно отдавать только товары или только акции.

generator (необязательно) — кто собрал фид: name ≤60 и version ≤20 символов. Мы показываем это владельцу магазина в кабинете; для готового OpenCart-расширения так работает подсказка «доступно обновление».

products — до 5000 в одном ответе

Больше 5000 позиций — отдавайте страницами: суммарный размер каталога не ограничен, ограничен один ответ.

Поле Тип Обяз. Описание
external_id string ≤200 Стабильный уникальный id товара/вариации у вас (ключ обновления: тот же id — тот же товар)
name string ≤500 Название
price число/строка ≥0 Текущая цена продажи (по акции — уже сниженная)
old_price число/строка Цена «было», зачёркнутая. Должна быть выше price, иначе пара игнорируется
special_until ISO-дата До какого момента действует акция; без таймзоны считаем UTC
quantity int ≥0 Остаток (0 = нет в наличии)
color, size string Вариация
description string ≤8000 Описание для агента. Хватает 1500–2000 символов: в поиск попадает начало текста, а клиенту агент пересказывает своими словами — длинные простыни характеристик только раздувают фид
category string ≤255 Название категории; создаётся автоматически
is_active bool false — скрыть товар у агента

promotions — до 200 в одном фиде

Акции попадают в Базу знаний агента: он рассказывает условия словами («скидка 20% на обувь до 10 августа»). Точные акционные цены конкретных товаров передавайте через old_price / special_until товара.

Поле Тип Обяз. Описание
external_id string ≤200 Стабильный id акции (иначе ключ — от названия)
title string ≤400 Название акции
description string ≤8000 Условия
starts_at, ends_at ISO-дата Период. Акция с истёкшим ends_at игнорируется

pages — до 500 в одном фиде

Информационные страницы сайта (доставка, оплата, гарантия, о магазине) — тоже в Базу знаний: агент отвечает на вопросы клиентов по их содержимому.

Поле Тип Обяз. Описание
external_id string ≤200 Стабильный id страницы (иначе ключ — от URL/названия)
title string ≤400 Заголовок
content string ≤100000 Текст страницы (без HTML-тегов)
url string ≤1000 Адрес страницы — агент даст клиенту ссылку

Результат забора

Сводку по последнему забору кабинет показывает сразу после кнопки «Забрать сейчас»:

{
  "products_received": 120,
  "products_created": 3,
  "products_updated": 117,
  "products_deactivated": 2,
  "products_skipped": 0,
  "skipped_reasons": [],
  "knowledge_created": 1,
  "knowledge_updated": 0,
  "knowledge_unchanged": 4,
  "knowledge_deleted": 0,
  "knowledge_skipped": 0,
  "pages_fetched": 1,
  "truncated": false
}

skipped_reasons: duplicate_external_id — повторный id в одном фиде; old_price_not_above_price — пара акции отброшена (товар сохранён).

pages_fetched — сколько страниц забрали за этот заход, truncated: true — обход не дошёл до конца (кнопка «Забрать сейчас» ждёт не дольше 40 секунд, чтобы не держать кабинет). Забранное применено, остальное доберёт ближайший цикл; ничего при этом не скрывается.

Если фид недоступен или не проходит проверку формата, забор прерывается и причина попадает в кабинет строкой «Последняя ошибка» — каталог при этом остаётся прежним.

Проверка фида

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

curl -s "https://мой-магазин.kg/replai-feed.json" | head -c 400

Правила и советы

  • snapshot: true скрывает только товары, ранее пришедшие из фида; заведённые вручную или из других интеграций не трогаются. То же с Базой знаний — удаляются только фидовые записи.
  • Пустой products при snapshot: true скроет весь фидовый каталог — не отдавайте снимок, если каталог не собрался.
  • Один товар в разных цветах/размерах — отдельные записи с разными external_id (например 42-red-M, 42-red-L).
  • Держите один ответ ≤5000 позиций и ≤25 МБ; каталог больше — отдавайте страницами.