読者です 読者をやめる 読者になる 読者になる

決済API と Ruby 🍣 時々 Rails

Omise JapanのLead Developerです。OmiseやRubyのことをメインに書きます。

オンライン決済 Omise で円決済の実装

Omiseが昨年の2016年06月14日(火)から日本向けに円決済を提供していることを皆さんはご存知でしょうか? 日本の法人・個人向けに日本円での決済ができるのです。

細かいこと抜きで、ゲストアカウントでささっと円決済をOmise Rubyライブラリで試す方法をまとめてみます。

ゲストアカウントでサインアップ!

テストアカウントを作る手間を省くため、ゲストサインアップを利用します。

Omiseの登録ぺージ へ移動し、 ゲストとしてサインアップする のテキストリンクをクリック。 f:id:akinrt:20170307152345p:plain

アカウント作成のページへ移動した後に、日本を選択し、契約内容に同意にチェックをつけてアカウント作成ボタンをクリックします。 f:id:akinrt:20170307152355p:plain

その後 テストキー を取得します! 公開鍵(パブリックキー)と秘密鍵(シークレットキー)があるので、これを後ほど利用します! f:id:akinrt:20170307152404p:plain

PryでChargeをしてみよう

ruby2.3.1以降とpryがインストールされている状態をイメージして話をしていきます。 Omise Ruby の公式ライブラリを使ってChargeをしていきます。 gemで配布しているので、下記のようにインストールします。

gem install omise

それでは、 pry をターミナルで実行してrubyを書いていきましょう!

APIキーの設定(公開鍵・秘密鍵)

ここでは、先ほどの テストキー から秘密鍵と公開鍵を使っていきます。 下記の、秘密鍵と公開鍵はご自身のキーを入れてください。

Omise.api_key = "秘密鍵"
Omise.vault_key = "公開鍵"

Omise.vault_key は、Tokenを作成する時に利用します。 クレジットカードデータを扱うので、本番利用時には使用しないようにしましょう。(※Omise.jsでトークンを作るようにしましょう。)

Tokenを作成

ここではVISAカードのテストカード番号である 4242424242424242 を利用してテストのトークンを作成します。

token = Omise::Token.create(card: {
  name: "TARO OMISE",
  number: "4242424242424242",
  expiration_month: 3,
  expiration_year: 2019,
  city: "Tokyo",
  postal_code: "1510051",
  security_code: 123
})

これにより、Charge を行うためのTokenが取得できました。 次に3種類あるChargeの方法を一つずつ見ていきます。

1. TokenだけをつかったCharge

さきほど作った token のidを参照させてChargeを行うには下記になります。 わずかこれだけで課金ができてしまっています。

charge = Omise::Charge.create({
  amount: 100000,
  currency: "jpy",
  card: token.id
})

しかし、トークンは一度だけ使えるといった性質があるため、このコードを再利用するとエラーが返ってきます。 次に同じカードを再利用する方法を見ていきましょう。

2. CustomerにCard(Token)を保存してCharges

Customerオブジェクトにはカード(Token)を複数持たせることができます。 最初に登録したカードをデフォルトカードとして所有する性質があります。 さきほどのTokenは再利用できなくなってしまっているので、再度新しいTokenを発行します。

token = Omise::Token.create(card: {
  name: "TARO OMISE",
  number: "4242424242424242",
  expiration_month: 3,
  expiration_year: 2019,
  city: "Tokyo",
  postal_code: "1510051",
  security_code: 123
})

customer = Omise::Customer.create({
  email: "taro.omise@omise.co",
  description: "taro omiseさんに関するメモなどを書ける場所",
  card: token.id
})

こうすうることで、Customerオブジェクトへカード(Token)を紐づけることができ、Customerオブジェクトを使ったChargeができるようになります。 この場合のChargeは下記のように行います。

charge = Omise::Charge.create({
  amount: 100000,
  currency: "jpy",
  customer: customer.id
})

こうすることで Customerに紐づけたカードを使って、再利用可能なChargeができるようになりました。

3. Customerの所有するカードを明示的に指定してCharge

Customerには複数カードを持たせることができますが、2枚目以降のカードを使うようにするには、Card IDを指定して利用します。 ここでは、先ほどの customer へ Mastercardのテストクレジットカード 5555555555554444 を追加してMastercard(2枚目のクレジットカード)でChargeをやってみましょう!

token = Omise::Token.create(card: {
  name: "TARO OMISE",
  number: "5555555555554444",
  expiration_month: 3,
  expiration_year: 2019,
  city: "Tokyo",
  postal_code: "1510051",
  security_code: 123
})

