GS2-Money2 SDK for Game Engine API Reference

Specifications of models and API references for GS2-Money2 SDK for Game Engine

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.

TypeConditionRequiredDefaultValue LimitsDescription
slotint
0 ~ 100000000Slot 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.
summaryEzWalletSummary
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.
sharedFreeCurrencybool
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.
updatedAtlong
*
NowDatetime 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.

TypeConditionRequiredDefaultValue LimitsDescription
contentNamestring
~ 128 charsStore Subscription Content Model name
storeString Enum
enum {
  “AppleAppStore”,
  “GooglePlay”,
  “fake”
}
Store
The store platform where the purchase was made. Determines which verification method is used for receipt validation.
DefinitionDescription
“AppleAppStore”Apple App Store
“GooglePlay”Google Play
“fake”Fake
transactionIdstring
~ 1024 charsTransaction ID
The unique transaction identifier assigned by the store platform. Used to prevent duplicate processing of the same purchase.
statusDetailString 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.
DefinitionDescription
“active@active”Active
“active@converted_from_trial”Converted from free trial to paid plan
“active@in_trial”In free trial
“active@in_intro_offer”In introductory offer
“grace@canceled”User has manually canceled
“grace@grace_period”The payment failed, but it is within the grace period.
“grace@on_hold”Payment has failed. If payment is not completed within a specified period, the service will be unavailable.
“inactive@expired”Subscription has expired
“inactive@revoked”Subscription has been revoked
expiresAtlong
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.

TypeConditionRequiredDefaultValue LimitsDescription
contentNamestring
~ 128 charsStore Subscription Content Model name
userIdstring~ 128 charsUser ID
statusString 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.
DefinitionDescription
“active”Active
“inactive”Inactive
expiresAtlong
Expiration time
The timestamp at which the subscription expires. Updated when the subscription is renewed or its status changes.
detailList<EzSubscribeTransaction>[]0 ~ 100 itemsSubscription 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.

TypeConditionRequiredDefaultValue LimitsDescription
namestring
~ 128 charsStore Content Model name
metadatastring~ 1024 charsMetadata
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.
appleAppStoreEzAppleAppStoreContentApple AppStore Content
The Apple App Store product information (product ID) for this store content. Used during receipt verification to match the purchased product.
googlePlayEzGooglePlayContentGoogle 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).

TypeConditionRequiredDefaultValue LimitsDescription
paidint00 ~ 2147483646Count of paid currency
The total amount of currency that was purchased with real money (deposit transactions with price > 0).
freeint00 ~ 2147483646Count of free currency
The total amount of currency obtained for free (deposit transactions with price = 0), such as login bonuses or event rewards.
totalint00 ~ 2147483646Total
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.

TypeConditionRequiredDefaultValue LimitsDescription
pricedouble
0.0 ~ 100000000.0Purchase 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.
currencystring{price} > 0
✓*
~ 8 charsCurrency 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
countint
0 ~ 2147483646Quantity 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.

TypeConditionRequiredDefaultValue LimitsDescription
productIdstring~ 1024 charsProduct 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.

TypeConditionRequiredDefaultValue LimitsDescription
productIdstring~ 1024 charsProduct 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.

TypeConditionRequiredDefaultValue LimitsDescription
subscriptionGroupIdentifierstring~ 64 charsSubscription 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.

TypeConditionRequiredDefaultValue LimitsDescription
productIdstring~ 1024 charsProduct 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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSession
GameSession
slotint
0 ~ 100000000Slot 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

TypeDescription
itemEzWalletWallet

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);

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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSession
GameSession

Result

TypeDescription
itemsList<EzWallet>List of Wallets
nextPageTokenstringPage 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);

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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSession
GameSession
slotint
0 ~ 100000000Slot 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.
withdrawCountint
1 ~ 2147483646Quantity of premium currency to be consumed
paidOnlyboolfalseOnly for paid currency

Result

TypeDescription
itemEzWalletPost-withdraw Wallet
withdrawTransactionsList<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.

TypeBase TypeDescription
ConflictExceptionConflictExceptionThe wallet operation process conflicted. Retry required.
InsufficientExceptionBadRequestExceptionWallet 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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSessionGameSession
receiptstring
~ 1024 charsReceipt

Result

TypeDescription
itemEzSubscriptionStatusSubscription 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.

TypeBase TypeDescription
AlreadyUsedExceptionBadRequestExceptionThe 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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSessionGameSession
contentNamestring
~ 128 charsStore Subscription Content Model name

Result

TypeDescription
itemEzSubscriptionStatusSubscription 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);

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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSessionGameSession

Result

TypeDescription
itemsList<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);

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

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSessionGameSession
receiptstring
~ 1024 charsReceipt

Result

TypeDescription
itemEzSubscriptionStatusSubscription 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.

TypeBase TypeDescription
LockPeriodNotElapsedExceptionBadRequestExceptionThe 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

NameTypeDescription
namespaceNamestringNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstringUser ID
contentNamestringStore 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;
    });