メルペイ決済基盤における Source Payment による決済手段の抽象化

この記事は Merpay Tech Openness Month 2023 の 6 日目の記事です。

はじめに

こんにちは。メルペイの Payment Core チームでバックエンドエンジニアをしている komatsu です。
普段はメルカリ・メルペイが提供するさまざまな決済機能のために、決済基盤の開発・運用をしています。
この記事では、我々が開発している決済基盤マイクロサービスである Payment Service における、Source Payment と呼ばれる複数の決済手段を抽象化した概念について紹介します。

決済手段の多様性

メルカリやメルペイはさまざまな決済手段をお客さまに提供しています。
例えば、

  • メルカリの売上残高
  • 銀行口座からチャージした残高
  • 付与されたポイント
  • メルペイのスマート払い

などがあります。
Payment Service はこれらの決済手段を実現するための決済ハブとして、複数のマイクロサービスに決済関連の API を提供しています。
上に示した決済手段は、購入と決済のタイミングが同期的である、つまり、購入のタイミングで利用額が残高や与信枠に反映されるため、1 つのリクエストで決済処理を完了することができます。

一方で、例えばメルカリでは、

  • キャリア決済
  • クレジットカード (3DS; 3-Domain Secure 2.0)
  • コンビニ払い
  • ファミペイ

といった決済手段も提供しています。
コンビニ払いでは、お客さまがアプリ上で決済方法を選んでから実際にコンビニに行って支払いを行います。
キャリア決済やクレジットカード (3DS)、ファミペイでは、決済のタイミングでメルカリ外のページに遷移して認証情報などを入力し、支払いを行います。

carrier-payment-flow

これらの決済手段のフローは、複数のリダイレクトが複数のマイクロサービスや社外システムを横断するため、複雑になりやすいです。
このような購入と決済のタイミングが異なる支払い方法を実現するために、Payment Service では Source Payment という、複雑な決済手段を抽象化した概念を利用しています。

Charge: Payment Service における決済

前提として、Payment Service では 1 つの決済を Charge として表現します。
1 つの Charge は複数の Payment Method (残高決済やスマート払いなど) を持つことができ、さまざまな決済手段を組み合わせることができます。

一般に、決済の流れは authorize (仮売上) と capture (実売上) の 2 つのステップに分かれています。
authorize では消費する金額が利用可能かどうかを確認し、他の決済によって重複して利用されることがないように承認・記録します。
capture では authorize された金額を実際の売上として処理し、支払いを確定します。
例えば残高とスマート払いを利用して決済をする場合、次のような処理の流れになります。

balance-deferred-flow

ここで、Client はお客さまの操作に基づいて Payment Service やその他のマイクロサービスにリクエストを送る BFF のようなサービスです。
また、Balance Service は残高を管理するマイクロサービス、Deferred Service はスマート払いの機能を提供するマイクロサービスです。
この図のように、Payment Service は Client が指定した支払い方法ごとに、社内のマイクロサービスや社外のサービスを利用して決済を構築します。
すべての処理が同期的であり、決済の仮売上 (authorize) と実売上 (capture) がそれぞれ Client からの 1 つのリクエストで完了していることがわかります。

Source Payment とは

Source Payment とは、非同期的な決済フローを抽象化した概念で、Source はその決済手段を表します。
言い換えれば、Charge にとって残高やスマート払い、Source はすべて Payment Method であり、Source がキャリア決済なのかコンビニ決済なのかは Charge にとって関心事ではありません。
ちなみに、Source については Stripe なども同様の仕組みを提供しています [1]。

Source が Payment Method に指定された場合、その Source の支払いが完了した場合に Charge は Paid (支払い完了) に状態を遷移することができ、クライアントは決済 (Charge) を次のステップに進めることができます。
キャリア決済であればキャリア画面において支払いが完了した状態、コンビニ決済であればコンビニで支払いを完了した状態が Charge を Paid へ遷移できる状態に該当します。
より詳細なフローを見てみましょう。

carrier-payment-flow

convenience-payment-flow

