Как устроен магазин игрового доната изнутри: на примере платформы GameCore

—

от автора

Витрину магазина игрового доната можно собрать за неделю: каталог карточек, корзина, форма ввода ID. Месяцы уходят на то, чего покупатель не видит, — на договоры с поставщиками, нормализацию их каталогов, платёжные шлюзы, обработку сбоев и возвраты.

В блоге Exnode мы обычно пишем о том, как оплачивать зарубежные сервисы и игры из России. В этот раз заглянем на другую сторону прилавка и разберём, как такой магазин устроен инженерно. Примером будет платформа GameCore — мультитенантный движок, на котором работает сразу несколько витрин, и оптовый каталог по API.

Почему именно она: у GameCore открытая и подробная документация, где разобран не только «счастливый путь», но и пограничные случаи — частичные заказы, проверка ID игрока, повторы запросов и возвраты. На таком материале удобно показывать, как решаются типовые проблемы отрасли. Все цифры и форматы ниже взяты из публичной документации платформы по состоянию на октябрь 2026 года.

Это не обзор «где купить донат»: магазины в тексте — живые примеры того, как одна платформа превращается в совершенно разные витрины.

Анатомия: четыре слоя магазина доната

Магазин доната — это четыре слоя, и у каждого своя зона ответственности:

  • Витрина. Карточки, корзина, форма ввода ID, личный кабинет, промокоды, Telegram-бот, поддержка. Видимая часть, которую обычно и называют магазином.

  • Платёжный контур. Приём денег от покупателя через несколько платёжных шлюзов и маршрутизация между ними.

  • Склад. Единый каталог, баланс магазина у оптовика, создание заказов, выдача, ретраи и возвраты.

  • Поставщики. Десятки внешних API: дистрибьюторы гифт-карт, сервисы пополнения по ID, ручные исполнители.

В GameCore склад — общее ядро платформы, а витрины подключаются к нему как тенанты. Путь заказа выглядит так: покупатель выбирает товар, вводит ID игрока и платит на витрине; витрина принимает деньги одним из доступных способов оплаты и по B2B API с ключом магазина создаёт заказ на складе; ядро списывает деньги с баланса магазина и передаёт заказ поставщику; результат возвращается на витрину вебхуком, а сверка по расписанию страхует от потерянных уведомлений. Дальше разберём каждый из этих швов по очереди.

Мультитенантность: один склад, много витрин

Ключевое архитектурное решение — отделить склад от магазина. Склад (каталог, поставщики, выдача) общий для всех, а магазин — это тенант: домен, бренд, языки, наценка, набор платёжных методов, промо и поддержка. Благодаря такому разделению один и тот же склад обслуживает и сторонние витрины, подключённые по API, и магазин игрового доната под ключ, работающий целиком на движке платформы.

Что конкретно параметризуется на уровне тенанта, видно по API:

  • Видимость каталога. Список игр, который видит конкретный аккаунт, заметно короче платформенного: в нём уже учтены разрешённые регионы, назначенный шлюз поставщика и скрытые позиции. Один и тот же SKU одному тенанту виден, другому — нет.

  • Цена. В каталоге лежит оптовая цена; розничную тенант задаёт сам в админке. Оптовый тариф за объём применяется в момент создания заказа, а не в каталоге.

  • Пространство заказов. Номер заказа — это короткий префикс аккаунта плюс шесть символов. Поиск по номеру ограничен аккаунтом: чужой заказ отдаёт ровно тот же ответ «не найден», что и несуществующий, — так нельзя перебором узнать, есть ли заказ у соседа.

  • Язык и рынок. Витрина поддерживает до пяти локалей, у каждого тенанта свой набор.

Юнит-экономика тенанта простая и прозрачная. В примере из документации закупка 100 ₽, наценка 30% даёт розничную цену 130 ₽, платёжная комиссия около 3% съедает примерно 4 ₽, и с заказа остаётся 26 ₽. Отсюда понятно, почему так важны стоимость эквайринга и доля возвратов: при марже в два десятка рублей один ошибочный возврат съедает прибыль с нескольких заказов.

Как это выглядит на живых витринах

На платформе работают магазины с разным позиционированием, и по ним хорошо видно, сколько свободы оставляет общий склад.

vsenamid.ru (МИД, «Мобильный Игровой Донат») — витрина под мобильный донат для России и СНГ. Акцент на пополнении по UID без пароля, плюс отдельный раздел подписок: Spotify, Discord, ChatGPT, Telegram. Набор платёжных методов собран под регион: карты, СБП, ЮMoney, криптовалюта, для Казахстана Kaspi, для Узбекистана Uzcard и Humo. Поддержка вынесена в Telegram.

