# Инвойсбокс API — Маркетплейс и мини-приложения > Раздел документации целиком. Полное оглавление: https://docs.invoicebox.ru/llms.txt ## Маркетплейс и мини-приложения - [Добавление точки продаж](https://docs.invoicebox.ru/raw/marketplace/create.md) (раздел «Маркетплейс») - [Обновление точки продаж](https://docs.invoicebox.ru/raw/marketplace/update.md) (раздел «Маркетплейс») - [Акции и спецпредложения](https://docs.invoicebox.ru/raw/marketplace/special-offer.md) (раздел «Маркетплейс») - [Маркетплейс](https://docs.invoicebox.ru/raw/marketplace/marketplace.md) - [Общая информация](https://docs.invoicebox.ru/raw/marketplace/mini-apps/description.md) (раздел «Мини-приложения») - [Схема взаимодействия](https://docs.invoicebox.ru/raw/marketplace/mini-apps/schema.md) (раздел «Мини-приложения») - [Настройка заголовков](https://docs.invoicebox.ru/raw/marketplace/mini-apps/frame.md) (раздел «Мини-приложения») - [Мини-приложения](https://docs.invoicebox.ru/raw/marketplace/mini-apps/mini-apps.md) (раздел «Маркетплейс») - [Структура приложения](https://docs.invoicebox.ru/raw/marketplace/mini-apps/structure.md) (раздел «Мини-приложения») - [MiniApp SDK](https://docs.invoicebox.ru/raw/marketplace/mini-apps/miniapp-sdk.md) (раздел «Мини-приложения») - [Библиотека компонентов](https://docs.invoicebox.ru/raw/marketplace/mini-apps/components.md) (раздел «Мини-приложения») --- # Добавление точки продаж # Добавление точки продаж в маркетплейс Магазин и точка продаж добавляются в маркетплейс одним запросом: - метод: `POST` - ресурс: `/v3/marketplace/api/shop` - тело запроса - объект [CreateShopRequest](#createshoprequest) - тело ответа - объект [ShopResponse](#shopresponse) - Возможные [ошибки](/docs/dictionary/error/) #### Пример запроса ``` json POST /v3/marketplace/api/shop Authorization: Bearer b37c4c689295904ed21eee5d9a48d42e Content-Type: application/json User-Agent: MyApp 1.0 Accept: application/json { "title": "Тестовый магазин", "description": "Это наш тестовый магазин", "brandId": 123, "merchantId": "01771534-1a57-f184-dee3-ebeb91dded76", "externalUpdate": true } ``` Ответ (по схеме): ``` json { "data": { "id": 1, "title": "string", "description": "string", "shortDescription": "string", "seoTitle": "string", "seoKeywords": "string", "seoDescription": "string", "categoryId": 1, "shopDeliveryId": 1, "alias": "string", "shopUrl": "string", "minOrderSum": 100.5, "stockMode": "string", "priceMode": "string", "notificationEmail": "string", "defaultPriceId": 1, "imagePath": "string", "imageId": 1, "ogImagePath": "string", "ogImageId": 1, "mode": "string", "jivositeId": "01771534-1a57-f184-dee3-ebeb91dded75", "orderFlow": "string", "yandexMetrikaId": 1, "deliveryInfo": "string", "shopIds": {}, "accountProgramIds": {}, "type": "string", "orderLifetime": 1, "modelId": 1, "manualProperties": {}, "compiledProperties": {}, "properties": {}, "imageIds": {}, "modelIds": {}, "hours": { "mon": {}, "tue": {}, "wed": {}, "thu": {}, "fri": {}, "sat": {}, "sun": {} }, "address": "string", "lat": 100.5, "lon": 100.5, "distance": 100.5, "externalId": "01771534-1a57-f184-dee3-ebeb91dded75", "brandId": 1, "merchantId": "01771534-1a57-f184-dee3-ebeb91dded75", "countryId": "01771534-1a57-f184-dee3-ebeb91dded75", "cityId": 1, "active": false, "priority": 1, "merchantCategoryId": 1, "status": "string", "contactEmail": "string", "contactPhone": "string", "contactVkLink": "string", "contactTgLink": "string", "contactOkLink": "string" }, "metaData": { "totalCount": 1, "pageSize": 1, "page": 1 }, "extendedData": [ { "type": "string", "data": {} } ] } ``` ## CreateShopRequest | Свойство | Обязательное | Тип | Описание | Пример значения | |-------------------|--------------|---------------|----------------------------------------------------------------------------|---------------------------------------------------------------------------------| | title | да | string(50) | Название магазина | `Тестовый магазин` | | description | нет | string(2000) | Описание магазина | `Это наш первый тестовый магазин` | | brandId | нет | int | Идентификатор магазина с типом brand | 123 | | merchantId | нет | string(36) | Идентификатор магазина Инвойсбокс, для подгрузки чсти данных из Инвойсбокс | `01771534-1a57-f184-dee3-ebeb91dded76` | | accountProgramIds | нет | array | Массив идентификаторов программ лояльностей, котоыре принимает точка | [`01771534-1a57-f184-dee3-ebeb91dded71`,`01771534-1a57-f184-dee3-ebeb91dded72`] | ## ShopResponse Повторяет свойства объекта [CreateShopRequest](#createshoprequest) с дополнительными свойствами: | Свойство | Обязательное | Тип | Описание | Пример значения | |-------------------|--------------|-----------------|----------------------------------------------------------------------|---------------------------------------------------------------------------------| | id | да | int | Идентификатор магазина | 12 | | token | да | string(64) | Токен магазина | `95e5396611d261986cec0915a9f85799` | | type | да | string(50) enum | Тип магазина | `shop`,`marketplace`,`external`,`offline`,`brand` | | alias | да | string(20) | Алиас магазина | `1694158899` | | shopUrl | да | string(64) | Ссылка на магазин | `https://1694158899.expressclient.ru` | | accountProgramIds | нет | array | Массив идентификаторов программ лояльностей, которые принимает точка | [`01771534-1a57-f184-dee3-ebeb91dded71`,`01771534-1a57-f184-dee3-ebeb91dded72`] | --- # Обновление точки продаж # Обновление точки продаж Точка продаж меняется по своему идентификатору: - метод: `PUT` - ресурс: `/v3/marketplace/api/shop/:id` - где `:id` это идентификатор точки продаж - тело запроса - объект [UpdateShopRequest](#updateshoprequest) - тело ответа - объект [ShopResponse](#shopresponse) - Возможные [ошибки](/docs/dictionary/error/) #### Пример запроса ``` json PUT /v3/marketplace/api/shop/1 Authorization: Bearer b37c4c689295904ed21eee5d9a48d42e Content-Type: application/json User-Agent: MyApp 1.0 Accept: application/json { "description": "Это наш тестовый магазин", "notificationEmail": "test@test.me", "jivositeId": "321314123123", "yandexMetrikaId": 432141251234, "deliveryInfo": "Когда хотим, тогда и доставляем", "registrationAddress": "Санкт-Петербург, улица Рубинштейна, дом 12", "lat": 59.931228, "lon": 30.345557, "brandId": 123, "merchantId": "01771534-1a57-f184-dee3-ebeb91dded76", "externalUpdate": true } ``` Ответ (по схеме): ``` json { "data": { "id": 1, "title": "string", "description": "string", "shortDescription": "string", "seoTitle": "string", "seoKeywords": "string", "seoDescription": "string", "categoryId": 1, "shopDeliveryId": 1, "alias": "string", "shopUrl": "string", "minOrderSum": 100.5, "stockMode": "string", "priceMode": "string", "notificationEmail": "string", "defaultPriceId": 1, "imagePath": "string", "imageId": 1, "ogImagePath": "string", "ogImageId": 1, "mode": "string", "jivositeId": "01771534-1a57-f184-dee3-ebeb91dded75", "orderFlow": "string", "yandexMetrikaId": 1, "deliveryInfo": "string", "shopIds": {}, "accountProgramIds": {}, "type": "string", "orderLifetime": 1, "modelId": 1, "manualProperties": {}, "compiledProperties": {}, "properties": {}, "imageIds": {}, "modelIds": {}, "hours": { "mon": {}, "tue": {}, "wed": {}, "thu": {}, "fri": {}, "sat": {}, "sun": {} }, "address": "string", "lat": 100.5, "lon": 100.5, "distance": 100.5, "externalId": "01771534-1a57-f184-dee3-ebeb91dded75", "brandId": 1, "merchantId": "01771534-1a57-f184-dee3-ebeb91dded75", "countryId": "01771534-1a57-f184-dee3-ebeb91dded75", "cityId": 1, "active": false, "priority": 1, "merchantCategoryId": 1, "status": "string", "contactEmail": "string", "contactPhone": "string", "contactVkLink": "string", "contactTgLink": "string", "contactOkLink": "string" }, "metaData": { "totalCount": 1, "pageSize": 1, "page": 1 }, "extendedData": [ { "type": "string", "data": {} } ] } ``` ## UpdateShopRequest | Свойство | Обязательное | Тип | Описание | Пример значения | |---------------------|--------------|-----------------|-------------------------------------------------------------------------------------|----------------------------------------------------------------------------------| | description | нет | string(2000) | Описание магазина | `Это наш первый тестовый магазин` | | shopUrl | нет | string(64) | Ссылка на магазин | `https://1694158899.expressclient.ru` | | minOrderSum | нет | float | Минимальная сумма заказа | 99.99 | | notificationEmail | нет | string(500) | Email для отправки уведомлений | `test@test.me` | | yandexMetrikaId | нет | int | | 12332134222 | | deliveryInfo | нет | string(1000) | Описание доставки | `Не доставляем по выходным и праздникам` | | type | нет | string(50) enum | Тип магазина | `shop`,`marketplace`,`external`,`offline`,`brand` | | registrationAddress | нет | string(200) | Адрес магазина | `Санкт-Петербург, улица Рубинштейна, дом 12` | | lat | нет | float | Широта нахождения магазина | 59.931228 | | lon | нет | float | Долгота нахождения магазина | 30.345557 | | brandId | нет | int | Идентификатор магазина с типом brand | 123 | | merchantId | нет | string(36) | Идентификатор магазина Инвойсбокс, работает только в связвке с полем externalUpdate | `01771534-1a57-f184-dee3-ebeb91dded76` | | accountProgramIds | нет | array | Массив идентификаторов программ лояльностей, которые принимает точка | [`01771534-1a57-f184-dee3-ebeb91dded71`,`01771534-1a57-f184-dee3-ebeb91dded72`] | ## ShopResponse Повторяет свойства объекта [UpdateShopRequest](#updateshoprequest): --- # Акции и спецпредложения # Управление акциями и спецпредложениями магазина Магазин может управлять набором акций и спецпредложений, которые будут отображены в маркетплейсе. Для добавления или изменения спецпредложения, отправьте следующий запрос: - метод: `POST` - ресурс: `/v3/billing/api/merchant/special-offer` - тело запроса - объект [CreateSpecialOfferRequest](#createspecialofferrequest) - тело ответа - объект [SpecialOfferResponse](#specialofferresponse) - Возможные [ошибки](/docs/dictionary/error/) #### Пример запроса и ответа ``` json POST /special-offer Authorization: Bearer b37c4c689295904ed21eee5d9a48d42e Content-Type: application/json User-Agent: MyApp 1.0 Accept: application/json { "merchantId" : "ffffffff-ffff-ffff-ffff-ffffffffffff", "externalId" : "1234", "active" : true, "startAt" :"2023-01-01T12:00:00Z", "finishAt" :"2029-01-01T23:59:59Z", "name" : "Скидка на День Рождения", "description" : "Скидка 15% на всё меню в день рождения", "tags" : [ "birthday" ] } ``` ``` json { "data":{ "id" : 123, "merchantId" : "ffffffff-ffff-ffff-ffff-ffffffffffff", "externalId" : "1234", "active" : true, "startAt" : "2023-01-01T12:00:00Z", "finishAt" : "2029-01-01T23:59:59Z", "name" : "Скидка на День Рождения", "description" : "Скидка 15% на всё меню в день рождения", "tags" : [ "birthday" ] } } ``` Ответ (по схеме): ``` json { "data": { "id": 1, "merchantId": "01771534-1a57-f184-dee3-ebeb91dded75", "externalId": "01771534-1a57-f184-dee3-ebeb91dded75", "active": false, "startAt": "2026-08-03T12:00:00+03:00", "finishAt": "2026-08-03T12:00:00+03:00", "name": "string", "description": "string", "tags": {} }, "metaData": { "totalCount": 1, "pageSize": 1, "page": 1 }, "extendedData": [ { "type": "string", "data": {} } ] } ``` ## CreateSpecialOfferRequest | Свойство | Обязательное | Тип | Описание | Пример значения | |-----------------|--------------|-----------------|---------------------------------------------------------------------|----------------------------------------| | merchantId | да | string(36) | Идентификатор магазина | `01771534-1a57-f184-dee3-ebeb91dded76` | | externalId | да | string(36) | Идентификатор спецпредложения во внтуренней системе учёта магазина | `1234` | | active | да | bool | Флаг активности спецпредложения | `true` | | startAt | да | datetime | Время начала действия спецпредложения | `2023-01-01T12:00:00Z` | | finishAt | да | datetime | Время окончания действия спецпредложения | `2029-01-01T23:59:59Z` | | description | да | string(1000) | Описание | `Скидка 15% на всё меню в день рождения` | | tags | да | array of string | Теги | `birthday` | ## SpecialOfferResponse Повторяет свойства объекта [CreateSpecialOfferRequest](#createspecialofferrequest) с дополнительными свойствами: | Свойство | Обязательное | Тип | Описание | Пример значения | |---------------------------|--------------|-------|--------------------------------------------------|-----------------| | id | да | int | Идентификатор спецпредложения в маркетплейсе | `123` | --- --- # Маркетплейс # Размещение магазина/точки продаж в маркетплейсе Инвойсбокс Маркетплейс — это Витрина Инвойсбокс: каталог поставщиков, зарегистрированных в системе. Магазин публикует информацию о себе на ресурсах Инвойсбокса и может продавать через [мини-приложения](/docs/marketplace/mini-apps) — и в самом каталоге, и на [платёжной странице](/docs/merchant/payment-page/) в качестве дополнительных услуг. Пример: транспортная компания продаёт трансфер пассажиру, который в этот момент оплачивает авиабилет. Так работает любая пара категорий, если нет конфликта интересов. Магазин самостоятельно принимает решение о размещении информации в маркетплейсе. Чтобы разместить информацию, добавьте точку продаж и опишите её: название, описание, адрес, координаты, ссылки, фотографии, логотип и прочее. Маркетплейс представлен на платёжной странице Инвойсбокс, в сервисе маркетплейс Инвойсбокс и приложении Инвойсбокс. Точка продаж в рамках маркетплейса может предлагать товары или услуг как напрямую, так и в качестве сервиса дополнительных услуг в процессе основной покупки на платёжной странице Инвойсбокс. Например, такие услуги как транфсер или такси могут являться дополнительными услугами при продаже [авиабилетов](/docs/scenarios/air-carriers) или [железнодорожных](/docs/scenarios/railway-carriers) билетов. Точка продаж в рамках маркетплейса может являтся как офлайн точкой с конктерным физическим адресом, так и онлайн точкой. Онлайн точка может иметь [мини-приложение](/docs/marketplace/mini-apps/) (форма продажи), с помощью которого покупатель сможет оформить заказ непосредственно из маркетплейса Инвойсбокс. См. [схему взаимодействия](/docs/marketplace/mini-apps/schema/). Через API для работы с маркетплейсом, возможно добавлять и управлять точками продаж. ## Кросс-продажи на платёжной странице Второй источник продаж — чужая покупка. Пока покупатель оплачивает авиабилет, ему можно предложить трансфер; пока оплачивает поездку — страховку. Мини-приложение точки продаж показывается прямо на [платёжной странице](/docs/merchant/payment-page/), и покупателю не нужно никуда уходить. Отличие от продажи в самом каталоге — в том, чем заканчивается оформление: | Где продаёте | Что создаёт мини-приложение | Чем заканчивается | |---|---|---| | Витрина Инвойсбокса | свой [заказ](/docs/merchant/order/create/) | покупатель платит отдельным счётом | | Платёжная страница чужой покупки | [обновление переданного заказа](/docs/merchant/order/update/) | услуга попадает в счёт, который покупатель уже оплачивает | Оба режима по шагам — в [схеме взаимодействия](/docs/marketplace/mini-apps/schema/); методы, которыми мини-приложение говорит с родительским окном, — в [MiniApp SDK](/docs/marketplace/mini-apps/miniapp-sdk/). Чтобы предложение выглядело предложением, а не строкой в списке, точке продаж пригодятся [акции и спецпредложения](/docs/marketplace/special-offer/): срок действия, описание и признак активности задаются одним запросом. Пара категорий подбирается по смыслу: трансфер к билету, страховка к поездке, доставка к заказу. Условие одно — между продавцами нет конфликта интересов. Как это выглядит со стороны площадки, разобрано в кейсе [маркетплейса и сплит-корзины](/docs/scenarios/marketplace-split/). ## Читайте также - [Что можно сделать через API: добавить точку продаж](/docs/marketplace/create/) --- --- # Общая информация # Описание работы мини-приложения Как правило, мини-приложение состоит из двух основных компонентов - интерфейса приложения (frontend) и серверной части (backend). Интерфейс мини-приложения отвечает за взаимодействие с покупателем и интерфейсом Инвойсбокс (родительским окном). Для взаимодействия интерфейса мини-приложения с интерфейсом Инвойсбокс, вы можете использовать [MiniApp SDK](/docs/marketplace/mini-apps/miniapp-sdk/). Серверная часть мини-приложения отвечает за передачу данных между мини-приложением, магазином и системой Инвойсбокс. Серверная часть мини-приложения взаимодействует с системой Инвойсбокс через [методы API](/docs/api). > [!WARNING] > Обратите внимание, сервер, на котором расположено мини-приложение, должен отправлять заголовки, которые разрешают запускать контент мини-приложения на сторонних ресурсах в iframe. [Читать подробнее](/docs/marketplace/mini-apps/frame/) о настройках заголовков. Мини-приложение может быть инициализировано в двух основных режимах: - В качестве формы основного заказа (тип мини-приложения - `order`) - В качестве формы заказа дополнительной услуги (тип мини-приложения - `suborder`) В случае, если мини-приложение инициализируется в маркетплейсе или приложении Инвойсбокс, оно представляет из себя форму основного заказа. При инициализации, мини-приложение может получить от интерфейса Инвойсбокс сведения о покупателе (имя, адрес эл. почты, номер телефона), а также идентификатор точки продаж. Через интерфейс мини-приложения, покупатель выбирает необходимые товары и услуги, оформляет покупку. Мини-приложение, в соответствии со своими внутренними процессами, формирует заказ и через серверную часть передаёт в систему Инвойсбокс информацию о заказе, а в ответ получает ссылку для переадресации покупателя на платёжную форму. Получив ссылку, мини-приложение передаёт её родительскому окну для инициализации процесса оплаты заказа покупателем. После подтверждения оплаты заказа, покупатель может быть возвращён в мини-приложение магазина для продолжения процесса оформления покупки. В случае, если мини-приложение инициализируется на платёжной странице Инвойсбокс, оно представляет из себя форму заказа дополнительной услуги. Отличие от основной формы заказа: родительское окно передаст мини-приложению идентификатор основного заказа. Оформленный заказ в мини-приложении будет добавлен и в конечном счёте оплачен покупателем одним платежом. --- --- # Схема взаимодействия # Схема взаимодействия магазина, мини-приложения и маркетплейса Инвойсбокс Мини-приложение работает в одном из двух режимов, и от режима зависит почти всё: кто открывает платёжную страницу, куда возвращается покупатель и в какой момент магазин узнаёт об оплате. Ниже — обе схемы по отдельности. ## Мини-приложение как форма основного заказа Покупатель приходит из Витрины, оформляет покупку в мини-приложении и оплачивает её отдельным счётом.
sequenceDiagram autonumber participant Покупатель participant Витрина participant Мини-приложение participant Инвойсбокс participant Магазин rect rgba(43, 170, 93, 0.13) Покупатель->>Витрина: Выбор товара или услуги Витрина->>Мини-приложение: Инициализация Покупатель->>Мини-приложение: Оформление заказа Мини-приложение->>Инвойсбокс: Создание заказа Инвойсбокс->>Мини-приложение: Ссылка на оплату Мини-приложение->>Покупатель: Переход на платёжную страницу Покупатель->>Инвойсбокс: Оплата счёта Инвойсбокс->>Магазин: Уведомление об оплате Инвойсбокс->>Мини-приложение: Возврат покупателя Мини-приложение->>Покупатель: Что оплачено и что дальше end
1. Покупатель ищет товар, услугу или точку продаж в [Витрине Инвойсбокса](/docs/marketplace/). 1. Витрина открывает [мини-приложение](/docs/marketplace/mini-apps/) магазина. 1. Покупатель оформляет заказ в мини-приложении. 1. Мини-приложение вызывает [создание заказа](/docs/merchant/order/create/) от имени магазина. 1. В ответе приходит `paymentUrl` — ссылка на платёжную страницу. 1. Мини-приложение открывает платёжную страницу: методом [onDone](/docs/marketplace/mini-apps/miniapp-sdk/#метод-ondone), если работу можно завершить, или [onCheckout](/docs/marketplace/mini-apps/miniapp-sdk/#метод-oncheckout), если после оплаты нужно вернуться в мини-приложение. На мобильном устройстве с установленным приложением Инвойсбокс открывается приложение. 1. Покупатель подтверждает оплату счёта. 1. Инвойсбокс сообщает магазину [об оплате](/docs/merchant/notification/status/). 1. Покупатель возвращается в мини-приложение; при `onCheckout` вызывается [обработчик onPaymentResult](/docs/marketplace/mini-apps/miniapp-sdk/#обработчик-onpaymentresult) со статусом заказа. 1. Мини-приложение показывает, что оплачено, и передаёт управление родительскому окну. ## Мини-приложение как форма дополнительного заказа Покупатель уже оплачивает основную покупку на платёжной странице, а мини-приложение продаёт ему дополнительную услугу — трансфер к билету, страховку к поездке, доставку к заказу.
sequenceDiagram autonumber participant Покупатель participant Платёжная страница participant Мини-приложение participant Инвойсбокс participant Магазин rect rgba(31, 111, 235, 0.12) Покупатель->>Платёжная страница: Оплата основной покупки Платёжная страница->>Мини-приложение: Инициализация с идентификатором заказа Покупатель->>Мини-приложение: Выбор дополнительной услуги Мини-приложение->>Инвойсбокс: Обновление переданного заказа Мини-приложение->>Платёжная страница: onDone — управление возвращено Покупатель->>Инвойсбокс: Оплата счёта целиком Инвойсбокс->>Магазин: Уведомление об оплате end
1. Покупатель открывает платёжную страницу основной покупки — например, авиабилета. 1. Платёжная страница открывает мини-приложение и передаёт ему идентификатор текущего заказа. 1. Покупатель выбирает дополнительную услугу. 1. Мини-приложение [обновляет переданный заказ](/docs/merchant/order/update/) — своего счёта здесь не появляется, услуга добавляется в тот, который покупатель уже оплачивает. 1. Мини-приложение сообщает родительскому окну об успехе методом [onDone](/docs/marketplace/mini-apps/miniapp-sdk/#метод-ondone) и закрывается. 1. Покупатель оплачивает счёт целиком — вместе с дополнительной услугой. 1. Инвойсбокс сообщает магазину [об оплате](/docs/merchant/notification/status/). > [!NOTE] > В обоих режимах мини-приложение сообщает родительскому окну и о неудачах: об ошибке — > [onError](/docs/marketplace/mini-apps/miniapp-sdk/#метод-onerror), о собственной недоступности — > [onUnavailable](/docs/marketplace/mini-apps/miniapp-sdk/#метод-onunavailable). Молчание мини-приложения > родительское окно трактовать не умеет. --- --- # Настройка заголовков # Настройка отображения мини-приложения Для корректной работы мини-приложения в экосистеме Инвойсбокс, сервер мини-приложения должен позволять отображать его и связанное содержимое в iframe. Если в своём мини-приложении при отправке ответов с сервера вы используете заголовок `Content-Security-Policy`, то рекомендуем внести правки, чтобы поддержать его корректную работу. [Подробнее о Content Security Policy](https://developer.mozilla.org/ru/docs/Web/HTTP/CSP). **Пример настройки Nginx** ```nginx add_header Content-Security-Policy "frame-ancestors 'self' *.invoicebox.ru"; ``` **Пример настройки Apache** ```apacheconf Header always set Content-Security-Policy "frame-ancestors 'self' *.invoicebox.ru"; ``` ## Заголовок X-Frame-Options придётся убрать Если сервер мини-приложения отдаёт `X-Frame-Options` со значением `DENY` или `SAMEORIGIN`, приложение не откроется: браузер заблокирует кадр, и покупатель увидит пустой прямоугольник. Значение `ALLOW-FROM` современные браузеры не поддерживают, поэтому «разрешить только Инвойсбоксу» этим заголовком нельзя. Уберите заголовок и оставьте только `Content-Security-Policy: frame-ancestors` — пример настройки выше. Если оба заголовка присутствуют, браузер видит противоречие и запрещает встраивание. **Как проверить.** Откройте страницу мини-приложения в кадре на любой своей странице. Если она не показывается, в консоли браузера будет сообщение о `frame-ancestors` или `X-Frame-Options` — по нему видно, какой из заголовков блокирует. > [!WARNING] > Обратите внимание, если в своём мини-приложении при отправке ответов с сервера вы используете заголовок `X-Frame-Options`, то рекомендуем внести правки, чтобы поддержать корректную работу в современных браузерах. Использование заголовка `X-Frame-Options` устарел и может не поддерживаться. --- --- # Мини-приложения # Мини-приложения Мини-приложения — это открытая платформа встраиваемых кросс-платформенных приложений с помощью которых магазины могут предоставить витрину своих товаров и услуг на площадках системы Инвойсбокс - на платёжной странице, маркетплейсе и приложениях Инвойсбокс (далее - маркетплейс Инвойсбокс). Мини-приложение представляет из себя сервис оформления заказа (форму оформления заказа) магазина, реализованную в соответствии с требованиями [дизайн-системы Инвойсбокс](/docs/design) и работающую на стороне магазина. --- --- # Структура приложения # Структура приложения Для того, чтобы мини-приложение нативно отображалось в экосистеме Инвойсбокс, оно должно поддерживать обязательный набор экранов: - **Скелетон.** Скелетон должен отображаться сразу при навигации по ссылке мини-приложения и до тех пор, пока оно не будет полностью инициализировано (загружены необходимые данные, изображения, стили и прочие ресурсы) См. также: | [Storybook](https://ui.invoicebox.ru/?path=/docs/common-skeleton--docs) | [GutHub](https://github.com/InvoiceBox/invoicebox-ui/tree/main/src/components/common/Skeleton) - **Экран(ы) выбора и оформления услуги.** Мы рекомендуем реализовать процесс с использванием не более 3х-4х экранов для выбора и оформления покупки. В противном случае возврастает вероятность того, что покупатель запутается и завершит процесс без покупки из-за избытка информации. - **Экран успешной оплаты заказа.** Ссылка на такой экран должна быть передана серверной частью мини-приложения в систему Инвойсбокс при [создании заказа](/docs/merchant/order/create/). Пользователь будет возвращён на такой экран только в том случае, когда через мини-приложение оформляется основной заказ (тип мини-приложения `order`). В связи с тем, что информация от системы Инвойсбокс об оплате заказа поступает асинхронно, мы рекомендуем на таком экране покупателю отображать загрузчик до момента получения статуса оплаты или отобразить дополнительную информацию по истечению срока ожидания. - **Экран неуспешной оплаты заказа.** Ссылка на такой экран должна быть передана серверной частью мини-приложения в систему Инвойсбокс при [создании заказа](/docs/merchant/order/create/). Пользователь будет возвращён на такой экран только в том случае, когда через мини-приложение оформляется основной заказ (тип мини-приложения `order`). См. также: | [Storybook](https://ui.invoicebox.ru/?path=/docs/common-invoiceboxloader--docs) | [GutHub](https://github.com/InvoiceBox/invoicebox-ui/tree/main/src/components/common/InvoiceboxLoader) --- --- # MiniApp SDK # Инвойсбокс MiniApp SDK Библиотека `minapp-sdk` позволяет мини-приложениям использовать API Инвойсбокс и API операционной системы, установленной на устройстве пользователя. Библиотека — мост между мини-приложениями, работающими на стороне пользователя, и клиентской частью Инвойсбокс (десктопной версией платёжного сервиса, мобильной версией платёжного сервиса или мобильным приложением). Именно они обмениваются данными с серверами Инвойсбокс, а библиотека работает как посредник на стороне пользователя. - NPM: [minapp-sdk](https://www.npmjs.com/package/@invoicebox/minapp-sdk) - GitHub: [minapp-sdk](https://github.com/InvoiceBox/invoicebox-minapp-sdk) ## Как использовать библиотеку MiniApp SDK Чтобы использовать библиотеку: 1. Создайте проект мини-приложения 2. [Подключите MiniApp SDK](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-miniapp-sdk) 3. Используйте методы: - Метод [invoiceboxMinapp.connect](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-connect). Установить соединение с родительским окном. - Метод [invoiceboxMinapp.disconnect](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-disconnect). Разорвать соединение с родительским окном. - Метод [invoiceboxMinapp.isConnected](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-isconnected). Узнать, установлено ли соединение с родительским окном. - Метод [invoiceboxMinapp.getInitialData](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-getinitialdata). Получить данные покупателя от родительского окна. - Метод [invoiceboxMinapp.matchMetaDataValues](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-matchmetadatavalues). Узнать, есть ли в метаданных нужная информация. - Метод [invoiceboxMinapp.getMetaDataValues](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-getmetadatavalues). Получить, из метаданных нужную информацию. 4. Обработайте события: - Метод [invoiceboxMinapp.onHeightChange](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-onheightchange). Сообщить родительскому окну параметры высоты мини-приложения. - Метод [invoiceboxMinapp.onDone](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-ondone). Сообщить родительскому окну о готовности заказа к оплате. - Метод [invoiceboxMinapp.onCheckout](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-oncheckout). Открыть платежную страницу поверх мини-приложения с возможностью вернуться. - Обработчик [invoiceboxMinapp.onPaymentResult](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA-onpaymentresult). Обработать результат оплаты после возврата в мини-приложение. - Метод [invoiceboxMinapp.onError](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-onerror). Сообщить родительскому окну об ошибке в мини-приложении. - Метод [invoiceboxMinapp.onLink](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-onlink). Сообщить родительскому окну о необходимости открыть страницу. - Метод [invoiceboxMinapp.onUnavailable](/docs/marketplace/mini-apps/miniapp-sdk/#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4-onunavailable). Сообщить родительскому окну, что мини-приложение недоступно. Инструкция ниже актуальна для любой операционной системы. Для первых шагов потребуется знание языка JavaScript и умение работать с командной строкой. ## Подключение MiniApp SDK Родительским окном мини-приложения может быть `iframe` или `WebView`. ### Через пакет NPM Перейдите в созданный проект мини-приложения: ```bash cd <ПУТЬ_К_МИНИ_ПРИЛОЖЕНИЮ> ``` Установите библиотеку: ```bash npm install @invoicebox/minapp-sdk || yarn add @invoicebox/minapp-sdk ``` Инициализируйте MiniApp SDK в файле index.js: ```javascript import { invoiceboxMinapp } from '@invoicebox/minapp-sdk'; invoiceboxMinapp.connect(); ``` ### Включение скрипта в HTML-код страницы Этот способ подходит, если вы не используете менеджеры пакетов, такие как npm или yarn, для создания своего HTML-приложения. **В код каждой HTML-страницы, где вы будете вызывать библиотеку, добавьте ссылку на файл index.min.js** В репозитории MiniApp SDK этот файл находится в папке cjs (commonjs modules). Мы рекомендуем ссылаться на копию файла, расположенную на сервисе unpkg.com. В этом случае вы автоматически будете получать последнюю версию библиотеки и вам не нужно будет самостоятельно следить за выходом её обновлений. ```html ``` **В коде каждой HTML-страницы, где вы будете вызывать библиотеку, инициализируйте MiniApp SDK** ```html ``` ## Методы, которые вызывает мини-приложение Все перечисленные ниже вызовы делает само мини-приложение: сообщает высоту, завершает работу, открывает ссылку, переходит к оплате. Единственный обработчик, который оно устанавливает, — [onPaymentResult](#обработчик-onpaymentresult). ### Метод connect Для того, чтобы установить соединение с родительским окном, воспользуйтесь методом `connect`. ```ts connect(): void; ``` ### Метод disconnect Чтобы разорвать соединение с родительским окном, воспользуйтесь методом `disconnect`. ```ts disconnect(): void; ``` ### Метод isConnected Чтобы узнать установлено ли соединение с родительским окном, воспользуйтесь методом `isConnected`. ```ts isConnected(): boolean; ``` ### Метод getInitialData Для того, чтобы получить данные покупателя для оформления заказа, воспользуйтесь методом `getInitialData`. ```ts getInitialData(): Promise<{ shopId?: number; userEmail: string; userName: string; userPhone: string; fullHeight: boolean; locale: string; } & ( | { orderContainerId?: never; minappType: 'order'; } | { orderContainerId: string; minappType: 'suborder'; } )> ``` - minappType - значение `order` указывает, что мини-приложение работает в режиме основного заказа, значение `suborder` - в режиме дополнительной услуги - orderContainerId - обязательно, если `minappType: 'suborder'`, отсутствует, если `minappType: 'order'`, идентификатор родительского заказа, если этот заказ — дополнительная услуга - shopId - опционально, идентификатор точки продаж, если мини-приложение работает с множеством точек продаж - userEmail - адрес электронной почты покупателя - userName - имя покупателя - userPhone - номер мобильного телефона покупателя - fullHeight - флаг сообщающий, что мини-приложение должно занять всю высоту контейнера, в котором располагается - locale - локаль Пример использования ```ts invoiceboxMinapp.getInitialData().then(console.log); /* { minappType: 'suborder', orderContainerId: '3c15a3d1-3da8-4ba8-87e5-2dba828299fa', shopId: 123, userEmail: 'email@example.com', userName: 'Иван Иванов', userPhone: '+71231234567', fullHeight: false, locale: 'ru'; } */ ``` ### Метод matchMetaDataValues Общая информация по наличию метаданных в заказах описана в [документации](/docs/merchant/order/metadata/). Для того, чтобы узнать есть ли нужная информация в метаданных, воспользуйтесь методом `matchMetaDataValues`. ```ts matchMetaDataValues(targetKey: string, targetValues: unknown[]): Promise ``` - targetKey - ключ (название свойства) по которому будет осуществлен поиск - targetValues - массив возможных значений, если хотя бы одно значение из этого массива совпадет со значемием в метаданных, функция вернет `true`, в противном случае `false` Пример использования ```ts /* если метаданные содержат поле iataCode: "SU" или iataCode: "LED", метод вернет true */ invoiceboxMinapp .matchMetaDataValues("iataCode", ["SU", "LED"]) .then((isMatch) => { if (isMatch) { // do something } }); ``` ### Метод getMetaDataValues Для того, чтобы получить нужную информацию из метаданных, воспользуйтесь методом `getMetaDataValues`. ```ts getMetaDataValues(targetKey: string | string[]): Promise ``` - targetKey - ключ (название свойства) или массив ключей по котороым будет осуществлен поиск Пример использования ```ts invoiceboxMinapp .getMetaDataValues(["flightNumber", "departureTime"]) .then(console.log); /* ['NDJ37S', '2022-03-04T20:15:00+03:00'] */ ``` ### Метод onHeightChange Для управления высотой мини-приложения на платёжной странице используется метод `onHeightChange`. Мини-приложение может задать высоту, которая требуется для корректного отображения мини-приложения на платёжной странице. ```ts onHeightChange(height: number): void; ``` Пример использования ```ts const Conatiner = ({ children }: { children: ReactNode }) => { const [elRef, setElRef] = useState(null); useEffect(() => { if (!elRef) return; const observer = new ResizeObserver(() => { invoiceboxMinapp.onHeightChange(elRef.offsetHeight); }); observer.observe(elRef); return () => observer.disconnect(); }, [elRef, child]); return
{children}
; }; ``` ### Метод onDone Когда мини-приложение добавило новый заказ в существующий `orderContainer` или создало новый, оно вызывает метод `onDone`. `paymentUrl` приходит от сервера в момент создания заказа. Если заказ создан, но будет оплачен не через Инвойсбокс, метод можно вызвать без платёжной ссылки: `onDone(null)`. Пользователь увидит, что мини-приложение завершило работу, но переадресации на оплату не будет. ```ts onDone(paymentUrl: string | null): void ``` Пример использования ```ts createOrderRequest(someData).then((response) => { invoiceboxMinapp.onDone(response.data.url); }); ``` ### Метод onError При ошибке в мини-приложении — например, при оформлении заказа или при обращении к API Инвойсбокс — мини-приложение вызывает метод `onError`. Родительская страница уведомит пользователя об ошибке. Функция принимает один опциональный строковый аргумент - пользовательское сообщение. Если сообщение есть, то оно отобразится. Если нет, то отобразится сообщение по умолчанию `Что-то пошло не так`. ```ts onError(message?: string): void ``` Пример использования ```ts // Пользователь увидит "Ошибка создания заказа" invoiceboxMinapp.onError("Ошибка создания заказа"); // Пользователь увидит "Что-то пошло не так" invoiceboxMinapp.onError(); ``` ### Метод onLink Метод `onLink` позволяет произвести переадресацию пользователя по ссылке в родительском окне, как будто переадресация была вызвана не в контексте `iframe`/`webview`, а в контексте родительской страницы. ```ts onLink(href: string): void ``` Пример использования ```ts // На платёжной странице будет открыта новая вкладка с Google страницей // это никак не повлияет на работу мини-приложения invoiceboxMinapp.onLink("https://www.google.ru"); ``` ### Метод onUnavailable Метод `onUnavailable` позволяет сообщить родительскому окну, что мини-приложение недоступно. Мини-приложение будет закрыто. Пользователь увидит соответствующее сообщение. ```ts onUnavailable(): void ``` Пример использования ```ts invoiceboxMinapp.onUnavailable(); ``` ### Метод onCheckout
sequenceDiagram autonumber participant Мини-приложение participant Родительское окно participant Покупатель rect rgba(43, 170, 93, 0.13) Note over Мини-приложение,Покупатель: onDone — работа закончена Мини-приложение->>Родительское окно: onDone(paymentUrl) Родительское окно->>Покупатель: Платёжная страница вместо мини-приложения end rect rgba(31, 111, 235, 0.12) Note over Мини-приложение,Покупатель: onCheckout — работа продолжится Мини-приложение->>Родительское окно: onCheckout(paymentUrl) Родительское окно->>Покупатель: Платёжная страница поверх мини-приложения Покупатель->>Родительское окно: Оплата или отказ Родительское окно->>Мини-приложение: onPaymentResult(status) Мини-приложение->>Покупатель: Что дальше после оплаты end
Обе ветки открывают одну и ту же платёжную страницу, но по-разному заканчиваются: после `onDone` мини-приложение закрыто и о результате оплаты не узнает, после `onCheckout` — остаётся на фоне и получает статус в [onPaymentResult](#обработчик-onpaymentresult). Выбирайте `onCheckout`, если после оплаты покупателю есть что показать: билет, код брони, следующий шаг. Метод `onCheckout` позволяет открыть платежную страницу поверх мини-приложения с возможностью продолжить работу с мини-приложением после оплаты. В отличие от метода `onDone`, мини-приложение не закрывается, а остается открытым на фоне. ```ts onCheckout(paymentUrl: string): void ``` - paymentUrl - URL платежной страницы, полученный от сервера в момент создания заказа Пример использования ```ts createOrderRequest(someData).then((response) => { invoiceboxMinapp.onCheckout(response.data.url); }); ``` ## Обработчики, которые устанавливает мини-приложение Здесь мини-приложение передаёт библиотеке свою функцию и ждёт вызова — в отличие от методов выше, которые оно вызывает само. ### Обработчик onPaymentResult Метод `onPaymentResult` позволяет установить обработчик, который будет вызван при возврате пользователя в мини‑приложение со страницы оплаты. ```ts 'onPaymentResult'(handler: (status: 'pending' | 'completed' | 'canceled' | 'expired' | 'hold') => void): void ``` ### Параметры | Параметр | Тип | Описание | |----------|-----|----------| | `handler` | `(status: string) => void` | Функция‑обработчик, которая получает статус оплаты. | ### Статусы | Статус | Описание | |--------|-----------------------------------------------------------------------| | `pending` | Оплата находится в процессе обработки. | | `completed` | Платёж успешно завершён (оплачен). | | `canceled` | Платёж отменён. | | `expired` | Срок действия счёта истёк, счёт больше не может быть оплачен. | | `hold` | По счёту средства удерживаются (блокируются). | ### Пример использования ```ts invoiceboxMinapp.onPaymentResult((status) => { navigateTo('PaymentResultScreen', { status }); }); ``` ## Схема взаимодействия при оплате через onCheckout 1. Создание заказа: - Мини-приложение вызывает `onCheckout(paymentUrl)`, передавая URL платежной страницы - Основное приложение открывает WebView с платежной страницей поверх мини-приложения 2. Завершение оплаты: - После завершения оплаты платежная страница закрывается - Основное приложение возвращается к мини-приложению и передает статус оплаты - Вызывается обработчик, установленный через `onPaymentResult` 3. Продолжение работы: - Мини-приложение продолжает работу, отображая актуальный статус оплаты - Пользователь может продолжить взаимодействие с мини-приложением --- --- # Библиотека компонентов # Инвойсбокс библиотека компонентов Библиотека `invoicebox-ui` содержит ready-to-use компоненты для создания мини-приложений. - NPM: [invoicebox-ui](https://www.npmjs.com/package/@invoicebox/ui) - GitHub: [invoicebox-ui](https://github.com/InvoiceBox/invoicebox-ui) - Документация с примерами: [invoicebox-ui](https://ui.invoicebox.ru) ## Читайте также - [Компоненты соответствуют дизайн-системе Инвойсбокс](/docs/design/) ---