Djangoでサブスクリプションの支払い情報を受け取る(stripe)
前回の記事で、stripeを利用して、Djangoでサブスクリプション商品を売れるようになりました。でも、サブスクリプション商品は売っただけで終わりにはなりません。
クレジットカードで支払いがされていますが、支払いができなかった場合にどうするのか?
お客さんが解約したいと言った時にどうするのか?
いつ請求を送ったり、金額更新の連絡をするのか?
いろいろ考えることがあります。
まずは、stripeでサブスクリプションの支払いがうまくいっているか、Djangoで情報を受け取れるようにしていきましょう。
Djangoのプロジェクトは前回の続きから作成していきます。まだそちらをみていない方は、この記事の先頭にあるリンクから確認してください。
stripeからのwebhookイベントを取得する
webhookイベントは、stripeで何か動きを検知した時に、こちらに通知してくれる機能です。
例えば、前回の記事のサブスクリプション登録処理を行なった場合、checkout.session.completedイベントが発生します。イベントの一覧は下記から確認できます。
最低限、必要な対応として、checkout.session.completed、invoice.paid、invoice.payment_failedのイベントを確認できるようにしていきましょう。
invoice.paidは支払いが問題なく実施されたというイベント、invoice.payment_failedは支払いが失敗したというイベントです。
これらのイベントをDjangoで取得できるようにする必要がありますが、ローカル開発時には、残念ながら実施できません。
…というわけでここではreplit.comを利用します。replit.comにプロジェクトを追加すれば、urlが付与されるのでエンドポイントを試すことができます。replit.comの基本的な使い方は以下の記事を参考にしてください。
replit.comにプロジェクトをアップロードしたところ、以下のurlが設定されていました。後で、このurlにwebhookのイベントを取得したいアドレスを追加して、webhookを取得できるようにします。
https://django-tutorial-stripe-endpoint.sonnenkorona.repl.co/
次に、stripe側の設定を行います。stripeのダッシュボードの左メニューにあるWebhookをクリックします。
エンドポイントを作成します。エンドポイントというのは、webhookのイベントが発生した時に、どこに送るか設定しておくということです。
「+エンドポイントを追加」から作成を始めます。
エンドポイントurlに先ほどのurlに"webhook/"を追加したアドレスを設定し、3つのイベントを選択して「エンドポイントの追加」を押下します。
これでWebhookエンドポイントが作成されました。Webhookを作成したら、「署名シークレット」を控えておきます。
Django側の設定
まずはイベントを受け取るルーティングを作成しておきます。先ほどwebhookURLにwebhookを追加していたので、同じようにルーティングします。
# subscription/urls.py
...省略...
urlpatterns = [
...省略...
path('webhook/', views.subscription_webhook, name='webhook'),
]
そしてviews.pyにwebhookを受け取る処理を追加します。
subscription/views.py
...省略...
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def subscription_webhook_received(request):
stripe.api_key = 'sk_test_あなたのシークレットキーを入力してください'
webhook_secret = 'whsec_あなたの署名シークレットを入力してください'
post_data = json.loads(request.body.decode("utf-8"))
if webhook_secret:
# Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
signature = request.headers.get('stripe-signature')
try:
event = stripe.Webhook.construct_event(
payload=request.body, sig_header=signature, secret=webhook_secret)
data = event['data']
except Exception as e:
return e
# Get the type of webhook event sent - used to check the status of PaymentIntents.
event_type = event['type']
else:
data = post_data['data']
event_type = post_data['type']
data_object = data['object']
if event_type == 'checkout.session.completed':
# Payment is successful and the subscription is created.
# You should provision the subscription and save the customer ID to your database.
print(data)
elif event_type == 'invoice.paid':
# Continue to provision the subscription as payments continue to be made.
# Store the status in your database and check when a user accesses your service.
# This approach helps you avoid hitting rate limits.
print(data)
elif event_type == 'invoice.payment_failed':
# The payment failed or the customer does not have a valid payment method.
# The subscription becomes past_due. Notify your customer and send them to the
# customer portal to update their payment information.
print(data)
else:
print('Unhandled event type {}'.format(event_type))
return JsonResponse({'status': 'success'})
最初の2行はあなたのシークレットキーに設定してください。
stripeから取得する情報には、csrf tokenがないのでエラーが発生してしまいます。そのため、この関数には"@csrf_exempt"を設定しています。詳細は以下リンク先を確認してください。
この関数はstripeのサンプルをほぼそのまま使っています。やっていることはシンプルで、webhookを取得して、イベントの種類ごとに分岐しているだけです。
現在は各イベントでprint(data)の処理しかしていませんが、それぞれ適切な処理を実装していくことになります。アプリケーションによって処理は異なるので、今回は特に実装しません。
webhookのテスト
これで実装は完了したので、実際にwebhookの処理が行われるか、確認してみましょう。
replit.comのプロジェクト上で[Run]をクリックして実行します。
右側に小さなウィンドウでも実行結果が表示されますが、CSRF関係のエラーが出たので、右上にあるアイコン(カーソルを当てるとopen in a new tabと表示されるもの)を押して違うタブで開きます(その場合はなぜかちゃんと動きます)。
そして、テスト用のクレジットカードで、サブスクリプションに登録してみます。うまくいけばここでwebhookを受け取ることができるはずです。
購入ページに遷移した後、replit.comのconsoleを見ると…
ちゃんとstripeから情報を受け取っているようです!
まとめ
stripeの定期支払いを行う際に、webhookを利用してstripeからイベント情報を受け取る方法を紹介しました。
今回のサンプルコードはreplit.comに記載してあります。ただし、stripeのシークレットキーは削除しているので、[Run]しても動きません。ご自身の環境で試してみてください。
ここまで読んでいただけたなら、”スキ”ボタンを押していただけると励みになります!(*´ー`*)ワクワク
この記事が気に入ったらサポートをしてみませんか?