Game currency
Game currency uses a purchase flow with a separate calculation step. An authenticated player selects an owned game account and pays from cabinet balance. Without signing in, only offers delivered as an item to a character are available, and the buyer selects a payment method.
The purchase calculation fixes the offer, quantity, adjustments, total, recipient, and expiration. It is not a separate payment. Submit a valid calculation identifier to confirm the purchase.
After sign-in, operations use the selected game server and the current player's game accounts. For guest purchases, supply the server, character name and payer email. The purchase calculation returns the price and discount.
The server performs catalog lookup, price calculation, order creation, debit, and delivery as one coordinated flow. The client displays returned values and does not recalculate money through floating-point numbers.
Offer list
gameCurrencyOffers
Description
Returns enabled game-currency offers for the current project and server context. The result uses cursor pagination; the operation does not accept gameServerId from the client.
Input
| Field | Type | Required | Description |
|---|---|---|---|
first | Int | no | Page size from 1 to 100. The schema default is 50; pass it explicitly in the persisted operation |
after | ID | no | Cursor from pageInfo.endCursor of the previous page |
Result
GameCurrencyOfferConnection contains items and pageInfo. Each offer contains:
| Field | Type | Description |
|---|---|---|
id | ID! | Opaque offer identifier |
sku | String! | Unique offer code |
name | String! | Localized name |
description | String! | Localized description |
shortName | String! | Short game-currency name |
iconReference | String! | Offer artwork reference |
message | String! | Delivery message |
deliveryType | GameCurrencyDeliveryType! | CHARACTER_ITEM or ACCOUNT_POINTS |
unitsPerPurchase | Int! | Game units in one package |
unitPrice | GameCurrencyMoney! | Exact price of one package |
When pageInfo.hasNextPage is true, pass endCursor unchanged as after.
Exchange example
{
"documentId": "gameCurrencyOffers",
"variables": {
"first": 50,
"after": null
}
}
{
"data": {
"gameCurrencyOffers": {
"items": [
{
"id": "01910000-0000-7000-8000-000000000101",
"sku": "adena-pack",
"name": "Adena package",
"description": "Currency for the game account.",
"shortName": "ADENA",
"iconReference": "/assets/images/currency/adena.webp",
"message": "Currency is delivered after payment.",
"deliveryType": "ACCOUNT_POINTS",
"unitsPerPurchase": 100,
"unitPrice": {
"units": "250",
"code": "USD",
"scale": 2,
"decimal": "2.50"
}
},
{
"id": "01910000-0000-7000-8000-000000000201",
"sku": "soulshot-pack",
"name": "Soulshot package",
"description": "An item delivered to the selected character.",
"shortName": "SOULSHOT",
"iconReference": "/assets/images/currency/soulshot.webp",
"message": "Choose a character for delivery.",
"deliveryType": "CHARACTER_ITEM",
"unitsPerPurchase": 1000,
"unitPrice": {
"units": "500",
"code": "USD",
"scale": 2,
"decimal": "5.00"
}
}
],
"pageInfo": {
"endCursor": null,
"hasNextPage": false
}
}
}
}
Errors
GAME_CURRENCY_SCOPE_UNAVAILABLE- the player's server context is unavailable.GAME_CURRENCY_UNAVAILABLE- the catalog is temporarily unavailable.
Prepare a purchase
prepareGameCurrencyPurchase
Description
Creates a calculation for the selected offer and recipient with the price, discounts, quantity and expiry. This operation neither charges nor reserves funds.
Input
| Field | Type | Required | Description |
|---|---|---|---|
input.requestId | ID! | yes | New UUIDv7 for the preparation attempt; identical data is idempotent |
input.offerId | ID! | yes | Offer identifier from gameCurrencyOffers |
input.quantity | Int! | yes | Package count from 1 to 1,000,000 |
input.accountName | String! | yes | Login of an account owned by the player |
input.characterName | String | no | Required for CHARACTER_ITEM; omitted for ACCOUNT_POINTS |
characterName is required for character delivery and must be absent for account delivery.
Result
GameCurrencyQuote contains the calculation until its expiration:
| Field | Type | Description |
|---|---|---|
id | ID! | Calculation identifier |
offer | GameCurrencyOffer! | Offer snapshot |
quantity | Int! | Package count |
deliveredUnits | Int! | Total delivered units |
unitAmount | GameCurrencyMoney! | Price of one package |
subtotal | GameCurrencyMoney! | Amount before adjustments |
adjustments | [GameCurrencyPriceAdjustment!]! | Separate discounts and surcharges |
total | GameCurrencyMoney! | Amount to pay |
hasSavings | Boolean! | Whether the calculation contains a discount |
delivery | GameCurrencyDeliveryTarget! | Verified recipient |
expiresAt | DateTime! | Calculation expiration |
Money contains atomic units, currency code, scale, and a ready-to-display decimal value. adjustments.source distinguishes catalog, referral, VIP, and campaign rules.
Exchange example
{
"documentId": "prepareGameCurrencyPurchase",
"variables": {
"input": {
"requestId": "01910000-0000-7000-8000-000000000105",
"offerId": "01910000-0000-7000-8000-000000000101",
"quantity": 2,
"accountName": "account-one"
}
}
}
{
"data": {
"prepareGameCurrencyPurchase": {
"id": "01910000-0000-7000-8000-000000000102",
"offer": {
"id": "01910000-0000-7000-8000-000000000101",
"sku": "adena-pack",
"name": "Adena package",
"description": "Currency for the game account.",
"shortName": "ADENA",
"iconReference": "/assets/images/currency/adena.webp",
"message": "Currency is delivered after payment.",
"deliveryType": "ACCOUNT_POINTS",
"unitsPerPurchase": 100,
"unitPrice": {
"units": "250",
"code": "USD",
"scale": 2,
"decimal": "2.50"
}
},
"quantity": 2,
"deliveredUnits": 200,
"unitAmount": {
"units": "250",
"code": "USD",
"scale": 2,
"decimal": "2.50"
},
"subtotal": {
"units": "500",
"code": "USD",
"scale": 2,
"decimal": "5.00"
},
"adjustments": [
{
"code": "vip-20",
"kind": "DISCOUNT",
"source": "VIP",
"amount": {
"units": "100",
"code": "USD",
"scale": 2,
"decimal": "1.00"
}
}
],
"total": {
"units": "400",
"code": "USD",
"scale": 2,
"decimal": "4.00"
},
"hasSavings": true,
"delivery": {
"type": "GAME_ACCOUNT",
"accountName": "account-one",
"characterName": null
},
"expiresAt": "2026-08-31T10:10:00.000000Z"
}
}
}
Errors
GAME_CURRENCY_INVALID_REQUEST- request, quantity, or recipient rules are invalid.GAME_CURRENCY_ACCOUNT_UNAVAILABLE- the account or character is not available to the player.GAME_CURRENCY_OFFER_UNAVAILABLE- the offer is disabled, removed, or outside the current context.GAME_CURRENCY_SCOPE_UNAVAILABLE- the permitted project, server, or wallet cannot be resolved.GAME_CURRENCY_CONFLICT- a UUIDv7 was reused with different data.GAME_CURRENCY_UNAVAILABLE- the calculation is temporarily unavailable.
Purchase from the calculation
purchaseGameCurrency
Description
Creates and pays an order from a valid calculation. The amount, discount and recipient come from that calculation. To change the purchase, obtain a new calculation first.
Input
| Field | Type | Required | Description |
|---|---|---|---|
input.orderRequestId | ID! | yes | New UUIDv7 for order creation |
input.paymentRequestId | ID! | yes | New UUIDv7 for wallet debit |
input.quoteId | ID! | yes | Calculation identifier returned by preparation |
orderRequestId and paymentRequestId are separate idempotency keys. Repeating either step is safe; using different data produces a conflict instead of a second debit or delivery.
Result
| Field | Type | Description |
|---|---|---|
orderId | ID! | Order identifier |
quoteId | ID! | Used calculation |
orderStatus | GameCurrencyOrderStatus! | Order state |
paymentId | ID | Wallet payment |
paymentStatus | GameCurrencyPaymentStatus! | Debit or compensation state |
total | GameCurrencyMoney! | Recorded order total |
createdAt | DateTime! | Creation time |
A successful delivery normally ends with FULFILLED and PAID. Intermediate states describe processing; the client must not send another payment or create a manual delivery.
Exchange example
{
"documentId": "purchaseGameCurrency",
"variables": {
"input": {
"orderRequestId": "01910000-0000-7000-8000-000000000108",
"paymentRequestId": "01910000-0000-7000-8000-000000000109",
"quoteId": "01910000-0000-7000-8000-000000000102"
}
}
}
{
"data": {
"purchaseGameCurrency": {
"orderId": "01910000-0000-7000-8000-000000000103",
"quoteId": "01910000-0000-7000-8000-000000000102",
"orderStatus": "FULFILLED",
"paymentId": "01910000-0000-7000-8000-000000000104",
"paymentStatus": "PAID",
"total": {
"units": "400",
"code": "USD",
"scale": 2,
"decimal": "4.00"
},
"createdAt": "2026-08-31T10:01:00.000000Z"
}
}
}
A zero-total purchase is confirmed without payment: paymentId is null and paymentStatus is NOT_REQUIRED. The order progresses through CONFIRMED, FULFILLING and FULFILLED; confirmation does not yet mean delivery is complete.
States
GameCurrencyOrderStatus: CONFIRMED, PENDING_PAYMENT, PAID, FULFILLING, FULFILLED, CANCELLED.
GameCurrencyPaymentStatus: NOT_REQUIRED, DEBIT_PENDING, PAID, REVERSAL_PENDING, REVERSED, REQUIRES_REVIEW.
When the calculation expires, prepare a new one and display its result. If delivery fails, the server starts the defined compensation flow; the client does not perform a manual refund.
Errors
GAME_CURRENCY_REFRESH_REQUIRED- the calculation or order expired or is no longer payable; prepare again.GAME_CURRENCY_INSUFFICIENT_BALANCE- the permitted player wallet has insufficient funds.GAME_CURRENCY_PAYMENT_DEBT- repay the selected balance's debt, then start a new purchase.GAME_CURRENCY_CONFLICT- an idempotency key was reused with different data.GAME_CURRENCY_SCOPE_UNAVAILABLE- the project and server wallet scope is unavailable.GAME_CURRENCY_UNAVAILABLE- the operation is temporarily unavailable.
Guest purchase
The guest flow consists of the catalog, purchase calculation, payment-method preparation, and execution of the selected method. Every operation is public but rate-limited. Unknown and unavailable characters return the same GAME_CURRENCY_RECIPIENT_UNAVAILABLE code.
Guest catalog
guestGameCurrencyOffers
Returns only active CHARACTER_ITEM offers for the selected game server. ACCOUNT_POINTS offers require authentication and are excluded.
| Field | Type | Required | Description |
|---|---|---|---|
gameServerId | Int! | yes | Selected project game server |
first | Int | no | Page size from 1 to 100 |
after | ID | no | Cursor for the next page |
{
"documentId": "guestGameCurrencyOffers",
"variables": {
"gameServerId": 1,
"first": 50,
"after": null
}
}
{
"data": {
"guestGameCurrencyOffers": {
"items": [
{
"id": "019c8a00-0000-7000-8000-000000000001",
"sku": "ADENA_250000",
"name": "Adena",
"description": "250,000 Adena for the selected character.",
"shortName": "Adena",
"iconReference": "/assets/images/currency/adena.webp",
"message": "Currency is delivered after payment.",
"deliveryType": "CHARACTER_ITEM",
"unitsPerPurchase": 250000,
"unitPrice": {
"units": "199",
"code": "USD",
"scale": 2,
"decimal": "1.99"
}
}
],
"pageInfo": {
"endCursor": null,
"hasNextPage": false
}
}
}
}
Character calculation
prepareGuestGameCurrencyPurchase
Verifies the character and creates a short-lived calculation. The email belongs to the payer and is not used as the game-currency recipient.
| Field | Type | Required | Description |
|---|---|---|---|
input.gameServerId | Int! | yes | Game server from the guest catalog |
input.requestId | ID! | yes | Calculation UUIDv7 |
input.offerId | ID! | yes | Offer from the guest catalog |
input.quantity | Int! | yes | Package count from 1 to 1,000,000 |
input.characterName | String! | yes | Character on the selected server |
input.payerEmail | String! | yes | Payer email |
{
"documentId": "prepareGuestGameCurrencyPurchase",
"variables": {
"input": {
"gameServerId": 1,
"requestId": "019c8a10-0000-7000-8000-000000000001",
"offerId": "019c8a00-0000-7000-8000-000000000001",
"quantity": 10,
"characterName": "Asterion",
}
}
}
{
"data": {
"prepareGuestGameCurrencyPurchase": {
"id": "019c8a10-0000-7000-8000-000000000002",
"offer": {
"id": "019c8a00-0000-7000-8000-000000000001",
"sku": "ADENA_250000",
"name": "Adena",
"description": "250,000 Adena for the selected character.",
"shortName": "Adena",
"iconReference": "/assets/images/currency/adena.webp",
"message": "Currency is delivered after payment.",
"deliveryType": "CHARACTER_ITEM",
"unitsPerPurchase": 250000,
"unitPrice": {
"units": "199",
"code": "USD",
"scale": 2,
"decimal": "1.99"
}
},
"quantity": 10,
"deliveredUnits": 2500000,
"unitAmount": {
"units": "199",
"code": "USD",
"scale": 2,
"decimal": "1.99"
},
"subtotal": {
"units": "1990",
"code": "USD",
"scale": 2,
"decimal": "19.90"
},
"adjustments": [],
"total": {
"units": "1990",
"code": "USD",
"scale": 2,
"decimal": "19.90"
},
"hasSavings": false,
"delivery": {
"type": "CHARACTER",
"accountName": null,
"characterName": "Asterion"
},
"expiresAt": "2026-09-01T10:15:00.000000Z"
}
}
}
Errors
GAME_CURRENCY_RECIPIENT_UNAVAILABLE- the recipient is unknown or unavailable.GAME_CURRENCY_OFFER_UNAVAILABLE- the offer is disabled or does not support guest checkout.GAME_CURRENCY_RATE_LIMITED- the rate limit was exceeded; retry after the returned delay.GAME_CURRENCY_CONFLICT- a UUIDv7 was reused with different data.
Payment methods
prepareGuestGameCurrencyCheckout
Creates an order awaiting payment from an active calculation and returns eligible methods with a separate payment calculation for each method.
| Field | Type | Required | Description |
|---|---|---|---|
input.gameServerId | Int! | yes | The same game server |
input.orderRequestId | ID! | yes | Order-creation UUIDv7 |
input.paymentRequestId | ID! | yes | Payment-preparation UUIDv7 |
input.quoteId | ID! | yes | Active purchase calculation |
input.characterName | String! | yes | The same character |
input.payerEmail | String! | yes | The same payer email |
input.payerCountry | String | no | Two-letter country code when available |
{
"documentId": "prepareGuestGameCurrencyCheckout",
"variables": {
"input": {
"gameServerId": 1,
"orderRequestId": "019c8a10-0000-7000-8000-000000000003",
"paymentRequestId": "019c8a10-0000-7000-8000-000000000004",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"characterName": "Asterion",
"payerCountry": "DE"
}
}
}
{
"data": {
"prepareGuestGameCurrencyCheckout": {
"orderId": "019c8a10-0000-7000-8000-000000000005",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"orderStatus": "PENDING_PAYMENT",
"intent": {
"id": "019c8a10-0000-7000-8000-000000000006",
"status": "OPEN",
"expiresAt": "2026-09-01T10:20:00.000000Z"
},
"methods": [
{
"id": "019c8a10-0000-7000-8000-000000000007",
"code": "paygol",
"name": "PayGol",
"iconAssetId": "payment-method-paygol",
"paymentQuote": {
"id": "019c8a10-0000-7000-8000-000000000008",
"paymentAmount": {
"units": "1990",
"code": "EUR",
"scale": 2,
"decimal": "19.90"
},
"destinationAmount": {
"units": "1990",
"code": "USD",
"scale": 2,
"decimal": "19.90"
},
"payerFee": {
"units": "0",
"code": "EUR",
"scale": 2,
"decimal": "0.00"
},
"expiresAt": "2026-09-01T10:15:00.000000Z"
}
}
]
}
}
}
When no method is eligible, the operation returns GAME_CURRENCY_METHODS_UNAVAILABLE and does not create a payment attempt.
Start payment
startGuestGameCurrencyCheckout
Starts the selected method using its active calculation. Every recipient field must match the prepared order.
| Field | Type | Required | Description |
|---|---|---|---|
input.gameServerId | Int! | yes | Order game server |
input.requestId | ID! | yes | Start UUIDv7 |
input.orderId | ID! | yes | Prepared order |
input.quoteId | ID! | yes | Order purchase calculation |
input.characterName | String! | yes | Verified character |
input.payerEmail | String! | yes | Payer email |
input.methodProfileId | ID! | yes | methods[].id |
input.paymentQuoteId | ID! | yes | methods[].paymentQuote.id |
{
"documentId": "startGuestGameCurrencyCheckout",
"variables": {
"input": {
"gameServerId": 1,
"requestId": "019c8a10-0000-7000-8000-000000000009",
"orderId": "019c8a10-0000-7000-8000-000000000005",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"characterName": "Asterion",
"methodProfileId": "019c8a10-0000-7000-8000-000000000007",
"paymentQuoteId": "019c8a10-0000-7000-8000-000000000008"
}
}
}
{
"data": {
"startGuestGameCurrencyCheckout": {
"orderId": "019c8a10-0000-7000-8000-000000000005",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"orderStatus": "PENDING_PAYMENT",
"intent": {
"id": "019c8a10-0000-7000-8000-000000000006",
"status": "PROCESSING",
"expiresAt": "2026-09-01T10:20:00.000000Z"
},
"attempt": {
"id": "019c8a10-0000-7000-8000-000000000010",
"status": "REQUIRES_CUSTOMER_ACTION",
"expiresAt": "2026-09-01T10:15:00.000000Z"
},
"action": {
"kind": "REDIRECT",
"expiresAt": "2026-09-01T10:15:00.000000Z",
"redirect": {
"url": "https://payments.example/checkout/019c8a10"
},
"formPost": null,
"qrCode": null,
"deepLink": null,
"wait": null
}
}
}
}
action.kind selects one client action: REDIRECT, FORM_POST, QR_CODE, DEEP_LINK, or WAIT. Use its URL and fields unchanged until action.expiresAt.
Retry a payment action
retryGuestGameCurrencyCheckout
Continues the same order after an interrupted redirect or temporary failure. Input fields match startGuestGameCurrencyCheckout; use a new requestId while preserving the order, calculation, recipient, and method.
{
"documentId": "retryGuestGameCurrencyCheckout",
"variables": {
"input": {
"gameServerId": 1,
"requestId": "019c8a10-0000-7000-8000-000000000011",
"orderId": "019c8a10-0000-7000-8000-000000000005",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"characterName": "Asterion",
"methodProfileId": "019c8a10-0000-7000-8000-000000000007",
"paymentQuoteId": "019c8a10-0000-7000-8000-000000000008"
}
}
}
{
"data": {
"retryGuestGameCurrencyCheckout": {
"orderId": "019c8a10-0000-7000-8000-000000000005",
"quoteId": "019c8a10-0000-7000-8000-000000000002",
"orderStatus": "PENDING_PAYMENT",
"intent": {
"id": "019c8a10-0000-7000-8000-000000000006",
"status": "PROCESSING",
"expiresAt": "2026-09-01T10:20:00.000000Z"
},
"attempt": {
"id": "019c8a10-0000-7000-8000-000000000012",
"status": "PENDING_PROVIDER",
"expiresAt": "2026-09-01T10:15:00.000000Z"
},
"action": {
"kind": "WAIT",
"expiresAt": "2026-09-01T10:15:00.000000Z",
"redirect": null,
"formPost": null,
"qrCode": null,
"deepLink": null,
"wait": {
"recommendedPollAfterSeconds": 3
}
}
}
}
}
Repeating the same UUIDv7 with identical data is idempotent. Reusing it with different data returns GAME_CURRENCY_CONFLICT. An expired calculation or method returns GAME_CURRENCY_REFRESH_REQUIRED.
Delivery rules
ACCOUNT_POINTSdelivers currency to the verified game account;characterNameis not used.CHARACTER_ITEMdelivers an item to the selected character. After sign-in, choose a character from the game account; for a guest purchase, enter the character's name on the selected server.- Offers and recipients are limited to the project and server resolved from the session.
- Repeating a request with the same UUIDv7 does not create another order, debit, or delivery.
The complete GameCurrency* structures are in the API schema reference. Player balance top-up is described in Player balance top-up.
Free guest purchase
confirmFreeGuestGameCurrencyPurchase
Confirms a purchase whose calculated total is zero. Call after the guest explicitly presses Buy, using the active guest purchase calculation. Do not request payment methods or start payment for this purchase.
input field | Type | Meaning |
|---|---|---|
gameServerId | Int! | Selected game server. |
orderRequestId | ID! | UUIDv7 for order creation. |
confirmationRequestId | ID! | A different UUIDv7 for confirmation. |
quoteId | ID! | Active zero-total calculation ID. |
characterName | String! | Calculation recipient, up to 64 characters. |
payerEmail | String! | Calculation email, up to 254 characters. |
{
"documentId": "confirmFreeGuestGameCurrencyPurchase",
"variables": {
"input": {
"gameServerId": 1,
"orderRequestId": "019bf3dd-b08b-7000-8000-000000000310",
"confirmationRequestId": "019bf3dd-b08b-7000-8000-000000000311",
"quoteId": "019bf3dd-b08b-7000-8000-000000000312",
"characterName": "Asterion",
}
}
}
{
"data": {
"confirmFreeGuestGameCurrencyPurchase": {
"orderId": "019bf3dd-b08b-7000-8000-000000000313",
"quoteId": "019bf3dd-b08b-7000-8000-000000000312",
"orderStatus": "CONFIRMED",
"paymentId": null,
"paymentStatus": "NOT_REQUIRED",
"total": {
"units": "0",
"code": "ELX",
"scale": 3,
"decimal": "0.000"
},
"createdAt": "2026-09-13T10:00:00Z"
}
}
}
For a retry, keep both request identifiers and all other fields unchanged. Prepare a new calculation if it expires. The result is GameCurrencyPurchase, with paymentId: null and paymentStatus: NOT_REQUIRED. CONFIRMED means the confirmation was accepted, not that delivery has completed.