# Mastercardを先ほどのcustomerへ登録
customer.update(card: token.id)

# cardsの中身はarrayにhashでCardオブジェクトが入っています、2個目のCard IDを取得
mastercard_id = customer.cards.data[1]["id"]

charge = Omise::Charge.create({
  amount: 100000,
  currency: "jpy",
  customer: customer.id,
  card: mastercard_id
})

こんな感じでOmiseのChargeができます。 やってみるとすごく簡単だと思いますので、ぜひゲストアカウントからさくっと動かして見てください。

動作検証用のテストカードはこちらにたくさんあります。 正常動作とCharge時に各種エラー(failure code)がレスポンスに含まれるカードが整っています。

テストカードのGem omise_test_cards を作りました

これを使えばテストカードをウェブサイトから探さなくても簡単に利用できるようになります!

akinrt.hatenablog.com

Omise 商用へ移行した時にお伝えしたいこと(トークンとオーソリ)

商用へ移行され、実際に課金をテストされることがあるかと思います。
ここでは、商用へ移行された時に私たちが伝えきれていない?(と個人的には思います)情報を説明したいと思います。

1. 商用モードでのトークン作成って何をしているの?

カードの有効性チェックを行います。
そのため、日本の加盟店では、トークンを作成する時にカードが実際に使えるかを確認するため下記のことを行います。

クレジットカードの場合

  • トークンを作成開始
  • 送信したカードで100円の与信を行い100円の枠を抑える
  • 100円の与信が成功すれば、100円の与信枠を解放し、そのタイミングでの有効性を確認できたとして使えると判断する
  • 100円の与信が成功しなければ、トークン作成がエラーになる

デビットカードの場合

  • トークンを作成開始
  • 送信したカードで100円を本売上する
  • 100円の本売上が成功すれば、100円の返金をし、そのタイミングでの有効性を確認できたとして使えると判断する
  • 100円の本売上が成功しなければ、トークン作成がエラーになる

クレジットカードとデビットカードで言葉が若干違いますが、100円で課金できるかを確認して、そのタイミングでのカードの有効性を確認しています。

ですので、ほんの少しの間だけ100円の与信枠を確保と解放する時間がカードに発生します。
決済の裏事情ですね。。。。

※有効性チェックをオーソリともいいます。

※デビットカードの場合、明細書に100円の出金と返金が履歴に残るようです。
引き落としのギモン|Visaデビット|ジャパンネット銀行

2. そのタイミングでのカードの有効性って?

つまり、カードを使おうとした時に、カードがまだ使える状態かということです。

次の例の場合、課金(Charge)作成の時に失敗することがあります。

  1. 与信枠が残り2000円のカードで、カードを情報をフォームへ入力中
  2. カードフォームへ入力中に、どこかで登録している定期課金で2000円の与信が行われた
  3. カード情報を入力終わり、トークン作成
  4. トークン作成エラー(2. のタイミングで与信枠が足りなく(0円)なっているため)

3. 課金(Charge)作成時のエラーについて

課金(Charge)作成時のエラーについては、現時点では下記のエラーを返しています。
こちらは、日本でもタイでもインドネシアでも、英語が共通語としてChargeオブジェクトの failure_message に入ってきます。
日本語で対応されたい場合は、failure_code の文字列を参照していただき、switch文などでご利用に最適化した日本語に訳したテキストをアプリでご利用されると良いかと思います。

failure_code failure_message いつ発生するか
insufficient_fund “insufficient funds in the account or the card has reached the credit limit” 与信限度枠を超えた時
stolen_or_lost_card “card is stolen or lost” 盗難カード、または紛失カードの場合
failed_processing “failed processing” トランザクション処理のプロセスが失敗した場合
payment_rejected “payment rejected” 何らかの理由により、課金が拒否された場合
invalid_security_code “the security code is invalid” セキュリティコードが無効の場合
failed_fraud_check “failed fraud check” カードが不正だと判定した場合に発生
invalid_account_number “the account number is invalid” 利用できないカード番号の場合

4. 番外編 トークン作成時のステータスコードとレスポンス(Token/Errorオブジェクト)

TokenをOmise.jsで作成する時のつまづきポイントをメモしておきます。

ステータスコートとTokenオブジェクト

Tokenオブジェクトがレスポンスで返ってくる場合、ステータスコードは200が返ってきます。 このレスポンスには注意点がひとつあり、Tokenオブジェクトの中のCardオブジェクトの security_code_check が true になっているかも確認してください。 security_code_check が false の場合、そのTokenを使って課金(Charge)をしても invalid_security_code で課金は失敗します。

