ACH ダイレクトデビットによる支払いを受け付ける
カスタムの決済フォームを構築するか、Stripe Checkout を使用して、ACH ダイレクトデビットによる決済を受け付けます。
アプリでの ACH ダイレクトデビットによる決済の受け付けは、以下のように構成されます。
- 決済を追跡するためのオブジェクトを作成する
- 支払い方法の詳細を収集する
- 決済を処理するために Stripe に送信する
- 顧客の銀行口座を確認する
Stripe では、Payment Intent (支払いインテント) を使用して、支払いが完了するまでの状態のすべてを追跡および処理します。
注
ACH ダイレクトデビットは通知遅延型の支払い方法であるため、決済後すぐには売上が利用可能になりません。通常、決済金額がお客様のアカウントに入金されるまでに 4 営業日かかります。
Stripe を設定するサーバ側クライアント側
サーバ側
この組み込みには、Stripe API と通信するエンドポイントがサーバ上に必要です。Stripe の公式ライブラリを使用して、サーバから Stripe API にアクセスします。
クライアント側
React Native SDK はオープンソースであり、詳細なドキュメントが提供されています。内部では、ネイティブの iOS および Android の SDK を使用します。Stripe の React Native SDK をインストールするには、プロジェクトのディレクトリーで (使用するパッケージマネージャーによって異なる) 次のいずれかのコマンドを実行します。
次に、その他の必要な依存関係をインストールします。
- For iOS, go to the ios directory and run
pod install
to ensure that you also install the required native dependencies. - Android の場合は、依存関係をインストールする必要はありません。
注
公式の TypeScript ガイドに従って TypeScript のサポートを追加することをお勧めします。
Stripe の初期化
React Native アプリで Stripe を初期化するには、決済画面を StripeProvider
コンポーネントでラップするか、initStripe
初期化メソッドを使用します。publishableKey
の API 公開可能キーのみが必要です。次の例は、StripeProvider
コンポーネントを使用して Stripe を初期化する方法を示しています。
import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( <StripeProvider publishableKey={publishableKey} merchantIdentifier="merchant.identifier" // required for Apple Pay urlScheme="your-url-scheme" // required for 3D Secure and bank redirects > {/* Your app code here */} </StripeProvider> ); }
Stripe では、顧客の銀行口座を即座に確認できます。口座に関する追加データを取得する場合は、Stripe Financial Connections を使用してデータアクセスを登録します。
Stripe Financial Connections を使用すると、金融口座をビジネスに関連付けることで、顧客が財務データを安全に共有できます。Financial Connections を使用して、トークン化された口座番号と金融番号、残高データ、所有者の詳細、取引データなどの顧客に許可された財務データにアクセスします。
このデータにアクセスすることで、決済を開始する前に残高を確認するなどのアクションを実行し、残高不足による決済の失敗の可能性を減らすことができます。
Financial Connections は、ユーザーがより少ないステップで自身のアカウントを Link に関連付け、Stripe のすべての加盟店に銀行口座の詳細を保存して、素早く再利用できるようにします。
顧客を作成または取得する推奨サーバー側
ユーザーがビジネスでアカウントを作成する際に、Customer オブジェクトを作成するか、このユーザーに関連付けられた既存の Customer を取得します。この Customer オブジェクトの ID を、顧客を表す社内の内部表記と関連付けることで、保存されている支払い方法の詳細を後で取得して使用することができます。Financial Connections のリピートユーザーの最適化を有効にするには、Customer にメールアドレスを含めます。
PaymentIntent を作成するサーバー側
PaymentIntent (支払いインテント) は、顧客から支払いを回収する意図を表すオブジェクトで、決済プロセスのライフサイクルの各段階を追跡します。
サーバー側
まず、サーバーで PaymentIntent を作成し、回収する金額と通貨 usd
を指定します。Payment Intents API を使用した実装がすでにある場合は、PaymentIntent の支払い方法タイプのリストに us_
を追加します。Customer の ID を指定します。
将来その支払い方法を再利用する場合には、値を off_
に設定して setup_future_usage パラメーターを指定します。
デフォルトでは、銀行口座の支払い情報の収集では、手動の口座番号入力と少額入金の確認のフォールバックオプションを使用し、Financial Connections で顧客のアカウントを即時確認します。Financial Connections を設定し、ACH の実装を最適化するために追加の口座データにアクセスする方法については、Financial Connections に関するドキュメントをご覧ください。たとえば、Financial Connections を使用して、ACH 決済の開始前にアカウントの残高を確認できます。
注
顧客がアカウントを認証した後で、追加データにアクセスを拡張するには、権限を拡張してアカウントを再度関連付ける必要があります。
クライアント側
PaymentIntent には client secret が含まれています。これを React Native アプリで使用することで、PaymentIntent オブジェクト全体を渡すことなく安全に支払いプロセスを完了できます。アプリで、サーバーの PaymentIntent をリクエストし、その client secret を保存します。
function PaymentScreen() { // ... const fetchIntentClientSecret = async () => { const response = await fetch(`${API_URL}/create-intent`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ // This is an example request body, the parameters you pass are up to you customer: '<CUSTOMER_ID>', product: '<PRODUCT_ID>', }), }); const {clientSecret} = await response.json(); return clientSecret; }; return <View>...</View>; }
支払い方法の詳細を収集するクライアント側
PaymentIntent オブジェクト全体をクライアントに送信する代わりに、前のステップからの client secret を使用します。これは、Stripe API リクエストを認証する API キーとは異なります。
client secret は支払いを確定できるため、慎重に取り扱う必要があります。記録したり、URL に埋め込んだり、当該の顧客以外に漏洩することがないようにしてください。
collectBankAccountForPayment を使用して銀行口座の詳細を収集し、PaymentMethod を作成して PaymentIntent に関連付けます。ACH Direct Debit PaymentMethod を作成するには、billingDetails
パラメーターに口座名義人を含める必要があります。
import {collectBankAccountForPayment} from '@stripe/stripe-react-native'; export default function MyPaymentScreen() { const [name, setName] = useState(''); const handleCollectBankAccountPress = async () => { // Fetch the intent client secret from the backend. // See `fetchIntentClientSecret()`'s implementation above. const {clientSecret} = await fetchIntentClientSecret(); const {paymentIntent, error} = await collectBankAccountForPayment( clientSecret, { paymentMethodType: 'USBankAccount', paymentMethodData: { billingDetails: { name: "John Doe", }, }, }, ); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { Alert.alert('Payment status:', paymentIntent.status); if (paymentIntent.status === PaymentIntents.Status.RequiresConfirmation) { // The next step is to call `confirmPayment` } else if ( paymentIntent.status === PaymentIntents.Status.RequiresAction ) { // The next step is to call `verifyMicrodepositsForPayment` } } }; return ( <PaymentScreen> <TextInput placeholder="Name" onChange={(value) => setName(value.nativeEvent.text)} /> <Button onPress={handleCollectBankAccountPress} title="Collect bank account" /> </PaymentScreen> ); }
これにより、銀行口座の詳細の収集と確認を処理するモーダル UI が読み込まれます。処理が完了すると、PaymentMethod が PaymentIntent に自動的に関連付けられます。
戻り先 URL を設定する (iOS のみ)クライアント側
顧客がアプリを終了すると (Safari やバンキングアプリで認証するなど)、自動的にアプリに戻るための方法を提供します。多くの決済手段タイプで、戻り先 URL の指定が「必須」です。戻り先 URL を有効にしていても、指定がされていないと、戻り先 URL が必要な決済手段をユーザーに提示できません。
戻り先 URL を指定するには、以下のようにします。
- カスタム URL を登録します。ユニバーサルリンクはサポートされていません。
- カスタム URL を設定 します。
- 以下のように、URL を Stripe SDK に転送するようにルートコンポーネントを設定します。
注
Expo を使用している場合は、app.
ファイルでスキームを設定します。
import { useEffect, useCallback } from 'react'; import { Linking } from 'react-native'; import { useStripe } from '@stripe/stripe-react-native'; export default function MyApp() { const { handleURLCallback } = useStripe(); const handleDeepLink = useCallback( async (url: string | null) => { if (url) { const stripeHandled = await handleURLCallback(url); if (stripeHandled) { // This was a Stripe URL - you can return or add extra handling here as you see fit } else { // This was NOT a Stripe URL – handle as you normally would } } }, [handleURLCallback] ); useEffect(() => { const getUrlAsync = async () => { const initialUrl = await Linking.getInitialURL(); handleDeepLink(initialUrl); }; getUrlAsync(); const deepLinkListener = Linking.addEventListener( 'url', (event: { url: string }) => { handleDeepLink(event.url); } ); return () => deepLinkListener.remove(); }, [handleDeepLink]); return ( <View> <AwesomeAppComponent /> </View> ); }
同意書承認を収集し、決済を送信するクライアント側
決済を開始する前に、同意書の規約を表示して顧客から承認を得る必要があります。
Nacha の運営規則に準拠するため、決済を開始する前に、同意書の規約を表示して顧客から承認を得る必要があります。同意書の詳細については、こちらの記事をご覧ください。
顧客が同意書の規約を承認する際に、お客様は PaymentIntent を確定する必要があります。confirmPayment
を使用して、インテントを確定します。
import {confirmPayment} from '@stripe/stripe-react-native'; export default function MyPaymentScreen() { const [name, setName] = useState(''); const handleCollectBankAccountPress = async () => { // See above }; const handlePayPress = async () => { // use the same clientSecret as earlier, see above const {error, paymentIntent} = await confirmPayment(clientSecret, { paymentMethodType: 'USBankAccount', }); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { if (paymentIntent.status === PaymentIntents.Status.Processing) { // The debit has been successfully submitted and is now processing } else if ( paymentIntent.status === PaymentIntents.Status.RequiresAction && paymentIntent?.nextAction?.type === 'verifyWithMicrodeposits' ) { // The payment must be verified with `verifyMicrodepositsForPayment` } else { Alert.alert('Payment status:', paymentIntent.status); } } }; return ( <PaymentScreen> <TextInput placeholder="Name" onChange={(value) => setName(value.nativeEvent.text)} /> <Button onPress={handleCollectBankAccountPress} title="Collect bank account" /> <Button onPress={handlePayPress} title="Pay" /> </PaymentScreen> ); }
成功した場合、Stripe から以下のいずれかのステータスで PaymentIntent オブジェクトが返されます。
ステータス | 説明 | 次のステップ |
---|---|---|
RequiresAction | 銀行口座を確認するには、さらにアクションを実行する必要があります。 | ステップ 6: 少額入金で銀行口座を確認する |
Processing | 銀行口座が即座に確認されたか、確認が必要ありません。 | ステップ 7: PaymentIntent の成功を確認する |
PaymentIntent の確定に成功した後、同意書の確認メールと収集した銀行口座情報を顧客に送信する必要があります。Stripe はデフォルトでこれらの処理を行いますが、ご希望に応じてカスタム通知の送信を選択することもできます。
少額入金で銀行口座を確認するクライアント側
すべての顧客が銀行口座を即座に確認できるとは限りません。このような場合、Stripe は少額入金を銀行口座に送金します。この入金は、1 ~ 2 営業日後に顧客のオンライン明細書に表示されます。入金は以下の 2 つのいずれかの形式で行われます。
- 明細書表記コード。Stripe は、SM で始まる一意の 6 桁の
descriptorCode
を使用し、0.01 USD の 1 件の少額入金を顧客の銀行口座に送金します。顧客は、この文字列を使用して銀行口座を確認します。 - 金額。Stripe は、
ACCTVERIFY
という明細書表記を使用し、一意でない 2 件の少額入金を顧客の銀行口座に送金します。顧客は、この入金額を使用して銀行口座を確認します。
前のステップで行った confirmPayment
メソッドの呼び出しの結果として、requiresAction
ステータスの PaymentIntent が返される場合、PaymentIntent には、確認を完了するための有益な情報を含む nextAction
フィールドが含まれています。
nextAction: { type: 'verifyWithMicrodeposits'; redirectUrl: "https://payments.stripe.com/…", microdepositType: "descriptor_code"; arrivalDate: "1647586800"; }
請求書メールを指定した場合、Stripe はこのメールで入金の到着予定日を顧客に通知します。このメールには、Stripe がオンラインで提供する確認ページへのリンクが含まれ、顧客はそのページで入金額を確認して銀行口座の確認を完了させることができます。
警告
確認の失敗は、明細書表記ベースの少額入金の場合は 10 回、金額ベースの少額入金の場合は 3 回までです。この上限を超えると、Stripe は銀行口座を確認できなくなります。また、少額入金の確認は 10 日経過するとタイムアウトになります。この期間内に少額入金を確認できなかった場合、PaymentIntent は新しい支払い方法の詳細を要求する状態に戻ります。少額入金とは何か、どのように使用されるのかを顧客に明確に伝えることで、確認に関する問題を回避できます。
支払いが requiresAction
状態であり、nextAction
のタイプが verifyWithMicrodeposits
であることを確認できる場合は、2 つの方法で銀行口座の確認を完了できます。
- 明細書表記コードまたは金額を収集した後、
verifyMicrodepositsForPayment
を呼び出して、入金をアプリで直接確認します。
import { verifyMicrodepositsForPayment } from '@stripe/stripe-react-native'; export default function MyPaymentScreen() { const [verificationText, setVerificationText] = useState(''); return ( <TextInput placeholder="Descriptor code or comma-separated amounts" onChange={(value) => setVerificationText(value.nativeEvent.text)} // Validate and store your user's verification input /> <Button title="Verify microdeposit" onPress={async () => { const { paymentIntent, error } = await verifyMicrodepositsForPayment(secret, { // Provide either the descriptorCode OR amounts, not both descriptorCode: verificationText, amounts: verificationText, }); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { Alert.alert('Payment status:', paymentIntent.status); } }} /> ); }
- Stripe が自動的にオンラインで提供する確認ページを使用します。そのためには、
nextAction
オブジェクトのnextAction[redirectUrl]
URL (上記を参照) を使用し、顧客に確認プロセスを完了するよう指示します。
const {error, paymentIntent} = await confirmPayment(clientSecret, { paymentMethodType: 'USBankAccount', }); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { if ( paymentIntent.status === PaymentIntents.Status.RequiresAction && paymentIntent?.nextAction?.type === 'verifyWithMicrodeposits' ) { // Open the Stripe-hosted verification page Linking.openURL(paymentIntent.nextAction.redirectUrl); } }
銀行口座の確認に成功すると、Stripe は PaymentIntent オブジェクトを Processing
の status
で返し、payment_intent.processing Webhook イベントを送信します。
確認が失敗する原因はいくつか存在します。失敗は直接的なエラー応答で同期的に発生することも、payment_intent.payment_failed Webhook イベントを通じて非同期で発生することもあります (以下の例を参照してください)。
エラーコード | 同期または非同期 | メッセージ | ステータスの変化 |
---|---|---|---|
payment_ | 同期、または Webhook イベントを通じて非同期で発生 | 少額入金に失敗しました。指定した銀行口座、金融機関、支店の番号を確認してください | status は requires_ で、last_ が設定されます。 |
payment_ | 同期 | 指定された金額が銀行口座に送金された金額と一致しません。確認試行の残り回数はあと {attempts_remaining} 回です。 | 変化なし |
payment_ | 同期、または Webhook イベントを通じて非同期で発生 | 許容された確認の試行回数を超えました | status は requires_ で、last_ が設定されます。 |
payment_ | Webhook イベントを通じて非同期で発生 | 少額入金がタイムアウトになりました。顧客は要求された 10 日の期間内に銀行口座を確認しませんでした。 | status は requires_ で、last_ が設定されます。 |
PaymentIntent の成功を確認するサーバー側
ACH ダイレクトデビットは、通知遅延型の支払い方法です。このため、顧客の口座から引き落としを開始してから、決済の成功または失敗の通知を受けるまでに最大で 4 営業日かかります。
PaymentIntent を作成すると、その初期ステータスは processing
となります。決済が成功すると、PaymentIntent のステータスは processing
から succeeded
に更新されます。
Webhook を使用して決済が成功したことを確認し、顧客に決済完了を通知することをお勧めします。Stripe ダッシュボードでイベントを表示することもできます。
組み込みをテストする
Financial Connections を使用して即時確認を行うシナリオをテストする方法をご紹介します。
サンドボックスで取引メールを送信する
銀行口座の詳細を収集し、同意書を受け付けたら、サンドボックスで同意書の確認メールと少額入金の確認メールを送信します。
ドメインが {domain} でユーザー名が {username} の場合、{username}+test_email@{domain} というメール形式を使用してテスト取引メールを送信してください。
たとえば、ドメインが example.com でユーザー名が info の場合、ACH Direct Debit 決済のテストには info+test_email@example.com という形式を使用します。この形式により、メールが正しくルーティングされます。+test_email サフィックスを含めない場合、メールは送信されません。
よくある間違い
テスト中にこれらのメールをトリガーするには、Stripe の本番環境利用の申請を行う必要があります。
テスト用口座番号
Stripe では、手動入力の銀行口座の組み込みが本番環境に移行する準備が整ったかどうかを確認するため、テスト用の口座番号と対応するトークンをいくつか用意しています。
口座番号 | トークン | 金融番号 | 動作 |
---|---|---|---|
000123456789 | pm_ | 110000000 | 支払いは成功します。 |
000111111113 | pm_ | 110000000 | 口座が解約済みであるため、支払いは失敗します。 |
000000004954 | pm_ | 110000000 | この支払いは、不正利用のリスクが高いため、Radar によってブロックされています。 |
000111111116 | pm_ | 110000000 | 口座が見つからないため、支払いは失敗します。 |
000222222227 | pm_ | 110000000 | 残高不足のため、支払いは失敗します。 |
000333333335 | pm_ | 110000000 | 引き落としがオーソリされていないため、支払いは失敗します。 |
000444444440 | pm_ | 110000000 | 通貨が無効であるため、支払いは失敗します。 |
000666666661 | pm_ | 110000000 | 支払いで少額入金の送金が失敗します。 |
000555555559 | pm_ | 110000000 | 支払いによって不審請求の申請が開始されています。 |
000000000009 | pm_ | 110000000 | 支払いは無期限に処理中のままになります。これは PaymentIntent のキャンセルをテストするのに便利です。 |
000777777771 | pm_ | 110000000 | 支払い額がアカウントの週次支払い額の上限を超えているため、支払いが失敗しました。 |
テスト取引を完了する前に、自動的に支払いに成功または失敗するテスト用のすべての口座を確認する必要があります。確認するには、下記の少額入金のテスト用の金額または明細書表記コードを使用します。
少額入金の金額と明細書表記コードをテストする
さまざまなシナリオを再現するために、これらの少額入金の金額「または」明細書表記コードの値 0.01 を使用します。
少額入金の金額 | 明細書表記コードの値 0.01 | シナリオ |
---|---|---|
32 および 45 | SM11AA | アカウントの確認をシミュレーションします。 |
10 および 11 | SM33CC | 許容された確認回数の超過をシミュレーションします。 |
40 および 41 | SM44DD | 少額入金のタイムアウトをシミュレーションします。 |
売上処理の動作をテストする
テスト取引は即座に売上として処理され、利用可能なテスト残高に追加されます。この動作は、利用可能な残高で取引が売上として処理されるまでに数日かかることがある、本番環境とは異なります。