支払い取引のライフサイクル

販売者が支払いアプリを統合する方法と、Payment Request API で支払いトランザクションがどのように機能するかについて説明します。

Web Payments API は、ブラウザに初めて組み込まれた専用の支払い機能です。ウェブ決済を使用すると、販売者と決済アプリの統合が簡単になり、カスタマー エクスペリエンスが合理化されて安全になります。

ウェブ決済を使用するメリットについて詳しくは、ウェブ決済による支払いアプリの強化をご覧ください。

この記事では、販売者のウェブサイトでの支払いトランザクションについて説明し、支払いアプリの統合の仕組みについて説明します。

このプロセスには 6 つのステップが含まれます。

  1. 販売者が支払い取引を開始します。
  2. 販売者に支払いボタンが表示されます。
  3. お客様が支払いボタンを押します。

    BobPay(支払いアプリ)ボタンが表示されたチーズショップのウェブサイトの図。

  4. ブラウザが決済アプリを起動します。

    BobPay アプリがモーダルで起動されたチーズショップのウェブサイトを示す図。モーダルに配送オプションと合計金額が表示されます。

  5. 顧客が詳細(配送オプションや住所など)を変更すると、販売者は変更を反映して取引の詳細を更新します。

    BobPay アプリのモーダルでお客様が別の配送オプションを選択しているところを示す図。販売者が BobPay に表示される合計金額を更新している 2 つ目の図。

  6. 顧客が購入を確認した後、販売者は支払いを検証して取引を完了します。

    お客様が

ステップ 1: 販売者が支払い取引を開始する

購入者が購入を決定すると、販売者は PaymentRequest オブジェクトを作成して支払いトランザクションを開始します。このオブジェクトには、トランザクションに関する重要な情報が含まれています。

  • 取引を処理するために利用可能なお支払い方法とそのデータ。
  • 合計価格(必須)や商品アイテムに関する情報などの詳細情報。
  • 販売者が配送情報をリクエストできるオプション(配送先住所や配送オプションなど)。
  • 販売者は、請求先住所、支払人の名前、メールアドレス、電話番号をリクエストすることもできます。
  • 販売者は、PaymentRequest にオプションの配送タイプshippingdelivery、または pickup)を含めることもできます。決済アプリは、UI に正しいラベルを表示するためのヒントとしてこれを使用できます。
const request = new PaymentRequest([{
  supportedMethods: 'https://bobpay.xyz/pay',
  data: {
    transactionId: '****'
  }
}], {
  displayItems: [{
    label: 'Anvil L/S Crew Neck - Grey M x1',
    amount: { currency: 'USD', value: '22.15' }
  }],
  total: {
    label: 'Total due',
    amount: { currency: 'USD', value : '22.15' }
  }
}, {
  requestShipping: true,
  requestBillingAddress: true,
  requestPayerEmail: true,
  requestPayerPhone: true,
  requestPayerName: true,
  shippingType: 'delivery'
});
トランザクション ID を含める

支払いハンドラによっては、販売者に取引情報の一部として事前に発行した取引 ID の提供を求めることがあります。一般的な統合では、合計価格を予約するための販売者と支払いハンドラのサーバー間の通信が含まれます。これにより、悪意のある顧客が価格を操作したり、取引の最後に行われる検証で販売者を騙したりすることを防止できます。

販売者は、PaymentMethodData オブジェクトの data プロパティの一部として取引 ID を渡すことができます。

取引情報が提供されると、ブラウザはお支払い方法 ID に基づいて、PaymentRequest で指定された決済アプリの検出プロセスを実行します。これにより、販売者は取引を進める準備ができるとすぐに支払いアプリを起動するかを決定できます。

検出プロセスの詳細については、お支払い方法の設定をご覧ください。

ステップ 2: 販売者に支払いボタンが表示される

販売者はさまざまなお支払い方法をサポートできますが、支払いボタンは、ユーザーが実際に使用できる場合にのみ表示してください。使用できない支払いボタンを表示すると、ユーザー エクスペリエンスが低下します。販売者は、PaymentRequest オブジェクトで指定されたお支払い方法では利用できないと予測できる場合、フォールバック ソリューションを提供するか、そのボタンを一切表示しないようにできます。

販売者は PaymentRequest インスタンスを使用して、顧客が決済アプリを使用できるかどうかを照会できます。

お支払いアプリは利用できますか?

PaymentRequestcanMakePayment() メソッドは、ユーザーのデバイスで支払いアプリを利用できる場合に true を返します。「利用可能」とは、そのお支払い方法をサポートする決済アプリが検出され、プラットフォーム固有の決済アプリがインストールされているか、ウェブベースの決済アプリが登録の準備ができていることを意味します。

const canMakePayment = await request.canMakePayment();
if (!canMakePayment) {
  // Fallback to other means of payment or hide the button.
}

ステップ 3: お客様が支払いボタンを押す

ユーザーが支払いボタンを押すと、販売者は PaymentRequest インスタンスの show() メソッドを呼び出し、直ちに支払い UI の起動がトリガーされます。

最終的な合計価格が動的に設定される場合(サーバーから取得するなど)、販売者は合計が判明するまで支払い UI の起動を延期できます。

支払い UI の起動を延期する

最終的な合計料金が確定するまで支払い UI を延期するのデモをご覧ください。

支払い UI を遅らせるため、販売者は Promise を show() メソッドに渡します。Promise が解決されてトランザクションを開始する準備が整うまで、ブラウザには読み込みインジケーターが表示されます。

const getTotalAmount = async () => {
  // Fetch the total amount from the server, etc.
};

