ヤフー株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。LINEヤフー Tech Blog

テクノロジー

決済プログラミングをはじめてみよう

こんにちは、決済金融カンパニーの近藤です。

Yahoo! JAPAN ウォレット FastPayをリリースして1年近くたち、定期的にアップデートをしております。
(弊社で開催するOpen Hack DayでもFastPayを利用しています)

数行で動くのが売りのFastPayですが、基本的なところの問い合わせをいくつか受けたりします。今回は決済になじみのないエンジニア向けに、クレジットカード決済についてもう少し身近に感じてもらいたいと思い、執筆させていただいております。

クレジットカード決済の仕組み

大ざっぱにわけてカード利用者、カードが利用できる加盟店、利用者へのカード発行や加盟店管理を行うカード会社が関わっています。

三者の関係

このうち加盟店とカード会社間でやりとりでは、カードが利用可能かどうかを確認するオーソリ(与信枠の予約)、実際に商品やサービスの提供が決まった際の確定処理、返品やサービス解約に伴う返金・取消処理などを実装していく必要があります。

これらを実施するには独自の決済ネットワークと接続する必要がありますが、Webの世界からは気軽に使えないものとなっています。
そのためWebで決済代行サービス事業者を経由して利用するケースが多いです。

決済代行事業者の多くはクレジットカード支払いに加えて複数の支払い手段をセットで提供していることが多いですが、その分手数料が高くコストが高くなりがちです。

FastPayの特徴

FastPayの立ち位置としてはカード会社と加盟店の間に入る決済代行サービス事業者に相当します。

開発までステップが短い

実際の申込前でもYahoo! JAPAN IDさえあれば本番さながらの開発が可能です。多くの決済代行サービスでは資料請求などのステップを踏む必要があり、とりあえず試してみることができるための選択肢が少ないのが現状です。

また、比較的小規模のWebサービスでも導入しやすいように便利なライブラリやプラグインを提供しています。

クレジットカード情報漏洩リスクを低減

決済サービス事業者とのつなぎ込みを自前で開発する場合、クレジットカード番号を自社DBで保持するパターンや、下図のようにサーバを通過して決済代行サービスへ伝送するような作りになっているサービスをよくみかけます。

いずれの場合においてもセキュリティ脆弱性をついたカード番号漏洩のリスクが生じるため、加盟店側での運用や管理を徹底する必要があります。

クレジットカードを直接渡すパターン

FastPayの採用しているカードトークン形式の決済機能では下図のように利用者のカード情報を代わりにお預かりし、カード情報として代替利用できる一時的なカードトークンが加盟店サーバを通過するためするため、リスクを低減できます。

カードトークンを渡すパターン

ヤフーではクレジットカードの国際セキュリティ標準であるPCI DSSに準拠しており、カード情報は安全に管理しております。

クレジットカードを毎回打たせなくてもよい

カード番号を都度入力が必要なゲスト決済機能に加え、Yahoo! JAPAN IDにカード情報を紐付けておくID決済機能も提供しているので決済時に便利です。

FastPayで提供している決済パターン

おおきくわけて都度決済継続決済の二種類を決済パターンを提供しています。今回はシンプルな都度決済の実装について説明します。

FastPayを使ったカード支払いの流れはこの通りです。

  1. 商品ページなどに金額を指定した支払いボタン設置(開発者が実装)
  2. お客様が金額を確認してクレジットカード入力もしくはYahoo!ウォレット支払いの確認画面を表示(FastPayの機能)
  3. 支払いの確認完了後に加盟店ウェブサイトへカードトークンを返却(FastPayの機能)
  4. カードトークンを加盟店サーバへ送信(開発者が実装)
  5. 加盟店サーバからFastPayのAPIへリクエスト送信(開発者が実装)
  6. カード情報と決済ネットワークへのリクエスト送信(FastPayの機能)
  7. 決済ネットワークを通じたカード会社からのオーソリ回答をレスポンスとして返却(FastPayの機能)
  8. リクエスト結果に応じたお客様へ画面を表示(開発者が実装)

フロントエンドの実装

利用者のブラウザと加盟店サーバ間のやりとりを担う部分の実装です。2種類のフローを用意しています。

