LoginSignup
4
2

More than 3 years have passed since last update.

Stripe調査(クレジットカード・オンライン決済)

Posted at

オンライン決済サービスを調査。

どのサービスを使うかという点

何個かのサービスを比べてみた

  • 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
    }
  }
}
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2