ステータスコードとErrorオブジェクト

Errorオブジェクトがレスポンスで返ってくる場合、ステータスコードはエラーの値が返ります。

Omise.jsとCard.jsの謎に迫る

2016年11月18日に、Omise.jsがリニューアルされていましたが皆さんご存知でしょうか? Card.js と Omise.jsの違いがよく分からないとのお声がありましたので、この2つについてご紹介します。

Omise.jsとは

Omise.jsは、クレジットカード情報のトークン化を行うための機能を提供しています。

トークンとは、Omiseが運用するクレジットカード情報とのやりとりを間接的に行うための引換券のようなものです。 これにより、Omiseを利用される事業者さまが、クレジットカード情報を運用する手間とコストを省くことができ、できるだけ早くクレジットカード決済をサービスに取り込むことができるようになっています。

Omise.js経由で伝送するクレジットカード情報は、事業者さまのサーバーは経由せず、直接Omiseのサーバーへ伝送されて処理が行われるため、グローバルセキュリティ基準PCI DSS Version 3.2の元に運用される非常に高いセキュリティの元で支払いができます。

PCI DSS Version 3.2

Omise.jsの3つの機能

2017年2月6日現在のOmise.jsには大きく分けて下記の3つの機能を有しています。

  • クレジットカード情報のトークン化
  • 独自のクレジットカードフォームでトークン化のための Omise.createToken
  • Card.jsの進化版、PayによるUIと通貨の切り替え

それでは、ひとつずつ紹介していきます。

クレジットカード情報のトークン化

Omise.jsは、ユーザーさまがHTMLのフォームへ入力したクレジットカード情報をSubmitのタイミングでOmiseのサーバへ送信を行う機能を有していました。

それでは、なぜユーザーのサーバーではなく、Omiseのサーバーへクレジットカード情報を送信するのでしょうか。 理由は、リスク管理プログラムである PCI DSS と呼ばれるセキュリティ基準に準拠していない環境でのクレジットカード情報の取り扱いをさせないためです。

Omise(ペイメントプロバイダー)は、クレジットカード情報を運用するためのライセンス(PCI DSS)を所有している事業社ですので、ユーザーさまの代わりにクレジットカード情報を安全に運用することができるのです。

そのため、Omise.js経由でOmiseへ送信されてきたクレジットカードデータをOmiseで保管を行い、クライアントサイドへトークンを渡し、ユーザーはこのトークンを元にしてクレジットカード決済に関する処理を行うことができるようになります。

トークンは tokn_test_56wro5rcvo16xrsm795 の形式でユニークな値が割り当てられます。

独自のクレジットカードフォームでトークン化のための Omise.createToken

独自のクレジットカードフォームにてトークン化の仕組みを作る場合には Omise.createToken を利用してください。

# 日本のリージョンからOmise.jsを読み込む
<script src="https://cdn2.omise.co/omise.js"></script>

# 公開鍵を設定する
<script>
  Omise.setPublicKey("pkey_test_4xpip92iqmehclz4a4d");
</script>

# Omise.js自体はjQueryを必要としませんが、サンプルで利用するために読み込む
<script src="http://code.jquery.com/jquery-1.12.1.min.js"></script>

# カードフォームのHTML
<form action="/checkout" method="post" id="checkout">
  <div id="token_errors"></div>

  <input type="hidden" name="omise_token">

  <div>
    Name<br>
    <input type="text" data-omise="holder_name">
  </div>
  <div>
    Number<br>
    <input type="text" data-omise="number">
  </div>
  <div>
    Date<br>
    <input type="text" data-omise="expiration_month" size="4"> /
    <input type="text" data-omise="expiration_year" size="8">
  </div>
  <div>
    Security Code<br>
    <input type="text" data-omise="security_code" size="8">
  </div>

  <input type="submit" id="create_token">
</form>