リダイレクトフロー

加盟店ウェブサイトから同一ウィンドウ上でFastPay支払いページへ遷移させるフローです。

たとえば、商品選択⇒住所入力⇒支払い方法選択→支払い確認⇒購入完了、のように商品購入までのステップごとにページを切り替えて進めていく場合に適しています。

支払いボタン設置のためのHTMLは下記の通りです。

<script
    src="https://s.yimg.jp/images/wallet/fastpay/js/fastpay-v2-current.js" class="fastpay-button"
    data-key="アプリケーションID"
    data-amount="金額"
    data-redirect="加盟店サイトの戻り先URL"
>
</script>

data-amountで指定した金額がFastPayの支払い確認ページに表示され、data-redirectで指定した戻り先URLへカードトークンをfastpayTokenパラメータとしてURLクエリで返却します。

アプリケーションIDの確認、および戻り先URLのホワイトリスト設定はアカウントページから可能です。

開発者は戻り先URLにリダイレクトされた際、FastpayTokenパラメータを確認し自身のサーバへ送信する処理を実装する必要があります。また、ボタンを設置するページURLおよび支払い確認後の戻り先URLはHTTPSにしていただくことを推奨します。

ポップアップフロー

加盟店ウェブサイトのウィンドウは残したまま別ウィンドウで支払い確認画面が表示されるフローです。

ゲームの課金やデジタルコンテンツの購入などで、途中でページ遷移せずメインコンテンツを表示させたまま継続させたい場合に適しています。

ポップアップの支払いボタン設置のためのHTMLは下記の通りです。

<form action="post.php" method="POST">
<script
    src="https://s.yimg.jp/images/wallet/fastpay/js/fastpay-v2-current.js" class="fastpay-button"
    data-key="アプリケーションID"
    data-amount="金額"
>
</script>
</form>

リダイレクトフローと異なり、利用者が支払い同意後にトークンの受け渡しはpostmessageを利用しているため戻り先URLは不要です。

元のウィンドウはpostmessageを受け取ると、上の例ではformのaction属性に指定しているpost.phpへPOST送信を行います。

formを利用せずに自前で受け取るパラメータのハンドリングしたい場合はdata-callback属性に加盟店ウェブサイト上で定義したJavaScriptのcallback関数名をしてください。第一引数でfastpayTokenパラメータが取得できます。

<form action="post.php" method="POST">
<script
    src="https://s.yimg.jp/images/wallet/fastpay/js/fastpay-v2-current.js" class="fastpay-button"
    data-key="アプリケーションID"
    data-amount="金額"
    data-callback="your_callback"
>
</script>
</form>

<script type="text/javascript">
    function your_callback(token){
        alert(token);
    }
</script>

バックエンド側の実装

加盟店のサーバとFastPayのAPIのやりとりを行う部分の実装について説明します。

フロントエンドだけで終わった気になってしまうのですが、バックエンドで決済作成APIにリクエスト送信することで支払い完了なので注意してください。

ここではPHPライブラリを使った決済処理(確定処理含む)の実装例を示します。

<?php
require "vendor/autoload.php";
use FastPay\FastPay;
use FastPay\Error\CardError;
use FastPay\Error\InvalidRequestError;

// シークレットを引数に指定してください
$fastpay = new FastPay("my_secret");

// FastPayから渡されたカードトークンを取得
$token = $_REQUEST["fastpayToken"];

// FastPayで支払い確認した金額と同じ値を数値型で指定してください
$amount = 666;

try {
    // 決済を実行(オーソリと確定処理)
    $charge = $fastpay->charge->create(array(
        "card" => $token,
        "amount" => (int)$amount,
    ));

} catch (CardError $e) {
    // クレジットカードエラー(HTTPのステータスが402)
    echo "CardError : {$e->getMessage()} \n";

    switch($e->getCode()) {
        // オーソリエラー(与信枠の超過や利用停止など)
        case "card_declined":
            echo "利用ができないカードです";
            break;
        case "incorrect_cvc":
            echo "セキュリティコードが間違っています";
            break;
        case "expired_card":
            echo "有効期限が切れています";
            break;
        default:
    }    

} catch (InvalidRequestError $e) {
    // BadRequestなどクライアント側のエラー
    echo "InvalidRequestError : {$e->getMessage()} \n";
} catch (Exception $e) {
    // その他エラー
}

