Пополнение баланса игрока
Связанный пользовательский сценарий описан в разделе Пополнение баланса игрока.
Сценарий пополнения состоит из read-only поиска способов и двух шагов запуска:
playerWalletTopUpMethodsвыполняет read-only поиск подходящих способов по сумме.preparePlayerWalletTopUpилиprepareGuestPlayerWalletTopUpпосле выбора способа создаёт намерение и возвращает неизменяемый расчёт только для него.startPlayerWalletTopUpилиstartGuestPlayerWalletTopUpзапускает выбранный расчёт и возвращает действие, которое должен выполнить клиент.
Объект расчёта возвращается в поле quote.
Для получения способов оплаты передайте сумму и, при наличии, страну плательщика. Запрос не требует сессии. Авторизованные мутации пополняют баланс текущего игрока; для гостевых мутаций укажите email получателя. Режим общего или серверного баланса задаётся в настройках проекта. Во всех мутациях используются UUIDv7 запросов. Заголовок Origin должен совпадать с адресом, зарегистрированным для проекта.
Пополнение доступно и при задолженности. Зачисление основного баланса сначала погашает её, а остаток становится доступен для покупок. Бонусная часть не погашает задолженность. Текущее состояние возвращают me.paymentDebt, me.purchasesRestricted и запрос refreshBalance. После полного погашения purchasesRestricted становится false; отклонённую покупку нужно оформить заново с новым requestId.
Получение способов оплаты
playerWalletTopUpMethods
Входные данные
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
amount | String! | да | Положительная десятичная сумма без экспоненты и разделителей групп |
payerCountry | String | нет | Двухбуквенный код страны, например RU |
Результат
PlayerWalletTopUpMethodDiscovery содержит список карточек способов:
| Поле | Тип | Описание |
|---|---|---|
methodProfileId | ID! | Идентификатор профиля способа в текущем проекте |
methodCode | String! | Код способа в верхнем регистре, например BANK_CARD или PAYGOL; для подписи используйте displayName |
displayName | String! | Локализованное название |
iconAssetId | ID | Идентификатор иконки, если она настроена |
Запрос не создаёт намерение, расчёт или попытку оплаты и не резервирует средства. Повторяйте его после изменения суммы, страны или контекста баланса. После выбора methodProfileId передайте его в защищённую операцию подготовки.
Пример обмена
{
"documentId": "playerWalletTopUpMethods",
"variables": {
"input": {
"amount": "10.00",
"payerCountry": "RU"
}
}
}
{
"data": {
"playerWalletTopUpMethods": {
"methods": [
{
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"methodCode": "BANK_CARD",
"displayName": "Банковская карта",
"iconAssetId": "payment-method-card"
},
{
"methodProfileId": "01910000-0000-7000-8000-000000000006",
"methodCode": "SBP",
"displayName": "Система быстрых платежей",
"iconAssetId": null
}
]
}
}
}
Если подходящих профилей нет, возвращается TOP_UP_METHODS_UNAVAILABLE. Причины выбора или исключения конкретного профиля и ответы провайдера наружу не передаются.
Подготовка пополнения
preparePlayerWalletTopUp
Входные данные
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
requestId | ID! | да | Новый UUIDv7. Повтор того же запроса с теми же данными возвращает прежний результат |
amount | String! | да | Положительная десятичная сумма без экспоненты и разделителей групп |
methodProfileId | ID! | да | Профиль способа, выбранный из результата playerWalletTopUpMethods |
payerCountry | String | нет | Двухбуквенный код страны, например RU |
Результат
PlayerWalletTopUpPreparation содержит:
| Поле | Тип | Описание |
|---|---|---|
checkoutId | ID! | Идентификатор пользовательского сценария, который передаётся в запуск |
intent | PlayerWalletTopUpIntent! | Созданное намерение и сумма назначения |
methods | [PlayerWalletTopUpMethod!]! | Выбранный способ и его расчёт; после успешной подготовки список содержит один элемент |
Каждый PlayerWalletTopUpMoney содержит атомарные units, код code, точность scale и готовое десятичное представление decimal. Денежные значения следует отображать из decimal, не преобразуя их через float.
Пример обмена
{
"documentId": "preparePlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000001",
"amount": "10.00",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"payerCountry": "RU"
}
}
}
{
"data": {
"preparePlayerWalletTopUp": {
"checkoutId": "01910000-0000-7000-8000-000000000001",
"intent": {
"id": "01910000-0000-7000-8000-000000000002",
"status": "OPEN",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"createdAt": "2026-08-29T10:00:00.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"completedAt": null
},
"methods": [
{
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"methodCode": "BANK_CARD",
"displayName": "Банковская карта",
"iconAssetId": "payment-method-card",
"quote": {
"id": "01910000-0000-7000-8000-000000000004",
"sequence": 1,
"expiresAt": "2026-08-29T10:10:00.000000Z",
"paymentAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"payerFee": {
"units": "30",
"code": "USD",
"scale": 2,
"decimal": "0.30"
},
"conversion": {
"numerator": "1",
"denominator": "1",
"roundingMode": "HALF_UP"
},
"fees": [
{
"kind": "FIXED",
"amount": {
"units": "30",
"code": "USD",
"scale": 2,
"decimal": "0.30"
}
}
],
"funding": {
"baseAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"bonusAmount": {
"units": "300",
"code": "ELX",
"scale": 2,
"decimal": "3.00"
},
"totalAmount": {
"units": "1300",
"code": "ELX",
"scale": 2,
"decimal": "13.00"
},
"components": [
{
"source": "PAYMENT_PROMOTION",
"amount": {
"units": "100",
"code": "ELX",
"scale": 2,
"decimal": "1.00"
},
"percentage": 10,
"decidedAt": "2026-08-29T10:00:00.000000Z",
"validUntil": "2026-08-29T10:10:00.000000Z",
"grantLifetimeSeconds": null
},
{
"source": "LOYALTY",
"amount": {
"units": "200",
"code": "ELX",
"scale": 2,
"decimal": "2.00"
},
"percentage": 20,
"decidedAt": "2026-08-29T10:00:00.000000Z",
"validUntil": null,
"grantLifetimeSeconds": 86400
}
]
}
}
}
]
}
}
}
PAYMENT_PROMOTION и LOYALTY показываются отдельными строками. Расчёт фиксируется внутри поля quote: клиент не складывает проценты самостоятельно и не заменяет totalAmount собственным значением.
Запуск оплаты
startPlayerWalletTopUp
Входные данные
| Поле | Тип | Описание |
|---|---|---|
requestId | ID! | Новый UUIDv7 запуска; обеспечивает идемпотентный повтор |
checkoutId | ID! | Значение из подготовки |
methodProfileId | ID! | Выбранный способ из methods |
quoteId | ID! | Идентификатор расчёта выбранного способа |
Повтор запуска с теми же четырьмя значениями безопасен. Повтор requestId с другим набором значений завершается конфликтом.
Пример обмена
{
"documentId": "startPlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000010",
"checkoutId": "01910000-0000-7000-8000-000000000001",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"quoteId": "01910000-0000-7000-8000-000000000004"
}
}
}
{
"data": {
"startPlayerWalletTopUp": {
"checkoutId": "01910000-0000-7000-8000-000000000001",
"intent": {
"id": "01910000-0000-7000-8000-000000000002",
"status": "PROCESSING",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"createdAt": "2026-08-29T10:00:00.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"completedAt": null
},
"attempt": {
"id": "01910000-0000-7000-8000-000000000005",
"status": "REQUIRES_CUSTOMER_ACTION",
"createdAt": "2026-08-29T10:00:01.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z"
},
"action": {
"kind": "REDIRECT",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"redirect": {
"url": "https://checkout.example.test/pay/123"
},
"formPost": null,
"qrCode": null,
"deepLink": null,
"wait": null
}
}
}
}
Действия клиента
kind | Заполненное поле | Действие |
|---|---|---|
REDIRECT | redirect.url | Перейти на HTTPS-страницу оплаты |
FORM_POST | formPost.url, formPost.fields | Создать и немедленно отправить POST-форму |
QR_CODE | qrCode.payload, необязательное imageUrl | Показать QR-код; payload остаётся источником данных |
DEEP_LINK | deepLink.url | Показать QR-код и кнопку открытия приложения |
WAIT | wait.recommendedPollAfterSeconds | Повторить тот же запуск после указанной задержки |
Заполненным бывает только объект, соответствующий kind. action: null означает, что внешнее действие больше не требуется; итог определяется по intent.status.
Гостевая подготовка пополнения
prepareGuestPlayerWalletTopUp
Гостевая подготовка доступна без входа в кабинет. Укажите email получателя, сумму и выбранный способ оплаты.
Входные данные
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
requestId | ID! | да | Новый UUIDv7 подготовки; повтор с теми же данными возвращает прежний результат |
recipientEmail | String! | да | Email аккаунта-получателя |
amount | String! | да | Положительная десятичная сумма без экспоненты и разделителей групп |
methodProfileId | ID! | да | Профиль способа из playerWalletTopUpMethods |
payerCountry | String | нет | Двухбуквенный код страны, например RU |
Результат
Возвращается тот же PlayerWalletTopUpPreparation, что и для авторизованной подготовки: checkoutId, намерение и один рассчитанный способ с полем quote.
Пример обмена
{
"documentId": "prepareGuestPlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000011",
"amount": "10.00",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"payerCountry": "RU"
}
}
}
{
"data": {
"prepareGuestPlayerWalletTopUp": {
"checkoutId": "01910000-0000-7000-8000-000000000011",
"intent": {
"id": "01910000-0000-7000-8000-000000000012",
"status": "OPEN",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"expiresAt": "2026-08-29T10:15:00.000000Z"
},
"methods": [
{
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"methodCode": "BANK_CARD",
"displayName": "Банковская карта",
"iconAssetId": "payment-method-card",
"quote": {
"id": "01910000-0000-7000-8000-000000000013",
"sequence": 1,
"expiresAt": "2026-08-29T10:10:00.000000Z",
"paymentAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"payerFee": {
"units": "30",
"code": "USD",
"scale": 2,
"decimal": "0.30"
},
"funding": null
}
}
]
}
}
}
Если пополнение для получателя недоступно, возвращается TOP_UP_RECIPIENT_UNAVAILABLE. Если нет подходящего способа оплаты, возвращается TOP_UP_METHODS_UNAVAILABLE.
Запуск гостевой оплаты
startGuestPlayerWalletTopUp
Запускает гостевую оплату с получателем, способом и действующим расчётом из подготовки. Передайте их без изменений.
Входные данные
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
requestId | ID! | да | Новый UUIDv7 запуска |
checkoutId | ID! | да | Значение из гостевой подготовки |
recipientEmail | String! | да | Тот же email получателя; сервер разрешает его заново |
methodProfileId | ID! | да | Выбранный способ из подготовки |
quoteId | ID! | да | Идентификатор расчёта выбранного способа |
Результат и действия клиента
Возвращается тот же PlayerWalletTopUpCheckout, что и для авторизованного запуска: состояние намерения, попытка и одно из действий REDIRECT, FORM_POST, QR_CODE, DEEP_LINK или WAIT. Описание полей действий приведено в разделе Действия клиента.
Пример обмена
{
"documentId": "startGuestPlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000014",
"checkoutId": "01910000-0000-7000-8000-000000000011",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"quoteId": "01910000-0000-7000-8000-000000000013"
}
}
}
{
"data": {
"startGuestPlayerWalletTopUp": {
"checkoutId": "01910000-0000-7000-8000-000000000011",
"intent": {
"id": "01910000-0000-7000-8000-000000000012",
"status": "PROCESSING",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"expiresAt": "2026-08-29T10:15:00.000000Z"
},
"attempt": {
"id": "01910000-0000-7000-8000-000000000015",
"status": "REQUIRES_CUSTOMER_ACTION",
"createdAt": "2026-08-29T10:00:01.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z"
},
"action": {
"kind": "REDIRECT",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"redirect": {
"url": "https://checkout.example.test/pay/123"
},
"formPost": null,
"qrCode": null,
"deepLink": null,
"wait": null
}
}
}
}
Для гостевой оплаты используйте результат запуска; отдельной операции гостевой истории нет.
История платежей
playerPaymentHistory
Возвращает платежи текущего игрока с курсорной пагинацией. Фильтр statuses
необязателен; пустой список означает все состояния.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
first | Int! | да | Размер страницы от 1 до 100 |
after | ID | нет | endCursor предыдущей страницы |
statuses | [PlayerPaymentStatus!] | нет | Состояния для фильтрации |
{
"documentId": "playerPaymentHistory",
"variables": {
"first": 20,
"after": null,
"statuses": [
"PROCESSING",
"SETTLED"
]
}
}
{
"data": {
"playerPaymentHistory": {
"items": [
{
"id": "01910000-0000-7000-8000-000000000002",
"purpose": "PLAYER_WALLET_CREDIT",
"status": "SETTLED",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"quotedAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"settledAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"method": {
"code": "card",
"displayName": "Банковская карта",
"iconAssetId": "payment-method-card"
},
"description": "Пополнение баланса",
"createdAt": "2026-08-29T10:00:00.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"completedAt": "2026-08-29T10:02:10.000000Z"
}
],
"pageInfo": {
"endCursor": "01910000-0000-7000-8000-000000000002",
"hasNextPage": false
}
}
}
}
Один платёж
playerPayment
Принимает публичный paymentId из истории и возвращает тот же снимок платежа.
Если платёж не найден, возвращается PLAYER_PAYMENT_NOT_FOUND.
{
"documentId": "playerPayment",
"variables": {
"paymentId": "01910000-0000-7000-8000-000000000002"
}
}
{
"data": {
"playerPayment": {
"id": "01910000-0000-7000-8000-000000000002",
"purpose": "PLAYER_WALLET_CREDIT",
"status": "SETTLED",
"destinationAmount": {
"units": "1000",
"code": "ELX",
"scale": 2,
"decimal": "10.00"
},
"quotedAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"settledAmount": {
"units": "1030",
"code": "USD",
"scale": 2,
"decimal": "10.30"
},
"method": {
"code": "card",
"displayName": "Банковская карта",
"iconAssetId": "payment-method-card"
},
"description": "Пополнение баланса",
"createdAt": "2026-08-29T10:00:00.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"completedAt": "2026-08-29T10:02:10.000000Z"
}
}
}
Состояния
PlayerWalletTopUpIntentStatus: OPEN, PROCESSING, SETTLED, CANCELLED, EXPIRED.
PlayerWalletTopUpAttemptStatus: CREATED, REQUIRES_CUSTOMER_ACTION, PENDING_PROVIDER, AUTHORIZED, CAPTURED, DECLINED, CANCELLED, EXPIRED, REVIEW_REQUIRED.
Истёкший расчёт не запускается. Нужно снова вызвать подготовку и показать новый результат. Успешный callback зачисляет средства один раз; повтор callback не создаёт второе начисление.
Ошибки
| Код | Значение для клиента |
|---|---|
TOP_UP_INVALID_REQUEST | Неверный формат входных данных |
TOP_UP_INVALID_AMOUNT | Сумма вне допустимых границ |
TOP_UP_ORIGIN_NOT_ALLOWED | Текущий Origin не зарегистрирован для проекта |
TOP_UP_RECIPIENT_UNAVAILABLE | Получатель не найден, заблокирован или не может принять пополнение |
TOP_UP_MERCHANT_UNAVAILABLE | Пополнение проекта выключено или не настроено |
TOP_UP_METHODS_UNAVAILABLE | Для суммы и контекста нет доступного способа оплаты |
TOP_UP_REFRESH_REQUIRED | Намерение, способ или расчёт устарели; подготовку нужно повторить |
TOP_UP_SCOPE_UNAVAILABLE | Не удалось определить назначение баланса |
TOP_UP_CONFLICT | Идемпотентный идентификатор повторён с другими данными |
TOP_UP_RATE_LIMITED | Превышен лимит; extensions.retryAfterSeconds задаёт ожидание |
TOP_UP_UNAVAILABLE | Операция временно недоступна |
При истечении расчёта выполните подготовку заново. При временной ошибке сохраните параметры исходного запроса для повтора.