Общий принцип работы системы

24TTL создаёт веб-страницу с рич-контентом для продукта. Такая веб-страница конвертируется в e-package, который является ZIP-файлом и содержит HTML, CSS, iframe, JSON, медиа-файлы, а также манифест JSON (manifest.json). Манифест содержит основную информацию об e-package и соответствующем продукте. E-package получает уникальный URL-адрес, который передаётся на CDN. CDN создаёт новую ссылку на этот e-package и кэширует её.

24STREAM задействуется при посещении пользователем страницы продукта, к которой подключен виджет. CDN использует ссылку на файл manifest.json, чтобы проверить наличие соответствующего контента.

Если контент доступен для вставки, система даёт ответ «200», и виджет, в зависимости от выбранного метода, автоматически транслирует рич-контент на страницу продукта (метод findAndInsert) или предоставляет возможность для манипулирования контентом вручную (метод find). Если контент отсутствует, система даёт ответ «204».

Виджет 24STREAM передачи рич-контента

Виджет 24STREAM предназначен для трансляции рич-контента продуктов на торговые онлайн площадки.

Рич-контент - сочетание текстового описания, изображений, видео, анимации и т.д., которые предоставляют более информативное и наглядное описание товара. Расширенный контент позволяет виртуально взаимодействовать с продуктом, раскрывает его преимущества, вызывает яркие эмоции, повышает знания о бренде и мотивирует к покупке.

В системе представлено два типа рич-контента: minisite и AR (дополненная реальность).

Виджет 24STREAM подключается как скрипт на торговую площадку и предоставляет методы для поиска соответствующего рич-контента и его трансляции. 

Рич-контент загружается, когда посетитель торговой площадки заходит на страницу, к которой подключен виджет. Скрипт содержит все параметры, определяющие бренд и расширенный контент продукта, который необходимо транслировать.

24STREAM не собирает и не обрабатывает какие-либо данные.

Функции виджета заключаются в следующем: построить путь к статичному HTML-файлу, расположенному на CDN, результат (HTML-код) вставить в блок <div>, следить за размером блока, в который вставляется контент, и, в зависимости от размера блока, изменить классы во вставляемом HTML-файле. Разрешение контента ограничивается по ширине и имеет 4 типа: максимальное - 1200 пикс; от 1100 до 991 пикс - small pc; от 991 до 768 пикс - tablet; менее 768 до 320 пикс - mobile.

Скорость загрузки страниц не замедляется, поскольку виджет не использует внешние запросы к базам данных, а обращается исключительно к статичному контенту, находящемуся в CDN. Таким образом, независимо от местонахождения пользователя, контент всегда доставляется с ближайшего CDN-сервера.

К контенту можно обратиться напрямую, не используя виджет. Для этого необходимо построить правильный путь, используя обязательные атрибуты, описанные в разделе "Использование виджета". 

Подключение виджета

Виджет адаптирован для работы в различных средах и имеет два способа подключения: асинхронный и синхронный.

Для работы виджета в мобильных приложениях рекомендуется использовать WebView. Рич-контент будет отображён во всплывающем окне.

Асинхронное подключение

Асинхронный тип подключения виджета является рекомендованным для исполнения кода в браузере клиента.

Асинхронно подключенный виджет не блокирует загрузку основного контента.

В случае его полной недоступности, он не вызовет ошибок и не сломает основную функциональность сайта.

Для интеграции виджета вставьте в конец тела документа следующий код:


<script>
	(function (w, d, s, o) {
		var f = d.getElementsByTagName(s)[0];
		var j = d.createElement(s);
		w.TTLStreamReady = new Promise((resolve) => {
			j.async = true;
			j.src = '//content.24ttl.stream/widget.js';
			f.parentNode.insertBefore(j, f);
			j.onload = function () {
				w.ttlStream = new TTLStream(o);
				resolve(w.ttlStream);
			};
		});
	})(window, document, 'script', {});
</script>
								

Виджет готов к работе!

Синхронное подключение

Синхронное подключение отличается от асинхронного тем, что оно блокирует основной поток, и скрипты, идущие после кода подключения виджета, будут загружаться только после загрузки виджета.

Данный вид подключения может быть полезен тем, кто хочет получить данные как можно скорее и затем осуществлять с ними манипуляции.

