- StripeでConnectアカウントへ手数料を引いて送金するには?
- オーソリ(仮売上)とキャプチャ(売上確定)を分けるには?
- DjangoにおけるStripe Connectの扱い方は?
本記事ではこのような疑問を解決します。
Stripe Connectを利用していると、Connectアカウントへの送金が発生しますが、
売上をそのままConnectアカウントへ送金するのは現実的ではありません。
通常、プラットフォームの手数料分を指しい引いてから売上を送金するのが一般的でしょう。
そこで今回はStripeでConnectアカウントへ手数料を引いて送金する方法を解説していきます。
なお、Webフレームワークには当ブログお馴染みのDjangoを使用します。
そして、本記事ではStripeでの決済処理の基本であるPayment Intent APIを使用します。
そのため、Payment Intent APIについてまだ知らないという方はこちらの記事を参考に流れをご確認ください。
DjangoでStripeの決済機能を実装する方法とは?StripeのPayment Intentの使い方とは? 本記事ではこのような疑問を解決します。Webアプリを開発する際に、決済機能の実装はほぼマストです。そんな決済機能の実装[…]
本記事においても、基本的な実装の流れは上の記事を参考にしています。
前提
StripeではConnectアカウントの操作方法にいくつかパターンがあります。
詳しくはこちらの記事で解説しているので参考にしてみてください。
Stripe Connectの仕組みとは?アカウントタイプと決済フローの関係とは? 本記事ではこのような疑問を解決します。本店と支店のように各エンドポイントでの支払いを中央で一括管理したいという場面ってありますよね。例えば、複数の子[…]
そして、今回のConnectアカウントの操作方法パターンは以下の通りです。
・アカウントタイプ
→Custom
・決済フロー
→Destination charge
・支払い処理組み込み
→Stripe Elements
支払い受付から送金までの流れ
まずはユーザーからの支払いを受け付けてから、Connectアカウントへ送金するまでの流れを確認していきましょう。
①フロント側で支払いを受け付ける
→Webサイト等において支払い情報(クレジットカードなど)がPOSTされる
②サーバー側で支払い情報(Payment Intentオブジェクト)を生成する
→Payment Intentオブジェクトの中には手数料や子アカウントなどの情報が格納される(売上は未キャプチャのまま)
③任意のタイミングで売上のキャプチャを実行する
④キャプチャされると手数料を引いた金額が子アカウントの残高へ加算される
⑤設定した内容(週次や月次など)によって子アカウントの残高から口座へ自動入金される
ちなみに、上記の中で「キャプチャ」という言葉が出てきたので簡単に説明します。
クレジットカード決済は、
一般的に「オーソリ」と「キャプチャ」を行うことによって決済手続きが完了します。
オーソリとは「オーソリゼーション」の略で、
端的にいうと「お客さまのクレジットカードで決済できるかを確認する作業」のことです。
具体的にはお客さまのクレジットカードが有効かどうかや利用限度額に達していないかなどを確認して、クレジットカードのご利用枠を確保する処理のことです。
そして、オーソリの承認後にキャプチャ(売上処理)を経て決済が完了します。
「キャプチャ」は日本語で「捕まえる」という意味です。
実装手順
それでは実際に支払い受付からConnectアカウントへの送金までを実装していきましょう。
ここでは以下のDjangoプロジェクトを前提とし、当該Stripe機能に関係するファイルのみを操作します。
sampleproject ├── sampleapp │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── (中身省略) │ ├── models.py │ ├── tests.py │ └── views.py ├── sampleproject │ ├── __init__.py │ ├── __pycache__ │ │ └── (中身省略) │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── templates │ ├── payment.html │ └── thanks.html ├── static │ ├── js │ ├── stripe.js └── manage.py
バックエンド(Django)側の設定
DjangoでのStripe初期設定をする(settings.py)
# Stripeのダッシュボードからシークレットキーとパブリックキーをコピペする
STRIPE_API_KEY = 'Stripeのシークレットキー'
STRIPE_PUBLISHABLE_KEY = 'Stripeのパブリックキー'
URLを設定する(urls.py)
urlpatterns = [
path('payment/', views.payment, name="payment"),# 支払いフォームのページを表示する
path('thanks/', views.thanks, name="thanks"),# 支払い完了後に表示するページを表示する
path('capture/', views.capture, name="capture"),# 売上をキャプチャする
]
支払いフォームを返す処理を記述する(views.py)
from django.conf import settings
import stripe
def payment(request):
# StripeのAPIキーを登録する
stripe.api_key = settings.STRIPE_API_KEY
# 今回は支払い額を10,000円とする
amount=10000
#PaymentIntentを作成する
intent = stripe.PaymentIntent.create(
amount=amount,
currency='jpy',
description='テスト支払い',
payment_method_types=["card"],
off_session=True,
confirm=True,
transfer_data={
'amount': 8000,# Connectアカウントの送金する金額
'destination': '【ConnectアカウントのID】',# 送金先のConnectアカウント
},
capture_method='manual',# 未キャプチャにする
)
# 作成したPaymentIntentからclient_secretを取得する
client_secret = intent["client_secret"]
# テンプレートと渡すデータを指定する
template_name = "payment.html"
context = {
"amount": amount,
"client_secret": client_secret,
}
return render(request, template_name, context)
PaymentIntentオブジェクトの中でtransfer_dataを指定することによりConnectアカウントへの送金を設定します。
そして、ユーザーの支払い総額とConnectアカウントへの送金額の差がプラットフォーム(親アカウント)が受け取る手数料になります。
今回の場合は、10,000円ー8,000円=2,000円が手数料分です。
ちなみに、Connectアカウントへの送金がいつ行われるのかというとキャプチャが完了した時です。
また、capture_methodを’manual’にすることでクレジットカード決済をオーソリまでに止めます。(未キャプチャ)
クレジットカード情報が送信された後の処理を記述する(views.py)
# 単純に支払い完了ページを表示する処理
def thanks(request):
template_name = "thanks.html"
return render(request, template_name)
売上をキャプチャする処理を記述する(views.py)
from django.http import HttpResponse
# 売上をキャプチャする処理
def capture(request):
stripe.api_key = settings.STRIPE_API_KEY
stripe.PaymentIntent.capture(
'【先ほど生成したPaymentIntentオブジェクトのID】',
)
return HttpResponse('キャプチャ完了!')
PaymentIntentオブジェクトにcaptureメソッドを使うことでキャプチャが完了します。
キャプチャが完了するとConnectアカウント残高に送金結果が反映されます。
なお、こちらの処理は簡易的にHttpResponseで「キャプチャ完了!」と表示されるだけなので、キャプチャ後の処理は自由に変更してください。
フロントエンド(HTML・JavaScript)側の設定
支払いフォームのページを作成する(payment.html)
<!DOCTYPE html>
{% load static %}
<html lang="ja">
<head>
<meta charset="UTF-8">
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<!--inputタグでclient_secretを渡す→JavaScriptで値を取得する-->
<input type="hidden" id="client_secret" value="{{ client_secret }}">
<!--フォームが読み込まれたら、Payment Elementのインスタンスを作成して、それをコンテナーのDOMノードにマウントする-->
<form id="payment-form">
<div id="payment-element">
<!-- Elements will create form elements here -->
</div>
<p>お支払い金額:{{ amount }}円</p>
<button id="submit">支払いを確定する</button>
<div id="error-message">
<!-- Display error message to your customers here -->
</div>
</form>
<script src="{% static 'js/stripe.js' %}"></script>
</body>
支払い完了後に表示するページのファイルを作成する(thanks.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
</head>
<body>
<p>お支払い完了</p>
</body>
Stripe処理を行うJavaScriptファイルを作成する(stripe.js)
// JavaScriptを使用して、client secretを取得する
const client_secret = document.getElementById('client_secret').value;
// JavaScriptを使用して、Stripeのインスタンスを作成する
const stripe = Stripe('Stripeのパブリックキー');
// 支払いフォームで使用するElementsを設定し、上で取得したclient secretを渡す
const elements = stripe.elements({
clientSecret:client_secret,
appearance:{
theme: 'stripe',
},
});
// Payment Elementを作成し、既存のDOM要素から生成したDOM要素に置き換える
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// id=payment-formの要素を取得する
const form = document.getElementById('payment-form');
// クレジットカード情報が送信された時の処理を記述する
form.addEventListener('submit', async (event) => {
event.preventDefault();
// confirmPaymentを呼び出して支払い処理を完了させる
await stripe.confirmPayment({
//`Elements` instance that was used to create the Payment Element
elements,
confirmParams: {
return_url: '支払い完了後に呼び出すURL(ここでは/thanks)',
},
});
});
まとめ
以上がStripeでConnectアカウントへ手数料を引いて送金する方法になります。
本記事ではPython(Django)による実装でしたが、
他の言語でも多少書き方が異なるだけで扱うStripeのAPIは同じです。
なお、以下の公式ドキュメントにより詳しく記載されているので参考にしてみてください。
Stripe公式ドキュメント(プラットフォームでのデスティネーション支払いの作成)
実務1年未満でもOK!フリーランスエンジニアの案件獲得方法はこちら!
フリーランスエンジニアが案件獲得方法とは?自ら営業せずに案件を獲得するには?実務経験1年未満でも大丈夫なの? 本記事ではこのような疑問を解決します。これからフリーランスエンジニアとして独立したい方は、兎にも角にも案件の獲得が急務です[…]