1 つ目はキャリア決済、2 つ目はコンビニ決済を表しています。
実際にはより多くのマイクロサービスや社外のサービスを跨いでいるのでこれらは簡略した図ですが、 Payment Service が行う処理が似ていることがわかるかと思います。
類似したいくつもの決済手段を Source として共通化して抽象化することで、Charge から見て各決済手段の詳細な処理フローを意識せずに実装することができます。
その結果、複雑な決済手段を汎用的に扱うことが可能となります。

Source Payment のメリット

Source という決済手段を用意することで、リダイレクトや社内外含めて関連するサービスが多く、さまざまな状態を持つ複雑な決済手段の差分をそれぞれの Source Payment の決済処理 API で吸収し、メインの決済処理 (Charge) では「Payment Method が Source である」という汎用的な決済手段として扱うことで、拡張性の高い設計ができました。
Source によって実装をシンプルに保つことだけでなく、今後新しい決済手段に対応する際の開発工数も減らすことができるでしょう。
また、メルカリは複数の決済手段を組み合わせた複合決済にも対応しているため、残高やポイントと組み合わせて決済するようなケースにおいても、実装の一貫性を保つことができるようになりました。
このようなメリットから、Source Payment は決済基盤の開発や拡張をする上で有益です。

Source Payment のデメリット

一方で、Source Payment は 1 つの決済を行うために複数の API を利用する必要があるため、処理の流れを開発者が把握することが困難になりやすいです。
このような複雑なドメイン知識は適切にドキュメントを整備しないと知見が属人的になってしまうので、いかにチーム内の共通知識として共有できるかということが 1 つの課題です。
また、現状の実装では同じ Source Payment であるキャリア決済とコンビニ決済を組み合わせることはできないようになっています。
これは 1 つの Charge は各 Payment Method を多くとも 1 つずつ組み合わせることができる、という仕様になっているからです。
仮に将来的に複数の Source Payment を組み合わせた決済手段を提供する場合、内部の実装を見直す必要があるでしょう。

Source Payment の運用術

Source は capture された後、PayCharge によって親となる Charge に紐付けられます。
しかし、ネットワークやクライアントの状態、またはお客さまの操作によっては、Charge に紐付けられる前に意図せず処理が途中で止まることがあります。
例えばクレジットカード (3DS) 決済でパスワード認証を終え、利用枠の authorize が終わった後にネットワークの問題で処理が止まった場合、お客さまのクレジットカードの与信枠をずっと保持してしまうことになります。
実際の支払いが行われているわけではないですが、authorize がクレジットカード会社などによって自動的にキャンセルされるまではお客さまの利用枠は回復しません。
Payment Service は処理の途中でエラーを受け取った場合は自動で rollback を行い、途中で止まっている処理を初期状態、つまり authorize される前の状態に回復する仕組みになっています (このあたりの話は マイクロサービスにおける決済トランザクション管理 で詳しく触れられています)。
しかし、予期せぬエラーを受けて rollback すらできない場合や、rollback 中にもエラーを受け取る場合などもあります。
このような状況にも対応するために、Payment Service ではそのような状態の Source を自動でキャンセルするバッチ処理を運用しています。
これによって例えばクレジットカード会社による自動キャンセルは通常 2 ヶ月程度かかるのに対し、バッチ処理を用いることで最大でも 2 時間程度でキャンセルが可能となります。
このように、バッチ処理を運用することで、予期せぬ問題が発生した場合でもお客さまのメルカリ内外における決済体験を損ねないような仕組みを提供しています。

おわりに

この記事では、メルペイの決済基盤において、Source Payment という概念を用いて複雑な決済手段を統一的に扱うための方法を紹介しました。
増え続ける決済手段に柔軟に対応・開発するために Source は有用であり、我々の生産性向上に寄与してくれています。
今後も新しい決済手段への対応や既存の決済基盤の最適化に取り組むことで、お客さまにとってより便利で多様な決済体験を実現したいと思います。

脚注

[1] Stripe の Source は現在は deprecated となっています (ref. https://stripe.com/docs/sources)。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加