Чтобы подключить виджет, вставьте в конец тела документа следующий код:


<script src="//content.24ttl.stream/widget.js"></script>
<script>
	window.TTLStreamReady = new Promise(resolve => { window.ttlStream = new TTLStream({}); resolve(); });
</script>
								

Виджет готов к работе!

Использование виджета

После подключения виджет готов к использованию.

В зависимости от типа получаемого контента (параметр) настройки виджета могут отличаться.

На данный момент доступно 2 типа контента: 'minisite' и 'ar' (с англ. "augmented reality" - дополненная реальность).

Тип контента 'minisite'

Данный тип контента представляет из себя страницу перехода (landing page) с изображениями, текстом и видео.

Для удобства использования виджет предоставляет два метода для работы с ним:

- findAndInsert: дает возможность найти рич-контент и автоматически вставить его в блок;

- find: схож с методом findAndInsert, отличается возможностью манипулировать контентом вручную.

Пример транслируемого контента

Использование findAndInsert для minisite

Метод findAndInsert, аналогично методу find, принимает ряд параметров, при помощи которых виджет находит контент и вставляет его в блок.

В отличии от метода find, метод findAndInsert не возвращает данные для обработки вручную, а сам вставляет их в блок.

Могут быть переданы следующие параметры:

Параметр Обязательный Тип данных Описание
el Да Строка

CSS-селектор DOM-элемента, в который будет вставлен контент. Вы можете кастомизировать вид рич-контента, добавив свои CSS-правила. Перед вызовом виджета, блоку, в который вcтавляется рич-контент, необходимо задать стили через important, например, добавив следующий скрипт JS:

 var styleElement = document.createElement('style'); styleElement.innerHTML = 'body .exampleWrapperContent #stream-container * { '+ ' font-family: \'DINPro Technopark\' !important;'+ '}'; document.getElementsByTagName("head")[0].appendChild(styleElement); 

в котором.exampleWrapperContent необходимо заменить на класс того элемента, в который будет вставляться рич-контент

brand Да Строка Название бренда для продукта которого будет доставлен рич-контент на сайт ритейлера
productId Да Строка Идентификатор продукта, которым продукт определённого бренда уникально обозначается для ритейлера этого бренда
retailerDomain Да Строка Домен ритейлера, на который будет доставлен рич-контент
templateType Да Строка Тип возвращаемого шаблона, может принимать значения 'master_template' (html-шаблон) и 'img_template' (шаблон из картинок)
contentType Да Строка Тип возвращаемого контента, может принимать значение 'minisite' и 'ar'
resultType Да Строка Формат возвращаемого результата, может принимать значение 'html' и 'iframe', обязательный параметр, влияет на полученный результат
language Нет Строка

Код страны и языка для рич-контента. Чтобы получить для определенной страны контент на определённом языке, необходимо отправить запрос в формате 'страна_язык'. Код страны и код языка необходимо указать по стандартам ISO (код страны указывается согласно ISO 3166-1, код языка - ISO 639-1). Если необходимо получить три страницы на трех языках, следует сделать три запроса, указав в каждом соответствующие параметры языка

По умолчанию этот параметр установлен 'ru'

throwError Нет Логическое значение

Значение не указано или в положении true: если рич-контент не найден, в консоле будет ошибка 404 (контент не найден). Необходимо будет обработать эту ошибку

Если установить значение false, в случае отсутствия контента ошибка не выдаётся; соответственно, нет необходимости её обрабатывать

iframeMode Нет Логическое значение

Если интеграция выполнена через iframe, для получения рич-контента необходимо использовать "iframeMode": true

Пример кода


<script>
	TTLStreamReady.then(() => {
		ttlStream.findAndInsert({
			el: '.myCoolWrapper',
			brand: 'panasonic',
			productId: 'demoSKU',
			retailerDomain: 'beru.ru',
			templateType: 'master_template',
			resultType: 'html',
			contentType: 'minisite',
			language: 'ru',
		});
	});
</script>
								

Параметр resultType влияет на тип данных, которые будут вставлены на страницу, далее мы рассмотрим каждое из возможных его значений:

html

На страницу будет вставлен контент в виде html.

iframe

На странице будет создан тег iframe, его содержимым будет рич-контент.

