# 銀行認証なしのカード支払い

よりシンプルな地域限定の実装を構築します。

この導入は、アメリカとカナダのカードのみを受け付けるビジネスをサポートしています。初期統合はシンプルですが、グローバルな顧客ベースをサポートするように成長することはできません。

### この導入の仕組み

ヨーロッパやインドなどの地域の銀行は、購入を確定するために二要素認証を求めることがよくあります。主にアメリカとカナダでビジネスを行っている場合には、これらの地域の銀行はほとんど 2 段階認証を求めないため、*カード認証* (A bank might require the customer to authenticate a card payment before processing. Implementation varies by bank but commonly consists of a customer entering in a security code sent to their phone)を配慮しないことで実装がシンプルになります。

銀行が認証を要求すると、この基本的な組み込みは、決済を非同期で完了するための認証処理は行わず、直ちに決済を拒否します (カード拒否のように)。この利点は、決済の成功や失敗が直ちに決定され、決済確定がサーバーで行われるため、*Webhook* (A configurable endpoint that executes when it receives certain event notifications from an event destination) を使用せずに直ちに決済後のアクションを処理できることです。

### グローバル導入との比較

| 機能 | この組み込み | グローバル組み込み |
| --- | --- | --- |
| カスタムの支払いフォーム | ✔ | ✔ |
| 機密データがお客様のサーバに触れない | ✔ | ✔ |
| アメリカとカナダの顧客に対応 | ✔ | ✔ |
| カード詳細が不正確な場合や残高不足の場合に支払いを拒否 | ✔ | ✔ |
| 銀行から認証要求があると支払いを拒否 | ✔ |  |
| グローバルな顧客に対応 |  | ✔ |
| 銀行の認証が必要なカード支払いを自動的に処理 |  | ✔ |
| 支払い後のタスクに推奨される Webhook |  | ✔ |
| 他の支払い方法 (銀行引き落としなど) に簡単に拡張可能 |  | ✔ |

