84
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails 入門】Stripe API

Posted at

はじめに

stripe とは

決済代行サービスです(類似サービスとしてはPayPalがあります)。

具体的に説明すると、stripeのAPIを使う(stripeのサービスプラットフォームを使う)ことで、自身のサービスの決済処理を担ってくれます!

つまり、

  • ユーザーにお金を請求してその支払を受け取りたい!
  • 「買切り」や「定額プラン」を設定して請求したい!

といったことが可能になります。

私がstripeの特に良いと思ったところは、ユーザーがstripeのアカウントがなくても支払ができるということです。

アカウント作成の手間を省けるのは、UXとして大事な要素だと思います!

また、ドキュメントが読みやすいですね。
英語なので読めない人にとっては辛いかもしれないですが、よくまとまっていると思います(そういった方々のために少しでも記事が参考になれば幸いです)。

そこで今回は、**Railsで処理を行うStripe API(バックエンド側)**を説明いたします!

(stripeの決済処理を実現するためには、フロントエンドとしてJavascript、Vueなどを使い、クレジットカード情報の入力を処理する stripe checkoutstripe element などの実装や、バックエンド側に送信してあげる処理が必要となりますが、今回はバックエンド側の処理にフォーカスを当てています!)

stripeで何をやりたい?

Railsでstripeを実装するとなると、

顧客情報をstripeに登録し、その際に作られた顧客IDを中心にその他の課金等の処理を実行する

というのが実装の方針になるかと考えています。

それはなぜかと言うと、この顧客IDcus_xxxxxxxxxxxxxx)を取得してしまえば、その顧客に対して定期課金や登録しているクレジットカードの削除などの処理を行えば良いからです!

後で詳しく説明しますが、この顧客IDをもとにstripe側からクレジットカードの情報や、課金の内容等を取得することができるようになります。

以下のように機能ごとにまとめましたので、適宜やりたい内容の箇所に飛んで確認して下さい!
(掲載しているものは特に使用頻度の高いAPIとなっていますが、その他にも沢山ありますので是非チャレンジしてみて下さい!)

顧客管理

クレジットカード管理

課金

サービスプラン

Stripe APIを利用するための準備

stripeのサービス登録や、本番環境利用の申請等の準備は行っている前提でご説明しますね。

stripe gemのインストール

Gemfileに以下を追加し、bundle installをして下さい。

Gemfile
gem "stripe"

シークレットキーの設定

Rails(ruby)でstripeのAPIを利用するためには、アプリケーションにシークレットキーを設定する必要があります。

そのシークレットキーはstripeのダッシュボード(開発者→APIキー)から確認することができます。

画面左側下あたりのテストデータの表示中トグルをONにするとテスト用のシークレットキー、OFFにすると本番環境用のシークレットキーを取得することができます

参考に、テスト用のシークレットキー記載箇所の画像を添付しますね。

for_qiita.jpg

ここで重要なポイントがあり、このシークレットキー(特に本番用)はセキュリティ上、直でアプリケーションに入力するのは望ましくありません。

Rails5.2から追加されたcredentials.yml.encを使用したシークレットキーの参照をおすすめいたします。

今回の記事でシークレットキーを記述すべきところは、テスト用のシークレットキーを利用するという前提で、以下のように定数STRIPE_TEST_SECRET_KEYを使用して解説します。

Stripe.api_key = STRIPE_TEST_SECRET_KEY

シークレットキーは以下の場所に追加し、いつでもstripeのAPIにアクセスできる状態にしておきましょう!

config/initializers/stripe.rb
Stripe.api_key = STRIPE_TEST_SECRET_KEY
Stripe.api_version = "2020-03-02" # 最新のバージョンにしましょう

stripe APIの実装場所

単体クラスとしてlib/autoloads/payment.rbに私は実装しています。

config/application.rbに以下内容を追加すると、lib/autoloads配下のクラスを読むようになります。

