Как создать приложение для магазина/маркетплейс 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 для профессиональной помощи в разработке.