EX-決済API と Ruby 🍣 時々 Rails

EX-Omise JapanのLead Developerです。

Omise、Pay.jp、Stripeから自分にあった決済代行サービスの選び方

Omiseで働いているとユーザーからよくある質問が2点あります。

・「他社と比較して何が違うのか?」
・「Omiseはどのような場合にフィットするのか?」

まずひとつめの質問の回答は、料金体系と提供しているサービスの種類が各社異なるという点であり、コスト(API・カードブランド・手数料)に対してフォーカスして比較することができます。

これを、3つのセグメント(API・カードブランド・手数料)で見ていきましょう。

API

まずAPIですが、Stripeが先駆者としてオンライン決済の機能に止まらず、マーケットプレイス(店子)機能、その他にECがらみのバックオフィス系の機能まで多くの機能を提供しています。

OmiseとPay.jpについては、基礎的なオンライン決済の機能を提供しています。
Stripeのような高度なサービスはないため一見では見劣りしてしまいがちですが、基本的に必要となるオンライン決済の機能は提供しており、スリムな点では学習コストが低いためStripeより使い始めやすいかもしれません。

例えていうと、Rubyコミッターになりたい人がいきなりCRubyを始めるよりmrubyのほうがスリムで学習コストが低めに思えるような感じでしょうか。。。

Omise Pay.jp Stripe
顧客 ✔️ ✔️ ✔️
チャージバック ✔️ ✔️ ✔️
仮売上 ✔️ ✔️ ✔️
本売上 ✔️ ✔️ ✔️
定期課金 ✔️ ✔️ ✔️
プラン - ✔️ ✔️
レシピエント ✔️ - ✔️
検索 ✔️ - -
送金 ✔️ ✔️ ✔️
イベント ✔️ ✔️ ✔️
クーポン - - ✔️
割引 - - ✔️
その他EC向けの機能 - - ✔️

※ 上記テーブルではコアになるAPIだけを掲載しています。API比較表はこちら。

カードブランド

各社で日本向けにサポートしているカードブランドの一覧です。
対応カードブランドだけでみると Pay.jp > Omise > Stripe の順になります。

日本国内では、VISA > MasterCard > JCB の順で利用者数が多いので、最低でもこの3ブランドは対応したほうがユーザーに優しいかと思います。
※ 全ての数字で見ると VISA > MasterCard > AmericanExpress の順かと思います。

Omise Pay.jp Stripe
VISA ✔️ ✔️ ✔️
MasterCard ✔️ ✔️ ✔️
JCB ✔️ ✔️ -
AmericanExpress ✔️ ✔️ ✔️
Diners Club ✔️ ✔️ -
DISCOVER - ✔️ -

手数料

次に決済代行サービスのコスト面についてです。
各社とも薄利ですが、不正対策やセキュアなサービスを提供をしています。

Omise Pay.jp(ベーシック/プロ/Seed/NPO) Stripe
VISA 2.95% 3.0%/2.59%/2.59%/1.5% 3.6%
MasterCard 2.95% 3.0%/2.59%/2.59%/1.5% 3.6%
JCB 3.6% 3.6%/3.3%/3.3%/- -
AmericanExpress 3.6% 3.6%/3.3%/3.3%/- 3.6%
Diners Club 3.6% 3.6%/3.3%/3.3%/- -
DISCOVER - 3.6%/3.3%/3.3%/- -
初期費用 ¥0 ¥0 ¥0
月額費 ¥0 ¥0/¥10,000(税込)/¥0/¥0 ¥0
チャージバック手数料 ¥0 ?(※1) ¥1,500 または ¥0
送金手数料 ¥260 /回(VISA/MasterCardのみ) ¥0(※2) ¥0(※3)
消費税 有(※4) ?(※1) ?(※1)

※1:情報がみつかりませんでしたので、どなたか教えてください。。
※2:指定入金サイクル
※3:週一回まで、売上の振込が無料
※4:ご請求の際は決済手数料に別途消費税が加算されます