Использование find для minisite

Метод find принимает ряд параметров, при помощи которых виджет находит контент.

Могут быть переданы следующие параметры:

Параметр Обязательный Тип значения Описание
brand  Да Строка Название бренда для продукта которого будет доставлен рич-контент на сайт ритейлера
productId  Да Строка Идентификатор продукта, которым продукт определённого бренда уникально обозначается для ритейлера этого бренда
retailerDomain  Да Строка Домен ритейлера, на который будет доставлен рич-контент
templateType  Да Строка Тип возвращаемого шаблона, может принимать значения 'master_template' (html-шаблон) и 'img_template' (шаблон из картинок)
contentType  Да Строка Тип возвращаемого контента, может принимать значение 'minisite' и 'ar'
resultType  Да Строка Формат возвращаемого результата, может принимать значение 'html', 'iframe' и 'json', влияет на полученный результат, мы разберем его ниже
language Нет Строка

Код страны и языка для рич контента. Чтобы получить для определенной страны контент на определённом языке, необходимо отправить запрос в формате 'страна_язык'. Код страны и код языка необходимо указать по стандартам ISO (код страны указывается согласно ISO 3166-1, код языка - ISO 639-1). Если необходимо получить три страницы на трех языках, следует сделать три запроса, указав в каждом соответствующие параметры языка

По умолчанию этот параметр установлен 'ru'

Пример кода:


