Skip to content

API попапов для SDK ​

Раздел описывает серверный API, по которому SDK получает попапы и отправляет события по ним. Он нужен разработчикам SDK (JS, iOS, Android, React Native, Flutter) и тем, кто пишет собственный клиент для показа попапов. Для обычной интеграции на сайте и в приложении он не требуется: SDK работает с ним сам.

API находится на домене личного кабинета, а не на api.rees46.ru:

https://app.rees46.ru/api/v3/popups

Для white label кластеров домен свой (app.personaclick.com, app.rees46.kz и т.д.), а магазин со своим доменом личного кабинета передает его SDK в настройках (опция app_host в JS SDK).

Общие правила ​

  • Посетитель идентифицируется параметрами shop_id, did и sid — теми же, что и в остальных методах SDK. Cookie, авторизация и withCredentials не используются: API отвечает с Access-Control-Allow-Origin: *.
  • Ответ всегда JSON в стандартном формате: {"status": "success", "payload": {...}} или {"status": "fail", "message": "..."}.
  • Условия показа проверяются в два этапа: сервер отбирает попапы по аудитории, SDK показывает их по триггерам и условиям страницы (экрана). Подробнее — в разделах для сайта и in-app.

Проверка проекта ​

Одинакова для всех методов и выполняется первой:

КодСообщениеКогда
400Invalid request parametersнет shop_id, did или sid; неизвестный channel или event
404Resource not foundпроект с таким shop_id не найден; попап не найден или не на витрине
403Access deniedпроект отключен
402Payment requiredпроект не оплачен или у него нет продукта «Попапы»
429Too many requestsпревышен лимит событий (см. ниже)

Как SDK узнает, что попапы есть ​

Ответ /init содержит флаг popups_v3: true, если у проекта есть продукт «Попапы» и хотя бы один опубликованный попап нужного канала (для stream ios/android — канала mobile, иначе web; в тестовом режиме считаются и попапы в статусе «Тест»). Без флага SDK в API попапов не обращается — это экономит запрос на каждой странице у проектов без попапов.

json
{
  "did": "...",
  "popups_v3": true
}

Поле popup в ответах /init и /push относится к попапам предыдущей версии и для новых попапов не используется.

Список попапов ​

Серверный этап: попапы проекта, доступные посетителю. Список нужно кешировать на ttl секунд (5 минут) и запрашивать заново при старте сессии и после событий, которые меняют аудиторию: покупки, записи профиля, подписки, добавления в сегмент.

GET https://app.rees46.ru/api/v3/popups

Параметры ​

ПараметрТипОбязателен?Описание
shop_idStringДаAPI-ключ
didStringДаDevice ID
sidStringДаИдентификатор сессии
channelStringНетweb (по умолчанию) или mobile
deviceStringНетТолько для web: desktop или mobile. Без параметра определяется по User-Agent
testmodeBooleanНетtrue — тестовый режим: в ответ попадают и попапы в статусе «Тест»
debugBooleanНет1 — добавить в ответ список отсеянных попапов с причинами

Запрос ​

shell
curl "https://app.rees46.ru/api/v3/popups?shop_id=...&did=...&sid=...&channel=mobile"

Ответ ​

json
{
  "status": "success",
  "payload": {
    "ttl": 300,
    "popups": [
      {
        "id": 512,
        "layout": "modal",
        "placement": "center",
        "selector": null,
        "trigger_type": "time_on_screen",
        "trigger_value": 10,
        "trigger_event": null,
        "frequency": "once_day",
        "cooldown_minutes": 60,
        "promo_code_list_id": 7,
        "target_screens": ["product", "cart"],
        "design": { "frameStyle": {}, "rows": [], "elements": [], "variables": {} }
      }
    ],
    "excluded": [
      { "id": 513, "reason": "segments" }
    ]
  }
}

excluded есть только при debug=1. Причины: period — вне периода показа, device — не то устройство, segments — не подходит по сегментам, subscription — не подходит по подписке на рассылки.