ashop-games.com — универсальная витрина: мобильный донат, ключи Steam, Xbox и PSN, гифт-карты и софт. Пять локалей, включая отдельную версию для Пакистана с ценами в рупиях. Вокруг магазина построена Telegram-инфраструктура — бот для входа в один клик и статусов заказов, канал, чат. Кэшбэк и уровни лояльности доступны зарегистрированным покупателям.

SZ Market сейчас переезжает на платформу GameCore. Это магазин внутриигровой валюты и предметов для мобильных и ПК-игр с упором на ручное сопровождение: покупку можно оформить через Telegram-бота, а менеджер помогает выбрать способ доставки, если покупатель не понимает, что ему подходит.

Разные продукты и разные рынки, но под капотом одна и та же модель: склад отдаёт товары со схемами полей, тенант решает, как их показать, сколько за них взять и чем принимать оплату.

Поставщики: один API поверх зоопарка

Главная ценность агрегатора — не количество игр, а то, что десятки поставщиков с разными форматами сведены к одному контракту. По данным GameCore, в каталоге больше 5 800 игр и около 25 100 SKU. Живую статистику платформа отдаёт публичным запросом без ключа; в примере из документации от августа там было 5 311 игр и 21 834 SKU — цифры двигаются вместе с ассортиментом поставщиков.

Полный путь от ключа до первого заказа описан в документации API GameCore, здесь — только архитектурно важное.

Тип доставки как главный атрибут товара

У каждого товара есть тип доставки, и он определяет весь чекаут: что спросить у покупателя до оплаты и что вернётся после выполнения. Типов пять:

  • Пополнение по ID. Покупатель ничего не получает на руки — валюта приходит на аккаунт. Магазин передаёт игровой ID, иногда ещё сервер.

  • Гифт-карта. После выполнения возвращается код или ключ, заполнять обычно ничего не нужно.

  • Вход в аккаунт. Пополнение идёт через учётные данные покупателя.

  • Услуга. Работу вручную выполняет оператор.

  • Прочее. Тип не определён, ориентироваться нужно на схему полей товара.

Два неочевидных момента. Во-первых, у неклассифицированного товара тип пустой, а не «прочее», и фильтр каталога сравнивает на точное равенство — такой SKU не попадёт ни в одну выборку по типу. Поэтому синхронизация каталога должна хотя бы раз проходить без фильтра. Во-вторых, товары, которым нужен скриншот, полностью исключены из B2B-каталога: канала для файлов в API нет.

Схема полей вместо справочника по играм

Удачное решение в этой модели — схема полей доставки на уровне товара. Поставщики называют поле с ID игрока как угодно: только для PUBG Mobile встречается пять разных вариантов. Вместо того чтобы вести таблицу соответствий, платформа отдаёт вместе с товаром список нужных полей: техническое имя, тип, подпись для покупателя и признак обязательности.

Витрина строит форму из этой схемы в момент запроса: техническое имя становится ключом в данных заказа, подпись — текстом над полем, все значения передаются строками. Один рендерер на все игры, никакого ветвления по тайтлам, и новая игра у поставщика начинает продаваться без релиза витрины. Читать схему нужно для конкретного SKU, а не для игры: у одного тайтла имена полей могут различаться между регионами и номиналами.

Стабильные идентификаторы и плавающие цены

Названия товаров переводятся заново, цены меняются вместе с курсом, стабилен только числовой идентификатор товара. Поэтому в базе хранят именно его, а перед оформлением перечитывают карточку SKU — цена в корзине могла устареть.

Один запрос — несколько заказов

Корзину нельзя отдать одному поставщику целиком. Позиции группируются по игре поставщика и по самому поставщику, и каждая группа становится отдельным заказом со своим кодом и жизненным циклом. Корзина из трёх игр даёт минимум три заказа, а одна игра может дать два, если её номиналы приходят из разных источников. В модели данных магазина это связь «один заказ покупателя — много заказов у платформы», и закладывать её лучше сразу.

Проверка ID игрока: формат — да, существование — нет

Пополнение по ID — самая большая и самая рискованная часть каталога: UC в PUBG Mobile, алмазы в Mobile Legends и Free Fire, кристаллы в Genshin Impact. Ошибка здесь стоит реальных денег, потому что валюта уходит владельцу указанного аккаунта и вернуть её нельзя ни магазину, ни поставщику.