try {
  const result = await request.show(getTotalAmount());
  // Process the result…
} catch(e) {
  handleError(e);
}

show() の引数として Promise が指定されていない場合、ブラウザはすぐに支払い UI を起動します。

ステップ 4: ブラウザが決済アプリを起動する

ブラウザでは、プラットフォーム固有またはウェブベースの決済アプリを起動できます(詳しくは、Chrome が起動する決済アプリを決定する仕組みをご覧ください)。

支払いアプリの作成方法は、大部分がデベロッパーに委ねられていますが、販売者との間で出力されるイベントと、それらのイベントとともに渡されるデータの構造は標準化されています。

決済アプリが起動されると、ステップ 1 で PaymentRequest オブジェクトに渡される取引情報を受け取ります。これには以下が含まれます。

  • お支払い方法のデータ
  • 金額
  • 支払い方法

決済アプリは取引情報を使用して UI にラベルを付けます。

ステップ 5: ユーザーの操作に応じて販売者が取引明細を更新する方法

顧客は、決済アプリでお支払い方法や配送オプションなどの取引の詳細を変更できます。顧客が変更を行う間、販売者は変更イベントを受け取り、取引の詳細を更新します。

販売者が受け取る可能性のあるイベントには次の 4 種類があります。

  • お支払い方法変更イベント
  • 配送先住所変更イベント
  • 配送オプション変更イベント
  • 販売者検証イベント

お支払い方法変更イベント

決済アプリは複数のお支払い方法をサポートでき、販売者はお客様の選択に応じて特別な割引を提供する場合があります。このユースケースに対応するため、お支払い方法変更イベントで新しいお支払い方法を販売者に通知できます。これにより、販売者は割引が適用された合計金額を更新し、支払いアプリに返すことができます。

request.addEventListener('paymentmethodchange', e => {
  e.updateWith({
    // Add discount etc.
  });
});

配送先住所変更イベント

決済アプリでは、必要に応じてお客様の配送先住所を指定できます。これは、フォームに情報を手動で入力する必要がなく、複数の異なる販売者のウェブサイトではなく、好みの支払いアプリに配送先住所を保存できるため、お客様にとって便利です。

取引の開始後にユーザーが決済アプリで配送先住所を更新すると、'shippingaddresschange' イベントが販売者に送信されます。このイベントにより、販売者は新しい住所に基づいて送料を判断し、合計金額を更新して、支払いアプリに返すことができます。

request.addEventListener('shippingaddresschange', e => {
  e.updateWith({
    // Update the details
  });
});

更新された住所に発送できない場合、販売者は支払いアプリに返される取引の詳細にエラー パラメータを追加して、エラー メッセージを表示できます。

配送オプション変更イベント

販売者は、複数の配送オプションを顧客に提供でき、その選択肢を支払いアプリに委任できます。配送オプションは、顧客が選択できる価格とサービス名のリストとして表示されます。次に例を示します。

  • 通常便 - 無料
  • エクスプレス配送 - 5 米ドル

ユーザーが支払いアプリで配送オプションを更新すると、'shippingoptionchange' イベントが販売者に送信されます。販売者は送料を決定し、合計金額を更新して、支払いアプリに返すことができます。

request.addEventListener('shippingoptionchange', e => {
  e.updateWith({
    // Update the details
  });
});

販売者は、購入者の配送先住所に基づいて配送オプションを動的に変更できます。これは、販売者が国内外の顧客に異なる配送オプションを提供する場合に便利です。

販売者検証イベント

セキュリティ強化のため、支払いアプリは支払いフローに進む前に販売者の検証を行うことができます。検証メカニズムの設計は支払いアプリによって異なりますが、販売者検証イベントは、販売者に検証に使用できる URL を通知する役割を果たします。

request.addEventListener('merchantvalidation', e => {
  e.updateWith({
    // Use `e.validateURL` to validate
  });
});

ステップ 6: 販売者が支払いを確認し、取引を完了する

顧客が支払いの承認に成功すると、show() メソッドは PaymentResponse に解決される Promise を返します。PaymentResponse オブジェクトには次の情報が含まれます。

  • お支払い結果の詳細
  • 配送先住所
  • 配送オプション
  • 連絡先情報

この時点では、ブラウザの UI に、トランザクションがまだ完了していないことを示す読み込みインジケーターが表示されることがあります。

支払いの失敗またはエラーが原因で支払いアプリが終了した場合、show() から返された Promise は拒否され、ブラウザは支払いトランザクションを終了します。

お支払いの処理と検証

PaymentResponsedetails は、支払いアプリから返される支払い認証情報オブジェクトです。販売者は、この認証情報を使用して支払いを処理または検証できます。この重要なプロセスの仕組みは、支払いハンドラによって異なります。

トランザクションの完了または再試行

販売者は、取引が成功したかどうかを判断した後、次のいずれかを行うことができます。

  • .complete() メソッドを呼び出してトランザクションを完了し、読み込みインジケーターを閉じます。
  • retry() メソッドを呼び出して、お客様に再試行していただきます。
async function doPaymentRequest() {
  try {
    const request = new PaymentRequest(methodData, details, options);
    const response = await request.show();
    await validateResponse(response);
  } catch (err) {
    // AbortError, SecurityError
    console.error(err);
  }
}

async function validateResponse(response) {
  try {
    const errors = await checkAllValuesAreGood(response);
    if (errors.length) {
      await response.retry(errors);
      return validateResponse(response);
    }
    await response.complete("success");
  } catch (err) {
    // Something went wrong…
    await response.complete("fail");
  }
}
// Must be called as a result of a click
// or some explicit user action.
doPaymentRequest();

次のステップ