今回はこの機能について調べた。
Stripe CLI
Stripeは開発のためのいくつかの機能をCLIとして提供している1。
インストール
Homebrewからインストールできる。
brew install stripe/stripe-cli/stripe
またその他のインストール方法についてもドキュメントに記載されている。
ログイン
stripe-cliをインストールするとstripeコマンドが使えるようになる。 まずはstripeコマンドをログイン状態にする。
stripe login
実行するとURLが表示される。Enterキーを入力するとWebブラウザに遷移し、 Stripeへのログインを求められる。
Your pairing code is: XXXXX-XXXXXX-XXXXXXXXX-XXXXXX This pairing code verifies your authentication with Stripe. Press Enter to open the browser or visit https://dashboard.stripe.com/stripecli/confirm_auth?t=XXXXXXXXXXXXXXXXXXXXXXXX (^C to quit)
ログインするとペアリングコードを確認するメッセージが表示される。ターミ ナル上に表示されているペアリングコードと同じかどうかを目視で確認し、同 じであれば許可ボタンをクリックする。
⣻ Waiting for confirmation... > Done! The Stripe CLI is configured for example with account id XXXX_XXXXXXXXXXX Please note: this key will expire after 90 days, at which point you'll need to re-authenticate.
ログイン処理が完了すると ~/.config/stripe/config.toml
が作成され、その中にAPIキーなどが記述される。
ここで登録されるAPIキーの有効期限は90日である。
Stripeで発生するイベントをWebhookで受け取る
決済サービスのStripeにはWebookの機能があり、イベントが発生するとhttps経由で通知する2。
Stripel CLIを用いてイベントをWebhookとして受信する
Webhookはインターネットにエンドポイントを公開し、Stripeがそのエンポイ ントにリクエストを送信する。そのため、インターネットからアクセス可能な サーバーを準備するなどの作業が必要になる。または開発時はNgrokのような サービスを用いることもできる。
StripeではStripe CLIを用いることでインターネットからのアクセスを受け付
けるようなエンドポイントを準備することなく、Webhookの機能をテストを可
能にする機能を提供している。そのために stripe listen
を用いる。
stripe listen --forward-to localhost:8000
stripe listen
はStripeと通信し、発生したイベントを受け取る。そしてそ
の受け取ったイベントを --forward-to
で指定したところへ転送する。
+--------------------------------+
| |
| local |
| |
+----------------+ | +----------------+ |
| | | | | |
| Stripe +<---------------->| Stripe CLI | |
| | | | | |
-----------------+ | ------+----------+ |
| | |
| | forward-toで指定 |
| | |
| | |
| v |
| +-----+----------+ |
| | | |
| | 開発用サーバー | |
| | | |
| +----------------+ |
| |
+--------------------------------+
PythonでStripeのWebhookのハンドラを実装する
StripeのWebhookを受信する実装に言語的な制限はない。ここでは例として、 Pythonを用いてAPIを実装する。直接使用するライブラリは、stripeパッケー ジ以外は標準ライブラリを用いることにする。
incoming_webhook_handler.py::
from http.server import BaseHTTPRequestHandler, HTTPServer
import stripe
stripe_webhook_signing_secret = "DUMMY"
class StripeWebhookSimpleHandler(BaseHTTPRequestHandler):
def do_POST(self):
body_size_str: str = self.headers.get("Content-Length", "10")
if body_size_str.isdigit():
body_size = int(body_size_str)
else:
body_size = 10
payload = self.rfile.read(body_size)
sig_header = self.headers["Stripe-Signature"]
event = stripe.Webhook.construct_event(
payload=payload,
sig_header=sig_header,
secret=stripe_webhook_signing_secret,
)
print(event)
server = HTTPServer(("localhost", 8000), StripeWebhookSimpleHandler)
server.serve_forever()
以下のように実行する。
incoming_webhook_handler.py
起動したらインターネットに公開するか、前述したStripe CLIの機能を用いてイベントを受信する。 もちろん実際にWebhookを受け取ることも可能だが、SSL/TLS対応はしていないため、その場合、サーバー証明書を用意し適切にSSL終端をする必要がある。
Webhookでは拡張属性を利用できない
Webhookでは拡張属性(ドキュメントにexapandableと指定がある)は 用いることができない5。例えばcardオブ ジェクトのcustomer属性は拡張属性のため、cardに関連するイベントでは customerの情報(例えば顧客IDなど)を取得できない。取得するためには別途 APIを呼び出して取得する旨記述されていた。そのため必要な情報は予め保存 しておくケースが多いと考えられる。
StripeからのリクエストをIPアドレスで制限する
Stripeから送信されるWebhookは必ず特定のIPアドレスから送信され る6。Webhookを受け取る際はこのIPアド レスから来たリクエストかを検証する必要がある。
Stripe API
Stripeで決済やそれに関連する操作を行うにはいくつかの方法がある。 その中の一つにWeb APIを直接呼び出す方法がある。
カードトークンの発行
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_PUBLIC_KEY := (getenv "STRIPE_PUBLIC_KEY")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:DUMMY_CREDIT_CARD_NUMBER := (getenv "DUMMY_CREDIT_CARD_NUMBER")
:DUMMY_CREDIT_CARD_EXP_MONTH := (getenv "DUMMY_CREDIT_CARD_EXP_MONTH")
:DUMMY_CREDIT_CARD_EXP_YEAR := (getenv "DUMMY_CREDIT_CARD_EXP_YEAR")
:DUMMY_CREDIT_CARD_CVC := (getenv "DUMMY_CREDIT_CARD_CVC")
POST :STRIPE_API_ORIGIN/v1/tokens
card[number]=:DUMMY_CREDIT_CARD_NUMBER&card[exp_month]=:DUMMY_CREDIT_CARD_EXP_MONTH&card[exp_year]=:DUMMY_CREDIT_CARD_EXP_YEAR&card[cvc]=:DUMMY_CREDIT_CARD_CVC&key=:STRIPE_PUBLIC_KEY
顧客の作成
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
POST :STRIPE_API_ORIGIN/v1/customers
Authorization: Bearer :STRIPE_SECRET_KEY
description="test2"
支払方法の登録
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:DUMMY_CREDIT_CARD_NUMBER := (getenv "DUMMY_CREDIT_CARD_NUMBER")
:DUMMY_CREDIT_CARD_EXP_MONTH := (getenv "DUMMY_CREDIT_CARD_EXP_MONTH")
:DUMMY_CREDIT_CARD_EXP_YEAR := (getenv "DUMMY_CREDIT_CARD_EXP_YEAR")
:DUMMY_CREDIT_CARD_CVC := (getenv "DUMMY_CREDIT_CARD_CVC")
POST :STRIPE_API_ORIGIN/v1/payment_methods
Authorization: Bearer :STRIPE_SECRET_KEY
type=card&card[number]=:DUMMY_CREDIT_CARD_NUMBER&card[exp_month]=:DUMMY_CREDIT_CARD_EXP_MONTH&card[exp_year]=:DUMMY_CREDIT_CARD_EXP_YEAR&card[cvc]=:DUMMY_CREDIT_CARD_CVC
カードトークンを使用した支払方法の登録
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_CARD_TOKEN := (getenv "STRIPE_CARD_TOKEN")
POST :STRIPE_API_ORIGIN/v1/payment_methods
Authorization: Bearer :STRIPE_SECRET_KEY
type=card&card[token]=:STRIPE_CARD_TOKEN
支払い方法のアタッチ
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_PAYMENT_METHOD_ID := (getenv "STRIPE_PAYMENT_METHOD_ID")
:STRIPE_CUSTOMER_ID := (getenv "STRIPE_CUSTOMER_ID")
POST :STRIPE_API_ORIGIN/v1/payment_methods/:STRIPE_PAYMENT_METHOD_ID/attach
Authorization: Bearer :STRIPE_SECRET_KEY
customer=:STRIPE_CUSTOMER_ID
支払い情報を作成
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_PAYMENT_METHOD_ID := (getenv "STRIPE_PAYMENT_METHOD_ID")
:STRIPE_CUSTOMER_ID := (getenv "STRIPE_CUSTOMER_ID")
POST :STRIPE_API_ORIGIN/v1/payment_intents
Authorization: Bearer :STRIPE_SECRET_KEY
confirmation_method=manual&amount=500¤cy=jpy&payment_method_types[]=card&customer=:STRIPE_CUSTOMER_ID&payment_method=:STRIPE_PAYMENT_METHOD_ID
キャプチャー
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:PAYMENT_INTENT_ID := (getenv "PAYMENT_INTENT_ID")
:PAYMENT_METHOD_ID := (getenv "PAYMENT_METHOD_ID")
POST :STRIPE_API_ORIGIN/v1/payment_intents/:PAYMENT_INTENT_ID/capture
Authorization: Bearer :STRIPE_SECRET_KEY
確認
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_PAYMENT_INTENT_ID := (getenv "STRIPE_PAYMENT_INTENT_ID")
:STRIPE_PAYMENT_METHOD_ID := (getenv "STRIPE_PAYMENT_METHOD_ID")
POST :STRIPE_API_ORIGIN/v1/payment_intents/:STRIPE_PAYMENT_INTENT_ID/confirm
Authorization: Bearer :STRIPE_SECRET_KEY
payment_method=:STRIPE_PAYMENT_METHOD_ID
従量課金の量を設定する
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_USAGE_RECORD_ID := (getenv "STRIPE_SECRET_KEY")
:TIMESTAMP = 1615283548
POST :STRIPE_API_ORIGIN/v1/subscription_items/:STRIPE_USAGE_RECORD_ID/usage_records
Authorization: Bearer :STRIPE_SECRET_KEY
quantity=1×tamp=:TIMESTAMP
定期購読の作成
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_CUSTOMER_ID := (getenv "STRIPE_CUSTOMER_ID")
:STRIPE_PRICE_ID := (getenv "STRIPE_PRICE_ID")
POST :STRIPE_API_ORIGIN/v1/subscriptions
Authorization: Bearer :STRIPE_SECRET_KEY
customer=:STRIPE_CUSTOMER_ID&items[0][price]=:STRIPE_PRICE_ID
定期購読の更新
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_SUBSCRIPTION_ID := (getenv "STRIPE_SUBSCRIPTION_ID")
:STRIPE_PRICE_ID := (getenv "STRIPE_PRICE_ID")
POST :STRIPE_API_ORIGIN/v1/subscriptions/:STRIPE_SUBSCRIPTION_ID
Authorization: Bearer :STRIPE_SECRET_KEY
items[0][price]=:STRIPE_PRICE_ID
定期購読のキャンセル
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:STRIPE_SUBSCRIPTION_ID := (getenv "STRIPE_SUBSCRIPTION_ID")
DELETE :STRIPE_API_ORIGIN/v1/subscriptions/:STRIPE_SUBSCRIPTION_ID
Authorization: Bearer :STRIPE_SECRET_KEY
納税番号
国にはそれぞれに納税者に対してユニークな番号を発行している。それらは納 税番号と呼ばれる。この納税番号をStripe上に登録し管理するためのAPIがあ る。=type= で許容される値はドキュメントに記載されてい る7。
:STRIPE_API_ORIGIN =
:STRIPE_SECRET_KEY =
:STRIPE_CUSTOMER_ID =
:STRIPE_TAX_TYPE = jp_cn
:STRIPE_TAX_VALUE = 1234567890123
POST :STRIPE_API_ORIGIN/v1/customers/:STRIPE_CUSTOMER_ID/tax_ids
Authorization: Bearer :STRIPE_SECRET_KEY
Content-Type: application/x-www-form-urlencoded
type=:STRIPE_TAX_TYPE&value=:STRIPE_TAX_VALUE
プラン
プランは古いAPIであり、プライスにより置き換えられる。まだプランを使用 しているユーザーのために残されておりAPIも呼び出し可能だが、おそらくそ の内廃止になると思われる。
:STRIPE_API_ORIGIN := (getenv "STRIPE_API_ORIGIN")
:STRIPE_SECRET_KEY := (getenv "STRIPE_SECRET_KEY")
:PLAN_ID =
GET :STRIPE_API_ORIGIN/v1/plans/:PLAN_ID
Authorization: Bearer :STRIPE_SECRET_KEY
テスト用クレジットカード
テストで使用できるクレジットカードとして様々な状態のカード番号が用意されている。 https://stripe.com/docs/testing
クレジットカードのテストにはこれらを用いる。 当然だが本番環境では使用できない。