<script>
	TTLStreamReady.then(() => {
		ttlStream.find({
			brand: 'panasonic',
			productId: 'demoSKU',
			retailerDomain: 'beru.ru',
			templateType: 'master_template',
			resultType: 'html',
			contentType: 'minisite',
                       language: 'ru',
  }).then((data) => { // Функция будет вызвана в случае успешного нахождение контента // Переменная data будет содержать найденный контент }).catch((error) => { // Функция будет вызвана в случае, если контент не найден // Переменная error будет содержать данные о причинах ошибки }); }); </script>

Параметр resultType влияет на тип данных, которые будут возвращены, далее мы рассмотрим каждое из возможных его значений:

html

Переменная data в ответе будет содержать весь html-контент запрошенной страницы.

iframe

Переменная data в ответе будет содержать ссылку для вставки виджета как iframe.

json

Переменная data в ответе будет содержать необработанные данные в формате json.

Тип контента 'ar' (дополненная реальность)

Контент AR (англ. "augmented reality") - это визуализация товара в дополненной реальности, позволяющая продемонстрировать детализированную 3D копию продукта в пространстве.

Пример транслируемого AR-контента

Настройка AR

Для настройки отображения AR виджета используетя метод setArSettings.

Могут быть переданы следующие параметры:

Параметр Описание
preview Ряд настроек, которые отвечают за персональные настройки кнопки открытия
preview.html Текст кнопки

preview.style.backgroundColor

preview.style.backgroundImage

preview.style.backgroundSize

preview.style.backgroundRepeat

preview.style.backgroundPosition

Стили кнопки. Все стили пишутся как свойства объекта style
viewer Ряд настроек, которые отвечают за стилизацию просмотрщика
viewer.modalStyle Стили поп-апа. Все стили пишутся как свойства объекта style
viewer.viewerStyle Стили просмоторщика. Все стили пишутся как свойства объекта style
viewer.loaderColor Цвет полосы предзагрузки
viewer.closeStyle Стиль для кнопки закрытия просмотрщика. Все стили пишутся как свойства объекта style
qr Ряд настроек, которые отвечают за модальное окно QR кода
qr.modal.style Настройки стилей модального окна. Все стили пишутся как свойства объекта style
qr.box.style Настройки стилей блока с содержимым QR кода. Все стили пишутся как свойства объекта style
qr.btnOpen Настройки кнопки открытия модального окна QR кода
qr.btnOpen.html Текст кнопки
qr.btnOpen.style Стили кнопки. Все стили пишутся как свойства объекта style
qr.btnClose Настройки кнопки закрытия модального окна QR кода
qr.btnClose.html Текст кнопки
qr.btnClose.style Стили кнопки. Все стили пишутся как свойства объекта style
qr.title Настройки заголовка QR кода
qr.title.html Текст заголовка
qr.title.style Стили заголовка. Все стили пишутся как свойства объекта style
qr.subtitle Настройки подзаголовка QR кода
qr.subtitle.html Текст подзаголовка
qr.subtitle.style Стили подзаголовка. Все стили пишутся как свойства объекта style

Пример кода


<script>
  TTLStreamReady.then(() => {
      ttlStream.setArSettings({
          preview: {
              html: '',
              style: {
                  backgroundColor: '#231010',
                  backgroundImage: "url('https://24ar.tech/staticCDN/desktop/assets/buttons/ar.svg')",
                  backgroundSize: 'cover',
                  backgroundRepeat: 'no-repeat',
                  backgroundPosition: 'center',
              },
          },
          viewer: {
              modalStyle: {},
              viewerStyle: {},
              loaderColor: '#bd0d0d',
              closeStyle: {},
          },
          qr: {
              modal: {
                  style: {},
              },
              box: {
                  style: {},
              },
              btnOpen: {
                  html: 'Hello world!',
                  style: {},
              },
              btnClose: {
                  html: 'Закрыть',
                  style: {},
              },
              title: {
                  html: 'Как посмотреть в дополненной реальности',
                  style: {},
              },
              subtitle: {
                  html: 'Отсканируйте QR код с помощью камеры вашего телефона, чтобы посмотреть объект в реальности.',
                  style: {},
              },
          },
      });

      ttlStream.findAndInsert({
          el: '.myCoolWrapper',
          brand: 'panasonic',
          productId: 'demoSKU',
          retailerDomain: 'beru.ru',
          templateType: 'desktop',
          resultType: 'html',
          contentType: 'ar',
	  	});
	});
</script>
								
Использование findAndInsert для AR

Для типа контента AR используется исключительно метод findAndInsert.

Могут быть переданы следующие параметры:

Параметр  Обязательный Тип параметра Описание
el Да Строка CSS-селектор DOM-элемента, в который будет вставлен контент
brand Да Строка Название бренда для продукта которого будет доставлен рич-контент на сайт ритейлера
productId Да Строка Идентификатор продукта, которым продукт определённого бренда уникально обозначается для ритейлера этого бренда
retailerDomain Да Строка Домен ритейлера, на который будет доставлен рич-контент
templateType Нет Строка Тип используемого девайса, может принимать значения 'ios', 'android', 'desktop'. Если параметр не указан, девайс определяется автоматически
contentType Да Строка AR
resultType Да Строка Формат возвращаемого результата, может принимать значение 'html'
language Нет Строка

Код страны и языка для рич контента. Чтобы получить для определенной страны контент на определённом языке, необходимо отправить запрос в формате 'страна_язык'. Код страны и код языка необходимо указать по стандартам ISO (код страны указывается согласно ISO 3166-1, код языка - ISO 639-1). Если необходимо получить три страницы на трех языках, следует сделать три запроса, указав в каждом соответствующие параметры языка

По умолчанию этот параметр установлен 'ru'

throwError Нет Логическое значение

Значение не указано или в положении true: если рич-контент не найден, в консоле будет ошибка 404 (контент не найден). Необходимо будет обработать эту ошибку

Если установить значение false, в случае отсутствия контента ошибка не выдаётся; соответственно, нет необходимости её обрабатывать

iframeMode Нет Логическое значение

Если интеграция выполнена через iframe, для получения рич-контента необходимо использовать"iframeMode": true

Пример кода


<script>
	TTLStreamReady.then(() => {
		ttlStream.findAndInsert({
			el: '.myCoolWrapper',
			brand: 'panasonic',
			productId: 'demoSKU',
			retailerDomain: 'beru.ru',
			templateType: 'desktop',
			resultType: 'html',
			contentType: 'ar',
              }); }); </script>
Интеграция виджета в мобильное приложение
24STREAM Flutter

Flutter плагин для создания виджетов 24STREAM Rich Page.

Установка

В AndroidManifest.xml добавить разрешение на выход в интернет.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
...
<uses-permission android:name="android.permission.INTERNET"/>
...
</manifest>

Для установки добавьте stream24 в зависимости внутри pubspec.yaml вашего проекта.

dependencies:
  ...
stream24: ^0.1.2
...

Использование

Stream24RichPage

Webview виджет с рич контентом и автоматической настройкой высоты.

Параметр Тип Описание
brand string Обязательно. Название бренда страницы
productId string Обязательно. Идентификатор продукта страницы
retailerDomain string Обязательно. Домен ретейлера страницы
templateType string Обязательно. Тип шаблона страницы
language string Языковой код страницы в виде страна_язык. Код страны должен быть указан в стандарте ISO 3166-1, а код языка - в стандарте ISO 639-1. По умолчанию ru
onError Function(String) Функция, вызываемая при возникновении ошибки.
contentType Stream24ContentType Тип содержимого страницы. .shopInShops Или .minisite. По умолчанию .minisite

GetHtml

Возвращает HTML код страницы в виде строки.

Параметр Тип Описание
brand string Обязательно. Название бренда страницы
productId string Обязательно. Идентификатор продукта страницы
retailerDomain string Обязательно. Домен ретейлера страницы
templateType string Обязательно. Тип шаблона страницы
language string Языковой код страницы в виде страна_язык. Код страны должен быть указан в стандарте ISO 3166-1, а код языка - в стандарте ISO 639-1. По умолчанию ru
contentType Stream24ContentType Тип содержимого страницы. .shopInShops Или .minisite. По умолчанию .minisite

Примеры использования

Используя Stream24RichPage

import 'package:flutter/material.dart';
import 'package:stream24/stream24.dart';
import 'package:stream24/rich_page.dart';
import 'package:webview_flutter/webview_flutter.dart';



class WebViewPage extends StatefulWidget {
  WebViewPage({super.key});
  @override
  State<WebViewPage> createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
  @override
  Widget build(BuildContext context) {
    return  Stream24RichPage(
          brand: 'TestBrand',
          productId: '920-969696',
          retailerDomain: '24ttl.ru',
            templateType: 'master_template',
language: 'ru',

          contentType: Stream24ContentType.minisite,
            onError: (errorMsg){ print(errorMsg); }
        );
    }
}

ИЛИ

Используя getHtml

import 'package:flutter/material.dart';
import 'package:stream24/stream24.dart';
import 'package:webview_flutter/webview_flutter.dart';



class WebViewPage extends StatefulWidget {
  WebViewPage({super.key});
  @override
  State<WebViewPage> createState() => _WebViewPageState();
}



class _WebViewPageState extends State<WebViewPage> {
  late WebViewController controller;
    double height = 120;



  @override
  void initState() {
    super.initState();
       controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)



      // to automatically adjust height add the following block
      ..addJavaScriptChannel("FlutterWebviewHeight",
          onMessageReceived: (JavaScriptMessage msg) {
        setState(() {
          height = double.tryParse(msg.message) ?? 0;
        });
      })
      //////////////////////////////////////////////////////////////////



      //if you want to throw errors on 404 content add the following block
      ..addJavaScriptChannel("FlutterError",
          onMessageReceived: (JavaScriptMessage msg) {
            
        throw Exception(msg.message);
      })
      //////////////////////////////////////////////////////////////////



      ..loadHtmlString(Stream24.getHtml(
brand: 'TestBrand',
          productId: '920-969696',
          retailerDomain: '24ttl.ru',
            templateType: 'master_template',
language: 'ru',
          contentType: Stream24ContentType.minisite
));
  }



  @override
  Widget build(BuildContext context) {
    return SizedBox(
        height: height,
        child: WebViewWidget(
          controller: controller,
        ),
    );
  }
}
24STREAM Kotlin

Android плагин для использования Rich Page виджетов 24STREAM.

Установка

В AndroidManifest.xml добавить разрешение на выход в интернет.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
...
<uses-permission android:name="android.permission.INTERNET"/>
...
</manifest>

Для установки вам понадобится добавить JitPack в список репозиториев (если вы еще этого не сделали).
В старых проекта в корневом build.gradle файле добавьте  maven { url = uri("https://www.jitpack.io")} внутрь блока allprojects->repositories:

 allprojects {
repositories {
 ...
    maven {
            url = uri("https://www.jitpack.io")
        }

}
 }

В новых проектах он добавляется в settings.gradle. Он должен быть указан в dependencyResolutionManagement->repositories:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        ...
      maven {
            url = uri("https://www.jitpack.io")
        }

    }
}

Далее вам необходимо добавить сам плагин в зависимости(в build.gradle модуля приложения):

dependencies {
    ...
  implementation("stream.24ttl.git.pub:24stream_android:0.5.3") 
}

Использование

RichPage

Webview виджет с рич контентом и автоматической настройкой высоты.

Параметр Тип Описание
brand string Обязательно. Название бренда страницы
productId string Обязательно. Идентификатор продукта страницы
retailerDomain string Обязательно. Домен ретейлера страницы
templateType string Обязательно. Тип шаблона страницы
language string Языковой код страницы в виде страна_язык. Код страны должен быть указан в стандарте ISO 3166-1, а код языка - в стандарте ISO 639-1. По умолчанию ru
onError (String) -> Unit Функция, вызываемая при возникновении ошибки.
contentType Stream24ContentType Тип содержимого страницы. .shopInShops Или .minisite. По умолчанию .minisite

GetHTML

Возвращает HTML код страницы в виде строки.

Параметр Тип Описание
brand string Обязательно. Название бренда страницы
productId string Обязательно. Идентификатор продукта страницы
retailerDomain string Обязательно. Домен ретейлера страницы
templateType string Обязательно. Тип шаблона страницы
language string Языковой код страницы в виде страна_язык. Код страны должен быть указан в стандарте ISO 3166-1, а код языка - в стандарте ISO 639-1. По умолчанию ru
contentType Stream24ContentType Тип содержимого страницы. .shopInShops Или .minisite. По умолчанию .minisite

Примеры использования

Используя RichContent

import stream.ttl24.stream24.Stream24

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
      val rich = Stream24.RichContent(LocalContext.current, LocalDensity.current, "24ttl.ru", "TestBrand", "920-969696",  "master_template", "ru", ::onError, Stream24.Stream24ContentType.minisite)
        setContentView(rich)
    }
}