# 上記クレジットカードフォームでトークン化させるための処理を書く
<script>
$("#checkout").submit(function () {

  var form = $(this);

  // Submitボタンを無効化にし、二重クリックを防ぐ
  form.find("input[type=submit]").prop("disabled", true);

  // formの値を変数cardにオブジェクトとして集める
  var card = {
    "name": form.find("[data-omise=holder_name]").val(),
    "number": form.find("[data-omise=number]").val(),
    "expiration_month": form.find("[data-omise=expiration_month]").val(),
    "expiration_year": form.find("[data-omise=expiration_year]").val(),
    "security_code": form.find("[data-omise=security_code]").val()
  };

  // Omiseへトークン作成のリクエストを行う
  Omise.createToken("card", card, function (statusCode, response) {
    if (response.object == "error" || !response.card.security_code_check) {
      // エラーが返ってきた場合のメッセージ
      var message_text = "SET YOUR SECURITY CODE CHECK FAILED MESSAGE";
      if(response.object == "error") {
        message_text = response.message;
      }
      $("#token_errors").html(message_text);

      // Submitボタンを有効化にする
      form.find("input[type=submit]").prop("disabled", false);
    } else {
      // Omiseが返してきたトークンをomise_tokenの値として設定
      form.find("[name=omise_token]").val(response.id);

      // フォームを送信する前に、カード情報を空にする
      form.find("[data-omise=number]").val("");
      form.find("[data-omise=security_code]").val("");

      // トークンを事業者さまのサーバーへ送信
      form.get(0).submit();
    };
  });

  return false;
});
</script>

Card.jsの進化版、PayによるUIと通貨の切り替え

Card.jsでは、JSを読み込むことでOmiseが提供するカードフォームを提供してきました。 しかしながら、Card.jsはタイ国内限定の仕様で設計されており、日本の通貨 jpy を利用することができません。

そのため、新しいカードフォームで通貨の指定ができる機能を2016年11月18日のOmise.jsに組込むことになったのです。

労力をかけずに、簡単にカードフォームを実装する場合にオススメの機能です。

下記のスニペットをHTMLへ記述をすると、カードフォームを表示するためのボタンが表示されます。

<form name="checkoutForm" method="POST" action="checkout">
  <input type="hidden" name="description" value="商品合計 10,025円" />
  <script type="text/javascript" src="https://cdn2.omise.co/omise.js.gz"
    data-key="YOUR_PUBLIC_KEY"
    data-image="https://cdn1.www.st-hatena.com/users/ak/akinrt/profile.gif"
    data-frame-label="決済APIとRuby🍣時々Rails[f:id:akinrt:20170206225750p:plain]"
    data-button-label="クレジットカードで支払う"
    data-submit-label="Submit"
    data-location="yes"
    data-locale="ja"
    data-amount="10025"
    data-currency="jpy"
    >
  </script>
</form>

そして、ここでは クレジットカードで支払う と表示されたボタンをクリックするとOmiseのカードフォームが表示されます。

f:id:akinrt:20170206230840p:plain

※ クレジットカードで支払う ボタンは、ご自身でCSSを変更してレイアウトしてください。

scriptに渡しているパラメーターの役割は下記です。

param value content
data-key 秘密鍵 ユーザーさまの秘密鍵を設定してください
data-image 画像URL カードフォームへ表示させるサムネイルのURLを設定してください
data-frame-label タイトル カードフォームへ表示するタイトルを設定してください
data-button-label Payボタンのタイトル Payボタンに表示したいテキストを設定してください
data-submit-label 支払いボタンのラベル 青いボタンの左に表示されるテキストを設定してください
data-location ‘yes’ または ‘no’ 住所 & 連絡事項を表示する場合に ‘yes'、非表示にしたい場合に 'no’
data-locale ‘en'、'ja’ または ‘th’ ラベルの言語を英語・日本語・タイ語の中から指定できます
data-amount ユーザーの支払い金額 ユーザーへ支払いさせる金額を入力してください
data-currency ‘thb’ または ‘jpy’ ご利用の通貨を指定してください

Omise.jsの配信元

Omise.jsはAWSのS3を使ってシンガポールと東京のリージョンから配信しています。

東南アジア向けにご利用の場合はシンガポールリージョンの下記をご利用ください。

Primary CDN (Singapore)
<script src="https://cdn.omise.co/omise.js.gz"></script>

日本からはご利用の場合は、東京リージョンの下記をご利用ください。

Secondary CDN (Japan)
<script src="https://cdn2.omise.co/omise.js.gz"></script>

Card.jsは。。。

こちらは、ご利用にならないようにお願いします。
以前よりご利用されているタイのユーザーさま向けに配信は続けていますが、現在メインテナンスは行われていません。

※ Omise.jsのみメインテナンスされています。

Omise.jsのブラウザ対応状況は?

Internet Explorer 9 〜、とモダンブラウザに対応しています。
Omise.jsに含まれているPayはReactで作成されており、ES5 methodsをサポートしていないブラウザでは正常に動作しません。