Player Wallet Top-Up
See Player Balance Top-Up for the related user flow.
The top-up flow consists of read-only method discovery followed by two execution steps:
playerWalletTopUpMethodsperforms a read-only lookup of methods matching the amount.preparePlayerWalletTopUporprepareGuestPlayerWalletTopUpcreates an intent and an immutable calculation for the selected method.startPlayerWalletTopUporstartGuestPlayerWalletTopUpstarts the selected calculation and returns the action the client must perform.
To retrieve payment methods, submit the amount and, when available, the payer country. This request does not require a session. Authenticated mutations top up the current player's balance; guest mutations require the recipient email. Project settings determine whether the balance is project-wide or per-server. All mutations use UUIDv7 request identifiers. The Origin header must match an origin registered for the project.
Top-ups remain available while a payment debt is outstanding. Main-balance credits repay the debt first; any remainder becomes available for purchases. Bonus credits do not repay debt. Read the current state from me.paymentDebt, me.purchasesRestricted, or the refreshBalance query. Once the debt is fully repaid, purchasesRestricted becomes false; submit a previously rejected purchase again with a new requestId.
Discover payment methods
playerWalletTopUpMethods
Input
| Field | Type | Required | Description |
|---|---|---|---|
amount | String! | yes | A positive decimal amount without exponent notation or group separators |
payerCountry | String | no | A two-letter country code such as US |
Result
PlayerWalletTopUpMethodDiscovery contains method cards:
| Field | Type | Description |
|---|---|---|
methodProfileId | ID! | Method-profile identifier in the current project |
methodCode | String! | Uppercase method code such as BANK_CARD or PAYGOL; use displayName for the visible label |
displayName | String! | Localized method name |
iconAssetId | ID | Icon identifier when configured |
The query creates no intent, calculation, or payment attempt and reserves no funds. Repeat it after the amount, country, or balance context changes. Pass the selected methodProfileId to the protected prepare mutation.
Exchange example
{
"documentId": "playerWalletTopUpMethods",
"variables": {
"input": {
"amount": "10.00",
"payerCountry": "US"
}
}
}
{
"data": {
"playerWalletTopUpMethods": {
"methods": [
{
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"methodCode": "BANK_CARD",
"displayName": "Bank card",
"iconAssetId": "payment-method-card"
},
{
"methodProfileId": "01910000-0000-7000-8000-000000000006",
"methodCode": "SBP",
"displayName": "Fast Payments System",
"iconAssetId": null
}
]
}
}
}
When no configured profile matches, the operation returns TOP_UP_METHODS_UNAVAILABLE.
Prepare a top-up
preparePlayerWalletTopUp
Input
| Field | Type | Required | Description |
|---|---|---|---|
requestId | ID! | yes | A new UUIDv7. Repeating the same request with the same payload returns the original result |
amount | String! | yes | A positive decimal amount without exponent notation or group separators |
methodProfileId | ID! | yes | Method profile selected from playerWalletTopUpMethods |
payerCountry | String | no | A two-letter country code such as US |
Result
PlayerWalletTopUpPreparation contains:
| Field | Type | Description |
|---|---|---|
checkoutId | ID! | User-flow identifier passed to the start operation |
intent | PlayerWalletTopUpIntent! | Created intent and destination amount |
methods | [PlayerWalletTopUpMethod!]! | The selected method and its calculation; a successful preparation contains one item |
Every PlayerWalletTopUpMoney contains atomic units, asset code, scale, and a ready-to-display decimal value. Render money from decimal; do not convert it through float.
Exchange example
{
"documentId": "preparePlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000001",
"amount": "10.00",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"payerCountry": "US"
}
}
}
{
"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": "Bank card",
"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 and LOYALTY are displayed as separate rows. The funding calculation is frozen in the quote field: the client does not add percentages or replace totalAmount with a locally calculated value.
Start payment
startPlayerWalletTopUp
Input
| Field | Type | Description |
|---|---|---|
requestId | ID! | A new start UUIDv7 used for idempotent replay |
checkoutId | ID! | Value returned by preparation |
methodProfileId | ID! | Selected method from methods |
quoteId | ID! | Calculation identifier for the selected method |
Repeating the operation with the same four values is safe. Reusing requestId with different values returns a conflict.
Exchange example
{
"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
}
}
}
}
Client actions
kind | Populated field | Action |
|---|---|---|
REDIRECT | redirect.url | Navigate to the HTTPS checkout page |
FORM_POST | formPost.url, formPost.fields | Build and immediately submit a POST form |
QR_CODE | qrCode.payload, optional imageUrl | Render the QR code; payload remains authoritative |
DEEP_LINK | deepLink.url | Render a QR code and an open-app button |
WAIT | wait.recommendedPollAfterSeconds | Repeat the same start operation after the specified delay |
Only the object matching kind is populated. action: null means that no external action remains; use intent.status for the outcome.
Prepare a guest top-up
prepareGuestPlayerWalletTopUp
Guest preparation is available without signing in. Submit the recipient email, amount, and selected payment method.
Input
| Field | Type | Required | Description |
|---|---|---|---|
requestId | ID! | yes | A new preparation UUIDv7; repeating the same payload returns the original result |
recipientEmail | String! | yes | Recipient account email |
amount | String! | yes | A positive decimal amount without exponent notation or group separators |
methodProfileId | ID! | yes | Method profile returned by playerWalletTopUpMethods |
payerCountry | String | no | A two-letter country code such as US |
Result
The operation returns the same PlayerWalletTopUpPreparation as authenticated preparation: checkoutId, intent, and one method with its quote field.
Exchange example
{
"documentId": "prepareGuestPlayerWalletTopUp",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000011",
"amount": "10.00",
"methodProfileId": "01910000-0000-7000-8000-000000000003",
"payerCountry": "US"
}
}
}
{
"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": "Bank card",
"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
}
}
]
}
}
}
An unavailable recipient returns TOP_UP_RECIPIENT_UNAVAILABLE. If no payment method matches the amount or context, the operation returns TOP_UP_METHODS_UNAVAILABLE.
Start a guest payment
startGuestPlayerWalletTopUp
Starts guest payment with the recipient, method and valid calculation returned by preparation. Pass them unchanged.
Input
| Field | Type | Required | Description |
|---|---|---|---|
requestId | ID! | yes | A new start UUIDv7 |
checkoutId | ID! | yes | Value returned by guest preparation |
recipientEmail | String! | yes | The same recipient email used for preparation |
methodProfileId | ID! | yes | Selected method from preparation |
quoteId | ID! | yes | Calculation identifier for the selected method |
Result and client actions
The operation returns the same PlayerWalletTopUpCheckout as authenticated start: intent status, attempt, and one of REDIRECT, FORM_POST, QR_CODE, DEEP_LINK, or WAIT. See Client actions for the action fields.
Exchange example
{
"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
}
}
}
}
Use the start result for guest payment; there is no separate guest-history operation.
Payment history
playerPaymentHistory
Returns payments owned by the current player with cursor pagination. The
statuses filter is optional; an empty list means every status.
| Field | Type | Required | Description |
|---|---|---|---|
first | Int! | yes | Page size from 1 to 100 |
after | ID | no | endCursor from the previous page |
statuses | [PlayerPaymentStatus!] | no | Statuses to include |
{
"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": "Bank card",
"iconAssetId": "payment-method-card"
},
"description": "Balance top-up",
"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
}
}
}
}
One payment
playerPayment
Accepts a public paymentId from history and returns the same payment snapshot.
If the payment is not found, the result is 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": "Bank card",
"iconAssetId": "payment-method-card"
},
"description": "Balance top-up",
"createdAt": "2026-08-29T10:00:00.000000Z",
"expiresAt": "2026-08-29T10:15:00.000000Z",
"completedAt": "2026-08-29T10:02:10.000000Z"
}
}
}
States
PlayerWalletTopUpIntentStatus: OPEN, PROCESSING, SETTLED, CANCELLED, EXPIRED.
PlayerWalletTopUpAttemptStatus: CREATED, REQUIRES_CUSTOMER_ACTION, PENDING_PROVIDER, AUTHORIZED, CAPTURED, DECLINED, CANCELLED, EXPIRED, REVIEW_REQUIRED.
An expired calculation cannot be started. Prepare again and display the new result. A successful callback credits the wallet once; repeating the callback cannot create another credit.
Errors
| Code | Client meaning |
|---|---|
TOP_UP_INVALID_REQUEST | Invalid input format |
TOP_UP_INVALID_AMOUNT | Amount is outside the allowed range |
TOP_UP_ORIGIN_NOT_ALLOWED | Current Origin is not registered for the project |
TOP_UP_RECIPIENT_UNAVAILABLE | Recipient is unknown, blocked, or cannot receive a top-up |
TOP_UP_MERCHANT_UNAVAILABLE | Project top-up is disabled or not configured |
TOP_UP_METHODS_UNAVAILABLE | No payment method matches the amount and context |
TOP_UP_REFRESH_REQUIRED | Intent, method, or calculation is stale; prepare again |
TOP_UP_SCOPE_UNAVAILABLE | The wallet destination cannot be resolved |
TOP_UP_CONFLICT | An idempotency identifier was reused with different data |
TOP_UP_RATE_LIMITED | The limit was exceeded; extensions.retryAfterSeconds specifies the wait |
TOP_UP_UNAVAILABLE | The operation is temporarily unavailable |
If the calculation expires, prepare it again. For a temporary error, retain the original request parameters for retry.