fun onError(errorMessage:String){
    print(errorMessage)
}

Используя GetHtml

import stream.ttl24.stream24.Stream24

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val webview = WebView(this)
      val html = Stream24.GetHTML("TestBrand", "920-969696", "24ttl.ru", "master_template", "ru", Stream24.Stream24ResultType.html, Stream24.Stream24ContentType.minisite)
        webview.getSettings().javaScriptEnabled = true
        webview.loadData(html,
            "text/html", "UTF-8")
        setContentView(webview)
    }
}
24STREAM Swift

iOS плагин для создания виджетов 24STREAM Rich Page.

Установка

24STREAM доступен в CocoaPods и Swift Package Manager. Для установки, добавьте следующую строку в Podfile:

pod '24stream'

Для установки через Swift Package Manager:

File -> Add packages... -> Вбейте в поиск 'https://git.24ttl.stream/pub/24stream_swift' -> Add package

Использование

Для начала следует импортировать плагин: import _24stream. После этого можно будет использовать функционал плагина:

WebView

Параметр Тип Описание
brand string Обязательно. Название бренда страницы
productId string Обязательно. Идентификатор продукта страницы
retailerDomain string Обязательно. Домен ретейлера страницы
templateType string Обязательно. Тип шаблона страницы
language string Языковой код страницы в виде страна_язык. Код страны должен быть указан в стандарте ISO 3166-1, а код языка - в стандарте ISO 639-1. По умолчанию ru
page string Название страницы. По умолчанию index.html
onError Function((Float) -> Void) Функция, вызываемая при возникновении ошибки.
contentType _24StreamContentType Тип содержимого страницы. .shopInShops Или .minisite. По умолчанию .minisite
onHeightSet Function((Float) -> Void) Функция, вызываемая при изменении высоты. Используется, чтобы иметь динамически подстраиваемую под контент высоту виджета.

