オンライン決済サービスを調査。
どのサービスを使うかという点
何個かのサービスを比べてみた
- stripe
- paypal
- Gmoペイメントゲートウェイ
- Pay.jp
料金についてGMOは決済手数料以外に固定費がかかるので厳しい(サポートは厚そう)。
基本はstripeとpaypal中心で比較。
料金もどちらも基本無料。決済額に応じてn%(3%前後)。
対応カードも主要な所はOK。StripeがApplePay、GooglePayにも対応している。
利用開始の手軽さは間違いなくstripe。paypalはサービスの開始はすぐ出来るが、引き落とし可能になるまで審査などがある。セキュリティなどの信頼はpaypalか。
ただしpaypalは利用者がアカウントを作成する必要があり、ユーザーとしてはハードルが高そう。
開発が柔軟そうなのはstripeか。(Stripe はデベロッパー・ファーストを掲げ、開発着手の容易さをウリの一つにしている。とのこと)
そもそも、paypalアカウントを作らないと行けないというのが一ハードルが高そう。
Pay.jpは手数料低いし、日本の会社だからドキュメントも日本語で助かるがー...規模的に一旦除外。(サービス終了が怖い)
なので、取り敢えずStripeとする。
[参考リンク]
stripe・paypal比較
https://web.analogstd.com/tips/posts/web/compare-paypal-stripe.php
https://commerce-media.info/blogs/ec/shopify-paypal
https://n10shop.com/post-49191/
2021クレジットカード決済比較
https://notepm.jp/blog/2937
OMISEとPAY.JPの比較
https://www.puti-banbeena.com/cgi/2018/10/24/omise_or_payjp/
Stripe機能調査
取り敢えず簡単に動かす
CheckoutというStripe側に遷移して行う機能あり。これで良いなぁと思う。
https://stripe.com/jp/payments/checkout
https://stripe.com/docs/checkout/integration-builder
https://qiita.com/piggydev/items/c70630b5194406ca0e88
遷移はしない。cardという人まとまりのフォームを生成するか、一つずつ個別にフォームを作成する。
Stripe Elementsを使う。入力フォームごとにオブジェクトを生成してHTML上にmountするという使い方。
cardというオブジェクトでまとめて一つのフォームを作成出来る。
cardNumber、MM、 YY、 CVCなど個別に作成することも出来る。
カスタマイズパターン例
https://stripe.dev/elements-examples/
そもそもStripe Elementsも使わないパターン
Number, exp_month, exp_year、cvcを以下APIにでcard_tokenを取得することが出来る。
https://stripe.com/docs/api/tokens/create_card
https://stripe.com/docs/api/tokens
このtokenで決済出来る。わかりやすい。フォームのカスタマイズを想定するなら、これが一番やりやすそう。
カード情報を保存したい
stripeはこれも出来る。ありがたや。アプリ側で持つのではなくて、Stripeに保存出来る。
あとでカード番号などの編集はできない。編集する場合は削除+追加という流れになる。
customerを作成してそのsourceにcard_tokenをセットするという流れ。
以後は、customerをから、関連するsource情報を取得する。
下4桁は表示出来る。
ちょっと用語の確認
- charge = 売り切りの決済オブジェクト。chargeをcreateで決済する
- subscription = 継続課金のオブジェクト。subscriptionをcreateして決済する。次回以降は勝手に決済してくれる
- customer = 顧客オブジェクト。適当に作成出来る。アプリ側にcustomer_idを持って、そのidでstripeから各データを取得したり、決済するのが基本的な使い方で良さそう。
- source = カード情報など決済情報はsourceに保存する。customerオブジェクト必須。
もうちょっと理解
そもそもStripeでの決済のフロー (わかりやすかった)
https://qiita.com/y_toku/items/7e51ef7e69d7cbbfb3ca
APIリファレンス
https://stripe.com/docs/api
Rubyでの各決済関連処理の実装例 (参考になった)
https://qiita.com/tomokazu0112/items/89f69c47761ac782ce13
⇒subscriptionの登録はサービスプランとなっていて情報が古そう、シンプルにリファレンスのやり方でできた。詳細は後述。
https://stripe.com/docs/api/subscriptions/create
ここまで苦労した所
- customerを取得するときに、カード情報や設定しているsubscriptionを取得するときexpandしないと取れない場合がある。リファレンスでのそのプロパティにEXPANDABLEとあったら以下のようにexpandで項目名を指定する。
customer = Stripe::Customer.retrieve({
id:@@custmer_id,
expand:['sources'],
})
- chekcoutとかEelemnts使うと簡単にフォームは生成出来る。入力チェックとかもしっかりしているし。
- でもchekcoutとかEelemntsとかの前に取り敢えず、「card情報を入力してSDKなり、APIでTokenを生成して、そのTokenを使って決済が出来る」と理解しておけば良さそう。無理してSDK使わんで良い。
- Elementsを使うと、サンプルではcardオブジェクトを引数にtokenを作成するが、cardNumberオブジェクトを引数にしても出来る。
- テストモードのAPIキーで実行した決済などでは、領収書の自動メールは送信されない。
- token生成APIにリクエストするときに、application/jsonではエラーになり、application/x-www-form-urlencodedでないと上手くいかなかった。そのためjsでfetchする場合も以下リンクのようにqueryを作らないとエラーになってしまう....https://bigbinary.com/blog/using-stripe-api-in-react-native-with-fetch
サブスクリプション決済関連 詳細調査
サブスクリプションの決済について、もうちょっと調査実施
customerをexpandしてsubscriptionを取得すると、activeなものだけ取得出来る。
cancelしたものも取得したければ 以下のようにstatsuで調整する。
Stripe::Subscription.list(
{
customer: custmer_id,
status: :all
}
)
cancelについて
- APIにて、subscription.deleteを実行すると即時キャンセルとなり、statusがcanceledとなる。
- キャンセル時に、購入済みの期間が終わるまで継続という場合は、cancel_at_period_endをtrueにして対応する。
stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true
})
https://www.366service.com/jp/qa/730d74e478b36566a472e3d5a08a936b
https://wp-kyoto.net/cancel-stripe-billing/
prorateについてはまだ良くわから無い...
返金について
取り敢えず管理画面から、任意の金額で返金は出来る。便利ー。
ただし、手数料は戻らないので注意。
stripeとアプリのデータ同期まわり
stripeでイベントが発生したときに、すぐにアプリとデータ連携したい場合は、webhook機能がある。
それをトリガーとしてアプリ側で更新などを行うことになる。
https://stripe.com/docs/webhooks
選択可能なイベントは管理画面で選択する所で確認出来る。
例として "customer.subscription.deleted"の場合以 下のようなデータが送信される。dataとして削除されたsubscriptionオブジェクトが渡されている。
{
"created": 1326853478,
"livemode": false,
"id": "evt_00000000000000",
"type": "customer.subscription.deleted",
"object": "event",
"request": null,
"pending_webhooks": 1,
"api_version": "2020-08-27",
"data": {
"object": {
"id": "sub_00000000000000",
"object": "subscription",
"application_fee_percent": null,
"billing_cycle_anchor": 1610505452,
"billing_thresholds": null,
"cancel_at": null,
"cancel_at_period_end": false,
"canceled_at": 1610934767,
"collection_method": "charge_automatically",
"created": 1610505452,
"current_period_end": 1610937452,
"current_period_start": 1610851052,
"customer": "cus_00000000000000",
"days_until_due": null,
"default_payment_method": "pm_1I8zElDFW27RwAFON0UF6nQz",
"default_source": null,
"default_tax_rates": [
],
"discount": null,
"ended_at": 1610948851,
"items": {
"object": "list",
"data": [
{
"id": "si_00000000000000",
"object": "subscription_item",
"billing_thresholds": null,
"created": 1610505453,
"metadata": {
},
"price": {
"id": "price_00000000000000",
"object": "price",
"active": true,
"billing_scheme": "per_unit",
"created": 1610505247,
"currency": "jpy",
"livemode": false,
"lookup_key": null,
"metadata": {
},
"nickname": null,
"product": "prod_00000000000000",
"recurring": {
"aggregate_usage": null,
"interval": "day",
"interval_count": 1,
"usage_type": "licensed"
},
"tiers_mode": null,
"transform_quantity": null,
"type": "recurring",
"unit_amount": 100,
"unit_amount_decimal": "100"
},
"quantity": 1,
"subscription": "sub_00000000000000",
"tax_rates": [
]
}
],
"has_more": false,
"url": "/v1/subscription_items?subscription=sub_IkUD7xWhwqBRyv"
},
"latest_invoice": "in_1IAR9uDFW27RwAFOYiA3UjEB",
"livemode": false,
"metadata": {
},
"next_pending_invoice_item_invoice": null,
"pause_collection": null,
"pending_invoice_item_interval": null,
"pending_setup_intent": null,
"pending_update": null,
"schedule": null,
"start_date": 1610505452,
"status": "canceled",
"transfer_data": null,
"trial_end": null,
"trial_start": null
}
}
}