クレジットカード決済の実装方法


# クレジットカード決済

ブランドに合ったクレジットカードフィールドを追加することで、カスタマイズされたチェックアウト体験を提供します。

> カスタマイズされたカードフォームが必要な場合は、[高度なクレジットカードおよびデビットカード決済](#アドバンストクレジットカード決済実装方法)を統合してください。カスタマイズにこだわらず、より迅速な決済手段をお探しの場合は、[ベーシックなクレジットカードおよびデビットカード決済](#ベーシッククレジットカード決済実装方法)の設定をご覧ください。

## PayPalアカウント登録・API認証情報取得

[PayPalアカウント登録・API認証情報取得](https://qiita.com/PPJP/items/fe7cbd0f85b19de98260)

## アドバンストクレジットカード決済実装方法

ご利用には審査があります。お問い合わせはこちら。

https://www.paypal.com/jp/webapps/mpp/ucc-sales-form

> カスタマイズされたカードフォームが必要な場合は、[高度なクレジットカードおよびデビットカード決済](#アドバンストクレジットカード決済実装方法)を統合してください。カスタマイズにこだわらず、より迅速な決済手段をお探しの場合は、[ベーシックなクレジットカードおよびデビットカード決済](#ベーシッククレジットカード決済実装方法)の設定をご覧ください。

**REST API URL**

PayPal REST APIと通信するには、サンドボックス環境または本番環境のいずれかで、JSON形式のHTTPリクエストをAPIエンドポイントに渡します。

| 環境 | エンドポイント |
|:-|:-|
| Sandbox | https://api-m.sandbox.paypal.com |
| 本番環境 | https://api-m.paypal.com |

**APIべき等性**

[API idempotency](https://developer.paypal.com/docs/business/develop/idempotency/)

サーバーがリソースに対するアクションを複数回作成したり完了したりすることを気にすることなく、何度でもコールを行うことができます。ネットワークタイムアウトや HTTP 5xx ステータスコードで失敗した呼び出しを、サーバが ID を保存している限り再試行することができます。べき等性を使用すると、リクエストのペイロードをレスポンスのペイロードと相関させ、重複したリクエストを排除し、失敗したリクエストやレスポンスが不明瞭なリクエストを再試行することができます。

REST APIのPOST呼び出しでIdempotencyを強制するには、PayPal-Request-Idリクエストヘッダーを使用します。このヘッダーには、サーバーが一定期間保存する一意のユーザー生成IDが含まれています。

**注意** すべてのAPIがこのヘッダーをサポートしているわけではありません。お使いのAPIがこのヘッダーをサポートしているかどうか、およびサーバーがIDを保存する期間に関する情報については、お使いのAPIのリファレンスを参照してください。

たとえば、以前に指定したPayPal-Request-Idヘッダーをリクエストに含めると、PayPalは、同じヘッダーを使用した以前のリクエストの最新のステータスを返します。逆に、リクエストからPayPal-Request-Idヘッダーを省略すると、PayPalはリクエストを複製します。

**注意** 同じPayPal-Request-Idヘッダーを持つ2つのAPIリクエストを同時に送信すると、PayPalは最初のリクエストを処理し、2つ目のリクエストに失敗する可能性があります。

使用上の注意

- PayPal-Request-Idヘッダー値は、各リクエストとAPIコールタイプの両方で一意でなければなりません。たとえば、authorize paymentやcapture authorized paymentなどです。
- PayPalは、元のリクエストのステータスではなく、現在の時点でのリクエストのステータスを提供します。

### JavaScript SDK

JavaScript SDKは、あなたのページにPayPalがサポートしている支払い方法を表示し、バイヤーにパーソナライズされた合理的なチェックアウト体験を提供します。

JavaScript SDK スクリプトにクエリとスクリプトのパラメータを渡すことで、実装をカスタマイズできます。これらのパラメータは、PayPal が最適な決済方法とボタンを決定して、バイヤーに表示するのに役立ちます。

[JavaScript SDK script configuration](https://developer.paypal.com/docs/business/javascript-sdk/javascript-sdk-configuration/)
[JavaScript SDK Complete Reference](https://developer.paypal.com/docs/business/javascript-sdk/javascript-sdk-reference/)
[JavaScript SDK performance optimization](https://developer.paypal.com/docs/business/javascript-sdk/js-sdk-performance/)

### アドバンストクレジットカード決済

[Set up advanced credit and debit card payments](https://developer.paypal.com/docs/business/checkout/advanced-card-payments/)

概要

1. 以下のサンプルコードをコピーして、チェックアウトページに貼り付けてください。
1. コード中の YOUR_SB_CLIENT_ID を、使用するClient IDに置き換えてください。
1. 必要に応じてJavaScript SDKに渡すパラメータを明示的に指定して、デフォルトの値を上書きしてください。各パラメータのデフォルト値については[JavaScript SDK script configuration](https://developer.paypal.com/docs/business/javascript-sdk/javascript-sdk-configuration/)を参照してください。
1. 決済情報を送信するためのサーバ側コードを実装してください。createOrderとonApproveのメソッド内からサーバ側へリクエストしてください。サーバ側の実装は以降の説明を参照してください。

対応通貨
AUD, CAD, CHF, CZK, DKK, EUR, GBP, HKD, HUF, JPY, NOK, NZD, PLN, SGD, SEK, USD
(AmexとJCBは日本円のみ)

#### Access Tokenを作成する

[Exchange your API credentials for an access token](https://developer.paypal.com/docs/business/get-started/#exchange-your-api-credentials-for-an-access-token)

<details><summary>サンプルリクエスト</summary><div>

```
curl -v https://api-m.sandbox.paypal.com/v1/oauth2/token \
-H "Accept: application/json" \
-H "Accept-Language: en_US" \
-u "<client_id>:<secret>" \
-d "grant_type=client_credentials"
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
    "access_token": "A21AAGk9mYWDNvy-OzYmU985kgwscf16by3R_97_RF-t90y_0TFTFQIhSndxdUcpfuY9dnMOpbwuNkmOZrsfnlmVSIPIOGraQ",
    "app_id": "APP-804485P543195W28T",
    "expires_in": 32400,
    "nonce": "2019-12-04T09:29:10Z01fPaJg9ztZoKhcsgIG1cjlWPxTy_HCiHPIDtPKvfDs",
    "scope": "https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller https://uri.paypal.com/services/payments/refund https://api.paypal.com/v1/vault/credit-card https://api.paypal.com/v1/payments/.* https://uri.paypal.com/payments/payouts https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/subscriptions https://uri.paypal.com/services/applications/webhooks",
    "token_type": "Bearer"
}
```
</div></details>


#### Client Tokenを作成する

[Generate client token](https://developer.paypal.com/docs/business/checkout/advanced-card-payments/#2-generate-client-token)

customer_idは、貴社のプラットフォーム上で購入者を認識するためのユニークなユーザーIDを設定ください。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST https://api-m.sandbox.paypal.com/v1/identity/generate-token \
-H "Content-Type: application/json" \
-H "Accept-Language: en_US" \
-H "Authorization: Bearer <access token>" \
-d '{
 "customer_id": "customer_1234"
}'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
    "client_token": "eyJicmF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9NjNrdm4zN3Z0MjlxYjRkZiZjcmVhdGVkX2F0PTIwMTktMTItMDRUMpSllRR3VXOUJZMHo3bVQ3dWtiQ1FuenBtOVBiV1pPbkJpXzNqeGpbnRyZDk6Mjk6MzkuNjYyWiIsInZlcnNpb24iOiIzLXB5MDg2Yjk0NGZkZWU3NTAwYTVmMGM2MTI1NTExNzliNjc4N2M3OGQ3M2NhZWFkNDA3YjE4YXxtZXJjaGFudFptaURMYndlaEVYOWRIVEtpcURuRjRkV0s1eUZWWlpIQ3NFem04WkFwcUJNOUl2Wm9wNV93InheXBhbCJ9LCJwYXlwYWwiOnsiYWNjZXNzVG9rZW4iOiJBMjFBQUVWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiZTNjNzY2MmYwZTk19",
    "expires_in": 3600
}
```
</div></details>

#### クレジットカードフォームを追加する

[Add JavaScript SDK and card form](https://developer.paypal.com/docs/business/checkout/advanced-card-payments/#3-add-javascript-sdk-and-card-form)

PayPal JavaScript SDKのデフォルトのintentは、指定しない場合intent=captureであり、トランザクションのオーソリ(authorize)と売上(capture)の両方を直ちに行うことです。オーソリと売上を別々のアクションに分割するには、PayPal JavaScript SDK のスクリプトタグにintent=authorize を追加します。

フォームのカスタマイズは [Style for advanced credit and debit card payments](https://developer.paypal.com/docs/business/checkout/reference/style-guide/#style-for-advanced-credit-and-debit-card-payments) を参照してください。

**注意:**
**Internet Explorerではクレジットカード決済をご利用いただけません。以下のような注意文を掲載してください。**
Internet Explorerではクレジットカード決済をご利用いただけません。
Microsoft Edge, Google Chrome, Safariなどのブラウザをご利用ください。

<details><summary>サンプルフォーム</summary><div>

```html
<!doctype html>
<head>
  <script
    src="https://www.paypal.com/sdk/js?components=hosted-fields&client-id=<client_id>&currency=JPY&intent=capture"
    data-client-token="<client_token>">
    </script>
</head>

<body>
  <form id="my-sample-form">
    <label for="card-number">Card Number</label>
    <div id="card-number"></div>

    <label for="expiration-date">Expiration Date</label>
    <div id="expiration-date"></div>

    <label for="cvv">CVV</label>
    <div id="cvv"></div>

    <button value="submit" id="submit" class="btn">Pay with Card</button>
  </form>

  <script>
    // Check if card fields are eligible to render for the buyer's country. The card fields are not eligible in all countries where buyers are located.
    if (paypal.HostedFields.isEligible() === true) {
      paypal.HostedFields.render({
        createOrder: function (data, actions) {
          // logic to return an order ID from your server
          return fetch('/my-server/create-order', {
            method: 'POST'
          }).then(function (res) {
            return res.json();
          }).then(function (data) {
            return data.id;
          });
        },
        styles: {
          'input': {
            'font-size': '14px',
            'font-family': 'Product Sans',
            'color': '#3a3a3a'
          },
          ':focus': {
            'color': 'black'
          },
          '.invalid': {
            'color': '#FF0000'
          }
        },
        fields: {
          number: {
            selector: '#card-number',
            placeholder: 'Credit Card Number',
          },
          cvv: {
            selector: '#cvv',
            placeholder: 'CVV',
          },
          expirationDate: {
            selector: '#expiration-date',
            placeholder: 'MM/YYYY',
          }
        }
      }).then(function (hf) {

        document.querySelector('#my-sample-form').addEventListener('submit', event => {
          event.preventDefault();
          hf.submit().then(function (payload) {
            // Make a call to capture the order (payload.orderId) here
          });
        });
      });
    }
    else {
      /*
      * Handle experience when
      * Custom Card Fields is not eligible
      */
    }
  </script>

</body>
</html>
```
</div></details>


#### 決済を作成する

サンプルHTMLフォームの /my-server/create-order で下記 /v2/checkout/orders を貴社サーバからコールし決済を作成します。

[Create an order](https://developer.paypal.com/docs/business/checkout/server-side-api-calls/create-order)
[https://developer.paypal.com/docs/api/orders/v2/#orders_create](https://developer.paypal.com/docs/api/orders/v2/#orders_create)

IntentにCAPTUREまたはAUTHORIZEを設定します。JavaScriptのクエリパラメータで指定したintentと一致する必要があります。intent パラメータを[Captureにすると決済が確定](#決済を実行する)されます。[Authorizeの場合には、与信のみを取得して](#オーソリを実行する)決済の確定は行われません。

以下のパラメータを追加してください。

- shipping: 貴社サイト上で指定した配送先住所
- shipping_preference: "SET_PROVIDED_ADDRESS"
- name: 購入者の指名
- email_address: 購入者のメールアドレス
- phone: 購入者の電話番号
- address: 購入者の住所
- invoice_id: 貴社で発番した一意の注文ID

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access token>" \
-d '{
  "intent": "CAPTURE",
  "application_context": {
    "shipping_preference": "SET_PROVIDED_ADDRESS",
    "brand_name": "Your Site Name"
  },
  "payer": {
    "name": {
      "given_name": "太郎",
      "surname": "青山"
    },
    "email_address": "buyer@example.com",
    "address": {
      "address_line_1": "青山1-2-3",
      "address_line_2": "ペイパルビル 1001",
      "admin_area_2": "港区",
      "admin_area_1": "東京都",
      "postal_code": "107-0001",
      "country_code": "JP"
    }
  },
  "purchase_units": [
    {
      "amount": {
        "currency_code": "JPY",
        "value": "1000",
        "breakdown": {
          "item_total": {
            "currency_code": "JPY",
            "value": "1000"
          }
        }
      },
      "items": [
        {
          "name": "Sample Goods",
          "unit_amount": {
            "currency_code": "JPY",
            "value": "1000"
          },
          "quantity": "1"
        }
      ],
      "shipping": {
        "name": {
          "full_name": "太郎 青山"
        },
        "address": {
          "address_line_1": "青山1-2-3",
          "address_line_2": "ペイパルビル 1001",
          "admin_area_2": "港区",
          "admin_area_1": "東京都",
          "postal_code": "107-0001",
          "country_code": "JP"
        }
      },
      "invoice_id": "貴社発番の一意の注文ID",
      "custom_id": "貴社指定のカスタムパラメータ値"
    }
  ]
}'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "id": "3W9401969M757672V",
  "status": "CREATED",
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v2/checkout/orders/3W9401969M757672V",
      "rel": "self",
      "method": "GET"
    },
    {
      "href": "https://www.sandbox.paypal.com/checkoutnow?token=3W9401969M757672V",
      "rel": "approve",
      "method": "GET"
    },
    {
      "href": "https://api.sandbox.paypal.com/v2/checkout/orders/3W9401969M757672V",
      "rel": "update",
      "method": "PATCH"
    },
    {
      "href": "https://api.sandbox.paypal.com/v2/checkout/orders/3W9401969M757672V/capture",
      "rel": "capture",
      "method": "POST"
    }
  ]
}
```
</div></details>

#### 決済を実行する

> **即時決済の場合は[決済を実行する](#決済を実行する)を行う**
> **オーソリの場合は [オーソリを実行する](#オーソリを実行する)と[オーソリに対して決済を実行する](#オーソリに対して決済を実行する)を行う**

サンプルHTMLフォームの /my-server/capture-order で下記 /v2/checkout/orders/{order_id}/capture を貴社サーバからコールし決済を実行します。

[Capture an order](https://developer.paypal.com/docs/business/checkout/server-side-api-calls/capture-order)
[https://developer.paypal.com/docs/api/orders/v2/#orders_capture](https://developer.paypal.com/docs/api/orders/v2/#orders_capture)

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"

**注意点**

クレジットカード決済（PayPalアカウント決済でない）でカード会社からの拒否エラーであった場合、APIのレスポンスは以下のようになります。

[レスポンスヘッダ]
HTTP レスポンスコード: 2xx 台

[レスポンスボディ]
status: COMPLETED
purchase_units.payments.captures.status: DECLINED または DENIED (⇦非COMPLETED)

**そのため、決済成功をHTTP レスポンスコードが2xx台か、や、レスポンスボディのstatusがCOMPLETEDであるかだけで判定すると、正しく判定できないため、purchase_units.payments.captures.status: COMPLETEDとなっているかも判定するようご注意ください。**

なお、PayPalアカウント決済の場合は、AuthorizeもしくはCaptureで却下されるとHTTPステータスは422エラーが返されます。この点の挙動がクレジットカード決済と異なります。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order_id}/capture' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-H 'PayPal-Request-Id: 7c3df866-90b7-4173-83e6-f2d2b53c8480'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "id": "1S536099LR689001U",
  "status": "COMPLETED",
  "payment_source": {
    "card": {
      "last_digits": "8229",
      "brand": "VISA",
      "type": "CREDIT"
    }
  },
  "purchase_units": [
    {
      "reference_id": "default",
      "shipping": {
        "name": {
          "full_name": "太郎 青山"
        },
        "address": {
          "address_line_1": "青山1-2-3",
          "address_line_2": "ペイパルビル 1001",
          "admin_area_2": "港区",
          "admin_area_1": "東京都",
          "postal_code": "107-0001",
          "country_code": "JP"
        }
      },
      "payments": {
        "captures": [
          {
            "id": "47V78187KH288311P",
            "status": "COMPLETED",
            "amount": {
              "currency_code": "JPY",
              "value": "10"
            },
            "final_capture": true,
            "disbursement_mode": "INSTANT",
            "seller_protection": {
              "status": "NOT_ELIGIBLE"
            },
            "seller_receivable_breakdown": {
              "gross_amount": {
                "currency_code": "JPY",
                "value": "1000"
              },
              "paypal_fee": {
                "currency_code": "JPY",
                "value": "76"
              },
              "net_amount": {
                "currency_code": "JPY",
                "value": "924"
              }
            },
            "links": [
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/captures/47V78187KH288311P",
                "rel": "self",
                "method": "GET"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/captures/47V78187KH288311P/refund",
                "rel": "refund",
                "method": "POST"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/checkout/orders/1S536099LR689001U",
                "rel": "up",
                "method": "GET"
              }
            ],
            "create_time": "2021-01-25T07:56:18Z",
            "update_time": "2021-01-25T07:56:18Z",
            "processor_response": {
              "response_code": "0000"
            }
          }
        ]
      }
    }
  ],
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v2/checkout/orders/1S536099LR689001U",
      "rel": "self",
      "method": "GET"
    }
  ]
}
```
</div></details>

#### オーソリを実行する

> **即時決済の場合は[決済を実行する](#決済を実行する)を行う**
> **オーソリの場合は [オーソリを実行する](#オーソリを実行する)と[オーソリに対して決済を実行する](#オーソリに対して決済を実行する)を行う**

下記 /v2/checkout/orders/{id}/authorizeを貴社サーバからコールし決済を実行します。

[Authorize an order](https://developer.paypal.com/docs/business/checkout/server-side-api-calls/authorize-order)
https://developer.paypal.com/docs/api/orders/v2/#orders_authorize

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"

**注意点**

クレジットカード決済（PayPalアカウント決済でない）でカード会社からの拒否エラーであった場合、APIのレスポンスは以下のようになります。

[レスポンスヘッダ]
HTTP レスポンスコード: 2xx 台

[レスポンスボディ]
status: COMPLETED
purchase_units.payments.captures.status: DECLINED または DENIED (⇦非COMPLETED)

**そのため、決済成功をHTTP レスポンスコードが2xx台か、や、レスポンスボディのstatusがCOMPLETEDであるかだけで判定すると、正しく判定できないため、purchase_units.payments.captures.status: COMPLETEDとなっているかも判定するようご注意ください。**

なお、PayPalアカウント決済の場合は、AuthorizeもしくはCaptureで却下されるとHTTPステータスは422エラーが返されます。この点の挙動がクレジットカード決済と異なります。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order_id}/authorize' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access-token>' \
-H 'PayPal-Request-Id: 7c3df866-90b7-4173-83e6-f2d2b53c8480'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "id": "5KA56930N3113540J",
  "status": "COMPLETED",
  "payment_source": {
    "card": {
      "last_digits": "8229",
      "brand": "VISA",
      "type": "CREDIT"
    }
  },
  "purchase_units": [
    {
      "reference_id": "default",
      "shipping": {
        "name": {
          "full_name": "太郎 青山"
        },
        "address": {
          "address_line_1": "青山1-2-3",
          "address_line_2": "ペイパルビル 1001",
          "admin_area_2": "港区",
          "admin_area_1": "東京都",
          "postal_code": "107-0001",
          "country_code": "JP"
        }
      },
      "payments": {
        "authorizations": [
          {
            "status": "CREATED",
            "id": "1T3898K57614G8S79",
            "amount": {
              "currency_code": "JPY",
              "value": "1000"
            },
            "seller_protection": {
              "status": "NOT_ELIGIBLE"
            },
            "processor_response": {
              "response_code": "0000"
            },
            "expiration_time": "2021-02-23T08:07:50Z",
            "links": [
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79",
                "rel": "self",
                "method": "GET"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79/capture",
                "rel": "capture",
                "method": "POST"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79/void",
                "rel": "void",
                "method": "POST"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79/reauthorize",
                "rel": "reauthorize",
                "method": "POST"
              },
              {
                "href": "https://api.sandbox.paypal.com/v2/checkout/orders/5KA56930N3113540J",
                "rel": "up",
                "method": "GET"
              }
            ],
            "create_time": "2021-01-25T08:07:50Z",
            "update_time": "2021-01-25T08:07:50Z"
          }
        ]
      }
    }
  ],
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v2/checkout/orders/5KA56930N3113540J",
      "rel": "self",
      "method": "GET"
    }
  ]
}
```
</div></details>

#### オーソリに対して決済を実行する

下記 /v2/payments/authorizations/{authorization_id}/captureを貴社サーバからコールし決済を実行します。

[Capture an authorization for an order](https://developer.paypal.com/docs/business/checkout/server-side-api-calls/capture-authorization)
https://developer.paypal.com/docs/api/payments/v2/#authorizations_capture

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"

また、以下のように金額を指定してオーソリ金額の一部金額を売上処理することが可能です。後で残りも売上処理する場合は final_captureにfalseを指定します。

```json
{
  "amount": {
    "value": "700",
    "currency_code": "JPY"
  },
  "invoice_id" : "貴社発番の一意の注文ID",
  "final_capture": true
}
```

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79/capture' \
-H 'Authorization: Bearer <Access-Token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'PayPal-Request-Id: 1cc9e87b-0410-4999-9fef-76d732a94bc9'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "id": "0VG7SW2984469872W",
  "status": "COMPLETED",
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v2/payments/captures/0VG7SW2984469872W",
      "rel": "self",
      "method": "GET"
    },
    {
      "href": "https://api.sandbox.paypal.com/v2/payments/captures/0VG7SW2984469872W/refund",
      "rel": "refund",
      "method": "POST"
    },
    {
      "href": "https://api.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79",
      "rel": "up",
      "method": "GET"
    }
  ]
}
```
</div></details>

#### クレジットカード情報の保存機能

上記実装に下記の4つの手順を追加してください。

https://developer.paypal.com/docs/limited-release/vault-payment-methods/vault-sdk#vault-cards-for-advanced-credit-and-debit-card-payments

Sandboxで保存できるカード番号は下記に限定されていますので、ご注意ください。
[Test cards](https://developer.paypal.com/docs/limited-release/vault-payment-methods/vault-sdk#test-cards)


##### ユーザーにカード情報の保存の有無を選択させるラジオボタンを表示する

```html
<div>
  <input type="checkbox" id="vault" name="vault">
  <label for="vault">Save your card</label>
</div>
```

##### カード情報保存のフラグをtrueにするロジックを追加する

```javascript
document.querySelector('#my-sample-form').addEventListene('submit', (event) => {
    event.preventDefault();
    hf.submit({
          // pass the value of the checkbox when submitting the advanced credit and debit card payments instance
          vault: document.querySelector('#vault').checked
    }).then(function (payload) {
      // Make a call to capture the order (payload.orderId) here
    });
});
```

##### 保存されたカード情報を取得する

決済が成功するとカード情報が保存されますので、以下の方法によりその情報を取得します。レスポンスには、ユーザーIDに紐付くpayment_method_tokenが返却されます。payment_tokens.idを以降の決済で使用しますので、保存しておきます。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -k -X GET 'https://api-m.sandbox.paypal.com/v2/vault/payment-tokens?customer_id=customer_12345&total_required=true' \
 -H 'Authorization: Bearer <access_token>' \
 -H 'Content-Type: application/json'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "customer_id": "customer_12345",
  "payment_tokens": [
    {
      "id": "6km842",
      "status": "CREATED",
      "source": {
        "card": {
          "brand": "VISA",
          "last_digits": "1234"
        }
      },
      "links": [
        {
          "rel": "self",
          "href": "https://api.paypal.com/v2/vault/payment-tokens/6km842",
          "method": "GET"
        },
        {
          "rel": "delete",
          "href": "https://api.paypal.com/v2/vault/payment-tokens/6km842",
          "method": "DELETE"
        },
        {
          "rel": "edit",
          "href": "https://api.paypal.com/v2/vault/payment-tokens/6km842",
          "method": "PATCH"
        }
      ]
    }
  ],
  "links": [
    {
      "rel": "self",
      "href": "https://api.paypal.com/v2/vault/payment-tokens?customer_id=customer_12345&page=1&page_size=5&total_required=false",
      "method": "GET"
    },
    {
      "rel": "first",
      "href": "https://api.paypal.com/v2/vault/payment-tokens?customer_id=customer_12345&page=1&page_size=5&total_required=false",
      "method": "GET"
    },
    {
      "rel": "last",
      "href": "https://api.paypal.com/v2/vault/payment-tokens?customer_id=customer_12345&page=1&page_size=5&total_required=false",
      "method": "GET"
    }
  ]
}
```
</div></details>

/v2/vault/payment-tokens/{payment-token-id} を実行すると、保存されたカードのメタ情報（カードブランド、カード番号下4桁、有効期限）を取得することが可能です。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -k -X GET 'https://api-m.sandbox.paypal.com/v2/vault/payment-tokens/3pqky3r' \
 -H 'Authorization: Bearer <access_token>' \
 -H 'Content-Type: application/json'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>

```json
{
  "id": "3pqky3r",
  "status": "CREATED",
  "customer_id": "testuser001",
  "source": {
    "card": {
      "expiry": "2020-11",
      "brand": "VISA",
      "last_digits": "0026"
    }
  },
  "links": [
    {
      "href": "https://api.paypal.com/v2/vault/payment-tokens/3pqky3r",
      "rel": "self",
      "method": "GET",
      "encType": "application/json"
    },
    {
      "href": "https://api.paypal.com/v2/vault/payment-tokens/3pqky3r",
      "rel": "delete",
      "method": "DELETE",
      "encType": "application/json"
    }
  ]
}
```
</div></details>

##### 保存されたカード情報を削除する

保存されたカード情報を削除するには、同APIを以下のようにDELETEメソッドで実行します。

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -k -X DELETE 'https://api-m.sandbox.paypal.com/v2/vault/payment-tokens/3pqky3r' \
 -H 'Authorization: Bearer <access_token>' \
 -H 'Content-Type: application/json'
```
</div></details>

<details><summary>サンプルレスポンス</summary><div>
HTTPステータスとして204 No Contentが返され、Bodyは空となります。
</div></details>

保存されたカード情報を編集する場合は、編集用のAPIは用意されていないため、一旦削除してから新規に保存してください。

#### 保存したカード情報での決済

##### 保存したカード情報で決済を作成する

[アドバンストクレジットカード決済 - 決済を作成する](#決済を作成する) を参照してください。

貴社サーバから実行してください。カードフォームの表示は不要です。

##### 保存したカード情報で決済を実行する

[アドバンストクレジットカード決済 - 決済を実行する](#決済を実行する) を参照してください。

下記 /v2/checkout/orders/{id}/capture をサーバからコールし決済を実行します。

https://developer.paypal.com/docs/business/checkout/server-side-api-calls/capture-order

payment_source.token.id に、以前保存した payment_tokens.id を指定してください。カードフォームの表示は不要です。

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"

<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5573659X33Y75Y063/capture \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-H 'PayPal-Request-Id: 7c3df866-90b7-4173-83e6-f2d2b53c8480' \
-d '{
  "payment_source": {
    "token": {
      "id": "6km842",
      "type": "PAYMENT_METHOD_TOKEN"
    }
  }
}'
```
</div></details>


#### 保存したカード情報でオーソリを実行する

> **即時決済の場合は[保存したカード情報で決済を実行する](#保存したカード情報で決済を実行する)を行う**
> **オーソリの場合は [保存したカード情報でオーソリを実行する](#保存したカード情報でオーソリを実行する)と[保存したカード情報でオーソリに対して決済を実行する](#保存したカード情報でオーソリに対して決済を実行する)を行う**

[アドバンストクレジットカード決済 - オーソリを実行する](#オーソリを実行する) を参照してください。

下記 /v2/checkout/orders/{id}/authorize を貴社サーバからコールし決済を実行します。

https://developer.paypal.com/docs/business/checkout/server-side-api-calls/authorize-order

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"


<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST https://api-m.sandbox.paypal.com/v2/checkout/orders/5573659X33Y75Y063/authorize \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-H 'PayPal-Request-Id: 7c3df866-90b7-4173-83e6-f2d2b53c8480' \
-d '{
  "payment_source": {
    "token": {
      "id": "6km842",
      "type": "PAYMENT_METHOD_TOKEN"
    }
  }
}'
```
</div></details>


#### 保存したカード情報でオーソリに対して決済を実行する

> **即時決済の場合は[保存したカード情報で決済を実行する](#保存したカード情報で決済を実行する)を行う**
> **オーソリの場合は [保存したカード情報でオーソリを実行する](#保存したカード情報でオーソリを実行する)と[保存したカード情報でオーソリに対して決済を実行する](#保存したカード情報でオーソリに対して決済を実行する)を行う**

[アドバンストクレジットカード決済 - オーソリに対して決済を実行する](#オーソリに対して決済を実行する) を参照してください。

下記 /v2/payments/authorizations/{authorization_id}/capture を貴社サーバからコールし決済を実行します。

https://developer.paypal.com/docs/business/checkout/server-side-api-calls/capture-authorization

以下のヘッダを追加してください。
"PayPal-Request-Id: Unique-Session-Identifier"

また、以下のように金額を指定してオーソリ金額の一部金額を売上処理することが可能です。後で残りも売上処理する場合は final_captureにfalseを指定します。

```
{
  "amount": {
    "value": "700",
    "currency_code": "JPY"
  },
  "invoice_id" : "your-own-uniqueid-for-an-order",
  "final_capture": true
}
```


<details><summary>サンプルリクエスト</summary><div>

```
curl -v -X POST 'https://api-m.sandbox.paypal.com/v2/payments/authorizations/1T3898K57614G8S79/capture' \
-H 'Authorization: Bearer <Access-Token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'PayPal-Request-Id: 1cc9e87b-0410-4999-9fef-76d732a94bc9'
```
</div></details>





-----

#### 決済のキャンセル・返金

下記 /v2/payments/captures/{capture_id}/refund を貴社サーバからコールし決済のキャンセル、返金を実行します。

[Refund captured payment](https://developer.paypal.com/docs/api/payments/v2/#captures_refund)

PayPalアカウントの残高から返金されますので、実行するには十分な残高が必要です。返金可能な期間は取引日から180日間です。

金額を指定し一部金額を返金することが可能です。


#### オーソリのキャンセル・返金
下記 /v2/payments/authorizations/{authorization_id}/void を貴社サーバからコールしオーソリのキャンセルを実行します。

[Void authorized payment](https://developer.paypal.com/docs/api/payments/v2/#authorizations_void)


-----

## ベーシッククレジットカード決済実装方法

概要

1. 以下のサンプルコードをコピーして、チェックアウトページに貼り付けてください。
1. コード中の YOUR_SB_CLIENT_ID を、使用するClient IDに置き換えてください。
1. 必要に応じてJavaScript SDKに渡すパラメータを明示的に指定して、デフォルトの値を上書きしてください。各パラメータのデフォルト値については以下をご参照ください。

https://developer.paypal.com/docs/business/javascript-sdk/javascript-sdk-configuration/


#### クレジットカード決済ボタンを追加する

https://developer.paypal.com/docs/business/checkout/set-up-standard-payments/

PayPal JavaScript SDKのデフォルトのintentは、指定しない場合intent=captureであり、トランザクションのオーソリ(authorize)と売上(capture)の両方を直ちに行うことです。オーソリと売上を別々のアクションに分割するには、PayPal JavaScript SDK のスクリプトタグに &intent=authorize を追加します。

ボタンのカスタマイズは、下記を参照してください。

https://developer.paypal.com/docs/business/checkout/reference/style-guide

<details><summary>サンプルフォーム</summary><div>

```html
<!DOCTYPE html>
<html>
  <head>
  <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Ensures optimal rendering on mobile devices. -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- Optimal Internet Explorer compatibility -->
  </head>

  <body>
  <script src="https://www.paypal.com/sdk/js?client-id=YOUR_SB_CLIENT_ID&locale=ja_JP&currency=JPY&components=buttons,funding-eligibility&intent=capture"> // Replace YOUR_SB_CLIENT_ID with your sandbox client ID
  </script>

  <div id="paypal-button-container"></div>

  <!-- Add the checkout buttons, set up the order and approve the order -->
  <script>
    paypal.Buttons({

    <!-- クレジットカードボタンのみ表示する -->
    fundingSource: paypal.FUNDING.CARD,

    createOrder: function(data, actions) {
      return actions.order.create({
      intent: 'CAPTURE',
      payer: {
        name: {
        given_name: "太郎",
        surname: "青山"
        },
        address: {
        address_line_1: '青山1-2-3',
        address_line_2: '',
        admin_area_2: '港区',
        admin_area_1: '東京都',
        postal_code: '123-4567',
        country_code: 'JP'
        },
        email_address: "buyer@example.com",
        phone: {
        phone_type: "MOBILE",
        phone_number: {
          national_number: "819034567890"
        }
        }
      },
      purchase_units: [{
        amount: {
        value: '100'
        },
        shipping: {
        name: {
          full_name: "太郎 青山",
        },
        address: {
          address_line_1: "青山1-2-3",
          address_line_2: "",
          admin_area_2: "港区",
          admin_area_1: "東京都",
          postal_code: "123-4567",
          country_code: "JP"
        }
        }
      }]
      });
    },
    onApprove: function(data, actions) {
      return actions.order.capture().then(function(details) {
      alert('Transaction completed by ' + details.payer.name.given_name);
      actions.redirect('/done-page'); // Redirect to complete page
     });
    }
    }).render('#paypal-button-container'); // Display payment options on your web page
  </script>
  </body>
</html> 
```
</div></details>