Как создать приложение для магазина/маркетплейс InSales

--- ## Разработка приложений для InSales Полное руководство по созданию, тестированию и публикации приложений для платформы InSales. Включает требования к API, процесс интеграции и чек-лист для размещения в официальном маркетплейсе. --- ### Основы API InSales #### Архитектура API **API InSales** работает через HTTP протокол с использованием REST-принципов и поддержкой стандартных методов. **Технические характеристики:** | Параметр | Значение | |:---------|:---------| | Протокол | HTTP/HTTPS | | Методы | GET, POST, PUT, DELETE | | Форматы данных | XML, JSON | | Аутентификация | Basic Authorization | | Кодировка | UTF-8 | **Поддерживаемые форматы:** ```http Content-Type: application/xml Content-Type: application/json ``` > **Important:** Обязательно указывайте заголовок `Content-Type` в каждом запросе для корректной обработки данных. #### Структура API endpoints **Основные группы объектов:** | Объект | Endpoint | Операции | |:-------|:---------|:---------| | Заказы | `/admin/orders.json` | CRUD | | Товары | `/admin/products.json` | CRUD | | Категории | `/admin/collections.json` | CRUD | | Клиенты | `/admin/clients.json` | CRUD | | Платежи | `/admin/payment_gateways.json` | CRUD | | Доставки | `/admin/delivery_variants.json` | CRUD | **Пример базового запроса:** ```bash # GET запрос списка заказов curl -X GET \ https://your-store.myinsales.ru/admin/orders.json \ -H 'Content-Type: application/json' \ -u 'app_id:password' ``` --- ### Создание приложения #### Регистрация в бэк-офисе магазина Шаг 1. Создание приложения **Путь в админ-панели:** ``` Бэк-офис → Приложения → Разработчикам → Создать приложение ``` **Обязательные поля:** | Поле | Описание | Требования | |:-----|:---------|:-----------| | Название приложения | Отображается в списке приложений | До 50 символов, понятное название | | Идентификатор приложения | Используется как логин для Basic Auth | Только латиница и цифры, без пробелов | | Секрет | Секретный ключ для установки | Генерируется автоматически, можно изменить | | Краткое описание | HTML-описание в списке приложений | До 500 символов, с форматированием | | URL установки | Endpoint для установки | Без параметров, только базовый URL | | URL страницы приложения | Куда переходит пользователь после установки | Полный URL с протоколом | | URL удаления | Endpoint для деинсталляции | Полный URL с протоколом | | Картинка | Логотип приложения | 250x100 px, PNG/JPG | | Компания-разработчик | Название вашей компании | Полное официальное название | | Контакты | Email/телефон для пользователей | Рабочие контакты поддержки | Шаг 2. Настройка параметров **Пример заполнения:** ```json { "name": "Интеграция с 1С", "identifier": "integration_1c", "secret": "a1b2c3d4e5f6g7h8i9j0", "description": "

Автоматическая синхронизация товаров и заказов с 1С:Предприятие

