> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Economy (Legacy) のレシートを伴わない支払い処理

> レシートやエンタイトルメント ベースのシステムを使用しない支払いプロバイダー経由の購入を、PlayFab Economy (Legacy) で有効にするメカニズムについて説明します。

# レシートを伴わない支払い処理 (Legacy Economy)

> [!NOTE]
>
> Economy v1 API はメンテナンス モードにあり、新機能は追加されず、バグ修正のみが行われます。**v1 API は当面の間、維持されます。** PlayFab Economy の次のバージョンの詳細については、[Economy v2 の概要](/ja-jp/services/playfab/economy-monetization/economy-v2/overview.md) を参照してください。

各種プラットフォームのレシート検証に加えて、PlayFab はレシートやエンタイトルメント ベースのシステムを使用しない支払いプロバイダーを介して購入を可能にするメカニズムを提供します。これには、Facebook、PayPal、Xsolla、Steam などのプロバイダーが含まれます。

このチュートリアルでは、このカート スタイルの支払いシステムの使用手順を説明し、次のことを行う方法を示します。

* プレイヤーが購入したい商品のセットを定義する。

* 選択したプロバイダーでプレイヤーの処理を行う。

* 支払いが正常に処理されたことを検証し、適切なアイテムをプレイヤーのインベントリに追加する。

* さらに、プロセスのプレイヤー プロバイダー部分についても説明し、購入を完了する方法の完全な概要を示します。

以下の画像は、支払いフローで使用される API 呼び出しの概要を示しています。