Пример

import SwiftUI
import _24stream

struct ExamplePage: View {

    //необходимо для автоматического расчета высоты
    @State var richHeight: CGFloat = 0
    func setHeight(height:Float ) {
        richHeight = CGFloat(height)
    }

    // для обработки любых ошибок
    func onError(error: String) {
        print(error)
    }
    
    var body: some View  {
        ScrollView{
            RichPage(  brand: "TestBrand",
                       retailerDomain: "24ttl.ru",
                       productId: "920-969696",
                       templateType: "master_template",
                       language: "ru",
                       page: "index.html",
                       contentType: _24StreamContentType.minisite,
                       onHeightSet: setHeight,
                       onError: onError).frame(height:richHeight)
        }
        
    }
}

struct ExamplePage_Previews: PreviewProvider {
    static var previews: some View {
        ExamplePage()
    }
}
Back-to-back интеграция рич-контента

Серверное получение списка карточек и рич-контента через REST API

Общие сведения

Back-to-back интеграция позволяет ритейлеру получать рич-контент 24STREAM напрямую на сервер, без использования браузерного виджета. Это подходит для сценариев, когда контент нужно загрузить в собственную базу или CMS ритейлера и отдавать его на страницы товаров средствами самой площадки.

Рич-контент — это сочетание текстового описания, изображений, видео и анимации, которые дают более наглядное описание товара. Каждой единице рич-контента соответствует карточка (e-package). Работа с API строится вокруг двух шагов: сначала ритейлер получает список доступных ему карточек, затем по идентификатору карточки скачивает её HTML-контент.