", "install_url": "https://myapp.example.com/install", "app_url": "https://myapp.example.com/dashboard", "uninstall_url": "https://myapp.example.com/uninstall", "company": "ООО «Разработка»", "contacts": "support@example.com, +7 (999) 123-45-67" } ``` **Генерация секретного ключа:** ```javascript // Пример генерации безопасного секрета const crypto = require('crypto'); const secret = crypto.randomBytes(32).toString('hex'); console.log(secret); ``` > **Important:** Секретный ключ не должен быть известен никому, кроме вашей системы. Храните его в защищенном месте. --- ### Авторизация #### Basic Authorization **Принцип работы:** ``` Authorization: Basic base64(app_identifier:password) ``` **Параметры аутентификации:** | Параметр | Источник | Использование | |:---------|:---------|:--------------| | **Login** | Идентификатор приложения | Общий для всех магазинов | | **Password** | Генерируется при установке | Уникален для каждого магазина | Процесс установки и получения пароля **Когда пользователь устанавливает приложение:** 1. InSales отправляет POST-запрос на `install_url` 2. В теле запроса передается уникальный пароль 3. Приложение сохраняет пароль для этого магазина 4. Все последующие запросы используют этот пароль **Пример обработчика установки:** ```javascript // POST /install app.post('/install', (req, res) => { const { insales_id, // ID магазина shop, // Домен магазина token, // Пароль для API email, // Email владельца tariff // Тариф магазина } = req.body; // Сохранение credentials в базу данных await saveShopCredentials({ shop_id: insales_id, domain: shop, api_password: token, owner_email: email }); // Перенаправление на страницу настроек res.redirect(`https://myapp.example.com/setup?shop=${shop}`); }); ``` Примеры запросов с авторизацией **JavaScript (Node.js):** ```javascript const fetch = require('node-fetch'); const makeApiRequest = async (shop, endpoint) => { const credentials = await getShopCredentials(shop); const auth = Buffer.from( `${APP_IDENTIFIER}:${credentials.api_password}` ).toString('base64'); const response = await fetch( `https://${shop}/admin/${endpoint}`, { headers: { 'Authorization': `Basic ${auth}`, 'Content-Type': 'application/json' } } ); return await response.json(); }; // Использование const orders = await makeApiRequest('shop.myinsales.ru', 'orders.json'); ``` **Python:** ```python import requests from base64 import b64encode def make_api_request(shop, endpoint): credentials = get_shop_credentials(shop) auth_string = f"{APP_IDENTIFIER}:{credentials['api_password']}" auth_bytes = auth_string.encode('utf-8') auth_base64 = b64encode(auth_bytes).decode('utf-8') headers = { 'Authorization': f'Basic {auth_base64}', 'Content-Type': 'application/json' } response = requests.get( f'https://{shop}/admin/{endpoint}', headers=headers ) return response.json() # Использование orders = make_api_request('shop.myinsales.ru', 'orders.json') ``` **cURL:** ```bash # Формирование Base64 строки echo -n "app_id:password" | base64 # Результат: YXBwX2lkOnBhc3N3b3Jk # Запрос с авторизацией curl -X GET \ https://shop.myinsales.ru/admin/orders.json \ -H 'Authorization: Basic YXBwX2lkOnBhc3N3b3Jk' \ -H 'Content-Type: application/json' ``` --- ### Лимиты и ограничения API #### Rate Limiting **Ограничения запросов:** ``` 500 запросов к API одного магазина за 5 минут ``` **Как работает:** - Время рассчитывается с момента первого запроса в серии - После 500-го запроса доступ блокируется до окончания 5-минутного окна - Счетчик сбрасывается по истечении 5 минут с первого запроса Отслеживание лимитов **HTTP заголовок ответа:** ```http API-Usage-Limit: 245/500 ``` **Формат:** `текущее_количество/максимум` **Пример обработки лимитов:** ```javascript const makeApiRequestWithRetry = async (shop, endpoint, retries = 3) => { try { const response = await fetch(url, options); // Проверка лимита const usage = response.headers.get('API-Usage-Limit'); const [current, max] = usage.split('/').map(Number); console.log(`API Usage: ${current}/${max}`); // Предупреждение при приближении к лимиту if (current > max * 0.9) { console.warn('⚠️ Приближаемся к лимиту API!'); } return await response.json(); } catch (error) { if (error.status === 503 && retries > 0) { // Получение времени ожидания const retryAfter = error.headers.get('Retry-After'); console.log(`Превышен лимит. Ожидание ${retryAfter} секунд...`); // Ожидание и повторная попытка await sleep(retryAfter * 1000); return makeApiRequestWithRetry(shop, endpoint, retries - 1); } throw error; } }; ``` Обработка ошибки 503 **При превышении лимита:** ```http HTTP/1.1 503 Service Unavailable Retry-After: 180 ``` **Заголовок `Retry-After`:** Время в секундах до восстановления доступа. **Стратегии оптимизации:** 1. **Батчинг запросов:** ```javascript // Вместо 100 запросов по одному товару const product = await getProduct(id); // Делаем 1 запрос за список товаров const products = await getProducts({ ids: [1,2,3,...,100] }); ``` 2. **Кэширование:** ```javascript const cache = new Map(); const getCachedData = async (key, fetcher, ttl = 300) => { if (cache.has(key)) { const { data, timestamp } = cache.get(key); if (Date.now() - timestamp < ttl * 1000) { return data; } } const data = await fetcher(); cache.set(key, { data, timestamp: Date.now() }); return data; }; ``` 3. **Очередь с throttling:** ```javascript const Queue = require('bull'); const apiQueue = new Queue('insales-api'); // Ограничение: 100 задач в минуту apiQueue.process('api-request', { limiter: { max: 100, duration: 60000 } }, async (job) => { return await makeApiRequest(job.data); }); ``` --- ### Публикация в маркетплейсе InSales #### Требования для размещения > **Important:** Для размещения приложения в [apps.insales.ru](https://apps.insales.ru/) необходимо пройти тщательную проверку соответствия стандартам качества. **Необходимые документы:** - [ ] Актуальная карточка приложения - [ ] Подробная инструкция по установке и настройке - [ ] Описание функционала - [ ] Контакты технической поддержки - [ ] Тестовые аккаунты (при необходимости) **Куда отправлять:** Актуальную информацию о приложении нужно прислать через [форму регистрации в маркетплейсе](https://www.insales.ru/apps/submit) или на email: apps@insales.ru --- ### Чек-лист проверки приложения #### Документация и описание Карточка приложения **Требования к описанию:** - [ ] Соответствие всем актуальным данным - [ ] Корректное название и логотип (250x100 px) - [ ] Полное описание функционала - [ ] Понятные преимущества для пользователя - [ ] Информация о тарифах и ценах - [ ] Скриншоты интерфейса - [ ] Контакты поддержки > **Important:** Просто ссылка на сайт вместо инструкции — это недопустимо. Инструкция должна быть детальной и актуальной. **Пример хорошей инструкции:** ```markdown ## Установка приложения "Интеграция с 1С" ### Шаг 1. Установка 1. Перейдите в раздел "Приложения" в бэк-офисе 2. Найдите "Интеграция с 1С" 3. Нажмите "Установить" ### Шаг 2. Настройка в 1С 1. Откройте 1С:Предприятие 2. Установите обработку из файла setup_1c.epf 3. Запустите обработку ... ``` #### Установка приложения Уровень доступа **Проверка разрешений:** - [ ] Уровень доступа соответствует описанию - [ ] Нет лишних разрешений - [ ] Все необходимые разрешения запрошены **Примеры правильных разрешений:** | Приложение | Требуемые разрешения | |:-----------|:--------------------| | Синхронизация товаров | `read_products`, `write_products` | | Обработка заказов | `read_orders`, `write_orders` | | Email-маркетинг | `read_clients` | | Аналитика | `read_orders`, `read_products` | Совместимость с платформами **Тестирование на всех доменных зонах:** - [ ] .ru (Россия) - [ ] .kz (Казахстан) - [ ] .com.ua (Украина) - [ ] Другие зоны по мере запуска **Тестирование доменов:** - [ ] Латиница (shop.myinsales.ru) - [ ] Кириллица (магазин.myinsales.ru) **Пример обработки разных доменов:** ```javascript const normalizeShopDomain = (domain) => { // Поддержка кириллических доменов const punycode = require('punycode'); // Конвертация в ASCII const asciiDomain = punycode.toASCII(domain); return asciiDomain; }; ``` Автоматическое создание данных **При установке приложение должно автоматически создавать:** - [ ] Способы доставки (если требуются) - [ ] Способы оплаты (если требуются) - [ ] Дополнительные поля заказов/товаров - [ ] Веб-хуки для обработки событий - [ ] JavaScript-теги (если требуются) **Пример автоматического создания способа оплаты:** ```javascript const createPaymentGateway = async (shop, credentials) => { const response = await fetch( `https://${shop}/admin/payment_gateways.json`, { method: 'POST', headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ payment_gateway: { type: 'PaymentGateway::External', title: 'Оплата через наше приложение', description: 'Безопасная оплата картой', margin: 0, position: 1, active: true, payment_gateway_type: 'external' } }) } ); return await response.json(); }; ``` #### Пользовательский интерфейс Удобство настройки **Требования к интерфейсу:** - [ ] Сохранение введенных данных - [ ] Понятные названия полей - [ ] Подсказки к сложным параметрам - [ ] Валидация полей при вводе - [ ] Четкие сообщения об ошибках **Обязательные элементы:** - [ ] Кнопка перехода в бэк-офис магазина - [ ] Инструкция/FAQ прямо в интерфейсе - [ ] Контакты поддержки - [ ] Индикаторы загрузки при долгих операциях **Пример кнопки возврата в бэк-офис:** ```html
← Вернуться в админ-панель

