Webhook なしでカード支払いを受け付ける
サーバでカード決済を確定して、カードの認証リクエストを処理する方法をご紹介します。
より幅広いサポートと将来の保証のために、非同期的な支払いを目的とした標準的な実装を使用してください。
この組み込みは、Webhook を使用したり、オフラインイベントを処理したりせずに、クライアントからサーバーへの単一フローを使用して支払いを受け付けます。この組み込みはシンプルに見えるかもしれませんが、ビジネスの成長に合わせて拡張するのが難しく、以下のような制限もあります。
- カードのみをサポート: ACH や現地で一般的な決済手段に個別に対応するには、追加のコードを記述する必要があります。
- 二重請求のリスク: 顧客が支払おうとするたびに新たな PaymentIntent を同期的に作成することにより、顧客に対して誤って二重請求が行われるリスクがあります。必ずベストプラクティスに従ってください。
- 手動認証処理: 3D セキュアを備えたカード、または強力な顧客認証 (SCA) などの規制の対象となるカードでは、クライアント側での追加の手順が必要になります。
この実装の使用を選択した場合は、上記の制限にご注意ください。制限を設けたくない場合は、標準的な実装を使用します。
Stripe を設定するサーバ側クライアント側
サーバ側
この組み込みには、Stripe API と通信するエンドポイントがサーバ上に必要です。Stripe の公式ライブラリを使用して、サーバから Stripe API にアクセスします。
クライアント側
React Native SDK はオープンソースであり、詳細なドキュメントが提供されています。内部では、ネイティブの iOS および Android の SDK を使用します。Stripe の React Native SDK をインストールするには、プロジェクトのディレクトリーで (使用するパッケージマネージャーによって異なる) 次のいずれかのコマンドを実行します。
次に、その他の必要な依存関係をインストールします。
- iOS の場合は、ios ディレクトリーに移動して
pod install
を実行し、必要なネイティブ依存関係もインストールします。 - 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> ); }
決済ページを作成するクライアント側
カード番号、有効期限、セキュリティコード、郵便番号を収集する、SDK が提供する UI コンポーネント、CardField
を使用して、クライアント側でカード情報を安全に収集します。
CardField
は、リアルタイムで検証と形式の設定を行います。
CardField
コンポーネントを支払い画面に追加することで、顧客からカード詳細を安全に収集します。onCardChange
コールバックを使用して、カードのブランドや詳細情報の欠落の有無など、カードに関する機密性の低い情報を検査します。
import { CardField, useStripe } from '@stripe/stripe-react-native'; function PaymentScreen() { // ... return ( <View> <CardField postalCodeEnabled={true} placeholders={{ number: '4242 4242 4242 4242', }} cardStyle={{ backgroundColor: '#FFFFFF', textColor: '#000000', }} style={{ width: '100%', height: 50, marginVertical: 30, }} onCardChange={(cardDetails) => { console.log('cardDetails', cardDetails); }} onFocus={(focusedField) => { console.log('focusField', focusedField); }} /> </View> ); }
アプリを実行し、決済ページに CardField
コンポーネントが表示されることを確認します。
カード詳細を収集するクライアント側
顧客が購入する準備が整ったら、CardField
コンポーネントによって収集された詳細情報を使用して PaymentMethod (支払い方法) を作成します。
import { CardField, useStripe } from '@stripe/stripe-react-native'; function PaymentScreen() { const { createPaymentMethod, handleNextAction } = useStripe(); const pay = () => { // Gather customer billing information (for example, email) const billingDetails: CreatePaymentMethod.BillingDetails = { email: 'email@stripe.com', phone: '+48888000888', addressCity: 'Houston', addressCountry: 'US', addressLine1: '1459 Circle Drive', addressLine2: 'Texas', addressPostalCode: '77063', }; // Create payment method const { paymentMethod, error } = await createPaymentMethod({ paymentMethodType: 'Card', paymentMethodData: { billingDetails, } }); }; // ... }
サーバに PaymentMethod を送信するクライアント側
PaymentMethod が正常に作成されたら、その ID をサーバに送信します。
// ... const pay = () => { // ... // Send the PaymentMethod to your server to create a PaymentIntent const response = await fetch(`/pay`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ paymentMethodId: paymentMethod.id }), }); const { error, requires_action, payment_intent_client_secret } = await response.json(); if (error) { // Error creating or confirming PaymentIntent Alert.alert('Error', paymentIntentError); return; } if (payment_intent_client_secret && !requires_action) { // Payment succeeded Alert.alert('Success', 'The payment was confirmed successfully!'); } if (payment_intent_client_secret && requires_action) { // ...continued below } }; // ...
PaymentIntent を作成するサーバ側
リクエストを受信するためにサーバにエンドポイントを設定します。このエンドポイントは、後で でも、追加の認証ステップが必要なカードの処理に使用されます。
クライアント側で作成した PaymentMethod) の ID を使って新しい PaymentIntent を作成します。PaymentIntent の作成時に confirm プロパティを true に設定するか、作成後に confirm を呼び出すことにより、PaymentIntent を確定できます。カード支払いでは、オーソリとキャプチャーの分離もサポートされています。
支払いで3D セキュア認証などの追加アクションが必要な場合、PaymentIntent のステータスは requires_
に設定されます。支払いが失敗すると、ステータスは requires_
に戻され、ユーザにエラーを表示する必要があります。支払いで追加認証が求められない場合は、支払いが作成され、PaymentIntent のステータスは succeeded
に設定されます。
注
2019-02-11 以前の API のバージョンでは、requires_
の代わりに requires_
、requires_
の代わりに requires_
が表示されます。
後で再利用するためにカードを保存する場合は、PaymentMethod を格納するため Customer を作成して、PaymentIntent の作成時に以下の追加パラメータを渡します。
- 顧客。Customer の ID に設定します。
- setup_future_usage。
off_
に設定し、顧客が存在しない場合のオフセッションの支払いにこの PaymentMethod を再利用する予定であることを Stripe に伝えます。このプロパティを設定すると、PaymentIntent が確定され、ユーザによる必要な操作がすべて完了した後で、顧客に PaymentMethod が保存されます。詳細については、支払い後のカードの保存に関するコード例を参照してください。session
次のアクションを処理するクライアント側
通常、ステップ 4 のサーバーでの確定後に支払いは成功しますが、決済フローによっては、3D セキュアによる認証など、顧客による追加の対応が必要になることがあります。
次のアクションが必要なケースでは、PaymentIntentのステータスは requires_
になります。クライアント側でサーバーに PaymentIntent をリクエストし、その client secret を handleNextAction
に保存します。ネイティブハンドラはビューを表示し、顧客に認証フローを案内します。クライアントで必要なアクションを処理すると、PaymentIntent のステータスは requires_
となります。このステップにより、連携はバックエンドで注文のフルフィルメントを行い、フルフィルメントの結果をクライアントに返すことができます。
PaymentIntent ID をバックエンドに送信し、1 時間以内に再度確定して、支払いを完了します。1 時間以内に確定しない場合、支払いの試行は失敗し、requires_
に戻ります。
// ... const pay = () => { // ... // If PaymentIntent requires action, call handleNextAction if (payment_intent_client_secret && requires_action) { const { error, paymentIntent } = await handleNextAction(payment_intent_client_secret); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { if ( paymentIntent.status === PaymentIntents.Status.RequiresConfirmation ) { // Confirm the PaymentIntent again on your server const response = await fetch(`/pay`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ payment_intent_id: paymentIntent.id }), }); const { error, success } = await response.json(); if (error) { // Error during confirming Intent Alert.alert('Error', error); } else if (success) { Alert.alert('Success', 'The payment was confirmed successfully!'); } } else { // Payment succedeed Alert.alert('Success', 'The payment was confirmed successfully!'); } } } }; // ...
PaymentIntent を再度確定するサーバ側
このコードは、直前のステップでの処理と同様に、支払いに追加の認証が必要な場合にのみ実行されます。どの支払いでもこの追加ステップが必要になる場合があるため、コード自体はオプションではありません。
上記で設定したものと同じエンドポイントを使用し、PaymentIntent を再度確定することにより、支払いを完了して注文のフルフィルメントを実行します。この確定は支払い試行から 1 時間以内に実行してください。実行されない場合は、支払いが失敗して取引が requires_
に戻されます。
組み込みをテストする
この実装の準備ができていることを確認するために、サンドボックスで使用できるテストカードがいくつかあります。任意のセキュリティコードおよび将来の有効期限を指定して使用します。
番号 | 説明 |
---|---|
支払いが成功し、すぐに処理されます。 | |
認証が必要です。Stripe は、顧客に認証を求めるモーダルをトリガーします。 | |
常に支払い拒否コード insufficient_ で失敗します。 |
テストカードの一覧については、テストに関するガイドを参照してください。