API Reference of 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.
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
slot | int | ✓ | ~ 100000000 | Slot Number | |
summary | EzWalletSummary | ✓ | Wallet Status | ||
sharedFreeCurrency | bool | ✓ | Share Free Currency | ||
updatedAt | long | ✓ | Now | Datetime of last update (Unix time unit:milliseconds) |
EzWalletSummary
Wallet Status
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
paid | int | ✓ | 0 | ~ 2147483646 | Count of Paid |
free | int | ✓ | 0 | ~ 2147483646 | Count of Free |
total | int | ✓ | 0 | ~ 2147483646 | Count of Total |
EzDepositTransaction
Deposit Transaction
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
price | double | ✓ | ~ 100000000.0 | Purchase Price | |
currency | string | {price} > 0 | ~ 8 chars | Currency Code | |
count | int | ✓ | ~ 2147483646 | Count |
EzSubscribeTransaction
Subscription purchase information
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
contentName | string | ✓ | ~ 128 chars | Subscription Store Content Model Name | |
store | enum { “AppleAppStore”, “GooglePlay”, “fake” } | ✓ | ~ 128 chars | Store | |
transactionId | string | ✓ | ~ 1024 chars | Transaction ID | |
statusDetail | 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” } | ✓ | ~ 128 chars | Status | |
expiresAt | long | ✓ | Expiration date (Unix time unit:milliseconds) |
Enumeration type definition to specify as store
Enumerator String Definition | Description |
---|---|
AppleAppStore | Apple App Store |
GooglePlay | Google Play |
fake | Fake |
Enumeration type definition to specify as statusDetail
Enumerator String Definition | Description |
---|---|
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 | User has canceled, but still in grace period |
grace@on_hold | User has canceled, but still in grace period |
inactive@expired | Subscription has expired |
inactive@revoked | Subscription has been revoked |
EzSubscriptionStatus
Subscription status
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
contentName | string | ✓ | ~ 128 chars | Subscription Store Content Model Name | |
userId | string | ~ 128 chars | User Id | ||
status | enum { “active”, “inactive” } | ✓ | ~ 128 chars | Status | |
expiresAt | long | ✓ | Expiration date (Unix time unit:milliseconds) | ||
detail | List<EzSubscribeTransaction> | [] | ~ 100 items | Subscription status details |
Enumeration type definition to specify as status
Enumerator String Definition | Description |
---|---|
active | Active |
inactive | Inactive |
Methods
get
Get Wallet
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ✓ | ~ 128 chars | Access token | |
slot | int | ✓ | ~ 100000000 | Slot Number |
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
);
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
);
// 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 called when the value in the local cache that the SDK has is changed.
The local cache will only be changed by executing the SDK’s API, or by executing a stamp sheet via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled. GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
list
Get list of wallets
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ✓ | ~ 128 chars | Access token |
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
);
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
);
// 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 called when the value in the local cache that the SDK has is changed.
The local cache will only be changed by executing the SDK’s API, or by executing a stamp sheet via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled. GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
withdraw
Consume the balance from the wallet
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ✓ | ~ 128 chars | Access token | |
slot | int | ✓ | ~ 100000000 | Slot Number | |
withdrawCount | int | ✓ | 1 ~ 2147483646 | Quantity of billable 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.Conflict e) {
// The wallet operation process conflicted. Retry required.
} catch(Gs2.Gs2Money2.Exception.Insufficient 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
Allocate subscription status from receipt
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ~ 128 chars | Access token | ||
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.AlreadyUsed 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 Subscription status
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ~ 128 chars | Access token | ||
contentName | string | ✓ | ~ 128 chars | Subscription Store 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"
);
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
);
// 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 called when the value in the local cache that the SDK has is changed.
The local cache will only be changed by executing the SDK’s API, or by executing a stamp sheet via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled. GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
listSubscriptionStatuses
Get list of subscription statuses
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ~ 128 chars | Access token |
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
);
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
);
// 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 called when the value in the local cache that the SDK has is changed.
The local cache will only be changed by executing the SDK’s API, or by executing a stamp sheet via GS2-Distributor with GS2-Gateway notification enabled, or by executing a GS2-JobQueue with GS2-Gateway notification enabled. GS2-Gateway notification enabled.
Therefore, callbacks will not be invoked if the value is changed in any other way.
takeOverSubscriptionStatus
Take over the subscription status of a subscription that is already assigned to another user
Request
Type | Require | Default | Limitation | Description | |
---|---|---|---|---|---|
namespaceName | string | ✓ | ~ 128 chars | Namespace Name | |
accessToken | string | ~ 128 chars | Access token | ||
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.LockPeriodNotElapsed 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
Notification when the subscription status of the period changes
Name | Type | Description |
---|---|---|
namespaceName | string | Namespace Name |
userId | string | User Id |
contentName | string | Subscription Store 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;
});