GS2-Money2 SDK for Game Engine API Reference
Model
EzWallet
Wallet
Currency in the wallet is managed separately for currency purchased for a fee and currency obtained for free. Currency purchased for a fee is further managed by the unit price at the time of purchase, allowing for refunds in the event of service termination, or to determine if the balance is sufficient to meet the requirements of the Funds Settlement Act.
The wallet has slots and each slot has a different balance. If balances cannot be shared across platforms, they can be managed separately by using different slots for each platform. Currency acquired for free can also be shared across all platforms.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| slot | int | ✓ | 0 ~ 100000000 | Slot Number Identifies the wallet slot. Different slots can be used to manage currency separately per platform (e.g., one slot for iOS, another for Android) when cross-platform balance sharing is not allowed. | ||
| summary | EzWalletSummary | ✓ | Wallet Status A summary of the wallet’s current balance, broken down into paid currency, free currency, and total amounts. Calculated from the deposit transactions. | |||
| sharedFreeCurrency | bool | ✓ | Share free currency Indicates whether the free currency in this wallet is shared across all slots. Inherited from the namespace setting at wallet creation time. | |||
| updatedAt | long | * | Now | Datetime of last update Unix time, milliseconds * Set automatically by the server |
EzSubscribeTransaction
Subscription purchase information
Represents a subscription purchase record from a store platform. Tracks the detailed subscription status through its lifecycle including active, trial, intro offer, grace period, canceled, expired, and revoked states. Each transaction is linked to a specific store platform and user.
| Type | Condition | Required | Default | Value Limits | Description | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| contentName | string | ✓ | ~ 128 chars | Store Subscription Content Model name | ||||||||||||||||||||||
| store | String Enum enum { “AppleAppStore”, “GooglePlay”, “fake” } | ✓ | Store The store platform where the purchase was made. Determines which verification method is used for receipt validation.
| |||||||||||||||||||||||
| transactionId | string | ✓ | ~ 1024 chars | Transaction ID The unique transaction identifier assigned by the store platform. Used to prevent duplicate processing of the same purchase. | ||||||||||||||||||||||
| statusDetail | String Enum enum { “active@active”, “active@converted_from_trial”, “active@in_trial”, “active@in_intro_offer”, “grace@canceled”, “grace@grace_period”, “grace@on_hold”, “inactive@expired”, “inactive@revoked” } | ✓ | Status The detailed subscription status. Prefixed with the simplified category (active/grace/inactive) followed by the specific state. Active states indicate the subscription is usable; grace states indicate payment issues but temporary access; inactive states indicate the subscription is no longer valid.
| |||||||||||||||||||||||
| expiresAt | long | ✓ | Expiration time The timestamp at which this subscription transaction expires. Updated when the subscription is renewed by the store platform. |
EzSubscriptionStatus
Subscription status
Tracks a user’s subscription contract status for a specific subscription content. Provides a simplified active/inactive status derived from the detailed subscription transaction states, along with the expiration time and the list of associated subscription transactions.
| Type | Condition | Required | Default | Value Limits | Description | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| contentName | string | ✓ | ~ 128 chars | Store Subscription Content Model name | ||||||||
| userId | string | ~ 128 chars | User ID | |||||||||
| status | String Enum enum { “active”, “inactive” } | ✓ | Status The simplified subscription status. “active” includes active, trial, intro offer, and grace period states. “inactive” includes expired and revoked states.
| |||||||||
| expiresAt | long | ✓ | Expiration time The timestamp at which the subscription expires. Updated when the subscription is renewed or its status changes. | |||||||||
| detail | List<EzSubscribeTransaction> | [] | 0 ~ 100 items | Subscription status details The list of subscription transactions associated with this subscription. Each transaction represents a purchase record from a store platform with detailed status information (active, trial, grace period, expired, revoked, etc.). |
EzStoreContentModel
Store Content Model
This is a model for storing content from various store platforms.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| name | string | ✓ | ~ 128 chars | Store Content Model name | ||
| metadata | string | ~ 1024 chars | Metadata Arbitrary values can be set in the metadata. Since they do not affect GS2’s behavior, they can be used to store information used in the game. | |||
| appleAppStore | EzAppleAppStoreContent | Apple AppStore Content The Apple App Store product information (product ID) for this store content. Used during receipt verification to match the purchased product. | ||||
| googlePlay | EzGooglePlayContent | Google Play Content The Google Play product information (product ID) for this store content. Used during receipt verification to match the purchased product. |
EzWalletSummary
Wallet Status
A summary view of a wallet’s currency balance, separating paid and free amounts. Calculated by aggregating all deposit transactions in the wallet based on their price (paid if price > 0, free if price = 0).
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| paid | int | 0 | 0 ~ 2147483646 | Count of paid currency The total amount of currency that was purchased with real money (deposit transactions with price > 0). | ||
| free | int | 0 | 0 ~ 2147483646 | Count of free currency The total amount of currency obtained for free (deposit transactions with price = 0), such as login bonuses or event rewards. | ||
| total | int | 0 | 0 ~ 2147483646 | Total The total currency balance (paid + free). Represents the overall available amount in the wallet. |
EzDepositTransaction
Deposit Transaction
Represents a single deposit record in the wallet. Paid deposits (price > 0) are tracked per unit price to enable accurate refund calculations and compliance with the Funds Settlement Act. Free deposits (price = 0) are tracked separately. When withdrawing, deposit transactions are consumed based on the namespace’s currency usage priority.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| price | double | ✓ | 0.0 ~ 100000000.0 | Purchase Price The real-money price paid for this deposit in the local currency. A value of 0 indicates free currency. Used to calculate per-unit cost for refund purposes. | ||
| currency | string | {price} > 0 | ✓* | ~ 8 chars | Currency Code The ISO currency code (e.g., “JPY”, “USD”) of the real-money payment. Only applicable for paid deposits (price > 0). * Required if price is greater than 0 | |
| count | int | ✓ | 0 ~ 2147483646 | Quantity of premium currency The number of virtual currency units in this deposit. Decreases as currency is withdrawn from the wallet. |
EzAppleAppStoreContent
Content of Apple AppStore
Contains the Apple App Store product ID that corresponds to an in-app purchase product. Used to match receipts during verification.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| productId | string | ~ 1024 chars | Product ID The Apple App Store product identifier registered in App Store Connect for this in-app purchase item. |
EzGooglePlayContent
Content of Google Play
Contains the Google Play product ID that corresponds to an in-app purchase product. Used to match receipts during verification.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| productId | string | ~ 1024 chars | Product ID The Google Play product identifier registered in Google Play Console for this in-app purchase item. |
EzAppleAppStoreSubscriptionContent
Subscription content of Apple AppStore
Contains the Apple App Store subscription group identifier for subscription-based products. Used to manage and verify auto-renewable subscriptions.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| subscriptionGroupIdentifier | string | ~ 64 chars | Subscription Group ID The subscription group identifier registered in App Store Connect. Subscriptions within the same group are mutually exclusive, meaning a user can only subscribe to one at a time. |
EzGooglePlaySubscriptionContent
Google Play Subscription Content
Contains the Google Play product ID for subscription-based products. Used to manage and verify auto-renewable subscriptions on Google Play.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| productId | string | ~ 1024 chars | Product ID |
Methods
get
Get the player’s premium currency wallet balance
Retrieves the player’s wallet for the specified slot, showing the current balance of both paid and free premium currency. “Paid” currency is what the player purchased with real money (e.g., bought 100 Gems for $0.99), while “free” currency is earned through gameplay (e.g., event rewards, login bonuses). These are tracked separately because some features may require paid currency only (e.g., certain gacha or special offers). Use this to display the player’s currency balance — for example, “Gems: 350 (Paid: 100, Free: 250)” on the shop or header UI.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | ✓ | GameSession | |||
| slot | int | ✓ | 0 ~ 100000000 | Slot Number Identifies the wallet slot. Different slots can be used to manage currency separately per platform (e.g., one slot for iOS, another for Android) when cross-platform balance sharing is not allowed. |
Result
| Type | Description | |
|---|---|---|
| item | EzWallet | Wallet |
Implementation Example
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
var item = await domain.ModelAsync(); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
var future = domain.ModelFuture();
yield return future;
var item = future.Result; const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Wallet(
0 // slot
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}Value change event handling
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
// Start event handling
var callbackId = domain.Subscribe(
value => {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
domain.Unsubscribe(callbackId); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
// Start event handling
var callbackId = domain.Subscribe(
value => {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
domain.Unsubscribe(callbackId); const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Wallet(
0 // slot
);
// Start event handling
const auto CallbackId = Domain->Subscribe(
[](TSharedPtr<Gs2::Money2::Model::FWallet> value) {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
Domain->Unsubscribe(CallbackId);Warning
This event is triggered when the value stored in the SDK’s local cache changes.
The local cache is updated only when executing the SDK’s API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
list
Get a list of the player’s premium currency wallets
Retrieves all wallets the player currently has. Each wallet manages its own balance, with paid and free currency tracked separately. “Paid” currency is what the player purchased with real money (e.g., bought 100 Gems for $0.99), while “free” currency is earned through gameplay (e.g., event rewards, login bonuses). Use this to display the player’s full currency overview — for example, a currency management screen showing all wallet slots and their balances.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | ✓ | GameSession |
Result
| Type | Description | |
|---|---|---|
| items | List<EzWallet> | List of Wallets |
| nextPageToken | string | Page token to retrieve the rest of the listing |
Implementation Example
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var items = await domain.WalletsAsync(
).ToListAsync(); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var it = domain.Wallets(
);
List<EzWallet> items = new List<EzWallet>();
while (it.HasNext())
{
yield return it.Next();
if (it.Error != null)
{
onError.Invoke(it.Error, null);
break;
}
if (it.Current != null)
{
items.Add(it.Current);
}
else
{
break;
}
} const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto It = Domain->Wallets(
);
TArray<Gs2::UE5::Money2::Model::FEzWalletPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}Value change event handling
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// Start event handling
var callbackId = domain.SubscribeWallets(
() => {
// Called when an element of the list changes.
}
);
// Stop event handling
domain.UnsubscribeWallets(callbackId); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// Start event handling
var callbackId = domain.SubscribeWallets(
() => {
// Called when an element of the list changes.
}
);
// Stop event handling
domain.UnsubscribeWallets(callbackId); const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
// Start event handling
const auto CallbackId = Domain->SubscribeWallets(
[]() {
// Called when an element of the list changes.
}
);
// Stop event handling
Domain->UnsubscribeWallets(CallbackId);Warning
This event is triggered when the value stored in the SDK’s local cache changes.
The local cache is updated only when executing the SDK’s API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
withdraw
Spend premium currency from the player’s wallet
Deducts the specified amount of premium currency from the player’s wallet. By default (paidOnly = false), free currency is spent first, then paid currency is used for the remainder. This ensures players use up free currency before dipping into purchased currency. If paidOnly is set to true, only paid currency is consumed — this is required for features that legally must use paid currency only (e.g., paid-only gacha in some regions). Use this when the player makes a purchase using premium currency — for example, spending 100 Gems to buy a special item or pull a gacha. Note: if currency is consumed as a cost for purchasing products via GS2-Showcase, the consumption is handled automatically — you don’t need to call this API for those cases.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | ✓ | GameSession | |||
| slot | int | ✓ | 0 ~ 100000000 | Slot Number Identifies the wallet slot. Different slots can be used to manage currency separately per platform (e.g., one slot for iOS, another for Android) when cross-platform balance sharing is not allowed. | ||
| withdrawCount | int | ✓ | 1 ~ 2147483646 | Quantity of premium currency to be consumed | ||
| paidOnly | bool | false | Only for paid currency |
Result
| Type | Description | |
|---|---|---|
| item | EzWallet | Post-withdraw Wallet |
| withdrawTransactions | List<EzDepositTransaction> | List of consumed deposit transactions |
Error
Special exceptions are defined in this API. GS2-SDK for GameEngine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games. Please refer to the documentation here for more information on common error types and handling methods.
| Type | Base Type | Description |
|---|---|---|
| ConflictException | ConflictException | The wallet operation process conflicted. Retry required. |
| InsufficientException | BadRequestException | Wallet balance is insufficient. |
Implementation Example
try {
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
var result = await domain.WithdrawAsync(
withdrawCount: 50,
paidOnly: null
);
var item = await result.ModelAsync();
var withdrawTransactions = result.WithdrawTransactions;
} catch(Gs2.Gs2Money2.Exception.ConflictException e) {
// The wallet operation process conflicted. Retry required.
} catch(Gs2.Gs2Money2.Exception.InsufficientException e) {
// Wallet balance is insufficient.
} var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Wallet(
slot: 0
);
var future = domain.WithdrawFuture(
withdrawCount: 50,
paidOnly: null
);
yield return future;
if (future.Error != null)
{
if (future.Error is Gs2.Gs2Money2.Exception.ConflictException)
{
// The wallet operation process conflicted. Retry required.
}
if (future.Error is Gs2.Gs2Money2.Exception.InsufficientException)
{
// Wallet balance is insufficient.
}
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result;
var withdrawTransactions = future.Result.WithdrawTransactions; const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Wallet(
0 // slot
);
const auto Future = Domain->Withdraw(
50 // withdrawCount
// paidOnly
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
auto e = Future->GetTask().Error();
if (e->IsChildOf(Gs2::Money2::Error::FConflictError::Class))
{
// The wallet operation process conflicted. Retry required.
}
if (e->IsChildOf(Gs2::Money2::Error::FInsufficientError::Class))
{
// Wallet balance is insufficient.
}
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();
const auto WithdrawTransactions = Result->WithdrawTransactions;allocateSubscriptionStatus
Register a subscription using a store receipt
Links a subscription purchase to the player by verifying the receipt from the App Store or Google Play. After a player purchases a subscription (e.g., “Monthly Pass”) on their device, pass the store receipt to this API to activate the subscription on the server side. This is the essential step to connect the store purchase to the player’s account — without calling this, the server won’t know the player has subscribed. Use this in the purchase flow — for example, after the player buys a “Monthly Pass” in the in-app purchase dialog, send the receipt to activate VIP benefits.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | GameSession | ||||
| receipt | string | ✓ | ~ 1024 chars | Receipt |
Result
| Type | Description | |
|---|---|---|
| item | EzSubscriptionStatus | Subscription status |
Error
Special exceptions are defined in this API. GS2-SDK for GameEngine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games. Please refer to the documentation here for more information on common error types and handling methods.
| Type | Base Type | Description |
|---|---|---|
| AlreadyUsedException | BadRequestException | The subscription contract for that period has already been used by another user. |
Implementation Example
try {
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var result = await domain.AllocateSubscriptionStatusAsync(
receipt: "{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}"
);
var item = await result.ModelAsync();
} catch(Gs2.Gs2Money2.Exception.AlreadyUsedException e) {
// The subscription contract for that period has already been used by another user.
} var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var future = domain.AllocateSubscriptionStatusFuture(
receipt: "{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}"
);
yield return future;
if (future.Error != null)
{
if (future.Error is Gs2.Gs2Money2.Exception.AlreadyUsedException)
{
// The subscription contract for that period has already been used by another user.
}
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto Future = Domain->AllocateSubscriptionStatus(
"{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}" // receipt
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
auto e = Future->GetTask().Error();
if (e->IsChildOf(Gs2::Money2::Error::FAlreadyUsedError::Class))
{
// The subscription contract for that period has already been used by another user.
}
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();getSubscriptionStatus
Get a specific subscription status
Retrieves the subscription status for a specific content by name. The status shows whether the player is currently subscribed and related details such as expiration timing. Use this to check if the player has a specific subscription — for example, checking if the “Monthly Pass” is active before granting daily bonus rewards, or displaying “VIP Membership: Active” on the player’s profile.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | GameSession | ||||
| contentName | string | ✓ | ~ 128 chars | Store Subscription Content Model name |
Result
| Type | Description | |
|---|---|---|
| item | EzSubscriptionStatus | Subscription status |
Implementation Example
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).SubscriptionStatus(
contentName: "content-0001"
);
var item = await domain.ModelAsync(); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).SubscriptionStatus(
contentName: "content-0001"
);
var future = domain.ModelFuture();
yield return future;
var item = future.Result; const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->SubscriptionStatus(
"content-0001" // contentName
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}Value change event handling
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).SubscriptionStatus(
contentName: "content-0001"
);
// Start event handling
var callbackId = domain.Subscribe(
value => {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
domain.Unsubscribe(callbackId); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).SubscriptionStatus(
contentName: "content-0001"
);
// Start event handling
var callbackId = domain.Subscribe(
value => {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
domain.Unsubscribe(callbackId); const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->SubscriptionStatus(
"content-0001" // contentName
);
// Start event handling
const auto CallbackId = Domain->Subscribe(
[](TSharedPtr<Gs2::Money2::Model::FSubscriptionStatus> value) {
// Called when the value changes
// The "value" is passed the value after the change.
}
);
// Stop event handling
Domain->Unsubscribe(CallbackId);Warning
This event is triggered when the value stored in the SDK’s local cache changes.
The local cache is updated only when executing the SDK’s API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
listSubscriptionStatuses
Get a list of the player’s subscription statuses
Retrieves the subscription statuses for all subscription content that the player may have. A subscription is a recurring purchase like a “Monthly Pass” or “VIP Membership” from the App Store or Google Play. Each status shows whether the player is currently subscribed to that content. Use this to display a subscription overview — for example, showing “Monthly Pass: Active (expires March 15)” and “VIP Membership: Not subscribed” on a membership screen.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | GameSession |
Result
| Type | Description | |
|---|---|---|
| items | List<EzSubscriptionStatus> | List of Subscription statuses |
Implementation Example
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var items = await domain.SubscriptionStatusesAsync(
).ToListAsync(); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var it = domain.SubscriptionStatuses(
);
List<EzSubscriptionStatus> items = new List<EzSubscriptionStatus>();
while (it.HasNext())
{
yield return it.Next();
if (it.Error != null)
{
onError.Invoke(it.Error, null);
break;
}
if (it.Current != null)
{
items.Add(it.Current);
}
else
{
break;
}
} const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto It = Domain->SubscriptionStatuses(
);
TArray<Gs2::UE5::Money2::Model::FEzSubscriptionStatusPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}Value change event handling
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// Start event handling
var callbackId = domain.SubscribeSubscriptionStatuses(
() => {
// Called when an element of the list changes.
}
);
// Stop event handling
domain.UnsubscribeSubscriptionStatuses(callbackId); var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// Start event handling
var callbackId = domain.SubscribeSubscriptionStatuses(
() => {
// Called when an element of the list changes.
}
);
// Stop event handling
domain.UnsubscribeSubscriptionStatuses(callbackId); const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
// Start event handling
const auto CallbackId = Domain->SubscribeSubscriptionStatuses(
[]() {
// Called when an element of the list changes.
}
);
// Stop event handling
Domain->UnsubscribeSubscriptionStatuses(CallbackId);Warning
This event is triggered when the value stored in the SDK’s local cache changes.
The local cache is updated only when executing the SDK’s API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
takeOverSubscriptionStatus
Transfer a subscription from another account to this player
Moves a subscription that is currently linked to a different player account to this player’s account. This is used when a player migrates their account — for example, if a player switches devices and creates a new account, they can transfer their existing “Monthly Pass” subscription from the old account to the new one using the store receipt. The subscription is unlinked from the old account and linked to the new account, so the old account will no longer have the subscription benefits. Use this in the account migration flow — for example, after the player logs in to their new account and confirms the transfer.
Request
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| gameSession | GameSession | GameSession | ||||
| receipt | string | ✓ | ~ 1024 chars | Receipt |
Result
| Type | Description | |
|---|---|---|
| item | EzSubscriptionStatus | Subscription status |
Error
Special exceptions are defined in this API. GS2-SDK for GameEngine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games. Please refer to the documentation here for more information on common error types and handling methods.
| Type | Base Type | Description |
|---|---|---|
| LockPeriodNotElapsedException | BadRequestException | The lock period has not elapsed since the last user change. |
Implementation Example
try {
var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var result = await domain.TakeOverSubscriptionStatusAsync(
receipt: "{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}"
);
var item = await result.ModelAsync();
} catch(Gs2.Gs2Money2.Exception.LockPeriodNotElapsedException e) {
// The lock period has not elapsed since the last user change.
} var domain = gs2.Money2.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var future = domain.TakeOverSubscriptionStatusFuture(
receipt: "{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}"
);
yield return future;
if (future.Error != null)
{
if (future.Error is Gs2.Gs2Money2.Exception.LockPeriodNotElapsedException)
{
// The lock period has not elapsed since the last user change.
}
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->Money2->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto Future = Domain->TakeOverSubscriptionStatus(
"{\"Store\": \"AppleAppStore\", \"TransactionID\": \"transaction-0001\", \"Payload\": \"payload\"}" // receipt
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
auto e = Future->GetTask().Error();
if (e->IsChildOf(Gs2::Money2::Error::FLockPeriodNotElapsedError::Class))
{
// The lock period has not elapsed since the last user change.
}
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();Event Handler
OnChangeSubscriptionStatus
Push notification when the subscription status of the period changes
| Name | Type | Description |
|---|---|---|
| namespaceName | string | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| userId | string | User ID |
| contentName | string | Store Subscription Content Model name |
Implementation Example
gs2.Money2.OnChangeSubscriptionStatus += notification =>
{
var namespaceName = notification.NamespaceName;
var userId = notification.UserId;
var contentName = notification.ContentName;
}; gs2.Money2.OnChangeSubscriptionStatus += notification =>
{
var namespaceName = notification.NamespaceName;
var userId = notification.UserId;
var contentName = notification.ContentName;
}; Gs2->Money2->OnChangeSubscriptionStatus().AddLambda([](const auto Notification)
{
const auto NamespaceName = Notification->NamespaceNameValue;
const auto UserId = Notification->UserIdValue;
const auto ContentName = Notification->ContentNameValue;
});