GameCore до списания проверяет три вещи: что обязательные поля переданы и не пусты, что значение проходит форматное правило семейства игр и что товар доступен в регионах аккаунта. Правила для самых популярных игр такие: в PUBG Mobile, PUBG Mobile Lite, PUBG: NEW STATE и обоих Free Fire ID должен состоять из 6–15 цифр, в Genshin Impact и Honkai: Star Rail UID — из 8–10 цифр, в Zenless Zone Zero — из 9–11. Mobile Legends требует два значения — ID игрока и ID зоны, — и называются эти поля у разных поставщиков по-разному.

У этой проверки есть естественный предел, общий для всей отрасли: ни один агрегатор не видит базу аккаунтов издателя, поэтому существование аккаунта, его регион и то, что покупатель ввёл именно свой ID, на этом пути не проверяются. Корректно набранный чужой ID формально неотличим от правильного. Это прямо описано в документации, так что интегратор заранее знает, где проходит граница ответственности. Отдельная ловушка — Genshin: первая цифра UID кодирует сервер, поэтому UID из другого региона формально валиден и указывает на чужой аккаунт.

Отсюда архитектурный вывод: защита от ошибки в ID — зона ответственности воронки витрины, а не склада. Что работает на практике:

  1. Подпись поля берётся из схемы дословно, на языке покупателя, а не придумывается на витрине.

  2. ID подтверждается или вводится повторно до оплаты.

  3. На экране ввода прямо сказано, что ошибочный ID не возвращается. Это снимает больше обращений в поддержку, чем любой FAQ.

  4. Для Mobile Legends отправляются все обязательные поля; если чего-то не хватает, заказ отклоняется без списания.

Витрины решают это по-разному. В МИД сценарий покупки строится вокруг UID без пароля, а для Mobile Legends отдельно просят ID игрока и ID сервера. Если товару нужно больше, это указано на его странице.

Отдельно про вход в аккаунт

Когда пополнение требует входа в аккаунт, схема просит логин и пароль. Здесь есть неприятная деталь: тип поля не размечает секрет. В живом каталоге пароль приходит обычным текстовым полем, потому что поставщики используют только текст, числа и выпадающие списки. Определять чувствительное поле приходится по его имени и подписи — password, pass, pwd, «пароль», — и так же поступает классификатор самой платформы.

Правила обращения с такими данными стандартные, но их стоит проговорить: только TLS, никаких логов приложения и трекера ошибок, удаление после завершения заказа и рекомендация покупателю сменить пароль. Коды гифт-карт — тоже инструмент на предъявителя: хранить зашифрованными, показывать один раз, логировать, кто раскрыл.

Платёжный контур: два кошелька и каскад шлюзов

В магазине доната два независимых денежных потока, и их полезно не путать:

  1. Покупатель → магазин. Розничная оплата через эквайринг: СБП, карты МИР, Visa/Mastercard, криптовалюта. На витрине GameCore для этого из коробки доступно шесть способов оплаты.

  2. Магазин → склад. Оптовая закупка с B2B-баланса тенанта в режиме предоплаты или овердрафта в пределах кредитного лимита.

Разрыв между ними — главный источник головной боли: деньги покупателя уже пришли, а закупка может не пройти, и наоборот. Поэтому на каждом шве нужна атомарность и идемпотентность.

Каскад шлюзов

Шесть способов оплаты на витрине — это не шесть кнопок на странице, а задача маршрутизации: за каждым методом стоят платёжные провайдеры, между которыми нужно выбирать.

В индустрии каскад обычно строят на трёх правилах:

  • Маршрутизация по методу и стране. Метод оплаты определяет набор провайдеров-кандидатов: СБП и МИР — российские, Kaspi и Uzcard — региональные, крипта — отдельный процессинг. Это видно и по витринам: ASHOP принимает Visa и Mastercard только для карт зарубежных банков, а крипту — от 1 500 ₽ за заказ, МИД показывает Kaspi для Казахстана и Uzcard/Humo для Узбекистана.

  • Фоллбэк при отказе. Если провайдер вернул технический отказ (таймаут, недоступность, лимит), платёж обычно переводят на следующего по приоритету. Ключевое слово — технический: отказ банка-эмитента («недостаточно средств», подозрение на мошенничество) повторять через другого провайдера нельзя, это прямой путь к блокировке мерчанта.

  • Взвешивание по метрикам. Приоритет провайдеров принято пересчитывать по конверсии, доле отказов и комиссии за скользящее окно. Разница в полпроцента комиссии на марже в 26 ₽ с заказа заметна.