Порядок работы

  • Получить список карточек, доступных вашей площадке (метод /search).
  • Сопоставить карточки со своими товарами по полю skuId.
  • Скачать HTML рич-контента по идентификатору карточки (/download).
  • Периодически запрашивать обновления по фильтру updatedAt и синхронизировать свою базу.

 

Доступ и аутентификация

Для доступа к API необходим API-ключ, который генерируется на стороне 24TTL. Для получения ключа и идентификатора ретейлера (retailerId) обратитесь к вашему ритейл-менеджеру.

Базовый URL:

https://panel.24ttl.stream/api/v1

Все запросы выполняются по протоколу HTTPS методом POST.

Заголовки запроса

Заголовок Значение Описание
Authorization ApiKey <ваш_ключ> Обязательный. API-ключ передаётся только в заголовке, не в теле запроса.
Content-Type application/json Обязательный
Accept-Charset utf-8 Рекомендуется

Общие соглашения

Формат даты и времени

Все даты передаются и возвращаются в формате ISO 8601, например 2026-08-01 00:00:00.

Пагинация

Списочные методы используют курсорную пагинацию. В ответе возвращается поле cursor; чтобы получить следующую страницу, передайте это значение в поле cursor следующего запроса. Пустой или отсутствующий курсор в ответе означает, что страниц больше нет.

Коды ответов

Код Значение
200 Запрос успешно обработан.
400 Некорректное тело запроса (ошибка валидации параметров).
401 Отсутствует или неверный API-ключ.
404 Запрошенный контент не найден.
429 Превышен лимит запросов. Повторите запрос позже.
Метод 1. Список карточек

Возвращает постраничный список карточек рич-контента, доступных вашей площадке. Метод используется как для первичной выгрузки всего списка, так и для получения только обновлённых карточек по фильтру updatedAt.

Запрос

url -X POST https://panel.24ttl.stream/api/v1/retailers/{retailerId}/retailer-epackages/search 
-H "Accept-Charset: utf-8" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey generatedApiKey" \
-d '{
"limit": 1000,
"cursor": "###",
"fields": ["name", "brand"] // Опциональные поля, которые будут добавлены в ответ
"filters ":{
  "updatedAt":{
    "gte": "yyyy-mm-dd hh:mm:ss"
    "gt": "yyyy-mm-dd hh:mm:ss" 
    "lte": "yyyy-mm-dd hh:mm:ss",
    "lt": "yyyy-mm-dd hh:mm:ss",
  },
  "isActive":{
    "eq": true
  },
  "skuId":{
    "in": ["example_sku_id"]
  },
  "reId":{
    "in": ["er_id"]
  }, 
}
}
' \

Параметры тела запроса

Параметр

Обяз.

Описание

limit

Нет

Количество элементов на странице. По умолчанию 100, максимум 1000.

cursor

Нет

Курсор пагинации. Для получения следующей страницы передайте значение cursor из предыдущего ответа.

fields

Нет

Дополнительные поля в ответе. Допустимые значения: name, brand.

filters.updatedAt.gte

Нет

Дата обновления «больше или равно».

filters.updatedAt.gt

Нет

Дата обновления «больше».

