4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

StripeのPayment Intent / Checkoutで「オーソリ(仮売上)」と「キャプチャ」を分割する方法

Posted at

この記事は、JP_Stripesアドベントカレンダー7日目の記事です。

ECサイトや予約システムでは、「顧客が注文した際に、クレジットカード利用枠の確認・確保(与信)だけ行い、請求自体は商品の発送や来店されたタイミングで行う」といった、「注文と決済」のタイミングが別々になることがあります。この記事では、このようなユースケースをStripeでサポートする方法を、簡単に紹介します。

「そのクレジットカードに請求を行って良いか?」を確認する

クレジットカードで支払いを受け付ける時、システムはまず顧客の契約しているクレジットカード会社に対して、「このカードには、この金額の決済を受け付ける残高が残っているか?」や「このカードに対する紛失や盗難等の届出が出ていないか」といった確認を行います。このステップのことを一般的に「オーソリ」や「仮売上」「与信確保」などと呼びます。

スクリーンショット 2023-12-06 21.58.07.png
https://stripe.com/docs/payments/cards/overview

請求を行う前にオーソリを実施することで、盗まれたクレジットカードを利用した不正な注文や顧客がクレジットカードの利用可能枠を超えて注文を行ってしまうリスクを回避することができます。また、注文してから発送するまでの間にキャンセル依頼が発生しやすいショップなどでは、商品を発送してからキャプチャするようにすることで、キャンセルされた注文にかかる決済手数料の支出を抑えることができます。

Stripeでは、30日間(越境 / 外貨決済は7日)までカードの利用枠を確保できる

オーソリは「仮売上」と呼ばれるように、クレジットカードの利用残高から請求予定の金額を「仮押さえ」します。そのため、クレジットカードへの請求そのものはまだ行われていない状態であっても、クレジットカードの利用可能な残高はオーソリを実施した金額分減少することになります。

クレジットカードの利用可能枠を仮押さえするため、オーソリには有効期限が設定されています。Stripeでは30日間オーソリを維持することが可能で、30日を経過すると自動的にオーソリがキャンセルされ、仮押さえされていたクレジットカードの利用可能な残高も戻されます。

Payment Intentでオーソリと決済(キャプチャ)を個別に実施する方法

Payment Intentでオーソリだけを行う方法

Stripe Elementsなどで利用するPayment Intentには、「オーソリだけを行う」パラメータが用意されています。次のサンプルコマンドのように、Payment Intentを作成するリクエストパラメータにcapture_method=manualを追加しましょう。

curl https://api.stripe.com/v1/payment_intents \
  -u "sk_test_から始まるシークレットAPIキー:" \
  -d amount=1099 \
  -d currency=jpy \
+  -d capture_method=manual

複数の決済手段をサポートする場合の注意点
支払い手段を明示的に指定していない場合、capture_method=manualを設定すると、「オーソリだけを行うことができる決済手段」のみがPaymentElementの決済フォームに表示されます。また、payment_method_typesを設定している場合、「オーソリだけを行うことができない決済手段」が含まれているとAPIエラーが発生します。

もしクレジットカード決済以外の決済手段、特にオーソリのみを行うことができない決済手段の提供も検討している場合には、payment_method_options[支払い手段][capture_method]=manualのように、payment_method_optionsを利用して、「オーソリだけを実施できる決済手段では、オーソリだけにする」設定を行いましょう。

curl https://api.stripe.com/v1/payment_intents \
  -u "sk_test_から始まるシークレットAPIキー:" \
  -d amount=1099 \
  -d currency=jpy \
-  -d capture_method=manual
+  -d "payment_method_options[card][capture_method]"=manual

オーソリしたPayment Intentで決済(キャプチャ)を実施する

オーソリした金額を実際に請求する場合、Payment Intentsが持つCapcture APIを利用します。Payment IntentのIDをパスに設定したPOSTリクエストを送信しましょう。

curl -X POST https://api.stripe.com/v1/payment_intents/pi_ANipwO3zNfjeWODtRPIg/capture  \
  -u "sk_test_から始まるシークレットAPIキー:"

請求を行うAPIリクエストにPayment Intent IDが必要です。そのため、注文や予約を管理するDBを用意している場合は、DBのカラム・項目にStripeのPayment Intent IDを保存できるように設計することをお勧めします。

Stripe Checkoutででオーソリと決済(キャプチャ)を個別に実施する方法

オーソリとキャプチャの分割は、リダイレクト型の決済フローを提供するStripe Checkoutでも実装できます。

Checkout Sessionでオーソリだけを行う方法

Stripe Checkoutの場合、Payment IntentではなくCheckout SessionをAPIで作成します。その際にpayment_intent_data[capture_method]=manualをリクエストBodyに加えましょう。

curl -X POST "https://api.stripe.com/v1/checkout/sessions" \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY':  \
  -d "success_url"="https://example.com" \
  -d "line_items[0][price_data][unit_amount]"=1099 \
  -d "line_items[0][price_data][currency]"="jpy" \
  -d "line_items[0][price_data][product_data][name]"="test product" \
  -d "line_items[0][quantity]"=1 \
+  -d "payment_intent_data[capture_method]"="manual" \
  -d "mode"="payment"

オーソリしたCheckout Sessionで決済(キャプチャ)を実施する

Stripe Checkoutで注文を受け付けた場合、CheckoutのSession IDから注文の詳細を見ることができます。

curl https://api.stripe.com/v1/checkout/sessions/cs_から始まるCheckout_SESSION_ID  \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY': 

レスポンスからは、Checkout Sessionに関連づけられたPayment IntentのIDをpayment_intentパラメータで取得できます。

