ボクココ

個人開発に関するテックブログ

クレジットカードを扱うサービス開発で注意すべきこと

ども、@kimihom です。

最近は SaaS サービスもどんどん増えてきて、決済手段としてクレジットカードを選択する場合が多くなってきた。SaaS サービスであれば、月額課金モデルというところがベースになってくるので、実際に運用している側から検討した方がいいことをまとめてみようと思う。

顧客の 5% は決済に失敗すると覚悟せよ

まずコレ。この記事で一番言いたいことでもある。意外とクレカの利用制限を超えてしまっていたり、有効期限が切れていたりなどして毎回顧客の 5 % くらいは月額決済に失敗する。その時の対策をあらかじめ考えておく必要がある。決済に失敗したらその翌月は一切使えないようにするってのは、意図せずにクレカ失敗した顧客に対してあまりに可哀想なので、そこで "決済してないけど使える状態" という一時的に矛盾した状態が発生することがよく起こる。

この問題に対応するには、いくつかの方法が考えられる。

  1. 与信枠をあらかじめ確保する
  2. 失敗した企業に対しては、以降 定期的に自動で決済を走らせる
  3. 相手のクレジットカード更新を待ち、手動で決済する
  4. 別の決済手段を案内して、その月はクレジットカード決済しなくても使い続けられるようにする

1 の与信枠の確保は、毎月利用金額が固定であれば効果を発揮する。与信枠の確保をあらかじめ1週間前以上から行っておくことで、実際に決済を走らせる時の失敗をゼロにすることが可能だ。とはいえその時までに顧客がクレジットカードを更新してくれなければ、この方法だけではうまくいかないので、100%の解決策にはなっていないことに注意だ。

2 の失敗企業に対しては定期的に決済を走らせる処理は、有効な手段だと言える。決済がうまくいくまで定期的に決済にチャレンジし、何回やっても失敗するようならアカウント凍結をするというような流れになるだろう。人の手が入ることがなくなり、すべてが自動化できるため運用としては楽だが、意図しない決済が走ってしまうといったプログラム的なミスをやらかす場合もあるので注意が必要だ。 ここら辺は Stripe のような月額決済サービスを使えば勝手にやってくれるという噂も聞いたことがある。ただ月額の金額が従量課金制の場合は、それぞれ顧客に紐付いた金額を請求しなければならないため、自前で定期的に決済を走らせるような処理が必要になってくる場合もあるかと思う。

3 の方法は手間はかかるけども確実な方法だ。多いって言ってもたかだか5%なので、顧客と連絡をやりとりしながら、「更新しました」って言われた時点でサクッとプログラムを実行して決済するような流れにする。そうすれば割と柔軟な対応を顧客にもできるし、顧客のクレカ反映の後すぐに決済ができるので未回収のリスクも下がるだろう。

4 の方法は顧客にとっては一番最適な手段かもしれない。もちろん私たちは銀行振り込みの確認など面倒な手間が入ってしまうけども、一時的にクレカが使えないような状態で、他にカードがない顧客のことを考えてあげるのであれば、4の方法を選ぶことになるだろう。ただし、顧客がそれに甘えていつまでもカードを更新せず支払いを遅らせるような場合も出てくる可能性があるので注意してほしい。

私たちの場合は月額決済サービスであるけども顧客毎に金額が毎月変動する 定額 + 従量課金制 であるため、都度 決済金額を計算して API を呼び出す形としなければならなかった。そのため、毎月の深夜に決済を走らせて、失敗した企業に対しては金額をメモし、翌月以降で手動で決済する方法を取っていた。ただ、顧客が増えるにつれて、それの管理が大変になったり一切連絡のつかない顧客が出始めてきたため、2の自動化の開発に乗り出したというのが近況のアップデートである。

これがプランに応じて毎月固定金額であれば、WebPay でも Stripe でも提供されている月額決済のAPIを使えば良さそうなので簡単そうな感じはする。この場合、失敗企業には自動でメールが入ったりするのかどうかは調べていない。

テストは慎重に、そして確実に。

こういう決済周りの実装って本当に神経をすり減らすから大変なんだよね。私も一度完成したら、以降はあまり手をつけたくない分野である。ただ、どうしてもやらないといけない場面になった時は、思い切ってたくさんテストをしなければならない。

そんな時でも、最近の クレカ決済APIサービスは充実していて、テスト用の環境とクレジットカードをあらかじめ用意してくれている。WebPay の場合は、モック用のカード番号をあらかじめ掲示してくれているので、その番号を入力することで、決済時に失敗するカードを登録してテストをするなんてことも簡単にできるから便利だ。

テスト環境なら何回決済してもお金はかからないし、本番環境さながらでテストができるため、思い切ってどんどん実行していこう。

最悪のケースが発生して本番でやらかしたとしても、払い戻しを行えばいいだけの話だ。その分の手数料はこっち持ちになってしまうけどね。そうならないようにするためにも、決済のテストは億劫にならず確実に実行していこう。

月額の場合は BillHistory などのテーブルを用意しよう

月額課金で特に毎月の金額が変動するようなサービスの場合は、 毎月の決済を保存できるよう BillHistoryテーブルを用意しておこう。以下のようなカラムがあれば十分だろう。

BillHistories
    integer "id"
    string   "target_month"
    integer  "plan_id"
    string   "charge_id"
    integer  "contract_id"
    integer  "price"
    datetime "created_at"
    datetime "updated_at"

Plans
    integer "id"
    string   "name"
    string   "description"
    integer  "price"

taget_month には 201611のような文字列が入る。 plan_id には紐づく PlanテーブルのプランIDを。 charge_idは決済サービスから発行された決済IDを。contract_idは契約している企業のID。 priceは月ごとに変動する料金。

もちろんこれらを月額課金APIを用いて自前で持たなくてもいいようにする方法もあるので、自分の決済サービスにおいてはどっちが適切かどうかを把握しておく必要がある。個人的にはこういう情報は外部APIに持たせるよりは自前でやった方が柔軟性が高まるから良いと思う。そんな複雑でもないし。

終わりに

本記事では月額決済で良くある実装について考察した。やはり大きな違いとなってくるのは、毎月固定金額の課金なのか、何かしらの従量課金が発生するのかというサービス特性の違いだ。毎月固定金額でやっていたサービスがあったとしても、例えばアドオンの機能を追加して、毎月の金額が変動する場合が出てくるかもしれない。そうした今後の機能開発もあらかじめある程度想定した上で決済機能を慎重に設計し、実装していこう。