![PlayFab - Payment API flow](https://mintcdn.com/microsoft-4404708b/Oa_DP1q6U1lat7c2/images/playfab/economy-monetization/economy/tutorials/playfab-payment-api-flow.png?fit=max\&auto=format\&n=Oa_DP1q6U1lat7c2\&q=85\&s=39158e180c5d2c56c1bde5b197533419)

## 支払いプロバイダーのセットアップ

実際に支払いを処理するロジックを始める前に、まず意図する支払いプロバイダーを設定する必要があります。

そのためには:

* PlayFab Game Manager でゲームを選択します。
* **Add-ons** タブを選択します。

これで **Add-ons Marketplace** に移動し、**支払いプロバイダー** を含むすべてのサード パーティ統合を確認できます。

> [!NOTE]
>
> Facebook や Steam などの一部のプロバイダーは、単に支払いを処理する *以上* のことを行い、このチュートリアルの Platforms セクションでも取り上げます。

* 使用したい **プロバイダー** を選択します。
* 各プロバイダーで **Install** オプションを選択します。
* 要求された情報 (通常はアプリケーション キーとシークレット キー) を入力します。ただし、プロバイダーごとに独自の要件があります。

> [!NOTE]
>
> この情報により、購入の開始やステータス確認のために、PlayFab がお客様に代わってプロバイダーのサービスと通信できます。

* 完了したら、支払いフローの実装を開始する準備が整います。

## PlayFab API 呼び出し

クライアント側では、このプロセスの呼び出しシーケンスはほとんどのレシートを伴わない支払いプロバイダーで類似しています。

* [StartPurchase](xref:titleid.playfabapi.com.client.playeritemmanagement.startpurchase) - 購入する商品のリストを作成します。
* [PayForPurchase](xref:titleid.playfabapi.com.client.playeritemmanagement.payforpurchase) - 支払いプロバイダーを設定し、支払い価格をロックします。
* [ConfirmPurchase](xref:titleid.playfabapi.com.client.playeritemmanagement.confirmpurchase) - 購入が正常に完了したかを検証し、必要に応じてアイテムがプレイヤーのインベントリに追加されたことを確認します。

> [!NOTE]
>
> 例外として Xsolla は、このチュートリアルの最後で個別に取り上げます。

以降の例では、`{{TitleID}}` や `{{SessionTicket}}` のようなフィールドが表示されます。お客様のコードでは、これらの値をご自身のゲームに適した値やプレイヤーの認証チケットに置き換える必要があります。

## 購入の開始

購入フロー全体を通じて、プレイヤーが購入したいゲーム カタログ内の定義済みの商品セットを扱います。

これは、商品の "カート" であり、PlayFab クライアント API メソッド `StartPurchase` を呼び出してプロセスを開始することで定義します。

```csharp theme={null}
PlayFabClientAPI.StartPurchase(new StartPurchaseRequest() {
    CatalogVersion = "IAP1_0",
    Items = new List<ItemPurchaseRequest>() {
        new ItemPurchaseRequest() {
            ItemId = "BigBagOfGold",
            Quantity = 1,
            Annotation = "Purchased via in-game store"
        }
    }
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

この例では、ID `IAP1_0` のゲーム カタログで定義されたアイテム `BigBagOfGold` をカートに入れています。これはゲーム カタログで定義された `ItemId` です。

プレイヤーはこのアイテムを *1 つ* だけ購入したいと考えています。annotation は、アイテムがどのようにプレイヤー インベントリに入ったかを示すために使用され、後の確認に役立ちます。

> [!NOTE]
>
> StoreId パラメーターを含めることで、この購入がゲームで定義したストアの価格を使用していることを指定できます。

StartPurchase 呼び出しからの応答には多くの情報が含まれます - カタログのアイテムの `DisplayName` と `Description` の値、定義された価格、プレイヤーの仮想通貨残高などです。

しかし、次のステップで主に必要なのは `OrderId` (この購入を一意に識別) と、`PaymentOptions` に含まれる、使用したい特定のプロバイダーです。

> [!NOTE]
>
> タイトルで有効化した支払いプロバイダーだけが **`PaymentOptions`** に表示されます。

```json theme={null}
{
  "code": 200,
  "status": "OK",
  "data": {
    "OrderId": "1234567890ABCDEF",
    "Contents": [{
      "ItemId": "BigBagOfGold",
      "ItemInstanceId": "ABCDEF1234567890",
      "DisplayName": "A hefty sack of gold",
      "Description": "Why, it’s a stonking great bag of shiny!",
      "VirtualCurrencyPrices": {
        "RM": 999
      }
    }],
    "PaymentOptions": [{
        "Currency": "RM",
        "ProviderName": "Facebook",
        "Price": 999,
        "StoreCredit": 0
      },
      {
        "Currency": "RM",
        "ProviderName": "PayPal",
        "Price": 999,
        "StoreCredit": 0
      },
      {
        "Currency": "RM",
        "ProviderName": "Steam",
        "Price": 999,
        "StoreCredit": 0
      }
    ],
    "VirtualCurrencyBalances": {
      "VC": 0
    }
  }
}
```

## 支払いプロバイダーの設定: Webhook プロバイダー

### Facebook

通常、この時点でのフローは、どの支払いプロバイダーを使用するかを PlayFab に伝えることです。これは、PlayFab サービスがプロバイダーと通信し、トランザクションに関する情報を設定できるようにするためです。

Facebook はこの手順の例外です。購入は *まず* Facebook のサービスで開始する必要があります。その後、PlayFab のような第三者サービスは、Facebook が提供するトランザクション識別子を使って購入のステータスを検証できます。

ストア、カタログ、またはアイテム ID が英数字 *以外* の場合、`OpenGraphProduct` の URL を組み立てる際に [HTML / URL エンコード](https://www.w3schools.com/tags/ref_urlencode.asp) が必要です (以下のコードを参照)。

```csharp theme={null}
FB.ui({
    method: 'pay',
    action: 'purchaseitem',
    product: "https://{{TitleId}}.playfabapi.com/OpenGraphProduct/{{TitleId}}/{{StoreId}}/IAP1_0/BigBagOfGold",
    request_id: "1234567890ABCDEF"
}, function (response) {
    console.log('Payment completed', response);
    print(response);
    if (response.payment_id) {
        facebookPurchaseId = response.payment_id;
        payForOrder(); // This is a function call you need to write
                       // which makes the call to the Client API PayForPurchase
                       // (see below)
    }
});
```

この呼び出しを行う際、Facebook では product が *大文字と小文字を区別する* ことに注意してください。

特に、`TitleId` は PlayFab におけるゲームの *正しい* タイトル ID に置き換える必要がありますが、Facebook のサービスでは通常小文字です。Facebook が正しい製品を見つけられない問題が発生した場合は、[こちらのページ](https://developers.facebook.com/docs/payments/product/) に示されているように GET リクエストを使用して手動で製品を取得してみてください。

さらに、以前のフローで得た次の値も使用する必要があります。

* 購入するアイテムを含む PlayFab で定義されたカタログの `CatalogID` (`IAP1_0`)。

* 購入するゲームの PlayFab カタログ内のアイテムの `itemID` (`BigBagOfGold`)

* このプロセスの最初の `StartPurchase` 呼び出しから返された `OrderID` (`1234567890ABCDEF`)

応答が成功すると、Facebook は `payment_id` を返します。これを、クライアント API メソッド `PayForPurchase` の呼び出しの `ProviderTransactionId` として使用できます。

```csharp theme={null}
const string paymentId = "_SOME_PAYMENT_ID" ;
PlayFabClientAPI.PayForPurchase(new PayForPurchaseRequest() {
    OrderId = "1234567890ABCDEF",
    ProviderName = "Facebook",
    Currency = "RM",
    ProviderTransactionId = paymentId
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

これにより、単純な確認応答が返るはずです。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "OrderId": "1234567890ABCDEF",
        "Status": "Init",
        "PurchaseCurrency": "RM",
        "PurchasePrice": 999,
        "CreditApplied": 0
    }
}
```

これでループが完了し、購入の両側で PlayFab と接続され、ステータスをクエリできるようになります。

Facebook 支払いシステムの詳細については、Facebook Developer Portal をご覧ください: [https://developers.facebook.com/docs/payments/overview](https://developers.facebook.com/docs/payments/overview)

Facebook Payments のもう 1 つの側面は、支払いステータスへのリアルタイム変更通知を有効にするため、タイトルが webhook を使用する必要があるということです。

これは Facebook のモデルでは必要です。というのも、支払いは場合によっては非常に長い時間がかかることがあるからです。幸い、これは簡単です。Facebook のタイトル セットアップで、Callback URL として次のように入力します。

```html theme={null}
https://{{TitleId}}.playfabapi.com/ThirdPartyPayments/FacebookPaymentUpdate
```

ここで `{{TitleId}}` は PlayFab におけるゲームの **タイトル ID** です (例: [https://aaa.playfabapi.com/ThirdPartyPayments/FacebookPaymentUpdate](https://aaa.playfabapi.com/ThirdPartyPayments/FacebookPaymentUpdate))。

Facebook のセットアップでトークンを指定する必要はありません - Callback URL を設定し、**Game Manager** の **Facebook Add-ons** ページで PlayFab のセットアップが正しいことを確認するだけで完了です。

Facebook がこの webhook を使用して支払いのステータスを更新すると、PlayFab の注文ステータスが更新されます。成功した場合は、適切なアイテムがプレイヤーのインベントリに追加されます。

> [!NOTE]
>
> セキュリティ: この API は PlayFab が Facebook に再度呼び出してトランザクションを安全に認証・検証するためのトリガーです。*ハッカーが Facebook の支払いをバイパスするためのバックドアではありません*。

Facebook を支払いプロバイダーとして使用する場合でも、以下に示すように、クライアントで購入を確認することが *依然として重要* です。

## 支払いプロバイダーの設定: Webhook 以外のプロバイダー

### Steam

Steam は、*すべての* 支払いプロバイダーの中で最も簡単に統合できます。

```csharp theme={null}
PlayFabClientAPI.PayForPurchase(new PayForPurchaseRequest() {
    OrderId = "1234567890ABCDEF",
    ProviderName = "Steam",
    Currency = "RM"
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

`PayForPurchase` 呼び出しの結果として、PlayFab は Steam が提供する Web メソッドを使用してそのサービスで購入を開始します。これにより、Steam クライアント経由で購入確認ダイアログがユーザーに表示されます。

したがって、クライアント API `PayForPurchase` 呼び出しに対する応答を受け取ると同時に、ユーザーは支払いの受諾を求められます。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "OrderId": "1234567890ABCDEF",
        "Status": "Init",
        "PurchaseCurrency": "RM",
        "PurchasePrice": 999,
        "CreditApplied": 0
    }
}
```

Steam は、購入プロセスの完了をタイトルに通知するためにコールバック メカニズムを使用します。そのため、`MicroTxnAuthorizationResponse_t` コールバック用のコールバック ハンドラーを登録する必要があります。

登録済みの Steam 開発者は、こちらでこのプロセスの詳細情報を入手できます: [https://partner.steamgames.com/documentation/MicroTxn#WebPurchasing](https://partner.steamgames.com/documentation/MicroTxn#WebPurchasing)。

コールバックを受信すると、タイトルは [最終ステップ: 購入の確認](#last-step-confirm-the-purchase) セクションに示す `ConfirmPurchase` 呼び出しに進む必要があります。

### PayPal

PayPal では、`PayForPurchase` の呼び出しは Steam の場合とほぼ同じです。

```csharp theme={null}
PlayFabClientAPI.PayForPurchase(new PayForPurchaseRequest() {
    OrderId = "1234567890ABCDEF",
    ProviderName = "PayPal",
    Currency = "RM"
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

ただし、この場合は支払いリクエストをプレイヤーに送信する便利なクライアント アプリケーションが *ありません*。

PayPal では、購入に同意することを確認するように求める PayPal インターフェイスをプレイヤーに提示する必要があります。バック エンドではこのプロセスは [PayPal Express Checkouts](https://developer.paypal.com/api/nvp-soap/set-express-checkout-nvp/) を使用していますが、詳細はすべて PlayFab で処理します。

必要な作業は、`PurchaseConfirmationPageURL` として返される支払い確認ページをユーザーに表示するだけです。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "OrderId": "1234567890ABCDEF",
        "Status": "Init",
        "PurchaseCurrency": "RM",
        "PurchasePrice": 999,
        "PurchaseConfirmationPageURL": "https://...",
        "CreditApplied": 0
    }
}
```

この場合、ブラウザー ウィンドウが閉じられた時点で、PlayFab で購入を確認する時が来たと考えるべきです。

## 最終ステップ: 購入を確認する

プロセスの最終部分は、PlayFab が購入プロセスを完了し、(該当する場合) 購入したアイテムをプレイヤーのインベントリに追加することです。

一部のプロバイダーでは、この段階で購入が正常に完了したかどうかをタイトルが既に把握しています。

いずれの場合でも、クライアント API メソッド `ConfirmPurchase` の呼び出しでは、支払いが行われた場合、かつ既に追加されていない場合にのみ、アイテムがプレイヤーのインベントリに追加されます。

```csharp theme={null}
PlayFabClientAPI.ConfirmPurchase(new ConfirmPurchaseRequest() {
    OrderId = "1234567890ABCDEF"
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

この時点で注文が正常に完了していれば、クライアント API `StartPurchase` の呼び出しで設定したカート内のアイテムを反復処理します。

これによってアイテムがプレイヤーのインベントリに追加され、購入したアイテムに関する情報がタイトルに返されます。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "OrderId": "1234567890ABCDEF",
        "Status": "Succeeded",
        "PurchaseDate": "2016-07-19T09:04:28Z",
        "Items": [{
            "ItemId": "BigBagOfGold",
            "ItemInstanceId": "ABCDEF1234567890",
            "CatalogVersion": "IAP1_0",
            "DisplayName": "A hefty sack of gold",
            "UnitCurrency": "RM",
            "UnitPrice": 999
        }]
    }
}
```

### トランザクションの状態

バックエンドでは、注文はさまざまな状態変化を経ます。完全なリストを以下に示します。

> [!NOTE]
>
> 特定のプロバイダー プロセスによっては、これらの状態の一部が 3 つの購入プロセス API 呼び出しの結果に決して現れない場合があり、完全性のためにここに含めています。

* **CreateCart** - 注文オブジェクト自体はクライアント API `StartPurchase` の応答に返されませんが、この時点で作成されています。この段階では、アイテムと価格はオブジェクトに保存されていますが、まだ支払いプロバイダーには送信されていません。

* **Init** - 注文が支払いプロバイダーに送信されたが、まだプレイヤーによる承認が済んでいない場合に返されるステータスです。

* **Approved** - プレイヤーが支払いを承認した直後、PlayFab がアイテムをプレイヤーのインベントリに配置するプロセスを完了する前に発生します。*このリストは完全性のためにのみ含まれています。タイトルはこのステータスの注文を目にすることはないはずです*。

* **Succeeded** - 注文が正常に完了したことを示します。プレイヤーが支払いを承認し、すべてのインベントリ アイテムがそのプレイヤーのインベントリに追加されました。

* **FailedByProvider** - 何らかの理由でプロバイダーが支払いを拒否した場合 (プレイヤーが支払いを拒否した場合も含む)、注文はプロバイダーによって失敗とみなされます。

* **DisputePending** - 支払いプロバイダーが未解決の支払いに関する紛争を PlayFab に通知しました。

* **RefundPending** - 支払いプロバイダーが払い戻し要求が発行されたことを PlayFab に通知しました。この段階では、実際にはまだ払い戻しは発生していません。

* **Refunded** - 注文が返金されました。ほとんど (すべてではないにしても) の支払いプロバイダーは、この情報を開発者にも直接提供します。ステータスは、アイテムが消費可能な商品かどうか (既に消費されている可能性がある) など、多くの要因によって異なります。

* **RefundFailed** - 払い戻しが要求されましたが、支払いプロバイダーによって拒否されました。PlayFab はこれに関する追加情報を提供できません - より詳細な情報が必要な場合は、開発者が支払いプロバイダーに直接お問い合わせください。

* **ChargedBack** - このステータスは支払いプロバイダーによって異なり、注文が紛争中またはチャージバックされたことを示す場合があります。繰り返しになりますが、注文の詳細については支払いプロバイダーにお問い合わせください。

* **FailedByPlayFab** - このステータスは、支払いプロセスで予期しない失敗が発生したことを示します。このステータスの応答を確認した場合、タイトルは前の支払い API 呼び出しを再試行する必要があります。このステータスが続く場合は、[サポート フォーラム](https://community.playfab.com/) にこの問題を投稿し、問題に関するすべての詳細 (タイトル ID、PlayFab ID、注文 ID) を提供することをお勧めします。

## Xsolla を使った支払いの受諾

Xsolla では、プロセスが異なります。上記のコード フローを使用せず、代わりに次に説明する Xsolla の支払いフローを使用します: [https://developers.xsolla.com/doc/in-game-store/extensions/playfab-integration/](https://developers.xsolla.com/)。

タイトルで Xsolla の支払いサービスを使用するように構成するには、Xsolla のマーチャント ID、プロジェクト ID、およびマーチャント API キーが必要です。

* 開始するには、**Add-ons Marketplace の Xsolla** ページのリンクを使用して Xsolla アカウントに登録します。

* その構成ページを設定したら、次のステップは Xsolla サービスで商品のカタログを作成することです。

* Xsolla の各アイテムの item\_code が、PlayFab カタログのアイテム ID と一致することを確認してください。これらは、購入を完了し、適切なアイテムを安全にプレイヤー インベントリに追加するために使用される識別子です。

* Xsolla カタログで仮想アイテムのリストを設定するには、この手順の前半で提供したドキュメントを参照してください。

### 購入の開始 (Xsolla)

購入する準備ができたら、`GetPaymentToken` API 呼び出しを使用し、`TokenProvider` として Xsolla を指定して Xsolla サービスからトークンを要求します。

```csharp theme={null}
PlayFabClientAPI.GetPaymentToken(new GetPaymentTokenRequest() {
    TokenProvider = "xsolla"
}, result => {
    // Handle success
}, error => {
    // Handle error
});
```

この呼び出しは、次のステップで必要な Xsolla トークンである `ProviderToken` と、PlayFab の `OrderId` を返します。バックエンドで、この呼び出しは Xsolla とのトランザクションを開始します。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "ProviderToken": "1234567890ABCDEF",
        "OrderId": "1234567890ABCDEF"
    }
}
```

### 購入の完了 (Xsolla)

次に、クライアントは支払いプロセスを開始するためにトークンを Xsolla に渡す必要があります。以下のいずれかの URL を使用して、そのトークンを Xsolla に渡すことができます。

**サンドボックス決済**:

```html theme={null}
https://sandbox-secure.xsolla.com/paystation3/?access_token=[TOKEN]
```

**ライブ決済**:

```html theme={null}
 https://secure.xsolla.com/paystation3/?access_token=[TOKEN]
```

これを実行したら、Xsolla インターフェイスで購入を完了できます。

繰り返しになりますが、インターフェイスの使用に関する質問は、この手順の前半で提供したリンクにある Xsolla のドキュメントを参照してください。

これが完了すると、それ以上の操作は必要ありません。Xsolla と PlayFab は webhook 呼び出しを交換します。PlayFab は購入したアイテムをプレイヤー インベントリに配置して購入を履行し、適切なイベントを PlayStream に投稿します。

クライアント API `GetPurchase` をポーリングすることで、トランザクションのステータス (完全なリストは上を参照) を確認できます。

ほとんどの場合、このプロセスの完了には 2〜3 秒以上かかることはありません。

```csharp theme={null}
PlayFabClientAPI.GetPurchase(new GetPurchaseRequest()
{
    OrderId = "1234567890ABCDEF"
}, result =>
{
    // Handle success
}, error =>
{
    // Handle error
});
```

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "OrderId": "1234567890ABCDEF",
        "PaymentProvider": "Xsolla",
        "TransactionStatus": "Succeeded",
        "PurchaseDate": "2017-06-07T00:00:00Z"
    }
}
```

## 最終メモ

注意すべきことの 1 つは、一部のプロバイダーでは支払いの完了に長い時間がかかることです。

クライアント API `ConfirmPurchase` の呼び出しの応答の購入ステータスがまだ `Init` の場合は、再クエリの前に待つべきです。ここでのベスト プラクティスは、プロセスの開始時に `OrderId` を保存し、結果をクエリする際に指数バックオフを使用することです。

したがって、ステータスが Init の場合、クライアント API `ConfirmPurchase` の呼び出しを再試行する前に *1 分* 待ってから、次に *2 分* 待ってから、次に *4 分*、*8 分* というように、一定の最大値に達するまで待ちます。**完了したトランザクションを確認する** オプションを含めれば、ユーザーがそのタイマーをリセットする方法も提供できます。

最後に、一部の支払いプロバイダーでは、サンドボックス モードを使用して購入をテストできることに注目してください。

これを行うには、PlayFab Game Manager の **タイトル用アドオン** タブから **Use sandbox purchase testing** オプションをオンにします。


## Related topics

- [Economy (Legacy) のストアとセール](/ja-jp/services/playfab/economy-monetization/economy/tutorials/stores-and-sales.md)
- [ゲーム ストリーミング レイテンシー補正の詳細](/ja-jp/build/core-features/common/game-streaming/game-streaming-latency-compensation-deep-dive.md)
- [player_receipt_validation](/ja-jp/services/playfab/api-references/events/Player/player-receipt-validation.md)
- [Economy (レガシー) のクイックスタート](/ja-jp/services/playfab/economy-monetization/economy/quickstart.md)
- [Amazon IAP レシートの検証](/ja-jp/services/playfab/api-references/rest/client/platform-specific-methods/validate-amazon-iap-receipt.md)