{
  "id": "cs_test_a1G6BG3mHRNuIy7aKt6JKOA6DSxwf8jscsw71ime23XaxPByE9PWMqOD2v",
  "object": "checkout.session",
  "amount_subtotal": 1000,
  "amount_total": 1000,
  "automatic_tax": {
    "enabled": false,
    "status": null
  },
  "payment_intent": "pi_3OJsWmL8xlxrZ26g1ZSVauWq",
  "payment_link": null,
  "payment_method_collection": "if_required",
  "payment_method_configuration_details": {
    "id": "pmc_1KqYUCL8xlxrZ26gEPRetzGU",
    "parent": null
  },
  "payment_method_options": {},
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
...

このPayment Intent IDを利用して、キャプチャのAPIを呼び出しましょう。

curl -X POST https://api.stripe.com/v1/payment_intents/pi_ANipwO3zNfjeWODtRPIg/capture  \
  -u "sk_test_から始まるシークレットAPIキー:"

このように、Stripe Checkoutを利用する場合でも、Payment Intentに対してキャプチャを行う処理が用意されていれば、対応するための変更点などを少なくできます。

オーソリ後の金額変動に対応する

オーソリとキャプチャを分割するケースでは、追加注文や部分キャンセルなどによって金額が変動することがあります。金額が変動した場合のオーソリやキャプチャ方法についてもみてみましょう。

請求金額が増える場合は、差額分のオーソリが必要

追加注文やアップグレードなどで金額が変わる場合、増えた金額分のオーソリを実施する必要があります。そしてオーソリを実施するためには、再度クレジットカード情報を顧客に入力してもらう必要があります。そのため、アップグレード・アップセルなどの提案を顧客に行う想定のECサイトやショップでは、「1度入力したカード情報を、次回以降の支払いでも利用できるようにする」設定を行うことをお勧めします。

$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY':  \
  -d "amount"=1099 \
  -d "currency"="jpy" \
+  -d "customer"="cus_P5SHoCX0um98G4" \
+  -d "setup_future_usage"="on_session"

これによって、追加注文などで追加のオーソリを実施する必要が出た場合にも、顧客に再度クレジットカード情報の入力を求める必要がなくなります。

$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY':  \
  -d "amount"=1099 \
  -d "currency"="jpy" \
  -d "payment_method"="pm_1OHIFoEzgtKktpOykZPfaUAD" \
  -d "customer"="cus_P5SHoCX0um98G4"

このAPIリクエストのレスポンスには、statusがrequires_confirmationになっているPayment Intentが含まれています。これは「この支払い手段を利用して決済を行うこと」を顧客に確認する必要があることを示しています。

{
  "id":"pi_3OHIT3EzgtKktpOy0hGf06Qy",
  "object":"payment_intent",
 
  "client_secret":"pi_3OHIT3EzgtKktpOy0hGf06Qy_secret_ONJxi884ITsDcMBL1TCmSedzt",
  "payment_method":"pm_1OHIFoEzgtKktpOykZPfaUAD",
  ...
  "status":"requires_confirmation",
  ...
}

client_secretをStripe.js またはiOS / Android SDKに渡して、confirmCardPaymentで差額の支払いを確定させましょう。

stripe
  .confirmCardPayment('pi_3OHIT3EzgtKktpOy0hGf06Qy_secret_ONJxi884ITsDcMBL1TCmSedzt')
  .then(function(result) {
    // Handle result.error or result.paymentIntent
  });

合計金額でオーソリをやり直す場合は、以前のPayment Intentをキャンセルする

顧客のクレジットカード利用明細を1行にまとめたい場合や、システムが複数のPayment Intentをまとめてキャプチャする仕組みに対応していない場合などでは、Payment Intentを作り直して対応します。作り直す場合は、一度Payment Intentをキャンセルしましょう。

% curl -X POST https://api.stripe.com/v1/payment_intents/pi_3MtwBwLkdIwHu7ix28a3tqPa/cancel \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY': 

その後、「新しい合計金額」をamountに設定したPayment Intentを作成します。

$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY':  \
  -d "amount"=1099 \
  -d "currency"="jpy" \
  -d "payment_method"="pm_1OHIFoEzgtKktpOykZPfaUAD" \
  -d "customer"="cus_P5SHoCX0um98G4"

請求金額が減る場合は、キャプチャする金額を変えるだけ

部分キャンセルなどで金額が減った場合、オーソリを改めて行なう必要はありません。キャプチャの際に、実際に請求する金額をamount_to_captureに設定することで、新しい金額分のみ請求を行うことができます。

curl -X POST "https://api.stripe.com/v1/payment_intents/{intent}/capture" \
  -u 'REPLACE_WITH_YOUR_SECRET_KEY':  \
  -d "amount_to_capture"=980

オーソリで確保した額のうち、実際には請求されなかった金額については、この時点で解放されます。もし高額商品の予約などで、すみやかに差額の仮押さえを解放する必要がある場合には、金額を増やす場合と同じくオーソリをやり直すことになります。

クレジットカードでの決済処理を知ることで、より柔軟な決済フローの構築・提案を

今回紹介した「オーソリとキャプチャの分割」のように、オンラインでのクレジットカード決済には、様々なシナリオやユースケースが存在します。ショップ運営者からの要望や、ショップを利用する顧客の満足度を高めるための施策を考案または提案できるようになるためにも、クレジットカードによる決済がどのような流れで行われるかを知ることは重要です。

Stripeでは、クレジットカード支払いの仕組みを解説するコンテンツを複数公開しています。

Stripeの製品理解だけでなく、オンライン決済をより便利にするための参考になれば幸いです。

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?