利用者が入力したクレジットカードはバックエンドでの決済時に始めて有効かどうかわかるため、カードのオーソリエラーが発生した場合は加盟店ウェブサイト上で利用者に適切な案内を表示する必要があるので注意してください。

カード関連のエラーハンドリングは、FastPayライブラリを利用する場合はCardErrorExceptionを活用してください。ライブラリを利用しないで実装する場合はエラー処理を参考してください。

実際の注文とカード決済確定のタイミングをずらしたい場合

captureパラメータにfalseを指定することでオーソリ取得のみで、決済の確定処理をいったん止めておくことができます。これにより、商品の発送などオペレーションを終えた後などサービス提供完了後に利用者にカード請求をするなどの対応が可能です。

//...(省略)

// 決済処理を行う(オーソリのみ)
$charge = $fastpay->charge->create(array(
    "card" => $token,
    "amount" => (int)$amount,
    "capture" => "false" 
));

オーソリのみの場合でも決済IDは通常と変わらず作成されます。

後から注文の決済を確定もしくは返金したい場合は、対象の決済IDに対して確定API返金APIを使ってリクエストをする処理を実装してください。

また、決済作成後の処理はWebAPIを使って実装せずとも、管理者用の決済履歴画面から決済の参照・確定・返金・取消の処理を直接行うこともできます。

その他便利なパラメータの紹介

加盟店ウェブサイト上で管理している注文ID等とFastPayの決済IDを関連付けたいという場合を例に説明します。

支払いボタンのscriptの属性にdata-stateパラメータを利用すると便利です。

data-stateは任意の文字列を指定することが可能で、お客様がFastPayで支払い確認完了後にFastpayTokenと一緒に加盟店サイトへ渡される仕様になっており、
FastPayで支払い確認前後で同一の値を引き継ぐことができるようになっています。

設置例をみてみましょう。

<form action="post.php" method="POST">
<script
    src="https://s.yimg.jp/images/wallet/fastpay/js/fastpay-v2-current.js" class="fastpay-button"
    data-key="<アプリケーションID>"
    data-amount="<注文の総額>"
    data-state="<注文ID>"
>
</script>
</form>

この例ではポップアップフローでdata-stateに直接注文IDを指定しているため、ユーザが支払い確認後にカードトークンと注文IDパラメータが同時にわたってきてpost.phpへデータがPOSTされます。data-callbackを利用している場合はcallback関数の第2引数にstate値が渡ってくるのでハンドリングします。

つづいてデータを受け取るバックエンド側での処理例を示します。

<?php 
...(省略)...

// FastPayから渡されたカードトークンとstate値(注文ID)取得
$token = $_REQUEST["FastpayToken"];
$orderId = $_REQUEST["state"];

// 例)注文IDに関連する支払い金額を取得
$amount = getAmount($orderId);

// 決済処理を行う(オーソリのみ)
$charge = $fastpay->charge->create(array(
    "card" => $token,
    "amount" => (int)$amount,
    "description" => $orderId, 
    "capture" => "false" 
));

descriptionパラメータには注文IDなどのデータを指定しておくと、返り値の$chargeに代入される決済オブジェクトに注文IDが含まれるようになり、決済リスト取得API経由でも参照できるようになるため、加盟店側の注文IDとFastPayの支払いID(決済オブジェクトのID)との関連がわかるようになります。

加盟店とFastPay上の決済データ連携にdescriptionはいろいろと活用できると思います。

さいごに

ライブラリを使えば数行コピペで決済ができるシンプルな作りがFastPayの特長ではありますが、加盟店側で作りこむべき機能もその分自由度が高くなり作り込みが必要にはなってくると思います。とは言え、気軽に試すことはできますのでぜひ皆さんのサイトにクレジットカード決済機能を導入してもらえればと思います。

こちらの記事のご感想を聞かせください。

  • 学びがある
  • わかりやすい
  • 新しい視点

ご感想ありがとうございました

このページの先頭へ