config/application.rb
config.autoload_paths += %W[#{config.root}/lib/autoloads]

顧客管理

顧客登録

顧客登録のAPIであるStripe::Customer.createに実装方法が記載されていますが、私は以下のような実装を行っています。

lib/autoloads/payment.rb
class Payment
  def self.register_customer(card_token)
    Stripe::Customer.create({
      source: card_token,
    })
  end
end

このStripe::Customer.create内にあるキーsourcecard_token(変数名は自由に定義できます)をペアの値として設定しています。

このcard_tokenには、**ユーザーのクレジットカード情報をstripeが暗号化したもの(トークン)**がパラメータとして渡されなければなりません。

実際の流れで説明すると、

  1. ユーザーがクレジットカードの登録フォームに自身のクレジットカード情報を入力
  2. そのクレジットカード情報がフロントエンドを通してstripeで暗号化される
  3. その暗号化されたものをトークンとしてバックエンド(今回使用するRails側)に渡す
  4. そのトークン(card_token)をもとにStripe::Customer.create(stripeの顧客登録API)を行うことで、stripe側へ顧客情報(クレジットカード情報)を登録する

のようになっています!

その結果として、

  • ユーザーの顧客ID(cus_xxxxxxxxxxxxxx
  • 登録したクレジットカード情報(card_xxxxxxxxxxxxxxxxxxxxxxxx

を含む以下のような様々な情報が登録されます!

customer = Payment.register_customer("tok_visa")
=> #<Stripe::Customer:0x3fd2df28f888 id=cus_xxxxxxxxxxxxxx> JSON: {
  "id": "cus_xxxxxxxxxxxxxx",
  "invoice_prefix": "xxxxxxxx",
  "invoice_settings": {"custom_fields":null,"default_payment_method":null,"footer":null},
  "livemode": false,
  # 略
  "sources": {"object":"list","data":[{"id":"card_xxxxxxxxxxxxxxxxxxxxxxxx","object":"card","address_city":null # 続く
  # 略
}

# 上記メソッドの返り値である customer の参照例(顧客ID、クレジットカードID)
customer.id => "cus_xxxxxxxxxxxxxx"
customer.sources["data"][0].id => "card_xxxxxxxxxxxxxxxxxxxxxxxx"

このtok_visaはテスト用にstripeが準備したトークンで、このトークン以外にもテスト用に必要となるパラメータはこちらで準備されています。

実際のトークンはtok_xxxxxxxxxxxxxxxxxxxxxxxxのような文字列になっています。

それでは、このsourceは顧客登録のAPIに本当に必要なのか?というと、実はそうではありません。

公式リファレンスでは、

Stripe::Customer.create({
  description: 'My First Test Customer (created for API docs)',
})

となっており、このdescription(ダッシュボードで表示される説明欄の内容)のパラメータを渡すだけでも顧客登録ができます。

つまり、このAPIを使うにあたって入力が必須なパラメーターはありません
が、sourcedescriptionemailなど、自身が顧客登録に必要と考える何らかのパラメーターを渡してあげましょう!

それではなぜ私はsource(クレジットカードのトークン情報)を採用しているのか?

通常のアプリの流れを考えると、ユーザーが初めてサービスの支払(課金)を登録する際は、必ずクレジットカード情報を登録するはずです。

ですので、初回のクレジットカード登録時に一緒にstripeの顧客登録を行うことが望ましいと考えています!

顧客情報の取得

Stripe::Customer.retrieveのAPIを使用します。

lib/autoloads/payment.rb
  def self.fetch_customer(customer_id)
    Stripe::Customer.retrieve(customer_id)
  end
customer = Payment.fetch_customer("cus_xxxxxxxxxxxxxx")
=> #<Stripe::Customer:0x3fd91a7a72a8 id=cus_xxxxxxxxxxxxxx> JSON: {
  "id": "cus_xxxxxxxxxxxxxx",
  "object": "customer",
  "address": null,
  "balance": 0,
  "created": 1234567890,
  "currency": "jpy",
  "default_source": "card_xxxxxxxxxxxxxxxxxxxxxxxx",
  # 略
  "subscriptions": {"object":"list","data":[{"id":"sub_xxxxxxxxxxxxxx","object":"subscription" #続く
  # 略
}

# 参照例(ユーザーの特定の定期課金ID)
customer.default_source => "card_xxxxxxxxxxxxxxxxxxxxxxxx"
customer.subscriptions["data"][0].id => "sub_xxxxxxxxxxxxxx"

以上のように、この顧客情報の取得のAPIを使用すると、

顧客IDを入力するだけで登録しているクレジットカード情報や、定期課金の情報な、顧客に関する様々な情報にアクセスすることが可能になります。

この顧客IDだけというのが何を意味するのか?

それは、バックエンド側のDBに保存しておくべきものは、基本的に顧客IDのみであるということです。

後ほど説明する定期課金の処理で取得する定期課金ID("sub_xxxxxxxxxxxxxx")も、この顧客情報の取得を行うだけで参照が可能となります!

顧客削除

Stripe::Customer.deleteを利用します。

lib/autoloads/payment.rb
  def self.delete_customer(customer_id)
    Stripe::Customer.delete(customer_id)
  end
customer = Payment.delete_customer("cus_xxxxxxxxxxxxxx")
=> #<Stripe::Customer:0x3fccb338da00 id=cus_xxxxxxxxxxxxxx> JSON: {
  "id": "cus_xxxxxxxxxxxxxx",
  "object": "customer",
  "deleted": true
}

# 参照例
customer.deleted => true

クレジットカード

クレジットカード登録

**Stripe::Customer.create_source**を使用します。

sourceは入力必須のパラメータです。
指定した顧客のクレジットカードを登録するため、顧客ID(cus_xxxxxxxxxxxxxx)もパラメータとして入力しましょう。

lib/autoloads/payment.rb
  def self.register_card(customer_id:, card_token:)
    Stripe::Customer.create_source(
      customer_id,
      { source: card_token },
    )
  end
card = Payment.register_card(customer_id: "cus_xxxxxxxxxxxxxx", card_token: "tok_visa")
=> #<Stripe::Card:0x3fd0cfbc59c8 id=card_xxxxxxxxxxxxxxxxxxxxxxxx> JSON: {
  "id": "card_xxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "card",
  "address_city": null,
  "address_country": null,
  # 略
}

# 参照例
card.id => "card_xxxxxxxxxxxxxxxxxxxxxxxx"

クレジットカード削除

**Stripe::Customer.delete_source**を使用します。

lib/autoloads/payment.rb
  def self.delete_card(customer_id:, card_id:)
    Stripe::Customer.delete_source(
      customer_id,
      card_id,
    )
  end

このAPIではcard_idが必要となります。
これはどのように取得すれば良いでしょうか?

答えは、先程解説した顧客情報の取得の使用です!

顧客情報の取得で得られるデータには様々な情報が格納されていることから、今回説明していないstripeのAPIについても積極的に顧客情報の取得を使用するようにしましょう!

RailsのDBに保存するのは基本顧客IDぐらいで、それ以外は都度参照するような方針で実装するようになります。

card_id = Payment.fetch_customer("cus_xxxxxxxxxxxxxx").default_source

card = Payment.delete_card(customer_id: "cus_xxxxxxxxxxxxxx", card_id: card_id)
=> #<Stripe::Card:0x3fc7b95d2ddc id=card_xxxxxxxxxxxxxxxxxxxxxxxx> JSON: {
  "id": "card_xxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "card",
  "deleted": true
}

# 参照例
card.deleted => "true"

課金

一回課金(売り切り)

Stripe::Charge.createのAPIを使用します。

入力が必須なパラメータは2つですが、請求する顧客を指定する必要があるので、合わせてcustomerに顧客IDを入力させましょう(必要に応じて公式リファレンスを参考に追加して下さい)。

  • amount(金額)
  • currency(通貨)
  • customer(顧客ID)
lib/autoloads/payment.rb
  def self.one_time_charge(price:, customer_id:)
    Stripe::Charge.create({
      amount: price,
      currency: "jpy", # 請求通貨は円で固定していますが変更可能です
      customer: customer_id,
    })
  end
charge = Payment.one_time_charge(price: 1000, customer_id: "cus_xxxxxxxxxxxxxx")
=> #<Stripe::Charge:0x3fde477a6510 id=ch_xxxxxxxxxxxxxxxxxxxxxxxx> JSON: {
  "id": "ch_xxxxxxxxxxxxxxxxxxxxxxxx",
  "object": "charge",
  "amount": 1000,
  "amount_refunded": 0,
  # 略
}

# 参照例
charge.id = "ch_xxxxxxxxxxxxxxxxxxxxxxxx"
charge.amount => 1000
charge.paid => true
charge.status => "succeeded"

定期課金(月額契約など)

Stripe::Subscription.deleteのAPIを使用します。

入力が必須なパラメータは以下の2つです。

  • customer(顧客ID)
  • items (plan)(課金するサービスプラン)
lib/autoloads/payment.rb
  def self.subscribe(customer_id:, plan_id:)
    Stripe::Subscription.create({
      customer: customer_id,
      items: [{ plan: plan_id }],
    })
  end

このplan_idは、後ほどサービスプラン登録で説明しますね。

subscription = Payment.subscribe(customer_id: "cus_xxxxxxxxxxxxxx", plan_id: "plan_xxxxxxxxxxxxxx")
=> #<Stripe::Subscription:0x3fc5c0ab0430 id=sub_xxxxxxxxxxxxxx> JSON: {
  "id": "sub_xxxxxxxxxxxxxx",
  "object": "subscription",
  "application_fee_percent": null,
  # 略
  "plan": {"id":"plan_H6GDh7cO9gRfLy","object":"plan","active":true # 続く
  # 略
}

# 参照例
subscription.id = "sub_xxxxxxxxxxxxxx"
subscription.plan.id = "plan_xxxxxxxxxxxxxx"
subscription.plan.product => "pro_xxxxxxxxxxxxxx"

定期課金解除

Stripe::Subscription.deleteのAPIを使用します。

メソッドの引数として使用する定期課金ID(subscription_id)は、サービスプランが同じであっても、
各ユーザーごとに違うものであるのでご注意下さい!

subscription_idcard_idと同様に、顧客情報の取得で参照することが可能です!

lib/autoloads/payment.rb
  def self.unsubscribe(subscription_id)
    Stripe::Subscription.delete(subscription_id)
  end
subscription_id = Payment.fetch_customer("cus_xxxxxxxxxxxxxx").subscriptions["data"][0].id

subscription = Payment.unsubscribe(subscription_id)
=> #<Stripe::Subscription:0x3fcfb856c580 id=sub_xxxxxxxxxxxxxx> JSON: {
  "id": "sub_xxxxxxxxxxxxxx",
  "object": "subscription",
  "application_fee_percent": null,
  # 略
  "status": "canceled",
  "tax_percent": null,
  "trial_end": null,
  "trial_start": null
}

# 参照例
subscription.status => "canceled"

サービスプラン

サービスプラン登録

サービスプランについては、Rails側で管理するよりも、stripeのダッシュボードから設定を行う方が内容も充実しているので良いと思います。

Railsの内容ではないですが、サービスプラン登録の手順を軽くご説明します(変更や削除は解説しません)。

まずはダッシュボード左のBilling商品の順に進み、商品の登録と、プランを決めていきます。

ここでいう商品とは、Netflixの動画配信サービスのようなものを指し、プランとは、Netflixのサービスプランである、ベーシックスタンダードプレミアムのようなものです。

商品IDとプランIDはそれぞれ

  • prod_xxxxxxxxxxxxxx(商品ID)
  • plan_xxxxxxxxxxxxxx(プランID)

となっており、plan_xxxxxxxxxxxxxxについては、定期課金のパラメータとして使用するので確認しておく必要があります。

参考として操作画面を添付しますね。

  • 商品登録画面
    image.png

  • プラン内容登録画面

image.png

  • 作成した商品、プランの概要画面

image.png

84
76
3

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
84
76

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?