Настройки приложения

``` Работа на сайте **После настройки проверяется:** - [ ] Вывод необходимых полей и блоков - [ ] Отсутствие нарушений верстки сайта - [ ] Корректная работа на мобильных устройствах - [ ] Совместимость с разными темами оформления **Внедрение скриптов без нарушения верстки:** ```javascript // Правильно: изоляция стилей (function() { const styles = document.createElement('style'); styles.textContent = ` .my-app-widget { /* Специфичные стили с префиксом */ } `; document.head.appendChild(styles); })(); // Неправильно: глобальные стили ``` #### Функциональность Доставки и оплаты **Если приложение создает способы доставки/оплаты:** - [ ] Корректный вывод в чекауте - [ ] Расчет стоимости доставки - [ ] Обработка платежей - [ ] Обновление статусов **Пример обработки расчета доставки:** ```javascript // Endpoint для расчета стоимости доставки app.post('/calculate-shipping', async (req, res) => { const { weight, // Вес заказа dimensions, // Габариты destination, // Адрес доставки items // Список товаров } = req.body; try { // Расчет через API службы доставки const cost = await calculateShippingCost({ weight, destination }); res.json({ success: true, cost: cost, delivery_time: '2-3 дня' }); } catch (error) { res.json({ success: false, error: 'Не удалось рассчитать стоимость доставки' }); } }); ``` Передача данных **Синхронизация с внешними системами:** - [ ] Передача данных от InSales к приложению - [ ] Передача данных от приложения к InSales - [ ] Передача в сторонние системы (при необходимости) - [ ] Обработка ошибок синхронизации - [ ] Логирование операций > **Note:** Для проверки могут потребоваться тестовые аккаунты во внешних системах. Виджеты приложения **Если приложение использует виджеты:** - [ ] Корректное отображение виджета - [ ] Работа без ошибок JavaScript - [ ] Обновление данных в реальном времени - [ ] Адаптивность под размер окна **Типичные места размещения виджетов:** - Страница заказа в бэк-офисе - Страница товара в бэк-офисе - Страница клиента в бэк-офисе - Dashboard магазина **Пример регистрации виджета:** ```javascript // При установке приложения const createWidget = async (shop, credentials) => { await fetch(`https://${shop}/admin/widgets.json`, { method: 'POST', headers: { 'Authorization': `Basic ${credentials}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ widget: { code: 'order_tracking', placement: 'order_show', html: '' } }) }); }; ``` #### Биллинг Выставление счетов **Если предусмотрены платные тарифы:** - [ ] Четкое описание тарифных планов - [ ] Автоматическое выставление счетов - [ ] Пробный период (рекомендуется) - [ ] Уведомления об окончании подписки - [ ] Возможность смены тарифа **Пример реализации тарифных планов:** ```javascript const TARIFF_PLANS = { free: { name: 'Бесплатный', price: 0, features: { orders_per_month: 50, support: 'email' } }, pro: { name: 'Профессиональный', price: 990, features: { orders_per_month: 1000, support: 'priority' } }, enterprise: { name: 'Корпоративный', price: 4990, features: { orders_per_month: -1, // Без ограничений support: '24/7', dedicated_manager: true } } }; ``` #### Удаление и переустановка Удаление приложения **Требования при удалении:** - [ ] Не нарушается работа сайта - [ ] Автоматическое удаление виджетов - [ ] Автоматическое удаление JS-тегов - [ ] Автоматическое удаление источников для ПВЗ > **Important:** InSales автоматически удаляет виджеты и JS-теги. Остальное следует удалять через API при необходимости. **Что НЕ следует удалять:** - Созданные заказы - Добавленные товары - Структуру категорий - Исторические данные клиентов **Обработчик удаления:** ```javascript // POST /uninstall app.post('/uninstall', async (req, res) => { const { insales_id, shop } = req.body; try { // Удаление созданных приложением данных await cleanupAppData(shop, { // Удаляем способы доставки deleteDeliveryMethods: true, // Удаляем способы оплаты deletePaymentMethods: true, // НЕ удаляем заказы и товары preserveOrders: true, preserveProducts: true }); // Деактивация подписки await deactivateSubscription(insales_id); // Сохранение данных для возможной переустановки await archiveShopData(insales_id); res.status(200).send('OK'); } catch (error) { console.error('Ошибка при удалении:', error); res.status(500).send('Error'); } }); ``` Переустановка приложения **При переустановке должно происходить:** - [ ] Восстановление существующей учетной записи - [ ] Подхватывание старых данных и настроек - [ ] Отсутствие необходимости повторной регистрации - [ ] Сохранение истории и статистики **Обработка переустановки:** ```javascript app.post('/install', async (req, res) => { const { insales_id, shop, token } = req.body; // Проверка на существующий аккаунт const existingAccount = await findAccount(insales_id); if (existingAccount) { // Переустановка - восстанавливаем данные await reactivateAccount(insales_id, token); await restoreSettings(insales_id); res.redirect(`https://myapp.com/dashboard?shop=${shop}&reinstall=true`); } else { // Новая установка await createNewAccount(insales_id, shop, token); res.redirect(`https://myapp.com/setup?shop=${shop}`); } }); ``` #### Авторизация в приложении Вход в установленное приложение **Требования:** - [ ] Доступ не только при первой установке - [ ] Доступ при последующих входах - [ ] Автоматическая авторизация (рекомендуется) - [ ] Отсутствие повторных запросов логина/пароля **Реализация автоматической авторизации:** ```javascript // Генерация временного токена при входе из InSales app.get('/auth', (req, res) => { const { shop, timestamp, signature } = req.query; // Валидация подписи if (!validateSignature(shop, timestamp, signature)) { return res.status(403).send('Invalid signature'); } // Генерация сессионного токена const sessionToken = generateSessionToken(shop); // Установка cookie res.cookie('app_session', sessionToken, { httpOnly: true, secure: true, maxAge: 24 * 60 * 60 * 1000 // 24 часа }); res.redirect('/dashboard'); }); // Middleware для проверки авторизации const requireAuth = (req, res, next) => { const sessionToken = req.cookies.app_session; if (!sessionToken || !validateSessionToken(sessionToken)) { return res.redirect('/auth-required'); } next(); }; ``` --- ### Развертывание и CI/CD #### Использование GitLab > **Note:** InSales использует GitLab для управления кодом приложений. Для получения доступа обратитесь к администратору. **Структура репозитория:** ``` my-insales-app/ ├── .gitlab-ci.yml # CI/CD конфигурация ├── src/ │ ├── api/ # API endpoints │ ├── services/ # Бизнес-логика │ ├── models/ # Модели данных │ └── utils/ # Вспомогательные функции ├── public/ │ ├── assets/ # Статика │ └── widgets/ # Виджеты ├── tests/ │ ├── unit/ # Юнит-тесты │ └── integration/ # Интеграционные тесты ├── docs/ │ └── SETUP.md # Инструкция по установке ├── package.json └── README.md ``` **Пример .gitlab-ci.yml:** ```yaml stages: - test - build - deploy test: stage: test script: - npm install - npm run test - npm run lint build: stage: build script: - npm run build artifacts: paths: - dist/ deploy_production: stage: deploy script: - npm run deploy:prod only: - main when: manual ``` --- ### Полезные ресурсы #### Официальная документация **Основные ресурсы:** | Ресурс | URL | Описание | |:-------|:----|:---------| | API Reference | [api.insales.ru](https://api.insales.ru/) | Полная документация API | | Developers Guide | [insales-doc.myinsales.ru](http://insales-doc.myinsales.ru/) | Руководство разработчика | | API Cheat Sheet | [cheat-sheet.myinsales.ru](http://cheat-sheet.myinsales.ru/) | Быстрая справка по API | | Wiki | [wiki.insales.ru](https://wiki.insales.ru/wiki/) | База знаний | | GitHub | [github.com/insales](https://github.com/insales) | Открытый код и примеры | #### Шпаргалки и гайды **JavaScript API:** - [Шпаргалка по JS API InSales v2](http://cheat-sheet.myinsales.ru/js-api/) - Работа с корзиной, товарами, событиями **Liquid Templates:** - [Shopify Liquid Cheat Sheet](https://www.shopify.com/partners/shopify-cheat-sheet) - [Переменные Liquid в темах InSales](http://wiki.insales.ru/wiki/liquid) **UI Компоненты:** - [VueUI - Библиотека компонентов InSales](https://github.com/insales/vue-ui) - Готовые компоненты для построения интерфейсов #### Обучающие материалы **YouTube канал InSales:** - [Обучающие ролики](https://www.youtube.com/insales) - Видео-туториалы по разработке - Вебинары для разработчиков **Архитектура платформы:** ``` ┌─────────────────────────────────────────┐ │ InSales Platform │ ├─────────────────────────────────────────┤ │ ┌────────────┐ ┌───────────────────┐ │ │ │ Storefront │ │ Admin Panel │ │ │ │ (Liquid) │ │ (BackOffice) │ │ │ └────────────┘ └───────────────────┘ │ ├─────────────────────────────────────────┤ │ REST API (JSON/XML) │ ├─────────────────────────────────────────┤ │ ┌──────────┐ ┌────────┐ ┌──────────┐ │ │ │ Orders │ │Products│ │ Clients │ │ │ └──────────┘ └────────┘ └──────────┘ │ │ ┌──────────┐ ┌────────┐ ┌──────────┐ │ │ │ Webhooks │ │Payments│ │ Delivery │ │ │ └──────────┘ └────────┘ └──────────┘ │ └─────────────────────────────────────────┘ ▲ ▼ ┌─────────────────────────┐ │ Your Application │ │ (External Service) │ └─────────────────────────┘ ``` --- ### Техническая поддержка > **Important:** При возникновении вопросов по разработке или публикации приложений обращайтесь в поддержку InSales. **Контакты:** - **Email поддержки разработчиков:** developers@insales.ru - **Email для публикации приложений:** apps@insales.ru - **Telegram-чат разработчиков:** @insales_developers - **Форум:** [forum.insales.ru](https://forum.insales.ru/) **WS24.pro — Профессиональная разработка:** - Разработка приложений под ключ - Интеграции с внешними системами - Техническая поддержка и доработки - Консультации по архитектуре --- > **Note:** Разработка качественного приложения для InSales требует понимания платформы, соблюдения стандартов и тщательного тестирования. Следуйте этому руководству и чек-листу проверки, чтобы ваше приложение успешно прошло модерацию и было опубликовано в официальном маркетплейсе. При необходимости обращайтесь к специалистам WS24.pro для профессиональной помощи в разработке.