Документация для вендоров
Терминология
МойСклад - SaaS-сервис управления торговлей, доступный по адресу https://online.moysklad.ru/
Маркетплейс - это набор программных компонентов в рамках сервиса МойСклад, позволяющий сторонним вендорам размещать свои приложения на витрине приложений, а пользователям МоегоСклада устанавливать (подключать) эти приложения и пользоваться ими.
Витрина приложений - отдельный экран МоегоСклада https://online.moysklad.ru/app/#apps, на котором размещаются опубликованные приложения. Витрина приложений доступна только администраторам аккаунта.
Вендор - сторонний по отношению к МоемуСкладу разработчик приложений для Маркетплейса.
Приложение - разработанный вендором программный продукт, расширяющий и дополняющий функционал МоегоСклада. Приложение размещается на витрине Маркетплейса и доступно для установки на аккаунт администратором аккаунта.
Аккаунт - пользовательский аккаунт МоегоСклада. Обычно аккаунт соответствует одной компании/бизнесу, в аккаунте несколько пользователей.
Аккаунт разработчика - привязанный к конкретному вендору пользовательский аккаунт МоегоСклада. На таком аккаунте на витрине приложений отображаются приложения вендора в статусах Черновик (Draft) и Готово, отправлено на модерацию (Ready), что позволяет выполнять проверку и отладку приложений до их публикации для всех пользователей МоегоСклада. Технически к одному вендору может быть привязано несколько аккаунтов.
Приложение на аккаунте - приложение, установленное (подключенное) на аккаунт. Альтернативный взаимозаменяемый термин - экземпляр приложения.
Пользователь МоегоСклада - конечный пользователь сервиса МойСклад, работающий с МоимСкладом в рамках определенного аккаунта.
Администратор аккаунта - пользователь МоегоСклада с правами администратора (в рамках определенного аккаунта).
Активация приложения - процесс включения приложения для конкретного аккаунта в системе вендора, выполняемый при подключении приложения пользователем (или при возобновлении платного приложения). В рамках активации происходит оповещение сервера вендора со стороны МоегоСклада.
Деактивация приложения - процесс выключения приложения для конкретного аккаунта в системе вендора, выполняемый при отключении приложения пользователем (или при приостановке платного приложения). В рамках деактивации происходит оповещение сервера вендора со стороны МоегоСклада.
Приостановка приложения - автоматический процесс выключения платного приложения при уменьшении количества "Опций платных приложений" или неоплате подписки пользователем МоегоСклада. После приостановки токен доступа приложения аннулируется. Первыми приостанавливаются последние установленные приложения на аккаунте.
Возобновление приложения - процесс включения приостановленного платного приложения при появлении на аккаунте свободных "Опций платных приложений". Возобновление может быть выполнено как автоматически (после оплаты пользователем МоегоСклада подписки или дополнительных "Опций платных приложений"), так и вручную пользователем МоегоСклада (активация экземпляра приложения по кнопке после освобождения "Опции платных приложений" путем удаления экземпляра другого платного приложения). После возобновления приложению выдается новый токен доступа. Первыми возобновляются приложения, установленные ранее прочих.
Общая информация
В данном разделе можно узнать:
- какие бывают приложения в Маркетплейсе
- варианты платности приложений
- как создать свое приложение
Типы приложений в Маркетплейсе
Тип приложения определяет в первую очередь технический способ интеграции приложения с МоимСкладом.
Поддерживаемые на текущий момент типы приложений:
- Телефония (Phone API)
- Iframe-приложения
- Серверные приложения
- Интеграция с системами лояльности (Loyalty API)
Сводная таблица поддержки функций для типов приложений
Тип приложения | Количество приложений на аккаунте | Iframe и доступ к контексту пользователя | Активация и деактивация по Vendor API | Доступ по токену к JSON API 1.2 | Отладка на аккаунтах разработчика | Phone API | Loyalty API | Блок на витрине приложений | Виджеты |
---|---|---|---|---|---|---|---|---|---|
Телефония | 1 | + | + | Звонки | |||||
Iframe-приложения | Не ограничено | + | + | Новые | |||||
Серверные приложения | Не ограничено | + | + | + | + | Новые | + | ||
Системы лояльности | 1 | + | Скидки |
Серверные приложения
Серверные приложения - это приложения, основной функционал которых основан на обмене данными с МоимСкладом по JSON API. Для этого при активации приложения по Vendor API на сервер вендора передается токен доступа к JSON API 1.2 (доступ по токену поддерживается только в JSON API 1.2).
Для серверных приложений поддерживается активация и деактивация по Vendor API.
Для серверных приложений доступно получение контекста текущего пользователя МоегоСклада (через Vendor API) - то есть можно узнать, какой именно пользователь какого аккаунта открывает приложение в UI МоегоСклада.
Также серверное приложение может иметь свою вкладку среди iframe-приложений и пользовательский интерфейс. Используя данную возможность можно, например, реализовать управление настройками приложения со стороны пользователя МоегоСклада / администратора аккаунта. Поддерживается возможность расширенного iframe-окна (подробнее см. дескриптор).
Только для серверных приложений доступны виджеты.
В общем случае жесткие требования к внешнему виду / визуальному дизайну iframe-части приложений отсутствуют. Тем не менее, приветствуется визуальное соответствие дизайну МоегоСклада. Для этого мы разработали UI Kit (см. скриншот), который доступен по ссылке https://github.com/moysklad/html-marketplace-1.0-uikit.
Одновременно на аккаунте может быть подключено несколько серверных приложений.
Доступна отладка на аккаунтах разработчика.
Iframe-приложения
Iframe-приложение представляет собой веб-приложение, которое загружается по указанному вендором URL в iframe на отдельной вкладке/странице внутри UI МоегоСклада.
Iframe-приложения просты в разработке и размещении на площадке МоегоСклада, однако такие приложения тоже должны соответствовать требованиям к приложениям.
Для iframe-приложений поддерживается доступ к контексту пользователя и расширение окна iframe, однако не поддерживается активация и деактивация по Vendor API, а также доступ по токену к JSON API 1.2.
При построении пользовательского интерфейса в iframe-приложениях также желательно использовать UI Kit МоегоСклада.
Одновременно на аккаунте может быть подключено несколько iframe-приложений.
Доступна отладка на аккаунтах разработчика.
Телефония
Эти приложения представляют собой интеграцию с внешними сервисами телефонии по Phone API: https://online.moysklad.ru/api/phone/1.0/doc/index.html
Приложения телефонии на витрине приложений размещаются в блоке “Звонки”.
На текущий момент возможность получения доступа по токену к JSON API у приложений телефонии отсутствует, как и возможность активации и деактивации приложений телефонии по Vendor API (в перспективе такая возможность может появиться).
Одновременно на аккаунте может быть подключено только одно приложение телефонии.
Доступна отладка на аккаунтах разработчика.
Интеграция с системами лояльности
API для интеграции МоегоСклада с системами лояльности и внешними сервисами управления скидками: https://msloyaltyapi.docs.apiary.io
Данный тип приложений размещается на витрине в отдельном блоке “Скидки”.
Одновременно на аккаунте может быть подключено только одно приложение интеграции с системами лояльности.
На текущий момент для данного типа приложений недоступны возможности Маркетплейса (iframe, Vendor API, доступ по токену к JSON API, отладка на аккаунтах разработчика), так как данный тип приложений еще не заведен на механизмы Маркетплейса (но возможно ручное размещение приложений данного типа на витрине приложений).
Платные и бесплатные приложения
На текущий момент в Маркетплейсе поддерживаются как бесплатные, так и платные приложения.
Бесплатные приложения могут быть установлены пользователями на аккаунте вне зависимости от типа подписки (с ограничениями на Бесплатном тарифе) и в любом количестве. Пользователю должен быть доступен весь функционал приложения без дополнительной оплаты. Вендор может брать оплату с пользователей приложений самостоятельно, только если для работы приложения требуется свой сервис для учета транзакций (например: отправка смс, телефония и подобные услуги). Конкретный механизм самостоятельного взимания оплаты и его реализация остается на усмотрение вендора и не рассматривается в данном документе.
Для платных приложений в системе МойСклад на данный момент доступен любой вариант стоимости, кратный 500 рублям в месяц. Эта оплата взимается с пользователей в виде платной опции в рамках их подписки на МойСклад — "Опции платных приложений", поэтому здесь так же, как на подписку, для пользователей применяются скидки за оплату на 3, 6 и 12 месяцев.
Также мы написали для пользователей подробную инструкцию по тому, как устанавливать и оплачивать приложения. Вы можете посмотреть ее здесь.
Вендор получает 75% от стоимости своих приложений без учета скидок и комиссий. Например, если приложение стоимостью 500 руб было оплачено на 3 месяца, вендор будет получать 500 * 0,75 = 375 рублей ежемесячно.
В дальнейшем возможно изменение доли вендора в ту или иную сторону.
В дальнейшей перспективе будет реализован более гибкий биллинг приложений Маркетплейса, не привязанный в общем случае к подписке на МойСклад и в том числе позволяющий устанавливать вендорам произвольную стоимость приложений.
Пробный период платных приложений
В Маркетплейсе МоегоСклада есть возможность дать пользователям поработать с платным приложением бесплатно некоторое время - пробный период.
Что важно знать о пробном периоде:
Пробный период может быть назначен приложению как до публикации, так и после. После публикации пробный период активируется только для новых пользователей: им смогут воспользоваться только те, кто еще ни разу не устанавливал приложение.
Пробный период можно также изменить или убрать у уже опубликованного приложения. При этом уже установленные экземпляры приложений продолжат свою работу с прежним пробным периодом (который был на момент их установки).
Длительность пробного периода можно установить от 1 до 14 дней. Когда пробный период завершится, приложение продолжит работу платно при наличии "Опций платных приложений" в количестве, требуемом для оплаты приложения. Если у пользователя не окажется свободных опций — приложение будет приостановлено.
Приложения с пробным периодом могут быть установлены на любом тарифе и не зависят от наличия "Опции платных приложений" на аккаунте. Однако следует помнить об ограничениях функционала приложений на Бесплатном тарифе (в частности, будут недоступны вебхуки).
Приложение с пробным периодом можно создать через Личный кабинет вендора.
После публикации добавить, изменить или убрать пробный период вашему приложению может модератор МоегоСклада по запросу.
Изменение стоимости приложения
Доступны следующие действия над приложениями:
- Перевод бесплатного приложение в платное.
- Перевод платного приложение в бесплатное.
- Изменение стоимости платного приложения.
Для неопубликованных приложений стоимость и признак платности можно изменять через Личный кабинет вендора
Для опубликованных приложений Вендору необходимо обратиться к Администратору (модератору) Маркетплейса МоегоСклада.
При переводе опубликованного бесплатного приложения в платное, ему обязательно назначается пробный период от 7 до 14 дней. Таким образом пользователи, установившие приложение как бесплатное, смогут ещё некоторое время продолжить работу с ним бесплатно и принять решение об оплате.
Жизненный цикл приложения
На текущий момент для приложения Маркетплейса предусмотрены следующие статусы жизненного цикла:
- Черновик (Draft) - статус черновика, предназначен для разработки и тестирования, приложение не отображается на витрине у пользователей МоегоСклада.
- Готово, отправлено на модерацию (Ready) - статус готовности, означает, что приложение со стороны вендора готово к публикации (далее приложение будет промодерировано сотрудниками МоегоСклада и опубликовано), приложение все еще не отображается на витрине у пользователей МоегоСклада.
- Опубликовано (Published) - приложение опубликовано на витрине приложений и доступно к установке пользователями МоегоСклада.
- Снято с публикации (Hidden) - публикация приложения приостановлена. Приложение в статусе Hidden исчезает с витрины, но при этом у его текущих пользователей сохраняется возможность с ним работать.
Жизненный цикл приложения выглядит следующим образом:
- Приложение создается в Личном кабинете вендора со статусом Draft. Вендор проверяет и отлаживает работу приложения на аккаунте разработчика. По готовности приложения вендор передает его на публикацию, статус приложения меняется на Ready.
- Сотрудники МоегоСклада проверяют приложение и, в случае отсутствия замечаний, публикуют приложение на витрине, статус приложения меняется на Published. Приложение становится доступно для установки пользователями МоегоСклада.
- Пользователи МоегоСклада подключают/устанавливают приложение на свой аккаунт, выполняют его настройку (если таковая опция имеется в приложении), пользуются приложением и, если оно становится ненужным, отключают/удаляют приложение с аккаунта.
- Если по каким-то причинам приложение требуется убрать с витрины приложений, то оно переводится в статус Hidden. Установленные до этого момента экземпляры приложений на аккаунтах продолжают работать и отображаться на UI МоегоСклада до момента удаления приложения самим пользователем. Для прочих аккаунтов, а также для аккаунтов, удаливших приложение, оно скрывается и установка становится невозможна. Подобный вариант скрытия сейчас реализован только для бесплатных приложений.
Прямая ссылка на приложение
Вендоры могут получить прямую ссылку на серверные или iframe приложения. Для этого нужно в Личном кабинете вендора перейти в режим просмотра или редактирования нужного приложения и найти поле Прямая ссылка на приложение. Прямую ссылку можно также получить с витрины приложений из адресной строки браузера, если открыть карточку приложения на витрине.
При переходе по короткой ссылке открывается витрина с карточкой приложения. Если пользователь авторизован - то витрина с карточкой открывается сразу, если пользователь не авторизован - то через форму логина/авторизацию.
Если приложение не существует или не доступно на аккаунте пользователя, использующего прямую ссылку, по какой-либо из причин (то есть, если приложение не отображается на витрине, например, приложение в статусе Draft), то, при переходе этим пользователем по ссылке, открывается витрина и появляется сообщение о том, что приложение не найдено. Если приложение снято с публикации, но уже установлено некоторыми пользователями, то у них оно будет отображаться по ссылке, так же, как и на витрине, а у остальных, соответственно, нет.
Так как витрина приложений доступна только администраторам аккаунтов, то карточка приложения будет доступна только им.
Требования к приложениям
Ниже перечислены требования, которым должно соответствовать приложение для успешного прохождения модерации:
- приложение должно быть полезным для пользователей МоегоСклада
- форма сбора лидов модерацию не пройдет
- если приложение требует настройки пользователем, то настройка должны выполняться на стороне МоегоСклада (в iframe)
- не пройдет модерацию приложение, если оно представляет собой только связку с внешним сервисом, а сама настройка интеграции с МоимСкладом выполняется в этом внешнем сервисе
- приложение должно получать доступ к данным пользователей через JSON API 1.2 с использованием токена, выдаваемого приложению при установке на аккаунт
- запрашивать у пользователя логин-пароль для доступа с их использованием к JSON API НЕ допускается
- использовать для доступа к данным пользователя следует именно JSON API 1.2 (но не JSON API 1.1), так как только в JSON API 1.2 есть возможность доступа по токену
- для разработки UI в iframe желательно использовать наш UI Kit
(требование не жесткое)
Требования к иконкам приложений
При разработке иконки, которая будет отображаться на витрине приложений, нужно ориентироваться на следующие требования:
- Отчетливая крупная форма отчетливого цвета. Иконка будет на белом фоне и может теряться если в ней будут мелкие детали на белом фоне. К тому же один крупный знак будет просто и понятно восприниматься.
- Не делайте иконку без фона, если только она не заполняет выделенное пространство плотно, иначе она будет «исчезать» на фоне других иконок.
- Не ставьте скриншоты и фотографии и элементы интерфейса. Фотографии и экраны приложений могут включать много ненужных и плохо различичмых деталей. Детали интерфейса могут быть обманчивыми и путающими человека.
- По возможности не используйте слова. Используйте знак вашего логотипа, если у вас есть отдельный. Если используете какую-то букву из вашего логотипа как знак, то можно использовать его. Если вы так не делаете, то можно поставить полное название, учитывая все остальные пункты.
- Не ставьте логотип МоегоСклада или его имитации. Указать наш логотип значит сказать, что мы как-то учавствовали в разработке приложения, что будет неправдой.
- Размер иконки 90x90. Можно использовать все это пространство и не оставлять внутренних белых рамок.
Разработка и публикация приложений
Краткая инструкция по разработке, отладке и публикации приложений на примере iframe- и серверных приложений.
Разработка серверных приложений
При разработке серверного приложения следует определиться по следующим вопросам:
Должен ли будет пользователь настраивать приложение при его установке на аккаунт? Если да - то нужно реализовать iframe-часть для серверного приложения, по возможности используя UI Kit МоегоСклада.
Будет ли в iframe-части серверного приложения какой-либо пользовательский функционал, кроме настроек? Если да - то, возможно, следует предусмотреть, чтобы пользовательский функционал был доступен не только администратору аккаунта (как, например, настройки), но и другим пользователям аккаунта (всем или с определенными правами).
Нужны ли дополнительные поля для сущностей и/или документов? Если да - то можно будет их создавать через JSON API 1.2 в рамках активации приложения. Здесь скорее всего потребуется использовать сценарий асинхронной активации (с возвратом статуса Activating).
Будет ли у приложения виджет? Если да - то нужно реализовать iframe-часть и для виджета тоже.
Также заметим, что для серверных приложений является обязательным реализация эндпоинта /api/moysklad/vendor/1.0/apps (см. Vendor API) на стороне вендора, и предполагается, что серверное приложение будет взаимодействовать с МоимСкладом по JSON API 1.2 с авторизацией по токену (передаваемому приложению по Vendor API при активации).
Разработка iframe-приложений
При разработке iframe-приложения вендору следует определиться по следующим вопросам:
- Насколько будет использоваться UI Kit МоегоСклада для построения пользовательского интерфейса содержимого iframe? Приветствуется использование UI Kit МоегоСклада.
Личный кабинет вендора
Для упрощения и автоматизации работы над приложениями Маркетплейса был создан Личный кабинет вендора (ЛКВ). Это сервис, который позволяет вендорам самостоятельно создавать приложения в статусе Draft (Черновик), отлаживать и тестировать их на витрине приложений, вносить необходимые изменения (в том числе самостоятельно получать и изменять SecretKey) и, по окончании разработки, отправлять на модерацию в МойСклад.
Что можно делать в личном кабинете:
- Создавать Черновики приложений
- Редактировать Черновики приложений и просматривать информацию о приложениях в прочих статусах
- Редактировать информацию о разработчике
- Отправлять Черновики приложений на модерацию
- Следить за статусами публикации своих приложений
- Привязывать аккаунты в МоемСкладе к аккаунту в Личном кабинете для отладки неопубликованных приложений
Получение доступа к личному кабинету Вендора
Для получения доступа в Личный кабинет заполните, пожалуйста, анкету. Мы пришлем вам доступ и дальнейшие инструкции на указанный в анкете email в течение пары дней.
Создание черновика приложения
Форма создания черновика приложения открывается по кнопке Создать приложение.
В первую очередь предлагается заполнить Псевдоним приложения. Псевдоним - уникальный идентификатор, поэтому невозможно создать два приложения с одинаковыми псевдонимами.
В личном кабинете Вендора можно завести три типа приложений:
- Серверное приложение
- Телефонию
- Iframe-приложение
Создание Серверных и Iframe-приложений:
При создании Серверного или Iframe приложения можно указать платным или бесплатным будет ваше приложение: за это отвечает чекбокс Платное.
Для платных приложений нужно определить их стоимость, кратную 500 рублям. Максимальная стоимость приложения, которую можно задать через ЛКВ, 10000 рублей, минимальная, соответственно, 500 рублей. Если необходимо указать большую стоимость, вендор может обратиться к сотруднику МоегоСклада.
Для платных приложений открывается возможность добавить Пробный период. После установки отметки в чекбоксе Платное станет доступен селектор, в котором можно выбрать длительность Пробного периода (до 14 дней) или его отсутствие.
При создании Серверного или Iframe-приложения дескриптор обязателен для заполнения. Ознакомиться с правилами его заполнения можно в разделе Дескриптор приложения.
Создание Телефонии:
При создании приложения с типом Телефония нельзя проставить признак Платности, выбрать Пробный период и не нужно заполнять Дескриптор. Телефония оплачивается пользователем отдельно - через опцию CRM.
Редактирование черновика приложения
После того, как приложение было создано, может потребоваться что-то в нем изменить. Для этого необходимо выбрать его в списке приложений и нажать кнопку Редактировать приложение.
Что следует знать:
- Редактировать можно только приложения в статусе Черновик.
- После передачи на модерацию можно будет просматривать данные приложения (нажав на кнопку Редактировать приложение), но внести изменения не получится. Возможность редактирования снова появится, если приложение будет возвращено на доработку модератором.
- После публикации приложения изменения могут быть внесены только модератором МоегоСклада по запросу
- В форме редактирования доступны те же поля, что и в форме создания. К ним применимо все перечисленное в разделе "Создание черновика приложения"
- Доступны просмотр и перегенерация Секретного ключа.
- Для просмотра следует нажать на кнопку-глаз у скрытого точками поля, для генерации нового ключа - кнопку Сгенерировать.
- кнопка Сгенерировать, как и прочие изменения приложения, доступна только для Черновиков
- Также в форме редактирования отображаются read-only поля с техническими параметрами и статусом публикации приложения
Редактирование информации о вендоре
Для редактирования информации о вендоре (разработчике) приложения потребуется перейти на вкладку Вендор в верхнем меню Личного кабинета.
Функция доступна, пока на аккаунте отсутствуют приложения или есть только Черновики. В остальных случаях данные доступны только для просмотра, а для изменения следует обратиться к модератору МоегоСклада.
Привязка аккаунта к вендору
Отладка приложений для Маркетплейса производится на аккаунтах разработчика. Для того, чтобы аккаунт в МоемСкладе стал аккаунтом разработчика, его нужно привязать к вендору, и это тоже можно сделать в Личном кабинете вендора.
Инициировать привязку можно по кнопке Привязать, расположенной в верхнем меню Личного кабинета.
Важно: Для привязки необходимо иметь доступ к email ответственного сотрудника, назначенного в аккаунте МоегоСклада на странице Подписка. По умолчанию им является администратор, зарегистрировавший аккаунт, однако впоследствии этого пользователя можно изменить.
Изменить уже существующую привязку можно путем нажатия на имя текущей привязки. Предыдущая привязка будет удалена.
Ручная приостановка приложения
Возможности Личного кабинета позволяют разработчику тестировать и, при необходимости, отлаживать приложения при приостановке и возобновлении на аккаунте.
Для тестирования приостановки необходимо:
- Привязать аккаунт в МоемСкладе к аккаунту Вендора в ЛКВ (создать аккаунт разработчика)
- Завести платное приложение в ЛКВ
- Установить приложение на аккаунте разработчика
- Выбрать приложение в списке и нажать кнопку Приостановить на аккаунте
- Готово! Приложение приостановлено.
- Для отладки возобновления можно воспользоваться кнопкой Активировать в карточке приложения на витрине МоегоСклада.
Приостановка возможна только для приложений, которые уже установлены или устанавливаются.
Отправка на модерацию
Перед публикацией на витрине МоегоСклада новое приложение должно сначала пройти модерацию.
Для отправки на модерацию следует выбрать нужное приложение в статусе Черновик из списка и нажать кнопку Отправить на модерацию.
Важно: для получения оперативных оповещений о ходе модерации необходимо заполнить Email для уведомлений в разделе Вендор
Карточка вендора
Карточка вендора - это Google Sheets таблицы, через которые происходил обмен информацией между вендором и МоимСкладом до создания Личного кабинета.
На данный момент карточка не используется.
Отладка приложений на аккаунтах разработчика
Отладка неопубликованных приложений выполняется вендором на специальном аккаунте(ах), привязанных к вендору.
На таких аккаунтах неопубликованные приложения вендора появляются в специальном блоке на витрине приложений "ПРИЛОЖЕНИЯ В РАЗРАБОТКЕ". Для остальных пользователей приложения-черновики не будут видны.
Неопубликованные приложения можно подключать и отключать так же, как и обычные опубликованные приложения.
Привязка аккаунтов к вендору осуществляется через Личный кабинет вендора.
Общая схема процесса размещения приложения в Маркетплейсе
После готовности приложения на стороне вендора в общем случае вендору нужно выполнить следующие шаги по размещению приложения в Маркетплейсе:
- Создать Черновик приложения в Личном кабинете вендора.
- После создания Черновика на странице редактирования приложения будет доступен Секретный ключ (Secret Key).
- Создать аккаунт разработчика, привязав аккаунт МоегоСклада к аккаунту в Личном кабинете вендора.
- Протестировать и отладить приложение на аккаунте разработчика.
- Отправить приложение на модерацию через Личный кабинет вендора.
Далее сотрудник МоегоСклада смотрит на приложение и, при отсутствии замечаний, публикует его на витрине приложений.
Демо-приложение
Для демонстрации взаимодействия приложений с Маркетплейсом МоегоСклада было создано демо-приложение на PHP.
В демо-приложении реализованы следующие функции:
- Активация (с получением токена доступа к JSON API 1.2) и деактивация по Vendor API.
- Использование iframe для настройки приложения администратором аккаунта с обновлением статуса в Маркетплейсе.
- Получение контекста пользователя для iframe (отображение информации по пользователю, проверка прав администратора).
- Получение информации из МоегоСклада по JSON API 1.2 с доступом по токену.
Более подробную информацию и исходный код приложения можно получить по ссылке: https://github.com/moysklad/php-dummyapp-marketplace-1.0
Виджеты
Виджет - это плагин с визуальной частью, представляющей собой прямоугольный блок в конкретном месте в UI МоегоСклада. Содержимое блока определяется приложением.
FAQ по виджетам
Куда сейчас можно встраивать виджеты?
На данный момент для встраивания виджетов доступны страницы:
- Контрагент - новая карточка (entity.counterparty.edit)
- Контрагент - старая карточка (скоро перестанет поддерживаться) (entity.counterparty.view)
- Заказ покупателя (document.customerorder.edit)
- Отгрузка (document.demand.edit)
- Счет покупателю (document.invoiceout.edit)
- Заказ на производство (document.processingorder.edit)
- Заказ поставщику (document.purchaseorder.edit)
- Счет поставщика (document.invoicein.edit)
- Приемка (document.supply.edit)
Во всех точках расширения виджеты имеют одинаковый функционал.
Если у пользователя установлены сразу несколько приложений с виджетами, встроенными на одну страницу МС, то отобразятся все виджеты в порядке, соответствующем расположению родительских приложений на витрине. В новом редакторе контрагентов пользователь может сам поменять порядок отображения виджетов.
Список доступных для модернизации страниц (точек расширения) будет активно дополняться.
Хочу встроить виджет в точку МоегоСклада, которой нет в списке - что делать?
Если вы хотите встроить виджет в какую-то точку МоегоСклада, но её пока нет в списке доступных точек расширения - обращайтесь с предложением в Telegram или по электронной почте, мы всегда открыты для таких запросов.
Какими могут быть виджеты:
Сейчас можно создать только виджеты с
- фиксированной шириной: 416px - для всего виджета (с рамкой), 384px - для рабочей области (iframe, определяемый приложением).
- фиксированной высотой: задается в дескрипторе.
Планируется реализация поддержки двух режимов отображения виджетов:
- развернутая форма (полная) - реализована для всех точек расширения
- свернутая форма (краткая) - пока реализована только в новом редакторе контрагентов.
Жизненный цикл виджета
Виджет начинает отображаться на странице только после перехода приложения в статус Activated. Если приложение предполагает настройку и статус SettingsRequired - виджет отобразится после настройки приложения.
При первом открытии страницы с виджетом (в рамках одной вкладки браузера) cистема МоегоСклада загружает виджет по HTTP GET-запросом по URL'у, указанному в теге sourceUrl. При этом система генерирует и передает GET-параметром одноразовый contextKey, по которому виджет получает текущий контекст пользователя через Vendor API.
Прочие данные передаются при помощи postMessage в первом и последующих открытиях виджета.
В частности, при каждом открытии виджета система МоегоСклада отображает ранее загруженный iframe
виджета (без повторной загрузки с сервера вендора) и через postMessage передает
в iframe этого виджета сообщение Open
.
Без дополнительных настроек виджет отображает содержимое сразу, как только получает
сообщение Open
, даже если еще не успел обновить отображаемую информацию.
В случае, если виджет поддерживает протокол open-feedback, система не отображает
содержимое виджета сразу, а ждет ответного сообщения от виджета о готовности.
До этого момента внутри виджета отображается заглушка. Когда виджет готов, он
отправляет сообщение OpenFeedback
, после чего система полностью открывает
виджет пользователю.
При сохранении страницы с виджетом, если виджет, который находится на экране редактирования сущности,
поддерживает протокол save-handler, то он оповещается о факте сохранения объекта пользователем,
получая сообщение Save
.
Если виджет поддерживает протокол dirty-state, он (виджет) может сообщить хост-окну,
что в виджете есть несохраненные изменения. Для этого виджет отправляет хост-окну
сообщение SetDirty
. Виджет может отправить хост-окну сообщение ClearDirty
,
после чего диалог подтвержения закрытия окна не будет появляться (если, конечно,
отсутствуют несохраненные изменения в самом UI МоегоСклада или в других виджетах).
Внутренний dirty-флаг для виджета в хост-окне сбрасывается при открытии
(при отправке сообщения Open
) - т.е. хост-окно считает, что в виджете нет несохраненных изменений.
Поддержку виджетом протоколов open-feedback, save-handler, dirty-state необходимо указать в дескрипторе приложения.
Как работают виджеты
Описание конфигурации виджетов приложения в дескрипторе
Виджеты доступны для серверных приложений с дескриптором версии v2.
Пример дескриптора приложения с виджетом в новой карточке контрагента расположен в правой части экрана.
Дескриптор приложения с виджетом в новой карточке контрагента
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>...</iframe>
<vendorApi>...</vendorApi>
<access>...</access>
<widgets>
<entity.counterparty.edit>
<sourceUrl>https://b2b.moysklad.ru/widget/counter-party</sourceUrl>
<height>
<fixed>28px</fixed>
</height>
<supports>
<open-feedback/>
<save-handler/>
</supports>
<uses>
<good-folder-selector/>
</uses>
</entity.counterparty.edit>
</widgets>
</ServerApplication>
Подробнее со структурой дескриптора для приложения с виджетом можно ознакомиться в разделе Дескриптор приложений.
В результате после установки и настройки приложения пользователем виджет отображается на карточке контрагента:
Загрузка виджета на странице
Виджет на странице загружается в iframe по URL, указанному в теге
<sourceUrl>...</sourceUrl>
виджета в дескрипторе приложения.
Ширина содержимого виджета одинакова для виджетов всех приложений и равна 400px, а высота содержимого виджета статически указывается разработчиком в дескрипторе приложения (в данном примере 61px).
Так же, как и для основного iframe-приложения, виджету GET-параметром передается
contextKey
, по которому через Vendor API можно получить информацию о текущем
пользователе.
Пока происходит загрузка виджета - отображается ненавязчивый лоадер.
Кэширование виджетов
Система виджетов в МоемСкладе реализована таким образом, чтобы, по-возможности, загрузить виджет только один раз при первом открытии страницы с виджетом (в рамках одной вкладки браузера) и далее кэшировать iframe c загруженном в него виджетом, переиспользуя его во всех последующих (в рамках одной вкладки браузера) открытиях страницы с виджетом.
Несмотря на стремление к идеальному кэшированию - оно не гарантировано. То есть хост-окно может:
- физически создать несколько экземпляров iframe’ов для одной и той же точки расширения в рамках одной вкладки браузера (по тем или иным техническим причинам), причем эти экземпляры могут существовать одновременно
- не кэшировать iframe-виджета после загрузки
Открытие виджета
При открытии пользователем страницы с виджетом хост-окно отображает iframe
виджета (только что загруженный или ранее закэшированный) и передает в
этот iframe виджета сообщение Open
через postMessage.
Пример сообщения Open
cм. в правой части экрана.
Сообщение Open
{
"name": "Open",
"messageId": 12345,
"extensionPoint": "entity.counterparty.edit",
"objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c",
"displayMode": "expanded"
}
Здесь objectId
- это в данном случае идентификатор контрагента, так как
точка расширения entity.counterparty.edit
.
Виджет при получении сообщения Open
может, например, обратиться на сервер
за данными для указанного объекта objectId
и отобразить их пользователю.
Протокол обратной связи при открытии виджета
По умолчанию при открытии закэшированного виджета его содержимое отображается сразу.
Если виджет при открытии делает обращение к серверу, то может быть видна небольшая задержка и в это время будет отображается прежнее состояние/содержание виджета (например, данные для прошлого контрагента).
Протокол обратной связи позволяет виджету явно сообщить хост-окну в какой именно момент отобразить содержимое виджета. До этого содержимое виджета будет закрыто ненавязчивым лоадером:
Тег дополнительных протоколов supports с протоколом open-feedback
<supports>
<open-feedback/>
</supports>
Для переключения хост-окна на использование протокола обратной связи при открытии виджета в дескрипторе для виджета надо явно указать поддержку дополнительного протокола open-feedback. Пример тега дополнительных протоколов supports с указанным в нем протоколом open-feedback см. в правой части экрана.
Виджет передает сообщение OpenFeedback
хост-окну в качестве сигнала готовности содержимого
виджета для отображения пользователю. Пример сообщения OpenFeedback
- в правой части экрана.
Cообщение OpenFeedback
{
"name": "OpenFeedback",
"correlationId": 12345
}
Здесь correlationId
содержит значение messageId
ранее полученного сообщения Open
.
Хост-окно, получив сообщение OpenFeedback
, отображает содержимое виджета пользователю
(убирает ненавязчивый лоадер).
Сохранение пользователем редактируемого объекта
Хост-окно может оповещать виджет о факте сохранения редактируемого объекта. Для этого в дескрипторе для виджета нужно объявить поддержку опционального протокола save-handler.
Тег дополнительных протоколов supports с протоколом save-handler
<supports>
<save-handler/>
</supports>
Хост-окно отправляет виджету сообщение Save
(через postMessage)
при сохранении редактируемого объекта после сохранения объекта в БД (то есть на момент получения
виджетом сообщения Save сохраненное состояние объекта уже доступно через JSON API).
Сохранение редактируемого объекта инициируется пользователем:
при явном нажатии на кнопку “Сохранить”, в том числе при сохранении объекта без фактического внесения изменений
при покидании объекта и его явном сохранении через диалог подтверждения сохранения изменений, в том числе при листании кнопками-стрелочками на соседние объекты
при автоматическом сохранении изменений закрываемого объекта (например, при создании связанного документа Отгрузки из Заказа покупателя)
Протокол save-handler не поддерживается для точки entity.counterparty.view
.
Пример сообщения Save
cм. в правой части экрана.
Сообщение Save
{
"name": "Save",
"messageId": 32109,
"extensionPoint": "entity.counterparty.edit",
"objectId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"
}
Признак несохраненного состояния виджета
Тег дополнительных протоколов supports с протоколом dirty-state
<supports>
<dirty-state/>
</supports>
Хост-окно поддерживает подтверждение закрытия окна пользователем, если он изменил данные в форме виджета, но не сохранил их. Для этого в дескрипторе для виджета нужно объявить поддержку опционального протокола dirty-state.
Сообщение SetDirty
{
"name": "SetDirty",
"messageId": 12,
"openMessageId": 7
}
После внесения пользователем изменений в виджете, он отправляет хост-окну сообщение SetDirty
.
Пример сообщения SetDirty - в правой части экрана.
Здесь openMessageId содержит значение messageId ранее полученного сообщения Open.
Система учитывает, что в виджете есть несохраненные изменения. Далее, если пользователь нажимает кнопку “Закрыть“ (или другим способом пытается уйти с формы редактирования), система отображает диалог подтверждения сохранения изменений:
Сообщение ClearDirty
{
"name": "ClearDirty",
"messageId": 13
}
Если виджет после отправки SetDirty
отправляет хост-окну сообщение ClearDirty
,
то Система не учитывает данный виджет при отображении диалога подтверждения сохранения
изменений (т.е., если отсутствуют прочие несохраненные изменения самого объекта
или в других виджетах - Система не запрашивает диалог подтверждения сохранения изменений
при закрытии редактируемого объекта).
Протокол dirty-state не поддерживается для точки entity.counterparty.view
.
Сервисы хост-окна
Селектор группы товаров
Дескриптор с виджетом, использующим селектор группы товаров
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
<expand>true</expand>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<entity.counterparty.edit>
<sourceUrl>https://example.com/widget.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
<uses>
<good-folder-selector/>
</uses>
</entity.counterparty.edit>
</widgets>
</ServerApplication>
Позволяет виджетам приложений переиспользовать существующий в МоемСкладе селектор группы товаров с получением виджетом
результата выбора пользователя.
Чтобы виджет начал поддерживать селектор в дескрипторе необходимо добавить блок:
<uses>
<good-folder-selector/>
</uses>
Когда виджет отправляет хост-окну сообщение SelectGoodFolderRequest
(через Window.postMessage),
хост-окно запрашивает у пользователя выбор группы товаров, используя встроенный в МойСклад попап-селектор:
Cообщение SelectGoodFolderRequest
{
"name": "SelectGoodFolderRequest",
"messageId": 12345
}
Здесь messageId
- целочисленный идентификатор сообщения, уникальный в рамках текущего взаимодействия виджет -
хост-окно. Назначается виджетом.
После совершения пользователем выбора группы товаров или отказа от него хост-окно передает виджету результат
действий пользователя в сообщении SelectGoodFolderResponse
.
Cообщение SelectGoodFolderResponse(Пользователь выбрал группу товаров, имеющую идентификатор 8e9512f3-111b-11ea-0a80-02a2000a3c9c)
{
"name": "SelectGoodFolderResponse",
"correlationId": 12345,
"selected": true,
"goodFolderId": "8e9512f3-111b-11ea-0a80-02a2000a3c9c"
}
Здесь:
+ correlationId
- идентификатор соответствующего сообщения SelectGoodFolderRequest
;
+ selected
- признак наличия выбора;
+ goodFolderId
- идентификатор выбранной группы товаров.
Cообщение SelectGoodFolderResponse(Пользователь отменил выбор)
{
"name": "SelectGoodFolderResponse",
"correlationId": 12345,
"selected": false
}
Дескриптор приложения
Дескриптор приложения представляет собой XML-структуру, которая описывает технические параметры встраивания/интеграции приложения вендора в МойСклад.
Содержимое дескриптора должно соответствовать версии XSD-схемы. Актуальной версией считается v2.
История версий XSD-схемы дескриптора
Версия | Описание | Разрешенное содержимое дескриптора | Поддерживаемые типы приложений |
---|---|---|---|
1.0.0 | Серверные и простые iFrame-приложения | vendorApi, access, iframe | iFrame, Серверные |
1.1.0 | Расширение iFrame (тег expand) | vendorApi, access, iframe(c expand) | iFrame, Серверные |
2.0.0 | Виджеты в старой карточке контрагента. Прекращена поддержка приложений с типом iFrame | vendorApi, access, iframe(c expand), widgets | Серверные |
2.1.0 | Виджеты в Заказе покупателя и Отгрузке | vendorApi, access, iframe(c expand), widgets | Серверные |
2.2.0 | Виджеты с поддержкой селектора групп товаров | vendorApi, access, iframe(c expand), widgets | Серверные |
2.3.0 | Виджеты в Счете покупателю | vendorApi, access, iframe(c expand), widgets | Серверные |
2.4.0 | Виджеты в новой карточке Контрагента | vendorApi, access, iframe(c expand), widgets | Серверные |
2.5.0 | Виджеты с поддержкой протокола save-handler | vendorApi, access, iframe(c expand), widgets | Серверные |
2.6.0 | Виджеты с поддержкой протокола dirty-state | vendorApi, access, iframe(c expand), widgets | Серверные |
2.7.0 | Виджеты в Счете поставщика, Заказе поставщику, Заказе на производство, Приемке | vendorApi, access, iframe(c expand), widgets | Серверные |
Основные отличия дескриптора v2 от дескрипторов версий 1.x.x:
Изменение корневого тега - теперь каждый тип приложений представлен своим корневым тегом. В версии v2 есть только один тип приложений - ServerApplication (iframe-приложения объявлены deprecated и с отменой поддержки дескрипторов версий 1.x.x станут недоступны).
Добавлен блок widgets (необязательный) для указания конфигурации виджетов приложения.
Дескрипторы версий 1.x.x некоторое время будут продолжать поддерживаться.
Содержимое дескриптора приложения
Рассмотрим дескриптор приложения на примерах.
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
<expand>true</expand>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<entity.counterparty.edit>
<sourceUrl>https://example.com/widget.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
<uses>
<good-folder-selector/>
</uses>
</entity.counterparty.edit>
</widgets>
</ServerApplication>
На текущий момент в актуальной версии дескриптора приложения есть четыре блока: iframe, vendorApi, access, widgets. Порядок расположения этих блоков относительно друг друга в дескрипторе может быть произвольным.
Блок | Назначение | Доступно для типов приложений | Требует наличия других блоков |
---|---|---|---|
iframe | Описывает iframe-часть приложения. | iframe-приложения, серверные приложения | Не требует |
vendorApi | Описывает взаимодействие по Vendor API. | серверные приложения | Не требует |
access | Описывает требуемый доступ приложения к ресурсам пользовательского аккаунта. | серверные приложения | vendorApi |
widgets | Описывает виджеты. | серверные приложения | Не требует |
Блок iframe
В теге iframe/sourceUrl указывается URL, по которому будет загружаться содержимое iframe внутри UI МоегоСклада. В URL допускается использование только протокола HTTPS.
В случае отсутствия блока iframe в дескрипторе считается, что у приложения отсутствует iframe-часть.
В теге iframe/expand указывается boolean
значение, которое отвечает, будет ли iframe расширяться в основном приложении
МоегоСклада. Под расширением подразумевается автоматическое масштабирование iframe элемента в зависимости от контента.
Данный элемент является опциональным со значением false
по умолчанию. Чтобы расширение iframe работало верно,
на странице, которая указана в sourceUrl, должен работать скрипт, оповещающий страницу МоегоСклада об изменении высоты
его контента, то есть:
- Реализовать посылку сообщения “EventMessage” при любом изменении высоты контента, причем
- сообщение послать parent окну
- данные сообщения должны содержать свойство “height” - высоту содержимого, страницы, которая сейчас отображается (в px)
Для удобства можно добавить следующий js скрипт на свою страницу. Пример:
<!doctype html>
<html>
<head>
...
</head>
<body>
...
<script type="text/javascript" src="https://online.moysklad.ru/js/ns/appstore/app/v1/moysklad-iframe-expand-2.js"></script>
</body>
</html>
Блок vendorApi
В теге vendorApi/endpointBase указывается базовый URL эндпоинта на стороне вендора, к которому будет обращаться МойСклад. В URL допускается использование только протокола HTTPS.
Для получения полного адреса конкретного эндпоинта Vendor API на стороне вендора к базовому URL’у добавляется суффикс
/api/moysklad/vendor/1.0
и путь эндпоинта. То есть шаблон формирования полного URL ресурса в общем случае такой:
{endpointBase}/api/moysklad/vendor/1.0/{endpointPath}/…
Для эндпоинта активации/деактивации приложений на аккаунте шаблон следующий (endpointPath = apps):
{endpointBase}/api/moysklad/vendor/1.0/apps/{appId}/{accountId}
Например, если:
https://example.com/dummy-app - appId = 5f3c5489-6a17-48b7-9fe5-b2000eb807fe
- accountId = f088b0a7-9490-4a57-b804-393163e7680f
- endpointPath = apps
то полный URL ресурса на стороне вендора, к которому будет выполнять запросы МойСклад при активации (и деактивации) приложения на аккаунте, будет следующим:
https://example.com/dummy-app/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
В случае отсутствия блока vendorApi в дескрипторе не выполняется активация и деактивация приложения на серверах вендора.
Блок access
В тегах access/resource (в перспективе их может быть несколько) указываются ресурсы, к которым приложению нужен доступ.
В тегах access/scope (в перспективе их тоже может быть несколько) указываются требуемые разрешения/требуемый уровень доступа. При наличии блока access должны присутствовать как минимум по одному тегу resource и scope.
Наличие блока access требует наличия блока vendorApi для передачи токена(ов) к ресурсам аккаунта при активации приложения по Vendor API.
В случае отсутствия этого блока в дескрипторе приложения при установке на аккаунт приложению не выдаются никакие доступы к ресурсам аккаунта.
На текущий момент для access/resource возможно только одно значение: https://online.moysklad.ru/api/remap/1.2
Для access/scope на текущий момент доступно тоже только одно значение: admin
Другими словами, на текущий момент блок access может иметь только такой вид:
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
Блок widgets
Сначала необходимо определить в блоке widgets точку расширения - указать страницу, где будет расположен виджет.
Сейчас доступны следующие точки расширения:
- entity.counterparty.view - старая карточка Контрагента
- entity.counterparty.edit - новая карточка Контрагента
- document.customerorder.edit - документ "Заказ покупателя"
- document.demand.edit - документ "Отгрузка"
- document.invoiceout.edit - документ "Счет покупателю"
- document.processingorder.edit - документ "Заказ на производство"
- document.purchaseorder.edit - документ "Заказ поставщику"
- document.invoicein.edit - документ "Счет поcтавщика"
- document.supply.edit - документ "Приемка"
В одном дескрипторе может быть указано несколько точек расширения, то есть одно приложение сможет создать сразу несколько виджетов - на разных страницах. В то же время для приложения действует правило: одна страница - один виджет. То есть, в дескрипторе может быть указано только по одной точке расширения каждого типа.
Тем не менее, в итоге на одной странице может оказаться несколько виджетов (от разных приложений).
Сейчас виджеты во всех точках расширения обладают одинаковым функционалом, поэтому ниже приведен универсальный список тегов для любой из точек расширения:
Тег sourceUrl - обязательный. Содержит URL, по которому загружается код виджета в iframe. В URL допускается использование только протокола HTTPS.
Тег height - обязательный. В теге height/fixed задается фиксированная высота виджета в пикселях, в формате 150px.
Тег supports - опциональный. Предназначен для дополнительных протоколов, поддерживаемых виджетом. На данный момент в нем можно указать протоколы:
open-feedback - при открытии экрана обеспечивает скрытие содержимого виджета до явного уведомления от виджета о готовности. Параметры у протокола отсутствуют.
save-handler - при сохранении сущности или объекта позволяет уведомить об этом виджет. Параметры у протокола отсутствуют.
dirty-state - при наличии несохраненных изменений в виджете позволяет отобразить диалог подтверждения сохранения изменений. Параметры у протокола отсутствуют.
Подробнее про дополнительные протоколы open-feedback, save-handler, dirty-state можно прочитать в разделе Жизненный цикл виджета.
Тег uses - опциональный. Предназначен для сервисных протоколов, используемых виджетом. На данный момент в нем можно указать только протокол uses/good-folder-selector. Он позволяет виджетам приложений переиспользовать существующий в МоемСкладе селектор группы товаров с получением виджетом результата выбора пользователя. Подробнее про протокол можно прочитать в разделе Селектор группы товаров. Параметры у протокола отсутствуют.
Пример заполненного блока widgets:
Блок widgets с точками расширения в контрагенте и заказе покупателя
<widgets>
<entity.counterparty.edit>
<sourceUrl>https://example.com/widget-counterparty.php</sourceUrl>
<height>
<fixed>200px</fixed>
</height>
<supports><open-feedback/></supports>
</entity.counterparty.edit>
<document.customerorder.edit>
<sourceUrl>https://example.com/widget-customerorder.php</sourceUrl>
<height>
<fixed>50px</fixed>
</height>
<uses>
<good-folder-selector/>
</uses>
</document.customerorder.edit>
</widgets>
Примеры дескрипторов
Для серверных приложений (актуальная версия схемы дескриптора v2)
Дескриптор для серверных приложений с iframe-частью и расширением окна (expand)
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
<expand>true</expand>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
</ServerApplication>
Дескриптор для серверных приложений с виджетом в старой карточке контрагента
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<entity.counterparty.view>
<sourceUrl>https://example.com/widget.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
</entity.counterparty.view>
</widgets>
</ServerApplication>
Дескриптор для серверных приложений с виджетом в старой карточке контрагента, заказе покупателя и отгрузке и протоколами openfeedback и save-handler
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<entity.counterparty.view>
<sourceUrl>https://example.com/widget.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
<supports><open-feedback/></supports>
</entity.counterparty.view>
<document.customerorder.edit>
<sourceUrl>https://example.com/widget-customerorder.php</sourceUrl>
<height>
<fixed>50px</fixed>
</height>
<supports>
<open-feedback/>
<save-handler/>
</supports>
</document.customerorder.edit>
<document.demand.edit>
<sourceUrl>https://example.com/widget-demand.php</sourceUrl>
<height>
<fixed>50px</fixed>
</height>
<supports><open-feedback/></supports>
</document.demand.edit>
</widgets>
</ServerApplication>
Дескриптор для серверных приложений с виджетом в новой карточке контрагента, заказе покупателя и отгрузке и протоколами good-folder-selector и dirty-state
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<entity.counterparty.edit>
<sourceUrl>https://example.com/widget.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
<supports>
<dirty-state/>
</supports>
<uses>
<good-folder-selector/>
</uses>
</entity.counterparty.edit>
<document.customerorder.edit>
<sourceUrl>https://example.com/widget-customerorder.php</sourceUrl>
<height>
<fixed>50px</fixed>
</height>
<supports>
<dirty-state/>
</supports>
<uses>
<good-folder-selector/>
</uses>
</document.customerorder.edit>
<document.demand.edit>
<sourceUrl>https://example.com/widget-demand.php</sourceUrl>
<height>
<fixed>50px</fixed>
</height>
<supports>
<dirty-state/>
</supports>
<uses>
<good-folder-selector/>
</uses>
</document.demand.edit>
</widgets>
</ServerApplication>
Дескриптор для серверных приложений с виджетом в заказе покупателя и счете покупателю
<ServerApplication xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v2
https://online.moysklad.ru/xml/ns/appstore/app/v2/application-v2.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
<widgets>
<document.customerorder.edit>
<sourceUrl>https://example.com/widget-customerorder.php</sourceUrl>
<height>
<fixed>150px</fixed>
</height>
</document.customerorder.edit>
<document.invoiceout.edit>
<sourceUrl>https://example.com/widget-invoiceout.php</sourceUrl>
<height>
<fixed>110px</fixed>
</height>
</document.invoiceout.edit>
</widgets>
</ServerApplication>
Для серверных приложений (устаревшие версии схемы дескриптора 1.x.x)
Минимальный дескриптор для серверных приложений (без возможности настройки параметров приложения пользователем МоегоСклада, так как у приложения отсутствует iframe-часть)
<application xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v1
https://online.moysklad.ru/xml/ns/appstore/app/v1/application-1.1.0.xsd">
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
</application>
Дескриптор для серверных приложений с iframe-частью
<application xmlns="https://online.moysklad.ru/xml/ns/appstore/app/v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://online.moysklad.ru/xml/ns/appstore/app/v1
https://online.moysklad.ru/xml/ns/appstore/app/v1/application-1.1.0.xsd">
<iframe>
<sourceUrl>https://example.com/iframe.html</sourceUrl>
</iframe>
<vendorApi>
<endpointBase>https://example.com/dummy-app</endpointBase>
</vendorApi>
<access>
<resource>https://online.moysklad.ru/api/remap/1.2</resource>
<scope>admin</scope>
</access>
</application>
Для телефонии
Для приложений телефонии дескриптор на текущий момент не требуется (не поддерживается).
Для систем лояльности
Для интеграций с системами лояльности дескриптор на текущий момент не требуется (не поддерживается).
Доступ по токену к JSON API
Токен для доступа к JSON API 1.2 передается вендору при активации приложения через Vendor API в момент установки или возобновления приложения. Время жизни токена не ограничено.
Токен аннулируется при удалении и приостановке приложения. На момент деактивации приложения через Vendor API токен уже нерабочий (аннулирован).
Токен при доступе к JSON API 1.2 следует передавать как Bearer-токен, а именно в виде заголовка HTTP-запроса:
Authorization: Bearer <access_token>
Пример:
Authorization: Bearer 6ab89be1ae6ff147755625ee8da948e42612233b
Диаграмма последовательности предоставления доступа при подключении приложения
Диаграмма последовательности отзыва доступа при отключении приложения
Работа с вебхуками
Если ваше приложение может создать вебхук(-и) на аккаунте пользователя, то нужно иметь в виду следующее поведение:
- Вебхуки доступны только на пробном и платных тарифах
- Перед процессом удаления приложения, инициированного пользователем, МойСклад удалит все созданные приложением вебхуки.
- Перед процессом приостановки приложения (для платных приложений) вебхуки будут отключены, а после возобновления - включены.
Подробную информацию о работе с вебхуками можно получить по ссылке https://dev.moysklad.ru/doc/api/remap/1.2/dictionaries/#suschnosti-veb-huki
Особенности доступа к некоторым функциям JSON API 1.2
На данный момент для приложений существует ряд ограничений в работе со следующими сущностями JSON API 1.2:
- приложение не может быть автором Задач
- приложение не может работать с Событиями Контрагентов
- приложение не может использовать Шаблоны документов
Vendor API 1.0
Vendor API предназначено для взаимодействия Маркетплейса с системами вендоров касательно процессов, происходящих в рамках функционирования Маркетплейса.
На текущий момент Vendor API включает в себя следующие функции:
- Активацию и деактивацию приложений на аккаунте
- Получение контекста пользователя приложения
В данном разделе описаны спецификации REST-эндпоинтов на стороне МоегоСклада и вендора приложений.
Процесс активации приложения на аккаунте
В общем виде процесс активации приложения выглядит так:
- Пользователь МоегоСклада нажимает кнопку “Установить” приложение.
- Для платных приложений возможно возобновление в случаях:
- Пользователь, на аккаунте которого есть приостановленные приложения, оплачивает подписку с "Опцией платных приложений"
- Пользователь удаляет работающее платное приложение, после чего нажимает кнопку "Активировать" у приостановленного приложения.
- Для платных приложений возможно возобновление в случаях:
- Маркетплейс делает HTTP PUT запрос на сервер вендора, в том числе передавая причину активации и токен доступа к JSON API (если в дескрипторе приложения таковой доступ запрашивается). При этом доступ по переданному токену уже работает.
- Сервер вендора, в рамках допустимого тайм-аута, отвечает на запрос одним из статусов в теле ответа:
- Activating - этот статус предназначен для асинхронной активации на стороне вендора (то есть если в рамках допустимого тайм-аута обработки HTTP PUT запроса не получается активировать приложение - например, для активации приложения требуется несколько минут). Далее вендор должен оповестить МойСклад через эндпоинт “Обратного вызова изменения статуса приложения на аккаунте” о завершении активации приложения статусом Activated или о том, что приложению требуется настройка статусом SettingsRequired.
- SettingsRequired - таким статусом вендор сообщает МоемуСкладу, что приложению требуется настройка пользователем (через iframe-часть приложения). После того, как пользователь настроит приложение, вендор должен оповестить МойСклад через эндпоинт “Обратного вызова изменения статуса приложения на аккаунте” об активации приложения, передав статус Activated.
- Activated - этот статус означает, что приложение сразу полностью активировано и уже заработало.
Диаграмма деятельности активации приложения:
Процесс деактивации приложения на аккаунте
Процесс деактивации приложения существенно проще процесса активации:
- Пользователь МоегоСклада нажимает кнопку “Удалить” в карточке приложения.
- Для платных приложений возможна приостановка в случаях:
- У пользователя, на аккаунте которого есть установленные платные приложения, кончается подписка.
- Пользователь, на аккаунте которого есть установленные платные приложения, оплачивает подписку с количеством
"Опций платных приложений" меньше, чем требуется для оплаты установленных платных приложений.
- Для платных приложений возможна приостановка в случаях:
- Маркетплейс аннулирует доступ по токену (если таковой был выдан) и выполняет HTTP DELETE запрос с причиной деактивации к серверу вендора. То есть на момент получения вендором оповещения по деактивации доступ по токену уже не работает.
Диаграмма деятельности деактивации приложения:
Аутентификация взаимодействия по Vendor API
Все запросы от МоегоСклада к серверу вендора и в обратную сторону от сервера вендора к МоемуСкладу должны быть подписаны с использованием JWT (JSON Web Token) описанным ниже образом.
Секретный ключ secretKey
Если приложение предполагает взаимодействие по Vendor API (оповещение по активации и деактивации, получение контекста пользователя для iframe), то ему понадобится Секретный ключ.
Секретный ключ (secretKey) используется для построения/вычисления сигнатуры JWT.
Секретный ключ генерируется на стороне МоегоСклада и выдается вендору. На текущий момент процесс выглядит так:
- Вендор заводит Черновик приложения в Личном кабинете вендора.
- После этого будет доступна страница редактирования, на которой, в числе прочих read-only полей, доступен Секретный ключ.
- Пока приложение находится в статусе Черновик, вендор может перегенерировать Секретный ключ самостоятельно.
- После передачи приложения на модерацию и далее Секретный ключ доступен только для просмотра и копирования.
- Если по какой-то причине вендор хочет перегенерировать secretKey для приложения не в статусе Черновик, то он это делает через взаимодействие с сотрудником МоегоСклада.
Исходящие запросы МойСклад → Вендор
МойСклад подписывает свои запросы к REST-эндпоинтам вендора, передавая JWT-токен в заголовке HTTP-запроса следующим образом:
Authorization: Bearer <token>
Описание полей JWT-payload:
Поле | Описание | Предполагаемое использование вендором |
---|---|---|
iat | Время генерации токена в секундах от 1970-01-01T00:00:00Z UTC | На усмотрение вендора |
exp | Время жизни/“протухания“ токена в секундах от 1970-01-01T00:00:00Z UTC - позволяет ограничить срок валидности токена (после указанного момента времени токен считается невалидным) | При получении JWT после времени, указанного в exp, следует отклонять запрос с ошибкой аутентификации |
jti | Уникальный идентификатор токена - позволяет отслеживать одноразовость применения токена | При получении JWT с jti, который был уже получен ранее, следует отклонять запрос с ошибкой аутентификации |
JWT-header всегда такой:
{
"alg": "HS256",
"typ": "JWT"
}
JWT-payload включает в себя следующие поля:
{
"iat": 1516239022,
"exp": 1516239322,
"jti": "6S3BQLsaSRNdEnhPCoW9lplY2LozRUOq"
}
Входящие запросы Вендор → МойСклад
Вендор при выполнении REST запросов к МоемуСкладу по Vendor API также должен подписывать их токеном JWT, который также следует передавать в заголовке HTTP-запроса:
Authorization: Bearer <token>
Поле alg в JWT-заголовке всегда должно иметь значение HS256. Соответственно, JWT-сигнатура всегда должна генерироваться по алгоритму HMAC SHA-256 с использованием секретного ключа secretKey.
Описание полей JWT-payload:
Поле | Обязательное | Описание | Обработка на стороне МоегоСклада |
---|---|---|---|
sub | да | appUid приложения | Используется для идентификации и авторизации приложения |
iat | да | Время генерации токена в секундах от 1970-01-01T00:00:00Z UTC | Используется для ограничения допустимого времени жизни токена |
exp | нет | Время жизни/“протухания“ токена в секундах от 1970-01-01T00:00:00Z UTC (после какого момента токен считается невалидным) | Если данное поле присутствует, то оно также используется для проверки валидности токена по времени |
jti | да | Уникальный идентификатор токена | Используется для проверки одноразовости использования токена |
В системе МоегоСклада есть ограничение на максимальное время жизни для JWT-токена (порядка нескольких минут) - назовем его maxTokenLifetime. При проверке/валидации на стороне МоегоСклада значение exp ограничивается максимальным временем жизни: если (exp - iat) превышает maxTokenLifetime или поле exp отсутствует, то в качестве exp используется iat + maxTokenLifetime, то есть:
effectiveExp = exp ? min(exp, iat + maxTokenLifetime) : iat + maxTokenLifetime
JWT-header может быть как с указанием поля typ:
{
"alg": "HS256",
"typ": "JWT"
}
так и без поля typ:
{
"alg": "HS256"
}
JWT-payload должен содержать следующие поля (все поля являются обязательными за исключением exp - это поле опциональное):
{
"sub": "dummyapp.example-vendor",
"iat": 1516239022,
"exp": 1516239322,
"jti": "6S3BQLsaSRNdEnhPCoW9lplY2LozRUOq"
}
Ошибки аутентификации и авторизации
Обработка ошибок аутентификации и авторизации на стороне МоегоСклада осуществляется аналогично тому как это сделано в JSON API 1.2:
https://dev.moysklad.ru/doc/api/remap/1.2/
То есть при возникновении ошибок возвращается аналогичный объект error и заголовки HTTP-ответа X-Lognex-Auth и X-Lognex-Auth-Message.
REST-эндпоинты на стороне вендора приложений
Если вендору требуется
- активировать/деактивировать приложение у себя в системе при установке (возобновлении) и удалении (приостановке) приложения на аккаунте пользователя МоегоСклада
- получать токен для доступа к JSON API 1.2
то в этом случае вендору со своей стороны требуется реализовать REST-endpoint с доступом по HTTPS и поддерживающий HTTP-методы PUT, GET, DELETE:
https://<VENDOR-SERVER-ENDPOINT>/api/moysklad/vendor/1.0/apps/{appId}/{accountId}
где VENDOR-SERVER-ENDPOINT - тот URL, который указан в дескрипторе приложения.
Здесь
- appId
UUID
- идентификатор приложения в Маркетплейсе - accountId
UUID
- идентификатор аккаунта в МоемСкладе
Активация приложения на аккаунте
Запрос должен обрабатываться сервером идемпотентно. Маркетплейс может повторять/дублировать запросы в соответствии со своей внутренней логикой (например, при работе механизма Retry).
HTTP-метод: PUT
Content-Type: application/json
В теле запроса передаем:
- appUid
UUID
устанавливаемого приложения (может быть полезно видеть не только UUID приложения, но и его appUid - например, для разбора непонятных ситуаций и/или логирования) - accountName
String
- имя аккаунта, на который осуществляется подключение приложения (тоже полезно видеть не только UUID аккаунта, но и accountName) - cause
String
- основание (причина) активации, возможные значения:- Install - установка приложения на аккаунт
- Resume (возможно только у платных приложений) - возобновление работы приложения на аккаунте после приостановки
- access
Array
- доступы ресурсам, требуемым в дескрипторе приложения (например, к JSON API). Если ваше приложение не требует доступа к АПИ, то данный объект не придёт.- resource
String
- ресурс, к которому предоставлен доступ. Сейчас из ресурсов для приложений доступно только JSON API 1.2 (https://online.moysklad.ru/api/remap/1.2
) - scope
Array
- какие права предоставлены на доступ данному ресурсу. Сейчас доступ предоставляется с правами администратора аккаунта ("scope": ["admin"]
). - access_token
String
- Bearer токен доступа к данному ресурсу.
- resource
В теле ответа ожидаем получить следующую структуру:
- status
String
- статус активации приложения. Возможные значения: Activating, SettingsRequired, Activated.
Статус | Описание | Дальнейшие действия вендора | Отображаемый пользователю статус приложения на витрине приложений |
---|---|---|---|
Activating | приложение в процессе активации | вендор оповестит Маркетплейс по эндпоинту обратного вызова об изменении статуса приложения (на SettingsRequired или Activated) | приложение подключается |
SettingsRequired | требуется настройка приложения пользователем | вендор оповестит Маркетплейс об изменении статуса (на Activated), когда пользователь выполнит настройку приложения (через iframe) | приложение требует настройки |
Activated | приложение на аккаунте полностью активировано (и начало свою работу) | действий вендора не требуется | приложение подключено |
HTTP status codes:
- 200 OK - внешняя система (вендора) успешно обработала запрос на активацию приложения и вернула статус активации приложения на аккаунте в теле ответа
- 551 Lifecycle Processing Failed (кастомный статус) - внешняя система не смогла выполнить активацию приложения для аккаунта. Это ошибка активации приложения, установка приложения на аккаунте завершается с ошибкой, приложение НЕ становится установленным на аккаунт (переходит в специальное состояние ActivationFailed).
- прочие статусы обрабатываются как ошибка - запускается механизм Retry
Пример активации приложения при установке на аккаунт:
Request:
PUT https://example.com/baseurl/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
Body
{
"appUid": "example-app.example-vendor",
"accountName": "dummyaccount",
"cause": "Install",
"access": [
{
"resource": "https://online.moysklad.ru/api/remap/1.2",
"scope": ["admin"],
"access_token": "6ab89be1ae6ff147755625ee8da948e42612233b"
}
]
}
Response:
Response 200
Content-Type: application/json
Body:
{
"status": "SettingsRequired"
}
Пример активации платного приложения при возобновлении работы приложения на аккаунте (после поступления оплаты приложения):
Request:
PUT https://example.com/baseurl/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
Body
{
"appUid": "example-app.example-vendor",
"accountName": "dummyaccount",
"cause": "Resume",
"access": [
{
"resource": "https://online.moysklad.ru/api/remap/1.2",
"scope": ["admin"],
"access_token": "6ab89be1ae6ff147755625ee8da948e42612233b"
}
]
}
Response:
Response 200
Content-Type: application/json
Body:
{
"status": "Activated"
}
Деактивация приложения на аккаунте
HTTP-метод: DELETE
Тело запроса:
- cause
String
- основание (причина) деактивации, возможные значения:- Uninstall - удаление приложения на аккаунте
- Suspend (возможно только у платных приложений) - приостановка работы приложения на аккаунте
Тело ответа: пустое
HTTP status codes:
- 200 OK - приложение успешно отключено (деактивировано) во внешней системе вендора
- 404 Not Found - приложение отключено/или никогда не было подключено (никогда не активировалось для данного аккаунта)
- 551 Lifecycle Processing Failed (кастомный статус) - внешняя система не смогла выполнить деактивацию приложения для аккаунта
- прочие статусы обрабатываются как ошибка - запускается механизм Retry
Пример деактивации приложения при удалении с аккаунта:
Request:
DELETE https://example.com/baseurl/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
Body
{
"cause": "Uninstall"
}
Response:
Response 200
Content-Type: application/json
Пример деактивации платного приложения при приостановке приложения на аккаунте (при отсутствии оплаты приложения):
Request:
DELETE https://example.com/baseurl/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
Body
{
"cause": "Suspend"
}
Response:
Response 200
Content-Type: application/json
Проверка статуса активации приложения в системе вендора
HTTP-метод: GET
Тело запроса: пустое
Тело ответа:
- status
String
- статус активации приложения. Возможные значения: Activating, SettingsRequired, Activated.
HTTP status codes:
- 200 OK - приложение активировано или активируется во внешней системе (статус активации - в теле ответа)
- 404 Not Found - приложение отключено/или никогда не было подключено для данного аккаунта
Пример
Request:
GET https://example.com/api/moysklad/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f
Response:
Response 200
Content-Type: application/json
Response body
{
"status": "SettingsRequired"
}
REST-эндпоинты на стороне МоегоСклада
Rest-эндпоинты на стороне МоегоСклада позволяют Вендору ограниченно управлять состоянием установки приложения для конкретного аккаунта, а также позволяют узнать информацию о пользователе, который загружает iframe-приложение в UI МоегоСклада.
Базовый URL REST-эндпоинтов со стороны МоегоСклада (далее будем называть его MARKETPLACE-ENDPOINT
):
https://online.moysklad.ru/api/vendor/1.0
На текущий момент со стороны МоегоСклада есть следующие эндпоинты:
- Получение или изменение статуса приложения на аккаунте
- Получение контекста пользователя для iframe-приложений
Получение или изменение статуса приложения на аккаунте
С помощью этого эндпоинта вендор может получить или изменить статус приложения пользователя.
Resource: MARKETPLACE-ENDPOINT/apps/{appId}/{accountId}/status
Здесь
- appId
UUID
- идентификатор приложения в Маркетплейсе - accountId
UUID
- идентификатор аккаунта в МоемСкладе
Получение статуса приложения на аккаунте
HTTP-метод: GET
Тело запроса: отсутствует
Тело ответа:
В случае успешного ответа возвращается текущий статус приложения на аккаунте с опциональным указанием cause. В случае, если приложение не подключено на данном аккаунте (в том числе, если указанный аккаунт отсутствует в МоемСкладе) возвращается ошибка 404 Not Found (код 2004).
Атрибуты сущности
Название | Тип | Описание | Обязательное при ответе |
---|---|---|---|
status | String | Текущий статус приложения на аккаунте | да |
cause | String | Причина перехода в текущий статус | нет |
Таблица возможных статусов приложения на аккаунте
status | cause | Что означает |
---|---|---|
Activating | Install | Приложение в процессе установки на аккаунт |
ActivationFailed | Install | Произошла ошибка при установке приложения на аккаунт |
SettingsRequired | Приложение успешно установлено на акканут и для своей полноценной работы требует настройки пользователем | |
Activated | Приложение активно на аккаунте (успешно установлено на аккаунт и, если нужно, настроено пользователем) | |
Deactivating | Uninstall | Приложение в процессе удаления с аккаунта |
DeactivationFailed | Uninstall | Произошла ошибка при удалении приложения с аккаунта |
Deactivating | Suspend | Приложение в процессе приостановки на аккаунте |
DeactivationFailed | Suspend | Произошла ошибка во время приостановки приложения на аккаунте |
Suspended | Приложение приостановлено на аккаунте | |
Activating | Resume | Приложение в процессе возобновления работы на аккаунте |
ActivationFailed | Resume | Произошла ошибка во время возобновления работы приложения на аккаунте |
HTTP status codes:
- 200 OK - всё в порядке, в ответе отдается состояние приложения.
- 404 Not Found - приложение не подключено на данном аккаунте (код 2004).
Пример
Request:
GET https://online.moyslad.ru/api/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f/status
Response:
Response 200
Content-Type: application/json
Body:
{
"status": "Activating",
"cause": "Install"
}
Обратный вызов изменения статуса приложения на аккаунте
С помощью PUT запроса вендор может изменить статус устанавливающегося приложения пользователя. При активации приложения со стороны вендора, вендор может ответить одним из статусов Activated, Activating, SettingsRequired. Если вендор перевел в статусы Activating и SettingsRequired, то МойСклад ожидает, что вендор с помощью обратного вызова оповестит МойСклад о том, что активация на его стороне завершена.
HTTP-метод: PUT
Тело запроса:
- status
String
- текущий актуальный статус приложения. Возможные значения: Activating, SettingsRequired, Activated.
МойСклад при обработке данного запроса проверяет возможность перехода приложения на аккаунте в требуемое состояние в соответствии с жизненным циклом приложения на аккаунте. При отсутствии перехода по жизненному циклу - ошибка. Если приложение на аккаунте уже находится в целевом состоянии - то ошибки нет.
Тело ответа: пустое (за исключением ошибок)
HTTP status codes:
- 200 OK - МойСклад перевел приложение на аккаунте в соответствующее переданному статусу состояние (или приложение уже находилось в требуемом состоянии)
- 404 Not Found - приложение не подключено на данном аккаунте
- 409 Conflict - в случае отсутствия соответствующего перехода по жизненному циклу приложения на аккаунте
Пример
Request:
PUT https://online.moyslad.ru/api/vendor/1.0/apps/5f3c5489-6a17-48b7-9fe5-b2000eb807fe/f088b0a7-9490-4a57-b804-393163e7680f/status
Body
{
"status": "Activating"
}
Response:
Response 200
Content-Type: application/json
Получение контекста пользователя для приложений с iframe-частью
Через этот эндпоинт можно получить информацию по пользователю, который загружает приложение c iframe-частью в UI МоегоСклада.
В URL, по которому загружается iframe-часть приложения, добавляется GET-параметр contextKey.
Пример того, что будет загружаться в Iframe, при условии, что в дескрипторе приложения
Iframe имеет значение https://yoursite.ru/moysklad
: https://yoursite.ru/moysklad?contextKey=1c14e98cd272239c03bf3d9697f167699743292c
.
contextKey - это одноразовый ключ, который может быть использован не более одного раза для получения контекста
пользователя через данный эндпоинт. В случае повторного использования contextKey - эндпоинт вернет ошибку.
Resource: MARKETPLACE-ENDPOINT/context/{contextKey}
Здесь
- contextKey
String
- одноразовый ключ, переданный ранее GET-параметром при загрузке iframe
HTTP-метод: POST
Тело запроса: пустое
Тело ответа:
В случае успешного ответа возвращается такое же по структуре содержимое как в https://online.moysklad.ru/api/remap/1.2/context/employee
В случае ошибок - JSON-объект с ошибкой. Подробнее см. Обработка ошибок МоегоСклада.
HTTP status codes:
- 200 OK - все в порядке, в ответе отдается контекст пользователя
- 403 Forbidden - приложение не авторизовано на доступ по данному contextKey
- 404 Not Found - contextKey не найден
- 409 Conflict - приложение авторизовано, но данный contextKey уже был использован
Пример
Request:
POST https://online.moysklad.ru/api/vendor/1.0/context/6S3BQLsaSRNdEnhPCoW9lplY2LozRUOq6S3BQLsaSRNdEnh
Response 200 (application/json). Успешный запрос.
{
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.2/entity/employee/b0a02321-13e3-11e9-912f-f3d4002516e3?expand=cashier.retailStore",
"metadataHref": "https://online.moysklad.ru/api/remap/1.2/entity/employee/metadata",
"type": "employee",
"mediaType": "application/json",
"uuidHref": "https://online.moysklad.ru/app/#employee/edit?id=b0a02321-13e3-11e9-912f-f3d4002516e3"
},
"id": "b0a02321-13e3-11e9-912f-f3d4002516e3",
"accountId": "b0b309ee-13e3-11e9-9109-f8fc0001f188",
"owner": {
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.2/entity/employee/b0a02321-13e3-11e9-912f-f3d4002516e3",
"metadataHref": "https://online.moysklad.ru/api/remap/1.2/entity/employee/metadata",
"type": "employee",
"mediaType": "application/json",
"uuidHref": "https://online.moysklad.ru/app/#employee/edit?id=b0a02321-13e3-11e9-912f-f3d4002516e3"
}
},
"shared": true,
"group": {
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.2/entity/group/b0b3c289-13e3-11e9-9109-f8fc0001f189",
"metadataHref": "https://online.moysklad.ru/api/remap/1.2/entity/group/metadata",
"type": "group",
"mediaType": "application/json"
}
},
"updated": "2019-12-10 18:37:25.786",
"name": "Кожевников",
"externalCode": "Exh56G1wiRTPHpYBc-nx12",
"archived": false,
"created": "2019-01-09 10:53:45.202",
"uid": "admin@bkozhevnikov",
"email": "bkozhevnikov@moysklad.ru",
"lastName": "Кожевников",
"fullName": "Кожевников",
"shortFio": "Кожевников",
"cashiers": [
{
"meta": {
"href": "https://online.moysklad.ru/api/remap/1.2/entity/retailstore/b0b7cd8d-13e3-11e9-912f-f3d400251724/cashiers/b0b7d387-13e3-11e9-912f-f3d400251725",
"type": "cashier",
"mediaType": "application/json"
}
}
],
"permissions": {
"currency": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"uom": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"productfolder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"product": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"bundle": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"service": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"consignment": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"variant": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"store": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"counterparty": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"organization": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"employee": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"contract": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"project": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"country": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"customentity": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"demand": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"customerorder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"internalorder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"invoiceout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"invoicein": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"paymentin": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"paymentout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"cashin": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"cashout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"supply": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"salesreturn": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"purchasereturn": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"retailstore": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"receipttemplate": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"retailshift": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"retaildemand": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"retailsalesreturn": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"retaildrawercashin": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"retaildrawercashout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"prepayment": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"prepaymentreturn": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"purchaseorder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"move": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"enter": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"loss": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"facturein": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"factureout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"commissionreportin": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"commissionreportout": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"pricelist": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"processingplanfolder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"processingplan": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"processing": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"processingorder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"assortment": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"inventory": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"print": "ALL"
},
"bonustransaction": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"crptorder": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"approve": "ALL",
"print": "ALL"
},
"webhook": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL"
},
"task": {
"view": "ALL",
"create": "ALL",
"update": "ALL",
"delete": "ALL",
"done": "ALL"
},
"dashboard": {
"view": "ALL"
},
"stock": {
"view": "ALL"
},
"customAttributes": {
"view": "ALL"
},
"pnl": {
"view": "ALL"
},
"company_crm": {
"view": "ALL"
},
"tariff_crm": {
"view": "ALL"
},
"audit_dashboard": {
"view": "ALL"
},
"admin": {
"view": "ALL"
},
"dashboardMoney": {
"view": "ALL"
}
}
}
Обработка ошибок на стороне МоегоСклада
Обработка ошибок на стороне МоегоСклада (при взаимодействии Вендор → МойСклад) выполняется аналогично тому, как это сделано в JSON API 1.2 https://dev.moysklad.ru/doc/api/remap/1.2/ - в тело ответа включается JSON объект с описанием ошибки и также проставляются (если нужно) соответствующие HTTP-заголовки в ответе.
Механизм Retry
Механизм Retry повторяет попытки выполнить запрос к системе вендора в соответствии с некоторым конфигурационным профилем, глобальным для Маркетплейса, задаваемым в общем случае двумя параметрами:
- максимальным количеством повторений
- функцией delay(i), возвращающей время задержки до очередного повтора
Если израсходованы все количества повторений, то Retry завершается с ошибкой. Что система делает далее - зависит от контекста (какую операцию мы пытались выполнить).