KitchHike Tech Blog

KitchHike Product, Design and Engineering Teams

その悩み、オーソリ(仮売上)で解決できるかも - Stripeではじめるオーソリ導入ガイド

f:id:taogawa:20191218085105p:plain

この記事はStripe Advent Calendar 2019のDay 18となります。

聞いたことはあるけれど、機会がないとあまり馴染みのないクレジットカードのオーソリ。ですが、使ってみると非常に便利なしくみです。今回はStripeでのオーソリ決済の導入について、弊社キッチハイクの事例とともにご紹介いたします。

はじめに

こんにちは。エンジニアの小川です。

キッチハイクでは今年、一部の決済にオーソリを導入しました。 クレジットカードのオーソリは、端的にいえば、カードの使用者(ユーザー)の与信枠の中から、決済額を一定期間確保しておく仕組みのことを指します。このオーソリ、導入することで、カードが有効かどうかを事前チェックできたり、キャンセルで発生する手間を減らせたりと非常にメリットの大きい仕組みでもあります。

しかし、名前は聞いたことはあっても、あまり馴染みがなく、どう使えばいいのかイメージが湧かない方も多いのではないでしょうか。今回の記事では、そんなオーソリの導入のしかたを、キッチハイクでStripeのオーソリ決済を導入したお話しをまじえながらご紹介いたします。

オーソリって何がうれしいの?

オーソリの呼び名は英語の Authorization の略称から来ており、仮売上と呼ばれることもあります。

「仮売上」の呼び方が示すとおり、オーソリがつくられた時点では使用者側への請求は確定していません。オーソリをキャプチャ(確定)することで、はじめて使用者側に支払いが請求されることになります。

オーソリは在庫が確保できるかどうか不確定な商品の決済などによく用いられます。通常の決済の場合、仮に決済をしても在庫が確保できずキャンセルになると返金などの手続きが発生してしまいます。 そんなとき、オーソリであれば、キャンセルをすればいいだけで、返金作業は不要です。一定の率以上でのキャンセルが見込まれるのであれば、オーソリのほうが作業コストをへらすことができます。

また、与信枠をあらかじめ確保するので、サービス側としては事前チェックの意味合いもあります。在庫確保時点で本決済をする場合でも、オーソリ作成時にその分の額は確保されているので、限度額超過でエラーになることはありません。

もちろんですが、オーソリには期限があります。一定期間オーソリが確定されなかった場合、そのオーソリは自動的にキャンセルとなります。オーソリの期間は決済サービスやカード会社ごとに異なりますが、平均して数日〜1ヶ月ほどといったところです。

キッチハイクでのオーソリ導入事例

弊社キッチハイクでは2018年から決済サービスにStripeを導入しています。 (そのときの記事が以下となります)

tech.kitchhike.com

キッチハイクではサービスのなかでイベントの予約機能を提供しており、その決済でStripeを使用しています。

オーソリを導入したのは、この予約の際に予約タイミング(クレジットカード決済)と課金タイミング(チャージ・キャプチャ)をずらすケースに対応するためでした。

具体的には「どのようなごはんが食べたいか」や日付をユーザーが選択して申し込む予約方式なのですが、予約時点でお店や日付は確定しておらず、後日キッチハイク側でお店と日付を確定させると同時に予約が確定するフローとなっています。(なお、現在ではこの予約方式は終了しています)

f:id:taogawa:20191218010625p:plain

リリース当初はこの予約方式でもオーソリを使用していませんでした。しかし、運用を経る中で以下の課題が発生することがわかってきました。

  1. ユーザーが申し込んだ日付と、実際の決済日(予約の確定日付)にラグがあり、カード使用の履歴に身に覚えのない日付が出てしまう
  2. ユーザーの予約申し込み〜実際の予約確定日にラグがあるため、その間にカードの利用限度額を超えてしまった場合、予約の確定時に決済エラーが発生する

この課題を解決するために導入したのがオーソリでした。

下図のように、予約申し込みの時点でオーソリを作成し、予約確定時点でオーソリをキャプチャするようにします。

f:id:taogawa:20191218010732p:plain

このオーソリの導入によって上述の1、2の課題を解決することができました。

  • 1.の解決: オーソリの場合、決済の日付は予約申し込み日となるため、ユーザーのカード履歴に本来出てほしい日付がでるようになる
  • 2.の解決: 与信枠の確保時にカードのチェックをするので、予約確定前に有効性チェックができるようになった。与信枠を確保できれば、予約確定時にエラーになることはなくなる

Stripeのオーソリコード例

以上、キッチハイクでのオーソリの導入例を紹介してきましたが、次は実際にどのようなコードを書くのかみていきましょう。

