個人で開発しているアプリで、CtoC の決済を実現するために Stripe Connect について少しだけ調べたのでまとめておきます👷♀️ (実際に利用したらまた記事書きます)
アカウントのタイプ
Stripe Connect を導入するにあたり、アカウントタイプというものをビジネスシーンに合わせて3種類の中から選ぶことができるようです。
Standard
こちらのアカウントタイプを選択した場合は、売り手が Stripe のフォーム上でアカウントの作成やダッシュボードによる決済の管理をすることができます。これによりプラットフォーム(サービスの提供者)は、OAuth の Stripe 組み込みを実装するだけで、CtoC の決済処理を開始することができるようです👀
Custom
Custom アカウントは、登録フローや決済のダッシュボード管理などをプラットフォームがカスタマイズして作成できるアカウントタイプです。また、Standard と違い送金などのタイミングもプラットフォーム側でコントロールすることができるため、より柔軟な決済フローを構築することができます。
Express
Express は、Standard と Custom アカウントの中間のようなアカウントのタイプで、Custom のように決済の流れを制御しつつ Stripe から提供されているダッシュボードや登録フローを使用することで、Stripe とプラットフォームのブランドの調和をとることができます。
Standard Account + iOS
Standard Account + iOS での決済フローの手順を簡単に見ていきましょう。
大まかな手順は下記のようになります。4.
については、Connect に限らず Stripe による決済での共通的な処理が多いので割愛します(また明日書くかもしれません)。
- *Connected Account の作成(サーバ)
- Account Links の作成(サーバ)
- 取得したリンクにユーザをリダイレクトする(クライアント)
- 一般ユーザ支払いをハンドリング
1. Connected Account の作成
/v1/accounts
API を使用して、Standard のアカウントを作成します。
API: https://stripe.com/docs/api/accounts/create
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const account = await stripe.accounts.create({ type: 'standard', });
また、Connected Account を作成するのに必要な、情報を事前に入力している場合は、それらの情報をパラメータに渡すことで、Stripe プラットフォーム上でのフォーム入力の際に、それらの情報をユーザ再入力する必要がなくなるそうです。ですので、極力事前にユーザから取得した情報はパラメータに付与することで少しでも、フローの離脱率を下げることに貢献できそうです🧑🔧
2. Account Links の作成
このプロセスは、ConnectOnboarding などの Stripe がホストするアプリケーションにアクセスするための URL を取得するために必要です。
API: https://stripe.com/docs/api/account_links
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const accountLinks = await stripe.accountLinks.create({ account: 'acct_1032D82eZvKYlo2C', refresh_url: 'https://example.com/reauth', return_url: 'https://example.com/return', type: 'account_onboarding', });
これらのリクエストには、下記のパラメータが必要になります。
account
- Account の ID
type
account_onboarding
とaccount_update
がありますが、Standard Account の場合、指定できるのはaccount_onboarding
のみになります。
return_url
- ユーザが ConnectOnboarding フローを完了した時に、この URL へのリダイレクトを発行します。
refresh_url
- ConnectOnboarding フローで次のようなアクションが発生した場合に、この URL にリダイレクトされます。
- リンクの有効期限が切れた場合
- ユーザがページを更新するか、ブラウザで前後をクリック
- プラットフォームがアカウントにアクセスできなくなった場合
- アカウントが拒否された場合
- ConnectOnboarding フローで次のようなアクションが発生した場合に、この URL にリダイレクトされます。
また、return_url
でリダイレクトされた場合でも、ConnectOnboarding フローが正常に完了したとは限らないので、次のいずれかを実行して、アカウントの details_submitted
パラメータの状態を確認します。
また、iOS の場合これら return_url
・refresh_url
にユニバーサルリンクを設定することでよりシームレスに iOS アプリにリダイレクトすることができます。
※ 本番環境(Live Mode)では HTTPS しか使用できないので注意が必要
3. 取得したリンクにユーザをリダイレクトする
前の手順で取得した ConnectOnboarding フローのためのリンクにユーザをリダイレクトします。下記が Stripe Doc の Swift サンプルコードです。
import UIKit import SafariServices class ConnectOnboardViewController: UIViewController { // ... override func viewDidLoad() { super.viewDidLoad() let connectWithStripeButton = UIButton(type: .system) connectWithStripeButton.setTitle("Connect with Stripe", for: .normal) connectWithStripeButton.addTarget(self, action: #selector(didSelectConnectWithStripe), for: .touchUpInside) view.addSubview(connectWithStripeButton) // ... } @objc func didSelectConnectWithStripe() { if let url = URL(string: Settings.BackendAPIBaseURL)?.appendingPathComponent("onboard-user") { var request = URLRequest(url: url) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request) { (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let accountURLString = json["url"] as? String, let accountURL = URL(string: accountURLString) else { // handle error } let safariViewController = SFSafariViewController(url: url) safariViewController.delegate = self DispatchQueue.main.async { self.present(safariViewController, animated: true, completion: nil) } } } } // ... } extension ConnectOnboardViewController: SFSafariViewControllerDelegate { func safariViewControllerDidFinish(_ controller: SFSafariViewController) { // the user may have closed the SFSafariViewController instance before a redirect // occurred. Sync with your backend to confirm the correct state } }
用語
Connected Account: アプリを使用してサービスを提供する販売者のアカウント
参考
- https://stripe.com/docs/connect/enable-payment-acceptance-guide#create-account-ios
- https://stripe.com/ja-au/connect/account-types
- https://stripe.com/docs/api/accounts
- https://qiita.com/y_toku/items/7bfa42793801dfc5415d