Что проверил сервер: статус попапа и наличие опубликованной версии, период показа в часовом поясе проекта, сегменты, статус подписки на канал рассылок, устройство (только web). Посетитель без профиля считается не подписанным и не входящим ни в один сегмент.

Поля попапа ​

Общие для обоих каналов:

ПолеТипОписание
idIntegerИдентификатор попапа
layoutStringМакет. web: popup, bar, widget, embed; mobile: banner, modal, fullscreen
placementStringРасположение: center, top, bottom, bottom_left, bottom_right, selector
selectorString / nullCSS-селектор контейнера для embed
trigger_typeStringТриггер показа, см. ниже
trigger_valueInteger / nullЗначение триггера: мс для delay, проценты для scroll_percent, страницы для page_views, секунды для time_on_screen
trigger_eventString / nullИмя события для track_event
frequencyStringonce_session, once_life, once_day, once_week, once_month, every_page
cooldown_minutesIntegerПауза между показами в минутах, 0 — без паузы
promo_code_list_idInteger / nullСписок персональных промокодов для

Только channel=web:

ПолеТипОписание
web_devicesStringboth, desktop, mobile
page_typesArray[String]home, product, category, cart, purchase, search, custom; пусто — любые
url_includeArray[String]Правила «URL содержит», * — любые символы; пусто — без ограничений
url_excludeArray[String]Правила «URL не содержит»
product_idsArray[String]Только на страницах этих товаров
category_idsArray[String]Только на страницах этих категорий
htmlStringГотовый фрагмент: разметка, <style> и <script> попапа

Только channel=mobile:

ПолеТипОписание
target_screensArray[String]Коды экранов, на которых показывать; пусто — любой экран
designObjectДерево дизайна для нативной отрисовки, см. Формат дизайна

Триггеры ​

trigger_typeКаналКогда срабатывает
immediatewebсразу после загрузки страницы
delaywebчерез trigger_value мс
scroll_percentwebпри прокрутке до trigger_value % высоты страницы
exit_intentwebкурсор ушел за верхнюю границу окна; на мобильных не срабатывает
page_viewswebс trigger_value-й страницы за сессию
cart_addwebсобытие корзины; полная синхронизация — только если товаров стало больше
cart_removewebсобытие удаления из корзины
wishlist_addwebсобытие добавления в избранное
wishlist_removewebсобытие удаления из избранного
app_startmobileпри старте сессии
screen_openmobileпри открытии экрана из target_screens
time_on_screenmobileчерез trigger_value секунд после открытия экрана
track_eventmobileпри отправке события с именем trigger_event
manualmobileтолько по вызову из кода приложения

Что делает SDK после получения списка ​

  1. Ждет триггер попапа; у web перед показом проверяет web_devices, page_types, url_include/url_exclude, product_ids, category_ids; у mobile — target_screens.
  2. Проверяет частоту и паузу. Они хранятся на устройстве: ключ — идентификатор попапа, время последнего показа и сессия последнего показа. В тестовом режиме показы не записываются.
  3. Следит за конкуренцией: одно модальное окно (popup, modal, fullscreen) одновременно; bar и widget — не больше трех; embed без ограничений. Если слот занят, попап показывается после закрытия предыдущего.
  4. Если в попапе есть и задан promo_code_list_id, запрашивает промокод методом get_promo_code до показа. Нет кода — попап не показывается.
  5. Отправляет событие show, затем остальные события по действиям посетителя.

Попап по идентификатору ​

Для ручного показа из кода (r46('popup_v3', id), триггер manual). Условия аудитории не проверяются, но попап должен быть опубликован или, при testmode=true, в статусе «Тест».

GET https://app.rees46.ru/api/v3/popups/{id}

Параметры ​

ПараметрТипОбязателен?Описание
shop_idStringДаAPI-ключ
didStringДаDevice ID
sidStringДаИдентификатор сессии
testmodeBooleanНетtrue — разрешить попап в тесте

Ответ ​