Независимо от числа шлюзов для покупателя должен существовать ровно один платёж на чекаут. Повторная попытка через другой шлюз переиспользует тот же внутренний идентификатор, иначе при гонке webhook-уведомлений легко списать деньги дважды.

Атомарность закупки

На стороне склада GameCore решает проблему радикально: списание с баланса, запись платежа и создание заказов коммитятся одной транзакцией базы данных. Состояния «деньги ушли, а заказа нет» не существует. Если что-то падает — не хватило баланса, товар отклонён, внутренний сбой, — откатывается всё целиком.

Отдельно разобран случай гонки за баланс. Если два параллельных запроса одного магазина пытаются списать деньги одновременно, второй получает отказ о конкурентном изменении баланса: транзакция откатилась, денег не списано, пополнять ничего не нужно — достаточно повторить тот же запрос после короткой паузы. При этом у отказа «недостаточно средств» тот же HTTP-статус 402, но действия нужны совсем другие, поэтому ошибки стоит разбирать по тексту, а не только по коду.

Идемпотентность создания заказа

Запрос на создание заказа без ключа идемпотентности платформа не принимает вообще. Причина — классический сценарий: запрос дошёл, деньги списаны, заказ создан, а ответ потерялся по дороге. Без ключа клиент либо платит дважды, либо теряет оплаченный заказ.

Интересна реализация. Решение о повторе принимается не только по ключу, но и по отпечатку запроса, который считается только по составу корзины: товар, количество и данные доставки в нормализованном виде — с отсортированными полями, обрезанными пробелами и ником в нижнем регистре без ведущей «собаки». Позиции сортируются, так что перестановка корзины отпечаток не меняет. Адрес для уведомлений и внешний номер заказа в отпечаток намеренно не входят.

Дальше возможны четыре исхода. Повтор с тем же ключом и той же корзиной после успеха возвращает исходный ответ байт в байт, без второго списания. Повтор, пока первый запрос ещё выполняется, ждёт его и получает тот же результат. Тот же ключ с другой корзиной после успеха даёт конфликт 409. А тот же ключ после неудачной попытки считается обычной новой попыткой: записи идемпотентности пишутся внутри той же транзакции и откатываются вместе с ней, так что от неудачи ничего не остаётся.

Ключ хранится 24 часа, уборка идёт раз в час, поэтому реальное окно — от 24 до примерно 25 часов. Очередь повторов, способная пережить сутки, должна иметь собственную защиту от дублей.

Из этого следует простое правило для магазина: один ключ на одно бизнес-намерение, то есть на один чекаут покупателя, и сохранять его рядом с заказом до вызова. Ключ, сгенерированный внутри цикла ретраев, идемпотентным не является.

Антифрод: два периметра

В донате фрод приходит с двух сторон. Снаружи — покупатель с краденой картой, который хочет быстро превратить её в ликвидный цифровой товар. Изнутри интеграции — попытки подделать уведомления, перебрать ключи или заставить сервер ходить туда, куда не следует. Защита интеграции в документации GameCore расписана подробно, а платёжный скоринг любая платформа по понятным причинам держит закрытым — разберём оба периметра.

Периметр API: что видно в документации

  • Неразличимые отказы авторизации. Отсутствующий и неверный ключ дают одинаковый ответ 401 — по нему нельзя понять, существует ли ключ. Правильный ключ без оптовых прав получает 403.

  • Защита от SSRF в адресе вебхука. Адрес проверяется при создании заказа и повторно перед каждой доставкой. Отклоняются любые схемы кроме http и https, логин и пароль внутри адреса, приватные, локальные и облачные служебные адреса, IPv6-литералы и внутренние имена вроде localhost. Перед доставкой платформа резолвит DNS, проверяет полученный адрес и прибивает соединение к нему — так закрывается DNS rebinding.

  • Проверка Origin. Пишущий запрос с неразрешённым источником отклоняется ещё до лимитера — это защита от CSRF при вызовах из браузера.

  • Лимит запросов. 500 запросов в минуту на IP клиента, а не на ключ: несколько серверов за одним NAT делят бюджет, а второй ключ на том же сервере его не удваивает.

  • Подписанные вебхуки. HMAC-SHA256 по времени отправки и телу запроса, окно в 300 секунд против повторного проигрывания. Подробнее — в разделе про выдачу.