Omiseがどのような場合にフィットするか?

まず、「Omiseがどのような場合にフィットするか?」の答えですが、新規事業(スタートアップ)のプロダクトにフィットします。 その他には、WooCommerceで気軽に低コストで独自ECを始める場合にフィットすると言えます。

また、私の考えでは各社とも根本的には同じターゲットに向いているため、特にスタートアップは導入障壁の低さで必然的にフィットするようになっています。

最高のパートナーの見つけ方

決済代行はあなたのビジネスのパートナーです。だからこそパートナー選びに妥協をしてはいけません。 もしあなたが新規事業を始めるのであれば、各社に連絡を取り、サポートの質や相性、テスト導入での動きを確認し納得いくパートナーを選択するべきです。

Omise、Pay.jp、Stripeの3社は、いずれもRESTベースに構成されたAPIを提供しているため、実装にかかるコストがほぼ同じと言えます。 つまり言い換えると3社間での実装の入れ替えはそこまでコストがかかりません。

また、どこかが第2のWebpayになることもあるかもしれませんし、心のそこから信頼できるパートナーを選ぶにはPersonal Relationshipが重要です。

OmiseにもPay.jpにもStripeにも素晴らしき方々が多いので、実際にお会いになるのが得策です。

組み込み変数/定数

組み込み変数(Ruby Predefined Variables)

Rubyでの組み込み変数は Kernelの特殊変数 へまとめられています。 Kernel.global_variables で出力されるものが組み込み変数名称一覧です。

