API подарочных карт — получение кода и автоматическая выдача
Подарочная карта отличается от любого другого цифрового товара одним свойством — код невозвратен. Как только строка ушла покупателю, вы уже не знаете, активирована она или нет, и любой спор решается вашим журналом, а не здравым смыслом. Ниже — весь путь кода от создания заказа до доставки, с акцентом на местах, где обычно теряются деньги.
Пять этапов, которые нужно различать
Большинство поломок в выдаче кодов происходит потому, что разработчик считает всё это одной операцией. Это пять разных операций с разными режимами отказа:
| Этап | Что происходит | Кто владеет состоянием |
|---|---|---|
| 1. Заказ | Вы отправляете запрос на покупку | Ваша база + поставщик |
| 2. Выпуск | Поставщик резервирует и выпускает код | Поставщик |
| 3. Получение | Вы забираете код из ответа | Ваша база |
| 4. Хранение | Код зашифрован и лежит у вас | Ваша база |
| 5. Доставка | Покупатель видит код | Ваш фронтенд / письмо |
Каждый переход должен быть отдельной записью в вашей базе с временной меткой. Если у вас одна колонка status на весь путь, при первом же сбое вы не сможете ответить на вопрос «код вообще выпустился или нет».
Этап 1. Заказ
Заказ создаётся с идентификатором товара и количеством:
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
}'
Ответ — объект заказа со статусом active, полями id, price, createdAt, paymentExpiresAt и массивом items[].
Три правила на этом этапе:
- Записывайте в свою базу намерение до вызова поставщика, а не после. Строка «мы собираемся заказать это для клиента X» должна существовать раньше, чем уйдёт HTTP-запрос — иначе при падении процесса между отправкой и ответом у вас не останется следа.
- Сохраняйте
order_idпоставщика сразу, как только он пришёл. Это единственный ключ, по которому вы потом найдёте заказ. - Не смешивайте мок и прод в одной таблице без явного флага. У FoxReload объект заказа содержит поле
isMock— копируйте его к себе.
Этап 2. Выпуск на стороне поставщика
После создания заказ проходит active → paid (списание с баланса) → processing (выпуск у поставщика) → completed.
Этап processing — это чужая система, и он может длиться от секунд до заметно дольше в зависимости от типа карты. Ваша задача здесь только одна: не делать ничего разрушительного, пока состояние неизвестно. Никаких «наверное, не получилось, закажем ещё раз».
Этап 3. Получение кода
Код забирается опросом статуса заказа:
curl "https://public-api.foxreload.com/api/orders/{order_id}" \
-H "X-API-Key: YOUR_API_KEY"
Когда status == "completed", каждая позиция items[] содержит:
product— объект товара сid,name,userGuide,attributesexternalData[]— массив выданных кодов или PINerror— ошибка по этой конкретной позиции, если она есть
Поле userGuide не декоративное. Это инструкция по активации от поставщика, и её нужно доставлять покупателю вместе с кодом — половина обращений в поддержку «код не работает» на самом деле означает «покупатель активирует его не в том регионе или не в том разделе аккаунта».
Про вебхуки — проверьте своего поставщика
Некоторые поставщики умеют присылать уведомление о готовности заказа вебхуком, часто с HMAC-подписью. Проверьте, реализует ли это ваш конкретный поставщик. FoxReload вебхуков не поддерживает — результат получается только опросом.
Даже если вебхуки есть, опрос всё равно нужен как страховка: доставка вебхука никогда не гарантирована, а ваш обработчик может быть недоступен именно в тот момент. Вебхук — ускоритель, опрос — источник истины.
Частичное выполнение
В многопозиционном заказе позиции завершаются независимо. Возможна ситуация, когда одна позиция дала код, а другая ушла в ошибку с заполненным items[].error.
Правильная реакция:
- Всё, что реально выпущено, — сохранить и выдать покупателю. Эти деньги уже потрачены, код существует.
- По невыданной части — либо отдельная новая операция заказа, либо возврат клиенту.
- Никогда не помечать весь заказ провалившимся, если часть кодов уже ушла. Это приводит к возврату денег за товар, который клиент получил.
Этап 4. Защита от двойной выдачи
Это самая дорогая ошибка в категории. Она возникает в двух местах.
Дубль на уровне заказа
Вы отправили запрос на создание заказа, получили таймаут, повторили — и создали два заказа. Купили два кода, выдали один, второй лежит мёртвым грузом или, что хуже, уходит следующему покупателю по ошибке.
Некоторые API принимают заголовок Idempotency-Key, который решает это на стороне поставщика. Обязательно проверьте, поддерживает ли это ваш поставщик — многие не поддерживают. FoxReload заголовок Idempotency-Key не поддерживает.
Значит, защита строится у вас:
- Уникальный ключ операции сохраняется в вашей базе до вызова.
- При таймауте — сначала запрос списка заказов у поставщика с фильтром по статусам, проверка, не создался ли заказ.
- Повтор — только после подтверждения, что заказа нет.
curl "https://public-api.foxreload.com/api/orders/?statuses=active,processing&limit=20" \
-H "X-API-Key: YOUR_API_KEY"
Дубль на уровне выдачи
Второй источник — гонка внутри вашей системы. Клиент дважды нажал «получить код», два параллельных запроса прочитали строку заказа как «код готов, не выдан» и оба пошли выдавать.
Лечится транзакцией с блокировкой строки: выдача помечает заказ выданным и фиксирует транзакцию до того, как код уйдёт наружу. Если код доставляется письмом — отправка ставится в очередь внутри той же транзакции, а не выполняется синхронно посреди неё.
Ретраи
Общее правило: ретраить можно только то, что безопасно повторить.
429и5xx— ретрай с экспоненциальным backoff и джиттером.4xx, кроме429, — не ретраить никогда, ответ не изменится.- Таймаут на создании заказа — не ретрай, а сначала проверка состояния.
Подробнее — в статье про retry-паттерны.
Этап 5. Хранение — шифрование и доступ
Код подарочной карты — это предъявительский инструмент. Кто его прочитал, тот им и воспользовался.
- Шифруйте значение кода на уровне приложения, ключом из секрет-менеджера. Шифрования диска недостаточно: дамп базы, украденный бэкап или SQL-инъекция читают диск уже расшифрованным.
- Ограничьте расшифровку одним сервисом. Права на расшифровку не должны быть у аналитической реплики, у админки поддержки и у отладочных скриптов.
- Никогда не пишите код в логи. Ни в обычные, ни в debug, ни в трейсы APM, ни в тело письма в тикете. Маскируйте значение на выходе из слоя доступа к данным, а не в каждом месте вывода по отдельности.
- Храните рядом хэш кода. Он позволяет доказать «мы выдали именно этот код», не показывая значение повторно.
- Определите срок хранения. После выдачи и истечения окна споров зашифрованное значение можно удалить, оставив хэш и метаданные.
Этап 6. Доставка покупателю и аудит
Доставка — это тоже операция, которая может провалиться. Письмо не дошло, вкладка закрылась, покупатель ввёл чужой e-mail.
Работающая схема:
- Код показывается один раз на защищённой странице заказа, доступной только авторизованному покупателю.
- Повторный доступ — через личный кабинет, с записью каждого просмотра в журнал.
- Ссылка на разовый просмотр, если она есть, живёт ограниченное время и одноразова.
- Факт первого показа фиксируется с временной меткой — это то, чем вы оперируете в споре.
Аудит-трейл
Минимальный набор событий, который нужно писать по каждому коду:
| Событие | Что фиксируем |
|---|---|
| Заказ создан | Внутренний ID, товар, покупатель, время |
| ID поставщика получен | order_id поставщика |
| Код получен | Хэш кода, позиция заказа, время |
| Код показан покупателю | Время, IP, идентификатор сессии |
| Открыт спор | Ссылка на заказ и на тикет |
| Решение по спору | Возврат, отказ, замена |
Именно этот журнал — а не переписка в поддержке — отвечает на вопрос «был ли код выдан и когда». Про то, как эти данные работают в реальных спорах, — в материале про чарджбэки в цифровых товарах.
Отдельно держите в голове риски, которые не лечатся кодом: отзыв кода эмитентом, региональные ограничения активации, аннулирование карты при подозрении на фрод у эмитента. Разбор этих сценариев — в статье про отзыв кодов и региональные локи.
Где брать подарочные карты оптом
Схема выше имеет смысл строить один раз, под каталог, которого хватит на весь ассортимент. FoxReload — оптовый поставщик цифровых товаров с 900+ SKU: подарочные карты, игровые ключи, пополнения, eSIM и лицензии, всё через один REST API с автоматической выдачей и мультирегиональными SKU. Одна модель заказа и один формат ответа на все категории — вместо отдельной интеграции под каждого эмитента.