Периметр оплаты: как это обычно устроено

Конкретные правила скоринга GameCore не публикует, и это нормально: опубликованный антифрод перестаёт работать. Но набор сигналов в цифровых товарах типовой:

  • скорость попыток с одной карты, устройства или IP — краденые карты тестируют сериями мелких платежей;

  • несовпадение страны карты, IP и региона товара — покупка регионального номинала из другой страны часто оказывается фродом;

  • много разных ID игроков с одного аккаунта магазина — так выглядит перепродажа или отмыв через пополнения чужих аккаунтов;

  • первая покупка сразу на крупный номинал — фродер стремится вывести максимум до блокировки карты;

  • неуспешные проверки 3-D Secure перед успешной оплатой — признак подбора данных карты.

Сильнейший инструмент здесь — не скоринг, а дизайн продукта. Пополнение по ID с моментальной выдачей привлекательно для фродера ровно потому, что необратимо. Поэтому в магазинах встречаются минимальные суммы для отдельных методов оплаты (например, крипта в ASHOP — от 1 500 ₽), живая поддержка с возможностью ручной проверки и вход через Telegram: аккаунт в мессенджере с историей — более сильный сигнал идентичности, чем свежий email.

Выдача и возвраты: где деньги возвращаются сами, а где нет

После создания заказ находится в обработке, и дальше начинается самое интересное. У заказа и у каждой позиции свои статусы. Заказ бывает ожидающим, в обработке, выполненным или проваленным; статусы отмены и возврата в схеме есть, но через API недостижимы. У позиций словарь шире: кроме успеха и провала позиция может стоять в очереди повторов к поставщику, ждать код или ждать ручного подтверждения по скриншоту.

Правило, на котором ломаются интеграции: любой незнакомый статус позиции трактуется как «ещё в работе». Код, который ждёт только успеха или провала, навсегда зависнет на ожидании кода, и узнаете вы об этом из жалобы покупателя.

Второе правило: для пополнения по ID выполненная позиция с пустым списком ключей — это успех, а не потерянный ключ. В вебхуке поля с ключами у такой позиции нет вовсе, поэтому приёмник должен одинаково обрабатывать пустой список и отсутствие поля.

Три сценария сбоя

Возвраты в GameCore автоматические, но не везде. Полезно разложить их по сценариям.

Поставщик недоступен. Позиция уходит в очередь повторов с лестницей примерно 1 мин, 5 мин, 15 мин, 1 ч, 6 ч — до десяти попыток. Если очередь сдаётся, позиция помечается проваленной, а её стоимость автоматически возвращается на баланс магазина.

Частичное выполнение. Корзина выполнилась наполовину. Частичного статуса нет: заказ становится проваленным, выполненные позиции остаются выполненными, стоимость невыполненных возвращается на баланс автоматически. Главный подвох — вебхук в этом случае не отправляется вообще: события приходят, только когда выполнились или провалились все позиции.

Поставщик принял заказ и молчит. Платформа опрашивает его примерно раз в минуту сколько угодно долго. Таймаута, который сам провалил бы заказ, нет, и деньги автоматически не возвращаются. Разумная реакция — алерт, если автоматический заказ висит в обработке дольше часа, и обращение в поддержку с номером заказа.

Дизайн понятен: автоматически возвращается только то, что гарантированно не было доставлено. Если поставщик мог выполнить заказ, система не рискует вернуть деньги за уже выданную валюту.

Вебхуки: доставка не менее одного раза

Вебхук приходит на адрес, указанный в заказе, и событий всего два: заказ выполнен и заказ провален. В событии о провале нет списка позиций, зато есть человекочитаемая причина на русском, которую можно показать покупателю, например «ID игрока указан неверно».

Подпись — HMAC-SHA256 от строки из времени отправки, точки и сырого тела запроса. Тело нужно брать байтами, как пришло: если распарсить JSON и сериализовать заново, подпись не сойдётся. Сравнивать подпись нужно за постоянное время, а события старше 300 секунд отклонять. Каждая повторная попытка подписывается заново со свежим временем, поэтому старое время означает replay, а не медленный ретрай. Для дедупликации у события есть идентификатор, одинаковый во всех повторах.

Лестница ретраев: первая попытка плюс до восьми повторов с задержками 1 мин, 5 мин, 15 мин, 1 ч, 3 ч, 6 ч, 12 ч и 24 ч — до девяти доставок примерно за 46 часов. Таймаут ответа — 10 секунд, поэтому обработчик сначала сохраняет событие и отвечает 2xx, а работу делает потом.