識別子 初期値 概要 スコープ
$_ String, nil 最後に Kernel.#gets または Kernel.#readline で読み込んだ文字列です。 EOF に達した場合には、 nil になります。 (覚え方: Perlと同じ)
Kernel.#print のような Perl 由来の幾つかのメソッドは、引数を省略すると代わりに $_ を利用します。
ローカルスコープかつスレッドローカル
$~ MatchData, nil 現在のスコープで最後に成功したマッチに関する MatchDataオブジェクトです。 Regexp.last_match の別名です。このデータから n 番目のマッチ ($n) を取り出すためには $~[n] を使います。 ローカルスコープかつスレッドローカル
$;
$-F
Regexp, String, nil String#split で引数を省略した場合の区切り文字です。 グローバルスコープ
$@ [String], nil 最後に例外が発生した時のバックトレースを表す配列です。 Kernel.#raise によって設定されます。 スレッドローカル
$! Exception, nil 最後に例外が発生したときの Exception オブジェクトです。 該当する例外がないときは nil です。Kernel.#raise によって設定されます。 スレッドローカル、読み取り専用
$SAFE Fixnum, 0 カレントスレッドのセーフレベルを表す整数です。セーフレベルについては セキュリティモデル を参照してください。Thread.current.safe_level と同じです。 スレッドローカル
$& String, nil 現在のスコープで最後に成功した正規表現のパターンマッチでマッチした文字列です。 最後のマッチが失敗していた場合には nil となります。Regexp.last_match[0] と同じです。 ローカルスコープかつスレッドローカル、読み取り専用
$` String, nil 現在のスコープで最後に成功した正規表現のパターンマッチでマッチした 部分より前の文字列です。 最後のマッチが失敗していた場合には nil となります。Regexp.last_match.pre_match と同じです。 ローカルスコープかつスレッドローカル、読み取り専用
$‘ String, nil 現在のスコープで最後に成功した正規表現のパターンマッチでマッチした 部分より後ろの文字列です。 最後のマッチが失敗していた場合には nil となります。Regexp.last_match.post_match と同じです。 ローカルスコープかつスレッドローカル、読み取り専用
$+ String, nil 現在のスコープで最後に成功した正規表現のパターンマッチで マッチした中で最後の括弧に対応する部分文字列です。最後のマッチが失敗していた場合には nil。 ローカルスコープかつスレッドローカル
$= bool, false 過去との互換性のために残されていますが、もはや何の意味もありません。値は常に false です。代入しても無視されます。 グローバルスコープ
$KCODE
$-K
nil この特殊変数は何の影響も持たなくなりました。値を代入しても無視され、参照すると常に nil です。
$, String, nil デフォルトの出力フィールド区切り文字列です。 Array#join で引数を省略した場合と、 Kernel.#print の各引数の間で出力されます。 グローバルスコープ
$/
$-0
String, nil 入力レコード区切りを表す文字列です。 awk の RS 変数のように働きます。Kernel.#gets のような「行」単位の読み込みメソッドが「行」の区切りとして使用します。 Rubyがコマンドオプション -0 付きで起動されたときには -0 で指定された値が規定値となります。そうでないとき、規定値は “\n” です。この変数に nil を設定すると読み込みメソッドはファイル全体を一度に読み込みます。 空文字列 “” を設定するとパラグラフモードとみなされ、 2 つ以上連続した改行が「行」の区切りになります。$/ には正規表現は使えません。 グローバルスコープ
$\ String, nil 出力レコード区切りを表す文字列です。 Kernel.#print が最後にこの文字列を出力します。 グローバルスコープ
$stdin object 標準入力です。 グローバルスコープ
$>
$stdout
object, Object::STDOUT 標準出力です。 グローバルスコープ
$stderr object 標準エラー出力です。 グローバルスコープ
$< IO すべての引数または標準入力で構成される仮想ファイルです。 定数 Object::ARGF の別名です。 グローバルスコープ、読み取り専用
$. Fixnum, 0 いずれかの IO オブジェクトが最後に読んだ行の行番号です。 Object::ARGF などの IO 互換のオブジェクトも $. を更新します。 グローバルスコープ
$FILENAME String 仮想ファイル Object::ARGF で現在読み込み中のファイル名です。 ARGF.class#filename と同じです。 グローバルスコープ
$-i bool in-place 置換モードで用いられます。 グローバルスコープ
$* [String] Rubyスクリプトに与えられた引数を表す配列です。 組み込み定数 Object::ARGV の別名です。 グローバルスコープ
$:
$-I
$LOAD_PATH
[String] Rubyライブラリをロードするときの検索パスです。Kernel.#load や Kernel.#require がファイルをロードする時に検索するディレクトリのリストを含む配列です。 グローバルスコープ
$\ String, nil 出力レコード区切りを表す文字列です。 Kernel.#print が最後にこの文字列を出力します。 グローバルスコープ
$“
$LOADED_FEATURES
[String] Kernel.#require でロードされたファイル名を含む配列です。Kernel.#require で同じファイルを 複数回ロードしないようにするためのロックとして使われます。 グローバルスコープ
$? Process::Status, nil このスレッドで最後に終了した子プロセスのステータスです。Process::Status オブジェクトが入っています。 子プロセスの終了時ステータスは Process::Status#exitstatus で得られます。 スレッドローカル、読み取り専用
$$ Fixnum 現在実行中の Ruby プロセスのプロセス ID です。 Process.#pid と同じです。 グローバルスコープ
$VERBOSE
$-v
$-w
bool, nil 冗長メッセージフラグです。Rubyインタプリタへの コマンドラインオプション -v でセットされます。警告レベルは三段階あり、それぞれ以下の通りです。
nil : 警告を出力しない
false : 重要な警告のみ出力 (デフォルト)
true : すべての警告を出力する
$VERBOSEはグローバルスコープ
$-W 0, 1, 2 コマンドラインオプション -W を指定したとき、 そのコマンドライン引数の値が設定されます。 グローバルスコープ、読み取り専用
$DEBUG
$-d
bool この値が真のときはインタプリタがデバッグモードになります。 グローバルスコープ
$0
$PROGRAM_NAME
String 現在実行中の Ruby スクリプトの名前を表す文字列です。 グローバルスコープ
$1
$2
$3
$4…
String, nil 最後に成功したパターンマッチで n 番目の括弧にマッチした値が格納されます。 該当する括弧がなければ nil が入っています。(覚え方: \数字 のようなもの)番号 n はいくらでも大きな正整数を利用できます。 ローカルスコープかつスレッドローカル、読み取り専用
$-p bool コマンドラインオプション -p を指定したとき true に設定されます。 この変数には代入できません。 グローバルスコープ、読み取り専用
$-l bool コマンドラインオプション -l を指定したとき true に設定されます。 この変数には代入できません。 グローバルスコープ、読み取り専用
$-a bool 自動 split モードを表すフラグです。コマンドラインオプション -a を使ったとき true に設定されます。 この変数には代入できません。 グローバルスコープ、読み取り専用

組み込み定数(Ruby Predefined Constants)

定数 概要
TRUE true と同義
FALSE false と同義
NIL nil と同義
ARGF $< と同義。引数(なければ標準入力)で構成される仮想ファイル。
ARGV $* と同義。Rubyスクリプトに与えられた引数。
DATA スクリプトの __END__ (スクリプトの終り) 以降をアクセスする File オブジェクト。
ENV 環境変数を表す(疑似)連想配列。
RUBY_PLATFORM Rubyインタプリタのプラットフォームを示す文字列。
RUBY_RELEASE_DATE Rubyインタプリタのリリース日を示す文字列。
RUBY_VERSION Rubyインタプリタのバージョンを示す文字列。
STDERR 標準エラー出力。 $stderr のデフォルト値。
STDIN 標準入力。 $stdin のデフォルト値。
STDOUT 標準出力。 $stdout のデフォルト値。
TOPLEVEL_BINDING トップレベルでのバインディングオブジェクト。

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

Omiseのテストカードをウェブサイトから調べる手間を省く方法としてGem(omise_test_cards)を公開しました。

f:id:akinrt:20170310170758p:plain

omise_test_cards のインストール

gem install omise_test_cards

Pryでちょっと動かしてみる

cards = OmiseTestCards.test_cards

cards.successful_charge.code
# => "successful_charge"

cards.successful_charge.description
# => "these credit card numbers can be used in test mode"

cards.successful_charge.cards
# => <Hashie::Array [#<Hashie::Mash brand="Visa" number="4242424242424242">, #<Hashie::Mash brand="Visa" number="4111111111111111">, #<Hashie::Mash brand="MasterCard" number="5555555555554444">, #<Hashie::Mash brand="MasterCard" number="5454545454545454">, #<Hashie::Mash brand="JCB" number="3530111333300000">, #<Hashie::Mash brand="JCB" number="3566111111111113">]>

cards.successful_charge.cards.first.brand
# => Visa

cards.successful_charge.cards.first.number
# => 4242424242424242

ちなみに、Omiseのテストカードは10種類のステータス別のカードがあります。

cards = OmiseTestCards.test_cards

cards.successful_charge
cards.invalid_security_code
cards.fail_3ds_card_enrollment
cards.fail_3ds_card_validation
cards.insufficient_fund
cards.stolen_or_lost_card
cards.failed_processing
cards.payment_rejected
cards.failed_fraud_check
cards.invalid_account_number

このうちの cards.successful_charge に含まれるカードのいずれも、正常にテストでChargeができるカードになります。 それ以外のカードは、利用できないステータスなので、charge.paid? でChargeに失敗して入れば、 charge.failure_code を見て、エラー処理を入れてあげるといいでしょう!

Omise RubyライブラリはOmiseErrorをraiseするので、こんな感じでテストするといいですね。

require "omise"
require "omise_test_cards"

Omise.api_key = "SET_YOUR_TEST_SECRET_KEY"
Omise.vault_key = "SET_YOUR_TEST_PUBLIC_KEY"

# get sampla card
sample_card = OmiseTestCards.test_cards.successful_charge.cards.first

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

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

  if charge.paid
    # handle success
    puts "thanks"
  else
    # handle failure
    raise charge.failure_code
  end
rescue OmiseError => e
  # handle OmiseError raised by omise library
  raise e.message
end

リンク

github.com

omise_test_cards | RubyGems.org | your community gem host