Как подключить API поставщика цифровых товаров
Подключение API поставщика — это не «сделать один curl и радоваться». Это отдельный сервисный слой, который переживает падения чужого API, не выдаёт клиенту чужой код дважды и не роняет вашу витрину, когда у поставщика идёт деплой. Ниже — рабочая последовательность шагов от первого ключа до чек-листа выхода в прод.
Архитектура — три слоя, не два
Единственная схема, которая нормально живёт в продакшене, выглядит так:
API поставщика → ваш middleware → витрина.
Middleware — это ваш собственный сервис (или набор фоновых задач и внутренних эндпоинтов), который знает ключ поставщика, хранит локальную копию каталога, создаёт заказы, опрашивает их статус и отдаёт витрине только уже нормализованные данные.
Чего делать нельзя категорически:
- Вызывать API поставщика напрямую из браузера или мобильного приложения. Это означает, что ключ уехал на клиента. Ключ поставщика — серверный секрет, всегда.
- Ходить в API поставщика на каждый рендер страницы каталога. Вы упрётесь в rate limit и сделаете доступность своего сайта заложником чужого аптайма.
- Держать бизнес-логику выдачи в контроллере витрины. Выдача должна быть идемпотентной операцией в отдельном сервисе, иначе двойной клик клиента превратится в двойной заказ.
Шаг 1. Ключи и окружения
Первое, что вы получаете от поставщика, — ключ доступа. Уточните у него три вещи:
- Какой заголовок авторизации. Это может быть
X-API-Key, может бытьAuthorization: Bearer, может быть подпись запроса. У FoxReload этоX-API-Key: YOUR_API_KEY— никаких Bearer-токенов, OAuth или client_id/client_secret. - Показывается ли ключ повторно. У большинства поставщиков — нет. У FoxReload ключ показывается один раз, поэтому сразу кладите его в секрет-менеджер (Vault, AWS Secrets Manager, Doppler), а не в
.envв репозитории. - Есть ли IP-allowlist. Если есть — включайте. У FoxReload ключ можно ограничить по IP или CIDR, до 10 записей; запрос с чужого IP вернёт
HTTP 403, что гораздо лучше, чем утёкший и работающий отовсюду ключ.
Отдельный вопрос — тестовое окружение
Многие поставщики дают отдельный sandbox-домен. Многие — нет. У FoxReload отдельного sandbox-окружения не существует: тестирование делается флагом isMock: true в теле создания заказа — заказ возвращает мок-коды с той же структурой ответа, без реального списания с баланса.
Это принципиальный момент для проектирования: уточните у своего поставщика, как именно тестировать, до того как напишете первый интеграционный тест. Если тестовый режим — это флаг в теле запроса, ваш код должен уметь прокидывать этот флаг сквозь весь стек, а ваша база — отличать мок-заказы от реальных.
Шаг 2. Синхронизация каталога и цен
Каталог — это фоновая задача, а не запрос по требованию.
curl "https://public-api.foxreload.com/api/categories/?limit=20" \
-H "X-API-Key: YOUR_API_KEY"
Затем по каждой категории забираются товары:
curl "https://public-api.foxreload.com/api/products/?category_id_or_slug=gift-cards&limit=20" \
-H "X-API-Key: YOUR_API_KEY"
Товар приходит с id, name и price. Поле id — это то, что вы позже передадите как itemId при создании заказа, поэтому его нужно сохранить в своей таблице как внешний ключ поставщика.
Практические правила синхронизации:
- Храните
supplier_product_idрядом со своим внутренним SKU. Никогда не привязывайте свою витрину напрямую к идентификаторам одного поставщика — иначе добавление второго поставщика превратится в переписывание половины кода. - Обновляйте цены отдельной, более частой задачей, чем полный обход каталога. Названия и описания меняются редко, цены — регулярно.
- Никогда не удаляйте товар из своей базы по факту его отсутствия в одном ответе. Помечайте флагом
unavailable. Частичный ответ или таймаут не должны обнулять ваш каталог. - Ведите наценку в своей системе, а не в закупочной цене. Закупочная цена от поставщика — входные данные; розничная цена вашей витрины считается вашим движком ценообразования.
Шаг 3. Проверка баланса
Оптовые API цифровых товаров чаще всего работают с предоплаченного баланса: вы пополняете счёт, заказы списывают с него. Значит, у вас появляется новый класс отказов — заказ не выполнился не потому, что сломался код, а потому что кончились деньги.
Что нужно сделать:
- Читать баланс перед созданием заказа, если сумма заказа заметная.
- Держать фоновый мониторинг баланса с двумя порогами — «предупреждение» и «критично», с алертом в тот канал, который реально читают ночью.
- Корректно обрабатывать ошибку недостатка средств. У FoxReload это
BalanceNotEnough; пополнение делается черезPOST /api/topups/crypto/. Уточните у своего поставщика, какие способы пополнения он поддерживает и сколько времени занимает зачисление — это напрямую определяет, какой запас вам нужно держать.
Отдельно продумайте, что видит клиент. Если баланса не хватило, клиент не должен получить «ошибка 500». Он должен получить понятный отказ — а лучше вообще не иметь возможности оформить заказ по позиции, которую вы прямо сейчас не можете выкупить.
Шаг 4. Создание заказа
Заказ создаётся POST-запросом с массивом позиций:
curl -X POST "https://public-api.foxreload.com/api/orders" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"itemId": "product_01krgfgww8eth9xvvysd6y7r4j",
"quantity": 1
}
],
"isMock": false
}'
Ответ — объект заказа с id, price, status, createdAt, paymentExpiresAt и массивом items[].
Про идемпотентность — важная оговорка
Некоторые API принимают заголовок Idempotency-Key, чтобы повторная отправка того же запроса не создала второй заказ. Обязательно проверьте, реализует ли это ваш конкретный поставщик — далеко не все. FoxReload заголовок Idempotency-Key не поддерживает.
Если поддержки нет, защиту от дублей вы строите сами:
- Генерируете на своей стороне уникальный ключ операции и сохраняете его в своей базе до вызова поставщика.
- При сетевой ошибке или таймауте не создаёте заказ повторно вслепую — сначала запрашиваете список заказов у поставщика и проверяете, не создался ли он на самом деле.
- Только убедившись, что заказа нет, повторяете попытку.
Таймаут при создании заказа — это неопределённость, а не отказ. Считать его отказом и сразу ретраить — самый дорогой способ научиться разнице.
Шаг 5. Получение статуса — опрос как базовый механизм
Опрос (polling) — это механизм, который работает всегда. Вебхуки — это опция, которая есть не у всех.
Проверьте, отдаёт ли ваш поставщик вебхуки и подписывает ли он их (HMAC или иная схема). Если отдаёт — вебхук можно использовать как ускоритель, но опрос всё равно должен остаться в качестве страховки: доставка вебхуков не гарантирована, а ваш эндпоинт может быть недоступен в момент отправки. У FoxReload вебхуков нет — результат заказа получается исключительно опросом.
curl "https://public-api.foxreload.com/api/orders/{order_id}" \
-H "X-API-Key: YOUR_API_KEY"
Рабочая схема опроса:
| Фаза | Что делать |
|---|---|
| Первая минута | Частый опрос — каждые несколько секунд |
| Далее | Постепенно увеличивающийся интервал (backoff) |
| Предельный срок | Свой таймаут, после которого заказ помечается «требует внимания» |
| Терминальные статусы | Опрос прекращается — результат зафиксирован в вашей базе |
У FoxReload заказ проходит статусы active → paid → processing → completed, с терминальными ветками cancelled (с полем cancelReason) и failed (с ошибкой по каждой позиции в items[].error). Коды при completed лежат в items[].externalData. Подробный разбор состояний — в статье схема обработки заказа FoxReload.
Шаг 6. Обработка ошибок
Разделите ошибки на три группы и обращайтесь с ними по-разному:
- Не ретраить никогда.
HTTP 400,401,403,404— это ваша ошибка или ошибка конфигурации. Повторный запрос вернёт то же самое. Логируйте и разбирайтесь. - Ретраить с backoff.
HTTP 429(rate limit) и5xx. Экспоненциальный backoff с джиттером, ограниченное число попыток, потолок интервала. - Проверять перед ретраем. Сетевые таймауты на изменяющих операциях. Сначала выясняем, что произошло на стороне поставщика, потом действуем.
Ошибки по позициям внутри заказа — отдельный случай. Заказ может завершиться частично: одна позиция выдана, другая нет. Ваша модель данных должна уметь описывать частичное выполнение, иначе логика возвратов будет неверной.
Шаг 7. Чек-лист выхода в продакшен
- Ключ лежит в секрет-менеджере, в git его нет, история репозитория проверена.
- IP-allowlist включён, если поставщик его поддерживает.
- Мок-заказы (или sandbox) прогнаны по всем типам товаров, которые вы продаёте.
- Каталог синхронизируется по расписанию и не обнуляется при частичном ответе.
- Баланс мониторится, алерты настроены на два порога.
- Создание заказа защищено от дублей на вашей стороне.
- Опрос имеет таймаут и очередь «зависших» заказов с алертом.
- Ретраи стоят только на 429 и 5xx.
- Все запросы и ответы поставщика логируются с привязкой к вашему внутреннему order_id — это ваша доказательная база при спорах.
- Есть ручной сценарий: что делает оператор, когда заказ завис, а клиент уже пишет в поддержку.
Где брать товар
Слой интеграции имеет смысл строить один раз и под каталог, который закроет большую часть ассортимента. FoxReload — оптовый поставщик цифровых товаров с 900+ SKU: игровые ключи, подарочные карты, пополнения игровых аккаунтов, eSIM и лицензии на софт, всё через один REST API с автоматической выдачей и мультирегиональными SKU. Один ключ, один формат ответа, одна модель заказа на весь ассортимент — вместо пяти разных интеграций с пятью разными схемами авторизации.