成長を遂げている企業やグローバル企業には、Stripe の[グローバルなシステム](https://docs.stripe.com/payments/accept-a-payment.md)を使用して、銀行の 2 段階認証の要求に対応し、顧客がより広範な支払い方法を使用できるようにすることをお勧めします。

決済フロー (See full diagram at https://docs.stripe.com/payments/without-card-authentication)

```text
[顧客] -- カード詳細を提供して Pay (支払う) ボタンをクリックする --> [クライアント]
[クライアント] -- stripe.createPaymentMethod を呼び出す --> [Stripe]
[Stripe] -- PaymentMethod を返す --> [クライアント]
[クライアント] -- 注文の詳細と PaymentMethod ID を使用して支払いを確定する --> [サーバー]
[サーバー] -- POST /v1/payment_intents confirm=true --> [Stripe]
[Stripe] -- 支払いを試行 --> [Stripe]
[Stripe] -- 認証が不要な場合、「succeeded」のステータスで新しい PaymentIntent を返す --> [サーバー]
[Stripe] -- 支払いを試行 --> [Stripe]
[Stripe] -- 認証が必要な場合、「authentication_required」のコードで新しいエラーを返す --> [サーバー]
```

## 決済フォームの構築 [クライアント側]

Stripe.js の一部である [Elements](https://docs.stripe.com/payments/elements.md) は、顧客からカード情報を収集するドロップイン UI コンポーネントを提供します。Stripe はこれらをホストし、iframe として支払いフォームに配置するため、顧客のカード情報がコードに触れることはありません。

#### HTML + JS

まず、お客様のサイトの各ページの先頭に [Stripe.js](https://docs.stripe.com/js.md) スクリプトを含めます。

```html
<script src="https://js.stripe.com/endive/stripe.js"></script>
```

サイトの各ページにスクリプトを含めることで、Stripe の[アドバンス不正利用検出機能](https://docs.stripe.com/radar.md)および異常な閲覧動作を検知する能力を活用できます。

### セキュリティ要件

[PCI 準拠](https://docs.stripe.com/security/guide.md)を保持するには、このスクリプトを常に **js.stripe.com** から直接読み込んでください。このスクリプトをバンドルに含めたり、そのコピーを自身でホストすることはできません。

Elements を使用する際には、すべての情報は安全な HTTPS 接続を介して送信されます。

また、Elements を含むページのアドレスの先頭は、**http://** ではなく、**https://** にする必要もあります。SSL 証明書の取得や、それをサーバに組み込んで安全な HTTPS 接続を有効化する方法については、[セキュリティ](https://docs.stripe.com/security.md)のドキュメントをご覧ください。

### Elements をページに追加する

次に、Stripe アカウントが必要です。[今すぐ登録](https://dashboard.stripe.com/register)してください。

支払いフォーム内に、一意の ID を持つ空の DOM Elements (コンテナ) を作成してください。

```html
<form id="payment-form">
  <div id="card-element"><!-- placeholder for Elements --></div>
  <button id="card-button">Submit Payment</button>
  <p id="payment-result"><!-- we'll pass the response from the server here --></p>
</form>
```

[Stripe オブジェクト](https://docs.stripe.com/js.md#stripe-function)のインスタンスを作成し、公開可能な [API キー](https://docs.stripe.com/keys.md)を最初のパラメーターとして指定します。その後、[Elements オブジェクト](https://docs.stripe.com/js.md#stripe-elements)のインスタンスを作成し、それを使用してページにある空の DOM Element コンテナに Card Element を[マウント](https://docs.stripe.com/js.md#element-mount)します。

```javascript
const stripe = Stripe('<<YOUR_PUBLISHABLE_KEY>>');

const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
```

クライアントで [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) を使用してカード詳細を収集し、顧客が支払いフォームを送信したら、[PaymentMethod (支払い方法)](https://docs.stripe.com/api/payment_methods.md) を作成します。その PaymentMethod の ID をサーバに送信します。

```javascript
const form = document.getElementById("payment-form");

var resultContainer = document.getElementById('payment-result');

// cardElement is defined in the previous step
cardElement.on('change', function(event) {
  if (event.error) {
    resultContainer.textContent = event.error.message;
  } else {
    resultContainer.textContent = '';
  }
});

form.addEventListener('submit', async event => {
  event.preventDefault();
  resultContainer.textContent = '';
  const result = await stripe.createPaymentMethod({
    type: 'card',
    card: cardElement,
  });
  handlePaymentMethodResult(result);
});

const handlePaymentMethodResult = async ({ paymentMethod, error }) => {
  if (error) {
    // An error happened when collecting card details, show error in payment form
    resultContainer.textContent = error.message;
  } else {
    // Send paymentMethod.id to your server (see Step 3)
    const response = await fetch("/pay", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ payment_method_id: paymentMethod.id })
    });

    const responseJson = await response.json();

    handleServerResponse(responseJson);
  }
};

const handleServerResponse = async responseJson => {
  if (responseJson.error) {
    // An error happened when charging the card, show it in the payment form
    resultContainer.textContent = responseJson.error;
  } else {
    // Show a success message
    resultContainer.textContent = 'Success!';
  }
};
```

#### React

まず、[Stripe.js](https://github.com/stripe/stripe-js) と [React Stripe.js](https://docs.stripe.com/sdks/stripejs-react.md) をインストールします。

```bash
npm install --save @stripe/stripe-js @stripe/react-stripe-js
```

> このガイドは、React の基本的な実務知識があり、React プロジェクトがすでに設定されていることを前提としています。React を初めて使用する場合は、続行する前に React [使用開始](https://reactjs.org/docs/getting-started.html)ガイドを読むことをお勧めします。
> 
> 新しいプロジェクトを構築することなく React Stripe.js を簡単に試す方法をお探しの場合は、この [CodeSandbox のデモ](https://codesandbox.io/s/react-stripe-official-q1loc?fontsize=14&hidenavigation=1&theme=dark)から始めてください。

### セキュリティ要件

Elements を使用する際には、すべての情報は安全な HTTPS 接続を介して送信されます。

また、Elements を含むページのアドレスの先頭は、**http://** ではなく、**https://** にする必要もあります。SSL 証明書の取得や、それをサーバに組み込んで安全な HTTPS 接続を有効化する方法については、[セキュリティ](https://docs.stripe.com/security.md)のドキュメントをご覧ください。

### お客様のページへの Stripe.js および Elements の読み込み

Elements を使用するには、React アプリのルートを [Elements](https://docs.stripe.com/sdks/stripejs-react.md?ui=elements#elements-provider) プロバイダーでラップします。公開可能キーを使用して [loadStripe](https://github.com/stripe/stripe-js#loadstripe) を呼び出し、返された `Promise` を `Elements` プロバイダーに渡します。

Stripe の[アドバンス不正利用機能](https://docs.stripe.com/radar.md)および特異な閲覧動作を検知する能力を活用するため、React アプリのルートで `loadStripe` をインポートし、呼び出すことが重要です。

```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from '@stripe/stripe-js';

import CheckoutForm from './CheckoutForm';

// Make sure to call `loadStripe` outside of a component's render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe("<<YOUR_PUBLISHABLE_KEY>>");

function App() {
  return (
    <Elements stripe={stripePromise}>
      <CheckoutForm />
    </Elements>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
```

### PaymentMethod の作成

クライアントで、`CardElement` および [stripe.createPaymentMethod](https://docs.stripe.com/js/payment_methods/create_payment_method) を使用してカード詳細を収集し、顧客が支払いフォームを送信したら、[PaymentMethod (支払い方法)](https://docs.stripe.com/api/payment_methods.md) を作成します。その PaymentMethod の ID をサーバに送信します。

決済フォームコンポーネントから `stripe.createPaymentMethod` を呼び出すには、[useStripe](https://docs.stripe.com/sdks/stripejs-react.md?ui=elements#usestripe-hook) および [useElements](https://docs.stripe.com/sdks/stripejs-react.md?ui=elements#useelements-hook) フックを使用します。フックではなく従来のクラスコンポーネントを使用する場合は、代わりに [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md?ui=elements#elements-consumer) を使用できます。

#### フック

```jsx
import React from 'react';
import {useStripe, useElements, CardElement} from '@stripe/react-stripe-js';

export default function CheckoutForm() {
  const stripe = useStripe();
  const elements = useElements();

  const handleSubmit = async (event) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    event.preventDefault();

    const result = await stripe.createPaymentMethod({
      type: 'card',
      card: elements.getElement(CardElement),
      billing_details: {
        // Include any additional collected billing details.
        name: 'Jenny Rosen',
      },
    });

    handlePaymentMethodResult(result);
  };

  const handlePaymentMethodResult = async (result) => {
    if (result.error) {
      // An error happened when collecting card details,
      // show `result.error.message` in the payment form.
    } else {
      // Otherwise send paymentMethod.id to your server (see Step 3)
      const response = await fetch('/pay', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          payment_method_id: result.paymentMethod.id,
        }),
      });

      const serverResponse = await response.json();

      handleServerResponse(serverResponse);
    }
  };

  const handleServerResponse = (serverResponse) => {
    if (serverResponse.error) {
      // An error happened when charging the card,
      // show the error in the payment form.
    } else {
      // Show a success message
    }
  };

  const handleCardChange = (event) => {
    if (event.error) {
      // Show `event.error.message` in the payment form.
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement onChange={handleCardChange} />
      <button type="submit" disabled={!stripe}>
        Submit Payment
      </button>
    </form>
  );
}
```

## 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'
```

## 支払いの作成 [サーバ側]

サーバにエンドポイントを設定し、クライアントからリクエストを受信します。

Stripe は [PaymentIntent (支払いインテント)](https://docs.stripe.com/api/payment_intents.md) オブジェクトを使用して、顧客から支払いを回収する意図を示し、プロセス全体を通して請求の実施と支払い状態の変化を追跡します。

クライアント側ではなく、信頼できる環境のサーバ側で常に支払い金額を指定してください。これにより、悪意のある顧客が独自の金額を選択できないようにします。

ステップ 1 の AJAX リクエストに応答する HTTP エンドポイントを作成します。そのエンドポイントで、顧客にいくら請求するかを決定します。決済を作成するには、以下のコードで、ステップ 1 からの *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) ID を使用して PaymentIntent を作成します。

#### curl

```curl
# Check the status of the PaymentIntent to make sure it succeeded

curl https://api.stripe.com/v1/payment_intents \
  -u <<YOUR_SECRET_KEY>>: \
  -d amount=1099 \
  -d currency=usd \

# A PaymentIntent can be confirmed some time after creation,
# but here we want to confirm (collect payment) immediately.
  -d confirm=true \
  -d payment_method="{{PAYMENT_METHOD_ID}}" \

# If the payment requires any follow-up actions from the
# customer, like two-factor authentication, Stripe will error
# and you will need to prompt them for a new payment method.
  -d error_on_requires_action=true
```

> 支払いを確定する際に、[error_on_requires_action](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-error_on_requires_action) を `true` に設定すると、ユーザーから 2 段階認証が必要とされる場合、Stripe はその支払いを自動的に拒否します。

#### Payment Intents API レスポンス

API で支払いを作成すると、そのレスポンスには PaymentIntent のステータスが含まれます。支払いが成功した場合には、ステータスは `succeeded` になります。

```json
{
  "id": "pi_0FdpcX589O8KAxCGR6tGNyWj",
  "object": "payment_intent",
  "amount": 1099,
  "charges": {
    "object": "list",
    "data": [
      {
        "id": "ch_GA9w4aF29fYajT",
        "object": "charge",
        "amount": 1099,
        "refunded": false,
        "status": "succeeded",
      }
    ]
  },
  "client_secret": "pi_0FdpcX589O8KAxCGR6tGNyWj_secret_e00tjcVrSv2tjjufYqPNZBKZc",
  "currency": "usd",
  "last_payment_error": null,
  "status": "succeeded",
}
```

支払いが拒否されると、そのレスポンスにはエラーコードとエラーメッセージが含まれます。以下は、カードに 2 段階認証が必要とされるために支払いが拒否された例です。

```json
{
  "error": {
    "code": "authentication_required",
    "decline_code": "authentication_not_handled",
    "doc_url": "https://docs.stripe.com/error-codes#authentication-required",
    "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.",
    "payment_intent": {
      "id": "pi_1G8JtxDpqHItWkFAnB32FhtI",
      "object": "payment_intent",
      "amount": 1099,
      "status": "requires_payment_method",
      "last_payment_error": {
        "code": "authentication_required",
        "decline_code": "authentication_not_handled",
        "doc_url": "https://docs.stripe.com/error-codes#authentication-required",
        "message": "This payment required an authentication action to complete, but `error_on_requires_action` was set. When you're ready, you can upgrade your integration to handle actions at https://stripe.com/docs/payments/payment-intents/upgrade-to-handle-actions.",
        "type": "card_error"
      }
    },
    "type": "card_error"
  }
}
```

## 組み込みのテスト

Stripe では、この実装の準備ができていることを確認するために、*サンドボックス* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes)で使用できるテストカードをいくつか提供しています。任意のセキュリティコード、郵便番号、および今後の有効期限を指定して使用します。

| 番号 | 説明 |
| --- | --- |
| 4242424242424242 | 成功し、すぐに支払いを処理します。 |
| 4000000000009995 | 支払い拒否コード `insufficient_funds` で常に失敗します。 |
| 4000002500003155 | 認証を必要とします。この組み込みでは、`authentication_not_handled` というコードで拒否されます。 |

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

## カード認証を処理するために組み込みをアップグレードする

基本的なカード決済用の決済導入が完了しました。この導入は、**決済中に認証を必要とするカードを拒否する** ことにご注意ください。

ダッシュボードで決済が `Failed` としてリストされるようになった場合は、[連携をアップグレード](https://docs.stripe.com/payments/payment-intents/upgrade-to-handle-actions.md)する必要があります。Stripe グローバル導入は、決済を自動的に拒否するのではなく、これらの決済を処理します。