filters.updatedAt.lte

Нет

Дата обновления «меньше или равно».

filters.updatedAt.lt

Нет

Дата обновления «меньше».

filters.isActive.eq

Нет

Фильтр по активности карточки (true / false).

filters.skuId.in

Нет

Список пользовательских идентификаторов (skuId) для выборки конкретных карточек.

filters.reId.in

Нет

Список идентификаторов карточек (reId).

Фильтры по updatedAt удобно использовать для регулярного получения только изменившихся карточек — например, раз в час или раз в день за предыдущий период.

Ответ 200

{
 "code": 200,
 "message": "",
 "data":{
   "cursor": "eyJpZCI6...",
   "items": [
     {
       "reId": "12345678-1234-1234-1234-123456789012",
       "skuId": "ABC12",
       "isActive": true,
       "updatedAt": "2026-08-01T10:30:00+00:00",
       "name": "Название товара",
"brand": "Название бренда",

     }
   ]
 }
}

Поля ответа

Поле

Описание

data.cursor

Курсор для получения следующей страницы.

items[].reId

Идентификатор карточки. Используется в методах скачивания контента.

items[].skuId

Пользовательский идентификатор карточки (для сопоставления с вашим товаром).

items[].isActive

Признак активности карточки.

items[].updatedAt

Дата и время последнего обновления карточки.

items[].name

Название товара. Возвращается только если запрошено в fields.

items[].brand

Название бренда. Возвращается только если запрошено в fields.

Метод 2. Скачивание одной карточки

Возвращает HTML рич-контента для одной карточки по её reId.

Запрос

curl -X POST https://panel.24ttl.stream/api/v1/retailer-epackages/{reId}/download

-H "Accept-Charset: utf-8" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey generatedApiKey" \
-d '{
  "locale": "en",
  "contentType": "minisite",
  "template": "master_template",
  "format": "html",
  "source": "index.html"
  }'

Параметры

Параметр

Обяз.

Описание

{reId}

Да

Идентификатор карточки из метода 1 (в пути запроса).

locale

Да

Локаль рич-контента, например ru.

contentType

Нет

Тип контента. По умолчанию minisite.

template

Нет

Шаблон. По умолчанию master_template.

format

Нет

Формат контента. По умолчанию html.

source

Нет

Источник контента. По умолчанию index.html.

Ответы

Код

Тело ответа

200

HTML рич-контента карточки «как есть».

404

Карточка или её контент не найдены. Тело ответа — JSON с кодом ошибки (см. ниже).

Ответ 404

Возможные значения поля code в ответе 404:

{
 "code": 4040,
 "message": "Epackage retailer not found",
 "data": []
}

Код

Тело ответа

4040

Карточка не найдена.

4041

Не найден контент карточки.

Сценарии использования

Первичная загрузка рич-контента

  • Вызовите метод 1 и, проходя по пагинации, получите все доступные карточки.
  • Сопоставьте свои товары с карточками по skuId. Сохраните reId, skuId и updatedAt.
  • По reId скачайте HTML рич-контента (метод 2) и привяжите его к своему товару по паре reId + skuId.

 

Получение обновлений (по фильтру updatedAt)

  • Возьмите максимальный сохранённый updatedAt из своей базы (lastUpdatedAt = max(updatedAt)) и запросите метод 1 с фильтром filters.updatedAt.gt = lastUpdatedAt. Можно выполнять раз в час или раз в день.
  • Сравните полученный список обновлённых карточек с текущим состоянием вашей базы и примените действия по таблице ниже.
  • Для добавления или обновления контента используйте метод 2.

 

Матрица решений:

isActive в ответе skuId в вашей базе Действие
true Найден Обновить рич-контент.
true Не найден Создать запись и добавить рич-контент.
false Найден Удалить / снять рич-контент, если он есть.
false Не найден Ничего не делать.

Получение обновлений (полная выгрузка)

  • Получите весь список карточек, доступных вашей площадке (метод 1 без фильтра по дате).
  • По skuId найдите соответствующий товар и примените действия по матрице решений выше (добавить, обновить или снять рич-контент).

 

Для получения API-ключа, идентификатора ритейлера и параметров подключения обратитесь к вашему ритейл-менеджеру.

Песочница

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