Поля попапа — как в списке, набор зависит от канала попапа.

json
{
  "status": "success",
  "payload": {
    "popup": { "id": 512, "layout": "modal", "...": "..." }
  }
}

Попап не найден, черновик, на паузе или без опубликованной версии — 404.

События попапа ​

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

POST https://app.rees46.ru/api/v3/popups/{id}/events

Параметры ​

Тело application/json. Для отправки при уходе со страницы (navigator.sendBeacon) параметры можно передать в строке запроса, а тело — как text/plain.

ПараметрТипОбязателен?Описание
shop_idStringДаAPI-ключ
didStringДаDevice ID
sidStringДаИдентификатор сессии
eventStringДаshow, close, click, submit, subscribe, prize
channelStringНетТолько для subscribe: канал подписки email, sms, web_push, mobile_push, telegram, whatsapp, max
eventКогда отправлять
showпопап показан
closeпосетитель закрыл попап
clickклик по ссылке или кнопке попапа, кроме закрытия
submitотправлена форма профиля или оценка опроса
subscribeподписка через форму сбора email
prizeколесо фортуны выдало приз

Канал

channel здесь — канал подписки, а не канал попапа. Значение web или mobile отклоняется с 400.

Запрос ​

shell
curl -X POST "https://app.rees46.ru/api/v3/popups/512/events" \
  -H "Content-Type: application/json" \
  -d '{"shop_id": "...", "did": "...", "sid": "...", "event": "subscribe", "channel": "email"}'

Ответ ​

json
{
  "status": "success"
}

Правила обработки:

  • событие принимается только для попапа на витрине (опубликован или в тесте, есть опубликованная версия), иначе 404;
  • повтор того же события того же попапа в той же сессии в течение 5 секунд не записывается, ответ 200;
  • не больше 120 событий в минуту с одного устройства, сверх лимита — 429;
  • устройство без профиля (не было ни одного /init старого API или записи профиля) — 200 без записи: событие некому приписать.

Действия внутри попапа — запись профиля, подписка, добавление в сегмент, выдача промокода, оценка NPS/CSAT/CES — SDK выполняет обычными методами CDP. API событий только фиксирует факт для отчета.

Формат дизайна ​

Для канала mobile попап приходит деревом дизайна, которое приложение рисует нативными элементами. Для web то же дерево на сервере уже собрано в html.

json
{
  "frameStyle": {
    "width": 92, "widthMode": "%", "maxWidth": 480, "maxWidthMode": "px",
    "height": 320, "heightMode": "auto",
    "bgColor": "#ffffff", "borderColor": "#e5e7eb", "borderWidth": 1, "borderRadius": 16, "padding": 20
  },
  "rows": [
    {
      "id": "row-1",
      "columns": [50, 50],
      "cells": [{ "align": "left", "verticalAlign": "top" }, { "align": "center", "verticalAlign": "center" }],
      "gap": 8, "minHeight": 110,
      "bgColor": null, "bgImageUrl": null, "bgSize": "cover", "bgPosition": "center", "bgRepeat": "no-repeat"
    }
  ],
  "elements": [
    { "id": "el-1", "type": "text", "rowId": "row-1", "partIndex": 0, "style": { "message": "Скидка 10%", "fontSize": 18 } },
    { "id": "el-2", "type": "button", "rowId": "row-1", "partIndex": 1, "style": { "buttonText": "Купить", "buttonAction": "link", "linkHref": "{{ios_link}}" } }
  ],
  "variables": { "ios_link": "myapp://catalog/sale" }
}
  • frameStyle — рамка попапа: ширина (widthMode % или px, maxWidth), высота (heightMode auto или px), фон, рамка, скругление, отступ.
  • rows — строки сверху вниз. columns — ширины колонок в процентах, cells — выравнивание содержимого колонки (align: left/center/right, verticalAlign: top/center/bottom). Фон строки — цвет или картинка.
  • elements — плоский список элементов; rowId и partIndex указывают строку и номер колонки. Внутри колонки элементы идут в порядке списка. Элемент со style.cellVerticalAlign переопределяет вертикальное выравнивание ячейки для себя.
  • variables — статические переменные дизайна. Токен в текстах и ссылках заменяется на значение из variables. Так задаются, например, отдельные ссылки для iOS и Android: в кнопке , а значение — в variables.
  • Переменные витрины подставляются при показе, в variables их нет: promo_code (персональный промокод из promo_code_list_id), cart_total, remaining, progress, campaign_end, wheel_prize.