記載のコード例は stripe-rubyが前提になっていますが、他の言語のSDKでもあまり変わらないかと思います。

github.com

オーソリの作成はいたって簡単です。 Charge の新規作成時のオプションに capture: false を追加するだけです。これだけでオーソリを作成することができます。

charge = Stripe::Charge.create({
  amount: 2000,
  currency: 'jpy',
  customer: 'cus_...',
  capture: false,
})
=> #<Stripe::Charge:0x3fe876b718dc id=ch_...> JSON: {
  "id": "ch_...",
  "object": "charge",
  "amount": 2000,
  "amount_refunded": 0,
  "application": null,
  "application_fee": null,
  "application_fee_amount": null,
  "balance_transaction": null,
  ...
  "captured": false,
  ...
}

返り値の Charge オブジェクトの captured の値が false になっていますが、これが Charge がオーソリであることを示しています。

オーソリをキャプチャするときは、引数に先ほどの Charge のidを指定して、以下のように capture メソッドを呼ぶだけです。

charge = Stripe::Charge.capture("ch_...")
=> #<Stripe::Charge:0x3fce83a780b4 id=ch_...> JSON: {
  "id": "ch_...",
  "object": "charge",
  "amount": 2000,
  "amount_refunded": 0,
  "application": null,
  "application_fee": null,
  "application_fee_amount": null,
  ...
  "captured": true,
  ...
}

Charge オブジェクトの captured の値が true に変わっていることが分かるかと思います。これだけでキャプチャは終了です。

オーソリのキャンセルの場合も同じく Charge のidを指定します。

Stripe::Refund.create({ charge: "ch_..." })
=> #<Stripe::Refund:0x3fce850a3834 id=re_...> JSON: {
  "id": "re_...",
  "object": "refund",
  "amount": 2000,
  "balance_transaction": null,
  "charge": "ch_...",
  ...
  "status": "succeeded",
  ...
}

こちらに至っては、オーソリであることを指定する必要もなくキャンセルをすることができます。

コード例を見ていただければ分かる通り、拍子抜けするほど簡単ではないでしょうか?もし既に通常の決済のコードが実装されていれば、ほぼ数行の変更でオーソリに対応することができるでしょう。

Stripeのオーソリでの注意事項

以上のようにStripeでのオーソリの開発は非常に簡単です。とはいっても、考慮が必要な点がないわけではありません。そのひとつがオーソリの期限です。

以下ではこの点について説明したいと思います。

カード会社ごとの有効期限

Stripeに限らずですが、オーソリの有効期限はカードブランドによってばらつきがあることが多いです。

support.stripe.com

上記のFAQにあるように、Stripeでは日本円決済であれば、オーソリ期限はAMEXが7日、それ以外のカードブランドは30日となっています。

カードブランド オーソリ期限
AMEX 7日
AMEX以外のカードブランド 30日

したがって、Stripeを使っていてオーソリ期限をロジックに組み込む場合、カードブランドごとの期限の違いを考慮する必要があります。

オーソリの期限切れを確認するには

一方で、このようなカードブランドごとの違いを考慮せずに Charge 自体がオーソリの期限を持ってはいないのでしょうか。

残念ながら、2019年12月現在、Charge からオーソリの期限がいつになるかを知ることはできません。ただし、オーソリが期限切れであるかどうかを判定することはできます。

以下にコード例を示します。

charge = Stripe::Charge.retrieve("ch_...")
charge.refunded && !charge.captured

refunded: true かつ captured: false であれば、そのオーソリ( Charge オブジェクト)は期限切れになっています。

また、期限切れの判定にはWebhookを使う方法もあります。

stripe.com

上記の charge.expired のイベントをWebhookに設定しておけば、 Charge が期限切れになったタイミングで正確に処理をすることができます。厳密にオーソリが期限切れになったタイミングで処理をしたい場合は、これが一番正確な方法ではないかと思います。

まとめ

以上、Stripeでのオーソリのはじめかたについて、キッチハイクの事例をあげつつ説明してきました。

  • Stripeでのオーソリの導入は非常に簡単
  • キッチハイクではこのオーソリを導入することで、予約から予約の確定までにラグがある方式の課題を、非常に低コストで解決することができた
  • オーソリの期限切れについては多少考慮の必要がある

本記事がオーソリ導入に迷われている方にとっての一助になれば幸いです。

なお、オーソリの細かな仕様の把握についてはStripeサポートのみなさまにたいへんお世話になりました。今回ご紹介した内容も、問い合わせのなかで教えていただいた内容が元になっています。この場を借りてお礼を述べさせていただきます。

We're Hiring!

キッチハイクでは、いっしょに決済の開発をしてくれるエンジニアを大募集中です!

www.wantedly.com

www.wantedly.com

www.wantedly.com