Самая полезная деталь — как платформа реагирует на ответы приёмника. Любой 2xx означает «доставлено». На 429 и 408 она повторяет по лестнице и учитывает заголовок Retry-After, зажимая его в диапазон от 5 секунд до 6 часов. 5xx, таймаут и обрыв соединения тоже ведут к повтору. А любой другой 4xx и любой редирект отправляют событие сразу в dead-letter, без повторов.

Отсюда практический вывод: если приёмник не уверен, что делать с событием, он должен отвечать 500, а не 400. Один 401 от собственного auth-middleware, сработавшего раньше проверки подписи, — и событие потеряно с первой попытки. Из dead-letter события автоматически не доставляются, только по запросу в поддержку.

Сверка обязательна

Вебхуки молчат на частичных заказах и могут уйти в dead-letter, поэтому одних их недостаточно. Рабочая схема — вебхук как основной канал и периодическая сверка как страховка: раз в несколько минут перечитывать все свои заказы старше пары минут, которые ещё не в финальном статусе, и смотреть на статусы позиций, а не только заказа. Оба пути должны быть идемпотентны друг относительно друга: один и тот же заказ регулярно будет разрешаться дважды.

Возврат покупателю — уже политика витрины

Всё описанное выше — возвраты между складом и магазином. Как вернуть деньги покупателю, решает тенант, и витрины делают это по-разному. МИД обещает доставить заказ или вернуть деньги, если донат не пришёл в течение часа и покупатель написал в поддержку. ASHOP при подтверждённой проблеме возвращает всю сумму на внутренний баланс сайта. Возврат на баланс выгоден магазину: он не платит повторную комиссию эквайринга и не теряет клиента, но условия такого возврата должны быть явно прописаны в политике возвратов.

Чек-лист для тех, кто строит магазин доната

Независимо от того, берёте вы готовую платформу или пишете свою, эти вещи придётся решить:

  • Склад и витрина разделены: витрина — тенант с собственной наценкой, регионами, языками и методами оплаты.

  • Форма чекаута строится из схемы полей конкретного SKU, а не из справочника по играм.

  • В базе хранится стабильный идентификатор товара, цена перечитывается перед оформлением.

  • Один заказ покупателя может породить несколько заказов у поставщиков.

  • ID игрока проверяется по формату и подтверждается покупателем до оплаты; необратимость ошибки сказана прямо.

  • Учётные данные и коды гифт-карт не попадают в логи, хранятся зашифрованными и удаляются после выполнения.

  • Каскад шлюзов повторяет только технические отказы, а не отказы эмитента.

  • Списание, платёж и заказ коммитятся атомарно; ключ идемпотентности создаётся на чекаут, а не на ретрай.

  • Ошибки разбираются по HTTP-статусу и тексту, а не по одному признаку успеха.

  • Незнакомый статус позиции означает «в работе».

  • Вебхуки проверяются по сырому телу, за постоянное время, с окном против replay и дедупликацией.

  • На неожиданное событие приёмник отвечает 5xx, а не 4xx.

  • Есть сверка по расписанию: она ловит частичные заказы и потерянные вебхуки.

  • Есть алерт на заказы, зависшие в обработке дольше порога.

  • Политика возврата покупателю описана явно: на карту, на баланс или повторная доставка.

Вместо вывода

Магазин игрового доната — это маленький маркетплейс с необратимыми транзакциями. Большая часть сложности не в витрине, а в швах между тремя системами: эквайрингом покупателя, балансом магазина и API поставщиков. Платформы вроде GameCore забирают на себя склад и швы со стороны поставщиков, но ответственность за ввод ID, выбор шлюза и политику возврата всё равно остаётся у витрины.

Если хочется посмотреть, как эти решения выглядят в коде, у платформы открыта документация с примерами запросов к боевому API — от проверки здоровья сервиса до первого заказа. А на МИД и ASHOP видно, насколько разными могут быть продукты поверх одного склада; SZ Market сейчас переезжает на платформу GameCore.

А если вы смотрите на эту тему со стороны покупателя и ищете, как оплатить игру, подписку или другой зарубежный сервис из России, загляните в рейтинг сервисов оплаты Exnode. Там мы сравниваем площадки по комиссиям, способам оплаты и скорости зачисления.

ссылка на оригинал статьи https://habr.com/ru/articles/1092564/