Общие стили элемента ​

Любой элемент может содержать в style: bgColor, textColor, borderWidth, borderColor, borderRadius, paddingX, paddingY, fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, opacity, тень shadowY/shadowBlur/shadowColor, выравнивание в ячейке cellAlign/cellVerticalAlign, а также ссылку на весь элемент linkHref и linkTarget (_blank/_self), если элемент не кнопка и не форма.

Тексты (message, buttonText, подписи) могут содержать облегченную разметку: **жирный**, *курсив*, __подчеркнутый__, ~~зачеркнутый~~.

Элементы канала mobile ​

Приложение должно уметь рисовать эти типы; элементы других типов в попапе канала mobile создать нельзя.

typeЧто рисоватьОсновные поля style
textтекстmessage, messageAlign
boxконтейнер с необязательным текстомкак text, плюс фон и отступы
imageкартинкаimageUrl, imageAlt, imageHeightMode (auto/px/%), imageHeight, imageObjectFit, imageRadius, imageAspectRatio
buttonкнопкаbuttonText, buttonAction (link/close/copy), linkHref, copyText, buttonAlign, buttonBgColor, buttonTextColor, buttonFontSize, buttonPaddingX, buttonPaddingY, buttonRadius
closeкнопка закрытиякак button; closeIconMode (text/image/svg), closeIconSize, imageUrl, closeSvg
emailCollectorполе email, согласие, кнопкаemailPlaceholder, emailSubmitText, emailConsentLabel, emailConsentFields (email_bulk, email_chain, email_transactional), emailSegmentId, emailErrorMessage, emailSuccessTitle, emailSuccessMessage, emailLayout (inline/column), цвета полей и кнопки
formформа профиляformFields — список {id, kind, label, placeholder, required, propertyKey}, kind: email, phone, first_name, last_name, birthday, gender, custom; formConsentLabel, formConsentFields, formSegmentId, formSubmitText, formErrorMessage, formSuccessTitle, formSuccessMessage
promoCodeпромокод с кнопкой копированияpromoSource (personal — , static — promoStaticCode), promoLabel, promoShowCopy, promoCopyText, promoCopiedText, promoApplyHref, цвета и размер кода
surveyопрос NPS / CSAT / CESsurveyType (nps 0–10, csat 1–5, ces 1–7), surveyCampaignId, surveyCampaignCode, surveyQuestion, surveyMinLabel, surveyMaxLabel, surveyCommentPlaceholder, surveySubmitText, surveyThanksText, цвета шкалы
recommendationблок товарных рекомендацийrecommenderCode — код блока, товары запрашиваются методом рекомендаций

Что должно происходить по действиям — так же, как в JS SDK:

ДействиеЧто делает SDK
кнопка linkоткрыть linkHref; событие click
кнопка close / элемент closeзакрыть попап; событие close
кнопка copyскопировать copyText (или текст кнопки); событие click
emailCollectorзаписать профиль {email} с флагами из emailConsentFields = true; при emailSegmentId — добавить в сегмент; события subscribe с channel: email
formзаписать профиль из полей (custom — в свойство propertyKey); согласие — флаги formConsentFields; при formSegmentId — добавить в сегмент; событие submit
promoCode personalдо показа получить код из promo_code_list_id (get_promo_code); копирование — событие click
surveyотправить оценку и комментарий в кампанию опроса с каналом popup (методы nps review, csat review, ces review); событие submit
recommendationзапросить блок по recommenderCode и отрисовать товары