> For the complete documentation index, see [llms.txt](/llms.txt)

# GS2-Money2 SDK for Game Engine API リファレンス

ゲームエンジン向け GS2-Money2 SDK の モデルの仕様 と API のリファレンス



## モデル

### EzWallet

ウォレット<br>

ウォレット内の通貨は大きく有償で購入した通貨と、無償で入手した通貨が分けて管理されます。<br>
有償で購入した通貨は更に購入時の単価毎に管理され、サービス終了になってしまった際の返金や資金決済法に該当するだけの残高が存在するかが集計できます。<br>

ウォレットにはスロットがあり、スロットごとに異なる残高を管理できます。<br>
プラットフォームをまたいで残高を共有できない場合にはプラットフォーム毎に異なるスロットを利用することで分けて管理することができます。<br>
その際に無償で入手した通貨は全てのプラットフォームで共通した値を利用することもできます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| slot | int |  | ✓ |  | 0 ~ 100000000 | スロット番号<br>ウォレットスロットを識別します。プラットフォーム間の残高共有が許可されていない場合、異なるスロットを使用してプラットフォームごとに通貨を分けて管理できます（例：iOS用とAndroid用）。 |
| summary | [EzWalletSummary](#ezwalletsummary) |  | ✓ |  |  | ウォレットの状態<br>ウォレットの現在の残高サマリーで、有償通貨、無償通貨、合計額に分けて表示されます。入金トランザクションから算出されます。 |
| sharedFreeCurrency | bool |  | ✓ |  |  | 無償通貨を共有するか<br>このウォレットの無償通貨がすべてのスロット間で共有されるかどうかを示します。ウォレット作成時にネームスペースの設定から継承されます。 |
| updatedAt | long |  | ※ | 現在時刻 |  | 最終更新日時<br>UNIX 時間・ミリ秒<br>※ サーバーが自動で設定 |

**関連するメソッド:**
get - プレイヤーの課金通貨ウォレットの残高を取得する
list - プレイヤーの課金通貨ウォレット一覧を取得する
withdraw - プレイヤーのウォレットから課金通貨を消費する


---

### EzSubscribeTransaction

サブスクリプションの購入情報<br>

ストアプラットフォームからのサブスクリプション購入レコードを表します。有効、トライアル、初回割引、猶予期間、解約、期限切れ、取り消しなどのライフサイクルを通じた詳細なサブスクリプションステータスを追跡します。各トランザクションは特定のストアプラットフォームとユーザーに紐づけられます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| contentName | string |  | ✓ |  |  ~ 128文字 | ストア定期課金コンテンツモデル名 |
| store | 文字列列挙型<br>enum {<br>"AppleAppStore",<br>"GooglePlay",<br>"fake"<br>}<br> |  | ✓ |  |  | ストア<br>購入が行われたストアプラットフォームです。レシート検証に使用される検証方法を決定します。"AppleAppStore": Apple App Store / "GooglePlay": Google Play / "fake": Fake /  |
| transactionId | string |  | ✓ |  |  ~ 1024文字 | トランザクションID<br>ストアプラットフォームによって割り当てられた一意のトランザクション識別子です。同一購入の重複処理を防止するために使用されます。 |
| statusDetail | 文字列列挙型<br>enum {<br>"active@active",<br>"active@converted_from_trial",<br>"active@in_trial",<br>"active@in_intro_offer",<br>"grace@canceled",<br>"grace@grace_period",<br>"grace@on_hold",<br>"inactive@expired",<br>"inactive@revoked"<br>}<br> |  | ✓ |  |  | ステータス<br>詳細なサブスクリプションステータスです。簡易カテゴリ（active/grace/inactive）の後に具体的な状態が続きます。active 状態はサブスクリプションが利用可能であることを、grace 状態は支払いに問題があるが一時的にアクセス可能であることを、inactive 状態はサブスクリプションが無効であることを示します。"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": 払い戻しなどで強制的にキャンセルされた /  |
| expiresAt | long |  | ✓ |  |  | 有効期限<br>このサブスクリプショントランザクションが期限切れになる日時です。ストアプラットフォームによってサブスクリプションが更新されると更新されます。 |


**関連するモデル:**
EzSubscriptionStatus - サブスクリプションの契約状況



---

### EzSubscriptionStatus

サブスクリプションの契約状況<br>

特定のサブスクリプションコンテンツに対するユーザーのサブスクリプション契約状況を追跡します。詳細なサブスクリプショントランザクションの状態から導出された簡易的な有効/無効ステータスと、有効期限、関連するサブスクリプショントランザクションのリストを提供します。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| contentName | string |  | ✓ |  |  ~ 128文字 | ストア定期課金コンテンツモデル名 |
| userId | string |  |  |  |  ~ 128文字 | ユーザーID |
| status | 文字列列挙型<br>enum {<br>"active",<br>"inactive"<br>}<br> |  | ✓ |  |  | ステータス<br>簡易的なサブスクリプションステータスです。"active" は有効、トライアル、初回割引、猶予期間の状態を含みます。"inactive" は期限切れと取り消しの状態を含みます。"active": 有効 / "inactive": 無効 /  |
| expiresAt | long |  | ✓ |  |  | 有効期限<br>サブスクリプションが期限切れになる日時です。サブスクリプションが更新されたりステータスが変化した際に更新されます。 |
| detail | [List&lt;EzSubscribeTransaction&gt;](#ezsubscribetransaction) |  |  | [] | 0 ~ 100 items | 契約状況の詳細<br>このサブスクリプションに関連するサブスクリプショントランザクションのリストです。各トランザクションはストアプラットフォームからの購入レコードで、詳細なステータス情報（有効、トライアル、猶予期間、期限切れ、取り消しなど）を持ちます。 |

**関連するメソッド:**
allocateSubscriptionStatus - ストアレシートを使ってサブスクリプションを登録する
getSubscriptionStatus - 特定のサブスクリプション契約状況を取得する
listSubscriptionStatuses - プレイヤーのサブスクリプション契約状況一覧を取得する
takeOverSubscriptionStatus - 他のアカウントからこのプレイヤーにサブスクリプションを移行する


---

### EzStoreContentModel

ストアコンテンツモデル<br>

各種ストアプラットフォームのコンテンツを格納するモデルです。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128文字 | ストアコンテンツモデル名 |
| metadata | string |  |  |  |  ~ 1024文字 | メタデータ<br>メタデータには任意の値を設定できます。<br>これらの値は GS2 の動作には影響しないため、ゲーム内で利用する情報の保存先として使用できます。 |
| appleAppStore | [EzAppleAppStoreContent](#ezappleappstorecontent) |  |  |  |  | Apple App Store のコンテンツ<br>このストアコンテンツの Apple App Store 商品情報（プロダクトID）です。レシート検証時に購入された商品との照合に使用されます。 |
| googlePlay | [EzGooglePlayContent](#ezgoogleplaycontent) |  |  |  |  | Google Play のコンテンツ<br>このストアコンテンツの Google Play 商品情報（プロダクトID）です。レシート検証時に購入された商品との照合に使用されます。 |


---

### EzWalletSummary

ウォレットの状態<br>

ウォレットの通貨残高のサマリービューで、有償と無償の金額を分離しています。ウォレット内のすべての入金トランザクションを価格に基づいて集計して算出されます（価格 > 0 は有償、価格 = 0 は無償）。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| paid | int |  |  | 0 | 0 ~ 2147483646 | 有償通貨<br>実際のお金で購入された通貨の合計量です（価格 > 0 の入金トランザクション）。 |
| free | int |  |  | 0 | 0 ~ 2147483646 | 無償通貨<br>無償で入手した通貨の合計量です（価格 = 0 の入金トランザクション）。ログインボーナスやイベント報酬などが含まれます。 |
| total | int |  |  | 0 | 0 ~ 2147483646 | 総数<br>通貨残高の合計（有償 + 無償）。ウォレットで利用可能な全体量を表します。 |


**関連するモデル:**
EzWallet - ウォレット



---

### EzDepositTransaction

入金トランザクション<br>

ウォレット内の単一の入金レコードを表します。有償の入金（価格 > 0）は正確な返金計算と資金決済法への準拠のために単価ごとに追跡されます。無償の入金（価格 = 0）は別途追跡されます。出金時には、ネームスペースの通貨消費優先度に基づいて入金トランザクションが消費されます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| price | double |  | ✓ |  | 0.0 ~ 100000000.0 | 購入価格<br>この入金に対して現地通貨で支払われた実際の金額です。0 は無償通貨を示します。返金目的の単価計算に使用されます。 |
| currency | string | {price} > 0 | ✓※ |  |  ~ 8文字 | 通貨コード<br>実際の支払いのISO通貨コード（例："JPY"、"USD"）です。有償の入金（価格 > 0）の場合のみ適用されます。<br><br>※ price が 0 より大きければ 必須 |
| count | int |  | ✓ |  | 0 ~ 2147483646 | 課金通貨の数量<br>この入金における仮想通貨の単位数です。ウォレットから出金されると減少します。 |

**関連するメソッド:**
withdraw - プレイヤーのウォレットから課金通貨を消費する


---

### EzAppleAppStoreContent

Apple App Store のコンテンツ<br>

アプリ内課金商品に対応する Apple App Store のプロダクトIDを含みます。レシート検証時の照合に使用されます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| productId | string |  |  |  |  ~ 1024文字 | プロダクトID<br>このアプリ内課金アイテムについて App Store Connect に登録されている Apple App Store のプロダクト識別子です。 |


**関連するモデル:**
EzStoreContentModel - ストアコンテンツモデル



---

### EzGooglePlayContent

Google Play のコンテンツ<br>

アプリ内課金商品に対応する Google Play のプロダクトIDを含みます。レシート検証時の照合に使用されます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| productId | string |  |  |  |  ~ 1024文字 | プロダクトID<br>このアプリ内課金アイテムについて Google Play Console に登録されている Google Play のプロダクト識別子です。 |


**関連するモデル:**
EzStoreContentModel - ストアコンテンツモデル



---

### EzAppleAppStoreSubscriptionContent

Apple App Store の期間課金コンテンツ<br>

サブスクリプションベースの商品の Apple App Store サブスクリプショングループ識別子を含みます。自動更新サブスクリプションの管理と検証に使用されます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| subscriptionGroupIdentifier | string |  |  |  |  ~ 64文字 | サブスクリプショングループID<br>App Store Connect に登録されたサブスクリプショングループ識別子です。同じグループ内のサブスクリプションは相互排他的で、ユーザーは同時に1つしか契約できません。 |


---

### EzGooglePlaySubscriptionContent

Google Play の期間課金コンテンツ<br>

サブスクリプションベースの商品の Google Play プロダクトIDを含みます。Google Play での自動更新サブスクリプションの管理と検証に使用されます。

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| productId | string |  |  |  |  ~ 1024文字 | プロダクトID |


---

## メソッド

### get

プレイヤーの課金通貨ウォレットの残高を取得する<br>

指定したスロットのプレイヤーのウォレットを取得し、有償通貨と無償通貨それぞれの現在の残高を確認できます。<br>
「有償」通貨はプレイヤーがリアルマネーで購入したもの（例: 100ジェムを¥120で購入）、「無償」通貨はゲームプレイで獲得したもの（例: イベント報酬、ログインボーナス）です。<br>
一部の機能で有償通貨のみを要求する場合があるため（例: 特定のガチャや特別オファー）、別々に管理されています。<br>
プレイヤーの通貨残高を表示するのに使います。たとえば、ショップ画面やヘッダーUIで「ジェム: 350（有償: 100、無償: 250）」のように表示するのに便利です。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | ✓|  |  | GameSession |
| slot | int |  | ✓|  | 0 ~ 100000000 | スロット番号<br>ウォレットスロットを識別します。プラットフォーム間の残高共有が許可されていない場合、異なるスロットを使用してプラットフォームごとに通貨を分けて管理できます（例：iOS用とAndroid用）。 |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| item | [EzWallet](#ezwallet) | ウォレット|

#### 実装例




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    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;

```

**Unreal Engine 5**
```cpp
    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;
    }

```


##### 値の変更イベントハンドリング




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.Subscribe(
        value => {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.Subscribe(
        value => {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Money2->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Wallet(
        0 // slot
    );
    
    // イベントハンドリングを開始
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Money2::Model::FWallet> value) {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    Domain->Unsubscribe(CallbackId);

```


{{% alert title="Warning" color="warning" %}}このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。

ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。

そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
{{% /alert %}}

---

### list

プレイヤーの課金通貨ウォレット一覧を取得する<br>

プレイヤーが現在持つすべてのウォレットを取得します。各ウォレットはそれぞれ独立した残高を持ち、有償通貨と無償通貨が別々に管理されます。<br>
「有償」通貨はプレイヤーがリアルマネーで購入したもの（例: 100ジェムを¥120で購入）、「無償」通貨はゲームプレイで獲得したもの（例: イベント報酬、ログインボーナス）です。<br>
プレイヤーの通貨の全体像を表示するのに使います。たとえば、通貨管理画面で全ウォレットスロットとその残高を一覧表示する場合に便利です。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| items | [List&lt;EzWallet&gt;](#ezwallet) | ウォレットのリスト|
| nextPageToken | string | リストの続きを取得するためのページトークン|

#### 実装例




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.WalletsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    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());
    }

```


##### 値の変更イベントハンドリング




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.SubscribeWallets(
        () => {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    domain.UnsubscribeWallets(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.SubscribeWallets(
        () => {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    domain.UnsubscribeWallets(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Money2->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // イベントハンドリングを開始
    const auto CallbackId = Domain->SubscribeWallets(
        []() {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    Domain->UnsubscribeWallets(CallbackId);

```


{{% alert title="Warning" color="warning" %}}このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。

ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。

そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
{{% /alert %}}

---

### withdraw

プレイヤーのウォレットから課金通貨を消費する<br>

プレイヤーのウォレットから指定した量の課金通貨を差し引きます。<br>
デフォルト（paidOnly = false）では、無償通貨が先に消費され、不足分は有償通貨から消費されます。これにより、プレイヤーは購入した通貨を使う前に無償通貨を使い切ることができます。<br>
paidOnly を true にすると、有償通貨のみが消費されます。法律上有償通貨のみを使用しなければならない機能（例: 一部地域の有償限定ガチャ）に必要です。<br>
プレイヤーが課金通貨で購入する際に使います。たとえば、特別なアイテムの購入やガチャを引くためにジェム100個を消費する、といった場合です。<br>
注意: GS2-Showcase を通じた商品購入の対価として通貨を消費する場合は、自動的に処理されるため、このAPIを呼ぶ必要はありません。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | ✓|  |  | GameSession |
| slot | int |  | ✓|  | 0 ~ 100000000 | スロット番号<br>ウォレットスロットを識別します。プラットフォーム間の残高共有が許可されていない場合、異なるスロットを使用してプラットフォームごとに通貨を分けて管理できます（例：iOS用とAndroid用）。 |
| withdrawCount | int |  | ✓|  | 1 ~ 2147483646 | 消費する課金通貨の数量 |
| paidOnly | bool |  | | false |  | 有償通貨のみを対象とするか |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| item | [EzWallet](#ezwallet) | 消費後のウォレット|
| withdrawTransactions | [List&lt;EzDepositTransaction&gt;](#ezdeposittransaction) | 消費した入金トランザクションリスト|

#### Error

このAPIには特別な例外が定義されています。<br>
GS2-SDK for Game Engine ではゲーム内でハンドリングが必要そうなエラーは一般的な例外から派生した特殊化した例外を用意することでハンドリングしやすくしています。<br>
一般的なエラーの種類や、ハンドリング方法は [こちら]() のドキュメントを参考にしてください。

| 型 | 基底クラス | 説明 |
| --- | --- | --- |
| ConflictException | ConflictException | ウォレットの操作処理が衝突しました。リトライが必要です |
| InsufficientException | BadRequestException | ウォレットの残高が不足しています |

#### 実装例




**Unity (UniTask)**
```csharp

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.
}

```

**Unity (Vanilla)**
```cs
    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;

```

**Unreal Engine 5**
```cpp
    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

ストアレシートを使ってサブスクリプションを登録する<br>

App Store や Google Play のレシートを検証して、サブスクリプション購入をプレイヤーに紐づけます。<br>
プレイヤーが端末でサブスクリプション（例: 「月額パス」）を購入した後、ストアレシートをこのAPIに渡してサーバー側でサブスクリプションを有効にします。<br>
ストア購入をプレイヤーのアカウントに結びつけるための重要なステップです。この呼び出しがないと、サーバーはプレイヤーが契約したことを認識できません。<br>
購入フローで使います。たとえば、アプリ内課金ダイアログでプレイヤーが「月額パス」を購入した後、レシートを送信してVIP特典を有効にする、といった場合です。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | |  |  | GameSession |
| receipt | string |  | ✓|  |  ~ 1024文字 | レシート |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| item | [EzSubscriptionStatus](#ezsubscriptionstatus) | サブスクリプションの契約状況|

#### Error

このAPIには特別な例外が定義されています。<br>
GS2-SDK for Game Engine ではゲーム内でハンドリングが必要そうなエラーは一般的な例外から派生した特殊化した例外を用意することでハンドリングしやすくしています。<br>
一般的なエラーの種類や、ハンドリング方法は [こちら]() のドキュメントを参考にしてください。

| 型 | 基底クラス | 説明 |
| --- | --- | --- |
| AlreadyUsedException | BadRequestException | すでにその期間課金契約は他のユーザーによって利用されています |

#### 実装例




**Unity (UniTask)**
```csharp

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.
}

```

**Unity (Vanilla)**
```cs
    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;

```

**Unreal Engine 5**
```cpp
    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

特定のサブスクリプション契約状況を取得する<br>

コンテンツ名を指定して、特定のサブスクリプションの契約状況を取得します。<br>
ステータスには、プレイヤーが現在契約中かどうかと、有効期限などの関連情報が含まれます。<br>
プレイヤーが特定のサブスクリプションを持っているか確認するのに使います。たとえば、デイリーボーナス報酬を付与する前に「月額パス」が有効か確認したり、プレイヤープロフィールに「VIPメンバーシップ: 有効」と表示する場合に便利です。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | |  |  | GameSession |
| contentName | string |  | ✓|  |  ~ 128文字 | ストア定期課金コンテンツモデル名 |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| item | [EzSubscriptionStatus](#ezsubscriptionstatus) | サブスクリプションの契約状況|

#### 実装例




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SubscriptionStatus(
        contentName: "content-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    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;

```

**Unreal Engine 5**
```cpp
    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;
    }

```


##### 値の変更イベントハンドリング




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SubscriptionStatus(
        contentName: "content-0001"
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.Subscribe(
        value => {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SubscriptionStatus(
        contentName: "content-0001"
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.Subscribe(
        value => {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Money2->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->SubscriptionStatus(
        "content-0001" // contentName
    );
    
    // イベントハンドリングを開始
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Money2::Model::FSubscriptionStatus> value) {
            // 値が変化した時に呼び出される
            // value には変更後の値が渡ってくる
        }
    );

    // イベントハンドリングを停止
    Domain->Unsubscribe(CallbackId);

```


{{% alert title="Warning" color="warning" %}}このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。

ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。

そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
{{% /alert %}}

---

### listSubscriptionStatuses

プレイヤーのサブスクリプション契約状況一覧を取得する<br>

プレイヤーが契約している可能性のあるすべてのサブスクリプションコンテンツの契約状況を取得します。<br>
サブスクリプションとは、App Store や Google Play で購入する「月額パス」や「VIPメンバーシップ」のような定期購入です。<br>
各ステータスは、プレイヤーがそのコンテンツを現在契約しているかどうかを示します。<br>
サブスクリプションの概要を表示するのに使います。たとえば、メンバーシップ画面で「月額パス: 有効（3月15日まで）」「VIPメンバーシップ: 未契約」のように表示するのに便利です。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | |  |  | GameSession |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| items | [List&lt;EzSubscriptionStatus&gt;](#ezsubscriptionstatus) | サブスクリプションの契約状況のリスト|

#### 実装例




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.SubscriptionStatusesAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    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());
    }

```


##### 値の変更イベントハンドリング




**Unity (UniTask)**
```csharp
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.SubscribeSubscriptionStatuses(
        () => {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    domain.UnsubscribeSubscriptionStatuses(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Money2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // イベントハンドリングを開始
    var callbackId = domain.SubscribeSubscriptionStatuses(
        () => {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    domain.UnsubscribeSubscriptionStatuses(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Money2->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // イベントハンドリングを開始
    const auto CallbackId = Domain->SubscribeSubscriptionStatuses(
        []() {
            // リストの要素が変化した時に呼び出される
        }
    );

    // イベントハンドリングを停止
    Domain->UnsubscribeSubscriptionStatuses(CallbackId);

```


{{% alert title="Warning" color="warning" %}}このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。

ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。

そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
{{% /alert %}}

---

### takeOverSubscriptionStatus

他のアカウントからこのプレイヤーにサブスクリプションを移行する<br>

現在別のプレイヤーアカウントに紐づいているサブスクリプションを、このプレイヤーのアカウントに移動します。<br>
プレイヤーがアカウント移行を行う場合に使います。たとえば、機種変更で新しいアカウントを作成した場合、ストアレシートを使って旧アカウントの「月額パス」サブスクリプションを新アカウントに移行できます。<br>
サブスクリプションは旧アカウントから解除され新アカウントに紐づけられるため、旧アカウントではサブスクリプション特典を受けられなくなります。<br>
アカウント移行フローで使います。たとえば、プレイヤーが新アカウントにログインし、移行を確認した後に呼び出します。

#### Request

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| gameSession | GameSession | | |  |  | GameSession |
| receipt | string |  | ✓|  |  ~ 1024文字 | レシート |

#### Result

|  | 型 | 説明 |
| --- | --- | --- |
| item | [EzSubscriptionStatus](#ezsubscriptionstatus) | サブスクリプションの契約状況|

#### Error

このAPIには特別な例外が定義されています。<br>
GS2-SDK for Game Engine ではゲーム内でハンドリングが必要そうなエラーは一般的な例外から派生した特殊化した例外を用意することでハンドリングしやすくしています。<br>
一般的なエラーの種類や、ハンドリング方法は [こちら]() のドキュメントを参考にしてください。

| 型 | 基底クラス | 説明 |
| --- | --- | --- |
| LockPeriodNotElapsedException | BadRequestException | 前回のユーザーの付け替えから、ロック期間が経過していません |

#### 実装例




**Unity (UniTask)**
```csharp

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.
}

```

**Unity (Vanilla)**
```cs
    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;

```

**Unreal Engine 5**
```cpp
    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();

```


---

## イベントハンドラ

### OnChangeSubscriptionStatus

期間課金の契約状況が変化したときに使用するプッシュ通知

 | 名前 | 型 | 説明 |
| --- | --- | --- |
| namespaceName | string |ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。|
| userId | string |ユーザーID|
| contentName | string |ストア定期課金コンテンツモデル名|

#### 実装例





**Unity (UniTask)**
```csharp

    gs2.Money2.OnChangeSubscriptionStatus += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var userId = notification.UserId;
        var contentName = notification.ContentName;
    };
```

**Unity (Vanilla)**
```cs

    gs2.Money2.OnChangeSubscriptionStatus += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var userId = notification.UserId;
        var contentName = notification.ContentName;
    };
```

**Unreal Engine 5**
```cpp

    Gs2->Money2->OnChangeSubscriptionStatus().AddLambda([](const auto Notification)
    {
        const auto NamespaceName = Notification->NamespaceNameValue;
        const auto UserId = Notification->UserIdValue;
        const auto ContentName = Notification->ContentNameValue;
    });
```


---



