# カード支払いの事前設定

手動でのサーバー側の確定を使用するか、支払い方法を別途提示します。

# React Native


> [アプリ内決済を受け付ける](https://docs.stripe.com/payments/mobile/accept-payment.md?platform=react-native&type=setup)ガイドに従うことをお勧めします。このガイドは、サーバー側での手動確定を使用する必要がある場合、または連携で決済手段を別に提示する必要がある場合にのみ使用してください。すでに Elements との連携が完了している場合は、[Payment Element 移行ガイド](https://docs.stripe.com/payments/payment-element/migration.md)をご覧ください。

[Setup Intents API](https://docs.stripe.com/api/setup_intents.md) を使用すると、初回の支払いなしで顧客のカードを保存することができます。これは、今すぐ顧客をアカウント登録して支払いを設定し、将来顧客がオフラインの際に請求するときに役立ちます。

この組み込みを使用して、継続支払いを設定したり、最終金額が後で (顧客がサービスを受け取った後などに) 決定される 1 回限りの支払いを作成します。

## Stripe を設定する [サーバ側] [クライアント側]

### サーバ側

この組み込みには、Stripe API と通信するエンドポイントがサーバ上に必要です。Stripe の公式ライブラリを使用して、サーバから Stripe API にアクセスします。

#### Ruby

```bash
# Available as a gem
sudo gem install stripe
```

```ruby
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
```

### クライアント側

[React Native SDK](https://github.com/stripe/stripe-react-native) はオープンソースであり、詳細なドキュメントが提供されています。内部では、[ネイティブの iOS](https://github.com/stripe/stripe-ios) および [Android](https://github.com/stripe/stripe-android) の SDK を使用します。Stripe の React Native SDK をインストールするには、プロジェクトのディレクトリーで (使用するパッケージマネージャーによって異なる) 次のいずれかのコマンドを実行します。

#### yarn

```bash
yarn add @stripe/stripe-react-native
```

#### npm

```bash
npm install @stripe/stripe-react-native
```

次に、その他の必要な依存関係をインストールします。

- iOS の場合は、**ios** ディレクトリに移動して `pod install` を実行し、必要なネイティブ依存関係もインストールします。
- Android の場合は、依存関係をインストールする必要はありません。

> [公式の TypeScript ガイド](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project)に従って TypeScript のサポートを追加することをお勧めします。

### Stripe の初期化

React Native アプリで Stripe を初期化するには、決済画面を `StripeProvider` コンポーネントでラップするか、`initStripe` 初期化メソッドを使用します。`publishableKey` の API [公開可能キー](https://docs.stripe.com/keys.md#obtain-api-keys)のみが必要です。次の例は、`StripeProvider` コンポーネントを使用して Stripe を初期化する方法を示しています。

```jsx
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>
  );
}
```

> テストおよび開発時には API の[テストキー](https://docs.stripe.com/keys.md#obtain-api-keys)を使用し、アプリの公開時には[本番環境](https://docs.stripe.com/keys.md#test-live-modes)キーを使用します。

## 設定前に Customer を作成する [サーバー側]

将来の決済に備えて決済手段を設定するには、顧客を表すオブジェクトに関連付ける必要があります。顧客がアカウントを作成したとき、または初めて取引したときに、Accounts v2 API を使用して顧客設定の [Account](https://docs.stripe.com/api/v2/core/accounts/create.md) オブジェクト、または Customers API を使用して [Customer](https://docs.stripe.com/api/customers/create.md) オブジェクトを作成します。

#### Accounts v2

```curl
curl -X POST https://api.stripe.com/v2/core/accounts \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-09-30.preview" \
  --json '{
    "contact_email": "jenny.rosen@example.com",
    "display_name": "Jenny Rosen",
    "configuration": {
        "customer": {}
    },
    "include": [
        "configuration.customer"
    ]
  }'
```

作成に成功すると、顧客が設定した [Account](https://docs.stripe.com/api/v2/core/accounts/object.md#v2_account_object-configuration-customer) オブジェクトが返されます。オブジェクトの `id` を確認し、その値を後で取得できるようにデータベースに保存します。

#### Customers v1

```curl
curl https://api.stripe.com/v1/customers \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "name=Jenny Rosen" \
  --data-urlencode "email=jennyrosen@example.com"
```

作成に成功すると、[Customer](https://docs.stripe.com/api/customers/object.md) オブジェクトが返されます。オブジェクトの `id` を確認し、その値を後で取得できるようにデータベースに保存します。

これらの顧客は、ダッシュボードの[顧客](https://dashboard.stripe.com/customers)ページで見つけることができます。

## SetupIntent を作成する [サーバー側]

[SetupIntent (支払い方法設定インテント)](https://docs.stripe.com/api/setup_intents.md) は、将来の支払いに備えて支払い方法を設定するという意図を示すオブジェクトです。SetupIntent オブジェクトには、アプリに渡すための一意のキーである、[client secret](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-client_secret) が格納されます。

client secret を使用することで、`customer` のような機密情報を保護すると同時に、設定の確認や支払い方法の詳細の更新などの一定のアクションをクライアント側で実行できるようになります。client secret を使用すると、クレジットカードネットワークを利用してカード詳細を検証および認証できます。client secret は機密情報なので、ログに記録したり、URL に埋め込んだり、当該の顧客以外に漏洩することがないようにしてください。

### サーバー側

サーバー側で SetupIntent を作成し、その client secret をアプリに返すエンドポイントを作成します。

#### curl

```bash
curl https://api.stripe.com/v1/setup_intents/ \
  -u <<YOUR_SECRET_KEY>>: \
  -d "customer"="{{CUSTOMER_ID}}"
```

顧客がチェックアウトフローでオンセッション時にのみ、今後の支払いでカードを使用する場合、[usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage) パラメータを *on\_session* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method) に設定して、オーソリ率を改善します。

## カード詳細を収集する [クライアント側]

カード番号、有効期限、セキュリティコード、郵便番号を収集する、SDK が提供する UI コンポーネント、`CardField` を使用して、クライアント側でカード情報を安全に収集します。
![](https://d37ugbyn3rpeym.cloudfront.net/docs/mobile/ios/card-field.mp4)
`CardField` コンポーネントを支払い画面に追加することで、顧客からカード詳細を安全に収集します。`onCardChange` コールバックを使用して、カードのブランドや詳細情報の欠落の有無など、カードに関する機密性の低い情報を検査します。

```javascript
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>
  );
}
```

> 特にヨーロッパでは、カードの再利用に関する規制があるため、カード詳細を保存して今後の *オフセッションの支払い* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information) に使用する際は、カードを保存するための [許可を取得](https://docs.stripe.com/strong-customer-authentication.md#sca-enforcement) します。カードをどのように使用するかを顧客に知らせるテキストを決済フローに含めてください。

設定を完了するには、顧客のカードと請求情報を `confirmSetupIntent` に渡します。このメソッドには、`useConfirmSetupIntent` フックまたは `useStripe` フックを使用してアクセスできます。

```javascript
function PaymentScreen() {
  // ...

  const { confirmSetupIntent, loading } = useConfirmSetupIntent();

  // ...

  const handlePayPress = async () => {
    // Gather the customer's billing information (for example, email)
    const billingDetails: BillingDetails = {
      email: 'jenny.rosen@example.com',
    };
    // Create a setup intent on the backend
    const clientSecret = await createSetupIntentOnBackend();
    const { setupIntent, error } = await confirmSetupIntent(clientSecret, {
      paymentMethodType: 'Card',
      paymentMethodData: {
        billingDetails,
      }
    });

    if (error) {
      //Handle the error
    }
    // ...
  };

  return (
    <View>
      // ...
      <Button onPress={handlePayPress} title="Save" loading={loading} />
    </View>
  );
}
```

一部の支払い方法では、支払いを完了するために[追加の認証手順](https://docs.stripe.com/payments/payment-intents/verifying-status.md#next-actions)が必要です。SDK が、支払いの確定と認証フローを管理します。これには、認証に必要な追加の画面の表示が含まれる場合があります。認証プロセスをテストするには、テストカード `4000 0025 0000 3155` を、セキュリティコード、郵便番号、および有効期限とともに使用します。

`SetupIntent` が成功すると、(`setupIntent.paymentMethodID` で) 生成された PaymentMethod ID が、指定された `Customer` に保存されます。

## 保存されたカードに後で請求する [サーバー側]

顧客にオフセッションで支払いを行う準備ができたら、顧客 ID と PaymentMethod ID を使用して、PaymentIntent を作成します。支払いするクレジットカードを見つけるには、顧客に関連付けられた PaymentMethod を[リスト](https://docs.stripe.com/api/payment_methods/list.md)します。

#### Accounts v2

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d type=card
```

#### Customers v1

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer={{CUSTOMER_ID}}" \
  -d type=card
```

Customer ID と PaymentMethod ID を取得したら、支払いの金額と通貨を使用して PaymentIntent を作成します。下記のパラメータを設定し、オフセッションの支払いを行います。

- [off_session](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-off_session) を `true` に設定して、支払いの実行時に顧客が決済フローに存在しないことを示します。これにより、認証が必要な場合は PaymentIntent からエラーが返されます。
- PaymentIntent の [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) プロパティの値を `true` に設定します。これにより、PaymentIntent が作成されると直ちに確定されます。
- [payment_method](https://docs.stripe.com/api.md#create_payment_intent-payment_method) を PaymentMethod の ID に設定し、[customer](https://docs.stripe.com/api.md#create_payment_intent-customer) を Customer の ID に設定します。

#### curl

```bash
curl https://api.stripe.com/v1/payment_intents \
  -u <<YOUR_SECRET_KEY>>: \
  -d amount=1099 \
  -d currency=usd \
  -d customer="{{CUSTOMER_ID}}" \
  -d payment_method="{{PAYMENT_METHOD_ID}}" \
  -d off_session=true \
  -d confirm=true
```

### リカバリフローを開始する

PaymentIntent に他のステータスがある場合、支払いは成功せず、リクエストは失敗します。支払いを完了するために (メール、テキスト、プッシュ通知などで) アプリケーションに戻るように顧客に通知します。支払いが最初に失敗した理由を示し、顧客が再試行できるようにするリカバリフローをアプリで作成することをお勧めします。

リカバリフローで *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)) を使用して PaymentIntent を取得します。PaymentIntent の `lastPaymentError` を確認し、支払いの試行が失敗した理由を調べます。カードエラーの場合、支払いエラーの最後の[メッセージ](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-last_payment_error-message)をユーザーに表示できます。それ以外の場合は、汎用の失敗メッセ―ジを表示します。

```javascript
function PaymentScreen() {
  // ...

  const {retrievePaymentIntent} = useStripe();

  // ...

  const handleRecoveryFlow = async () => {
    const {paymentIntent, error} = await retrievePaymentIntent(clientSecret);

    if (error) {
      Alert.alert(`Error: ${error.code}`, error.message);
    } else if (paymentIntent) {
      // Default to a generic error message
      let failureReason = 'Payment failed, try again.';
      if (paymentIntent.lastPaymentError.type === 'Card') {
        failureReason = paymentIntent.lastPaymentError.message;
      }
    }
  };

  return (
    <View>
      // ...
      <Button
        onPress={handleRecoveryFlow}
        title="Recovery flow"
        loading={loading}
      />
    </View>
  );
}
```

### 顧客に再試行してもらう

保存されたカードを[更新](https://docs.stripe.com/api/payment_methods/update.md)または[削除](https://docs.stripe.com/api/payment_methods/detach.md)し、支払いを再試行するオプションをリカバリフローで顧客に提供します。最初の支払いを受け付けるのと同じ手順に従いますが、1 つ異なる点があります。元の失敗した PaymentIntent を*確定* (Confirming a PaymentIntent indicates that the customer intends to pay with the current or provided payment method. Upon confirmation, the PaymentIntent attempts to initiate a payment)するために新しい支払いインテントを作成するのではなく、その [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) を再利用します。

認証が必要なために支払いが失敗した場合は、新しい支払い方法を作成するのではなく、既存の PaymentMethod を使用して再試行してください。

```javascript
function PaymentScreen() {
  // ...

  const {retrievePaymentIntent} = useStripe();

  // ...

  const handleRecoveryFlow = async () => {
    const {paymentIntent, error} = await retrievePaymentIntent(clientSecret);

    if (error) {
      Alert.alert(`Error: ${error.code}`, error.message);
    } else if (paymentIntent) {
      // Default to a generic error message
      let failureReason = 'Payment failed, try again.';
      if (paymentIntent.lastPaymentError.type === 'Card') {
        failureReason = paymentIntent.lastPaymentError.message;
      }

      // If the last payment error is authentication_required, let the customer
      // complete the payment without asking them to reenter their details.
      if (paymentIntent.lastPaymentError?.code === 'authentication_required') {
        // Let the customer complete the payment with the existing PaymentMethod
        const {error} = await confirmPayment(paymentIntent.clientSecret, {
          paymentMethodType: 'Card',
          paymentMethodData: {
            billingDetails,
            paymentMethodId: paymentIntent.lastPaymentError?.paymentMethod.id,
          },
        });

        if (error) {
          // handle error
        }
      } else {
        // Collect a new PaymentMethod from the customer
      }
    }
  };

  return (
    <View>
      // ...
      <Button
        onPress={handleRecoveryFlow}
        title="Recovery flow"
        loading={loading}
      />
    </View>
  );
}
```

## 組み込みをテストする

ここまでで、以下を実行する組み込みが完成しています。

1. SetupIntent を使用して、顧客に請求することなくカード詳細を収集・保存する
2. オフセッションでカードに請求し、支払い拒否と認証リクエストを処理するリカバリーフローが備わっている

この組み込みの稼働準備ができていることを確認するために使用できるいくつかのテストカードがあります。任意のセキュリティコード、郵便番号、および今後の有効期限を指定して使用します。

| 番号               | 説明                                                                                      |
| ---------------- | --------------------------------------------------------------------------------------- |
| 4242424242424242 | 成功し、支払いがすぐに処理されます。                                                                      |
| 4000002500003155 | 初めての購入には認証が必要ですが、カードに `setup_future_usage` の設定があれば、以降の支払い (オフセッションの支払いを含む) に成功します。      |
| 4000002760003184 | 初めての購入には認証が必要で、以降の支払い (オフセッションの支払いを含む) には失敗し、支払い拒否コード `authentication_required` が返されます。 |
| 4000008260003178 | 初めての購入には認証が必要で、以降の支払い (オフセッションの支払いを含む) には失敗し、支払い拒否コード `insufficient_funds` が返されます。      |
| 4000000000009995 | (初めての購入を含め) 常に失敗し、支払い拒否コード `insufficient_funds` が返されます。                                 |

[テストカード](https://docs.stripe.com/testing.md)の全一覧をご覧ください。

