- 決済と売上システムは収益化に不可欠だが、財務・プロダクト・カスタマーサポート・法務・コンプライアンス・営業まで絡む複雑な中核システムであり、小さな障害でも大きな運用問題に発展し得る
- 初期段階の会社や新製品チームは、決済を単なるエンジニアリング課題と見なして自作しがちだが、実際の選択肢は自社構築・サードパーティ・ハイブリッドに分かれる
- 実際の決済システムは、冪等性、日付処理、利用量の計量、税金、返金、顧客階層、カスタム契約、価格変更、収益認識を同時に扱う必要がある
- 一部の問題は一度解決すれば安定するが、税務ルール・顧客のミス・手動訂正・国ごとの請求書要件は、成長とグローバル展開に伴って拡大し続ける
- プロダクト固有の利用量更新と顧客ライフサイクルイベントに集中し、サブスクリプション・請求・会計・収益認識は可能な限り既製の決済システムとERPに任せる方が安全
決済が単なる機能ではない理由
- 決済と売上システムは、ビジネスが収益を上げるために必須である
- 正常に動作しているときは目立たないが、実際には複数の組織と機能に同時に触れるタコのようなシステムである
- 財務
- プロダクト
- ユーザー体験
- カスタマーサポート
- 顧客
- 法務
- コンプライアンス
- 営業
- 一部が壊れると、関連領域にまで問題が急速に広がる可能性があり、実際によく壊れる
- 合法かつ正確に売上を回収できなければ、事業運営者が対処すべき問題は大きく増える
3つの構築パターン
- 決済システムには通常、3つのアプローチがある
- 自社構築
- 完全なサードパーティシステム
- 自社構築とサードパーティを組み合わせたハイブリッド
- 初期段階の会社や新製品を始めるチームは、エンジニアがいてシンプルに保ちたいという理由で、自作しようとする傾向がある
- 決済を「S3に請求ファイルを置き、CRONジョブが取得して決済すればよい問題」のように見ると、決済をエンジニアリング課題だけだと誤解してしまう
- セキュリティや日付処理を自前で実装しないのと同じように、決済も最初からすべてを自作しない方がよい
- 最良の決済システムとは、すべてを自作する必要がなかったシステムである
独自決済システムの14の苦痛
-
冪等性
- すべての請求と決済回収リクエストは、一意で冪等でなければならない
- API制限により再試行したり、決済システムのインスタンスを増やしたりすると、この問題が表面化する
- 適切に処理しなければ、重複請求のリスクが生じる
-
日付処理
- 30日ごとに請求するのか、毎月の加入日を基準に請求するのかを決める必要がある
- うるう日、タイムゾーンといった条件も併せて処理しなければならない
-
日割り計算と残額
- アップグレード時だけ日割り計算するのか、ダウングレードにも適用するのかを決める必要がある
- 返金、クレジット、無視、アップグレード・ダウングレードのブロックといった選択肢がある
-
利用量の計量
- 利用量の計算方法は数十通りになり得る
- 顧客タイプごとに異なったり、頻繁に変わったりする可能性がある
-
請求書の形式
- 1つの国だけで運営しているうちは簡単に見えるかもしれない
- 拡大すると、売上税だけでなくVAT、GST、国ごとの追加負担金まで処理する必要がある
- 市場ごとに個別のテンプレートが必要になる場合がある
B2Bとグローバル展開で増す複雑性
-
複雑な顧客階層
- 特にB2B顧客は、子会社やパートナーを持ち、請求関係を管理しようとする場合がある
- 利用量を実際の支払主体に合算する仕組みが必要である
- こうした要求は、成長と拡大の後になって初めて現れることが多い
- 顧客法人や利用場所が異なれば、税金が変わる可能性がある
- 法的に請求明細とインボイスを分けなければならない場合がある
- 関連するルールは数カ月ごとに変わり得る
-
決済回収と解約防止
- 決済の再試行をいつ諦めるかを決める必要がある
- チャージバックが発生した場合、アカウントを終了するのか、停止するのか、返金するのかを判断しなければならない
-
一時停止と再開
- 顧客がサブスクリプションを一時停止したとき、どのレベルのアクセス権を許可するかを決める必要がある
-
クレジットと返金
- 全額返金だけなら比較的単純である
- 部分的な誤りが発生すると、部分返金やストアクレジットを選ぶ必要が生じる場合がある
- クレジットに有効期限を設けるかどうかも別途決めなければならない
税金、契約、人のミス
-
税務処理
- 異なる項目に異なる税率が適用されるだけでも複雑である
- グローバル規模では、税率と税務ルールが頻繁に変わる
-
カスタム契約
- PLGだけであれば問題にならない場合がある
- 契約を結び始めると、既存の前提では簡単に設定できない例外や特別条件が急速に増える
-
人のミス
- 顧客はミスをし、それに伴う訂正が必要になる
- 企業内部でも顧客設定を誤って構成することがあり、後から修正しなければならない
- クレジット発行と請求書の再発行は時間のかかる作業である
- 顧客の法的情報が変わる場合も処理対象である
-
選択的な価格変更
- 価格変更はすべての顧客に適用されないことが多い
- 新規顧客だけに適用される場合は、既存契約を守るために異なる価格バージョンを維持する必要がある
-
収益認識と発生収益
- IFRS-15基準の収益認識ルールには、64ページのPDF仕様書がある
- カスタムERP統合まで自前で行うと、複雑性はさらに増す
一度で終わる問題と拡大し続ける問題
- ある問題は予想よりはるかに頻繁に変わり、ある問題は一度処理すればほとんど再び手を入れることがない
- 冪等性は、一度解決すればまれにしか再対応しないエンジニアリング課題の例である
- 税務ルールは世界中で頻繁に変わる
- 顧客のミスは比較的継続的に発生する
- 成長するほど規模が大きくなる
- より多くのカスタマーサポートと手動訂正が必要になる
- 決済は最初はエンジニアリング課題のように見えるが、実際には業界経験者にとっても理解しにくい複雑な問題空間に根ざしている
自作しなくてもよい領域
- 可能な限り多くの決済問題を外部システムに任せる方がよい
- 既製ソリューションをできるだけ多く購入するアプローチが推奨される
- サブスクリプションと請求領域のかなりの部分は、決済システムで処理できる
- 収益認識と会計は、すでに使っているERPや他のシステムに組み込まれた機能に任せる方がよい
- プロダクトチームは、利用量更新と基本的な顧客ライフサイクルイベントのように、プロダクトに固有の部分だけに集中すべきである
1件のコメント
Hacker News のコメント
請求に関する意思決定をしなければならないが経験があまりない人には良い記事で、経験者にとっても参考用として有用。
ただし「S3 に請求対象のファイルをダンプしておき、CRON ジョブに決済を回収させればいいのでは?」という文には大笑いした。エンジニアの頭で考えても、どんな状況でも良いアイデアではない。
私が気に入っている請求アーキテクチャ上の判断は、システム内で請求と権限をできるだけ分離すること。プリペイドのサブスクリプションなら、権限そのものには有効期限と有効期間中に付与される権限の詳細だけを保存し、請求システムはサブスクリプションを保存したうえで必要に応じて権限側へ同期する、という方式がよかった。こうすると、人が手動で請求したり、一時的な問題をデバッグ・パッチしたり、Stripe 連携を追加したりするのも楽になる。
もちろん将来の拡張余地は残しておくべきだが、この判断自体がシステムを大きく制限するわけではない。私独自のアイデアではないが、別の方法を試してあまりうまくいかなかった後で、特に気に入るようになった。
多くの問題は決済と請求の違いから生じる https://www.wingback.com/blog/saas-payment-vs-saas-billing。最初に顧客を受け入れるときは、数件の継続課金を受けられればよいので、Stripe や手動インボイスでも簡単に始められる。
しかし時間がたつと、より複雑な権限、複数の料金プラン、既存顧客の保護、カスタムの請求周期・条件・権限付与を必要とするエンタープライズ顧客が徐々に入ってくる。請求は技術的な焦点にならないことが多いため、小さなハックや追加機能が積み重なり、最終的にはプロダクト開発のリソースを奪い、営業の速度を落としたり、販売できる商品の範囲を制限したりする混乱状態になる。
請求の複雑さには隠れた落とし穴や例外が多く、最近はほとんどの料金プランが複数の上限や従量課金要素を含み、SaaS が世界中で売られるため、さらに複雑になっている。後期段階の企業には、請求だけを担当する15人以上のエンジニアチームがあることもある。プロダクトの中核でないなら、請求システムを自作すべきではないという点には同意する。ちなみに私は SaaS 請求プラットフォーム Wingback の CTO です。
今ではそういうシステムを作りたくなったし、思っていたより自分のほうがずっと適任のように感じる。
https://arnon.dk/why-you-should-separate-your-billing-from-e...
顧客は権限を私たちのシステムに保存して必要なときに確認し、決済プロバイダー側でサブスクリプションが更新・削除されるとルールと権限を追加する方式だ。こうすると、1つまたは複数の決済プロバイダーと連携しやすくなり、関心の分離も明確になる。関連する記事もこの文脈により合っているので共有する: https://warrant.dev/use-cases/pricing-tiers-and-entitlements..., https://arnon.dk/why-you-should-separate-your-billing-from-e...
理想的な権限システムは動的であるべきで、つまりルールはデータベースに保存され、エンタープライズ顧客のような一回限りのシナリオを処理でき、その上にポリシー層があるべきだ。たとえば Pro プランは5席以下、Growth プランは特定の機能を1日 N 回まで、といったほぼあらゆるシナリオをサポートできる必要がある。
非技術担当者がエンジニアリングの介入なしに顧客ごとの変更を行える UI も大きな利点だ。以前のエンジニア職では、こうしたことがいつも開発チームの足かせになっていた。
権限セットもあるが、その中間には、いつ権限を適用するか、または適用しないかを決めるポリシーメカニズムがある。重要なのは、権限は請求だけの問題ではないという点だ。ポリシーメカニズムは権限と他のすべてをつなぐ接着剤なので、最大顧客の役員に対して、請求と結び付けなくても権限を付与できる。
以前、小さな薬局チェーンの請求と売掛金システムを作ったことがあるが、保険会社が何の予告もなくかなり大きな小切手を送ってくることがあった。
私たちが何も請求していないのに郵便で15万ドルの小切手が届き、数か月後になってようやく相手がミスに気づき、返してほしいと言ってきた。こういうお金を入れておく magic money という特別な口座があった。請求の世界は本当にめちゃくちゃな場所だ。
単に magic money と呼びつつ、個人アカウントの債務はそのままにしていたのではないか。
請求システムを自作する苦痛だけでこのテーマにアプローチするのは適切ではないと思う。多くの企業がそうしたいなら、そうさせておけばよい。
請求システムが非常に複雑だということは認める。ただ、Chargebee、Solvimon、Stripe、Recurly、Orb、Metronome、Lago、Togai などがそうした知見を持っているなら、その知見を一か所に集めることもできる。
結局の正解は、自分に合ったアプローチだ。サブスクリプション型 SaaS ならそれに合った解決策があり、従量課金型 API ならそれに合った請求ソリューションがある。
慣行をやめさせるのではなく、知識、アプローチ、パラダイム、プログラミングパターン、良い慣行とベストプラクティスを一か所に集めることはできる。米国や欧州以外の企業で、Stripe のような請求ソリューションを使えない例外もある。例えばベネズエラの企業で Stripe アカウントを作れないなら、結局は自前の請求ソリューションを作り、現地の決済ゲートウェイの難解な SOAP-XML API に接続しなければならない。
それとは別に、「請求システムを自作する」のは、Elastic + Grafana 構成で「SIEM を自作する」のに似ていると感じる。おすすめはしないが、IT セキュリティ部門でなぜそれほど多く採られるのかは理解できる。
請求システムは、開発者が普段扱う対象ほど複雑ではない。記事は難しい法的要件を難点のように描いているが、実際には仕様を見つけやすく、文書化もよくされているという意味でもある。頻繁に変わる部分もあるが、そうした部分はラベル付けや説明がきちんとされている。
サブスクリプション型 SaaS と従量課金型 API ではそれぞれ適した請求方式がある、という点には同意する。ただし鍵になるのは、顧客が責任の負担を押し付けることを許すのか、売上が検証するほど重要なのか、手数料や損失を負担できるのかだ。
この記事が扱っていないものの一つに アフィリエイト販売 があるが、どこまで深く実装するかによってはかなりの作業量になり得る。
プラットフォーム内の販売について、他者がコミッションベースの支払いを受けられるようにするシステムだ。
アフィリエイトコードを販売とユーザーまで追跡し、アフィリエイトが設定した決済プロバイダーへ支払いを送り、きちんとやるなら訪問者指標やコンバージョン率、支払い履歴を確認できる UI も提供する必要がある。
幸い、たいていは段階的に作れる。固有コードをユーザーに紐づけ、そのコードを特定のコミッション率の販売に紐づけるだけで、残りは手動処理にするか省略できる。例えば私は月に一度、Zelle や PayPal でアフィリエイトに支払っているが、10分もかからない。コンバージョン追跡のフロントエンドはなく、そのせいでアフィリエイトをやらないと言った人もいなかった。
本当に印象的だったのは、この ルーブ・ゴールドバーグ・マシン 全体を逆回しできなければならない、という必要性だった。
「注文」はできるだけ静的に保ちたいし、「インボイス」には法的義務まである。
例えば5個買って割引を受けたが、3個だけ欲しくなり、名前と住所に誤字があったとしよう。問題ないと言ってインボイスを取消処理し、同じ金額で名前・住所を修正した新しいインボイスを作り、返品が到着して検品されるまで待ってから再度クレジット処理し、さらに新しいインボイスを作る。
返品配送はしばらく曖昧な状態にあり、顧客はさらに5個注文し、そのうち1個は壊れて届き、交換ではなく返金を望む。配送日が2つに分かれたため、システムは5個以上の割引を適用しない。最初は単純な注文2件だと思っていたことが、あっという間に大量の取引と書類に変わる。顧客はパスワードも忘れて、別のメールアドレスで新しいアカウントを作っていた。1年後にログを見ると、なぜ3個しか買っていないのに割引を受けていたのか把握しづらい。
この助言はよく分からない。記事で述べられている機能の半分は不要かもしれないし、事業が大きくなるにつれて十分に段階的に作っていける
インボイス、クレジット、課税期間、日割り計算の変更といった概念は理解しておく必要がある。だがその知識は、必ず外注・購入すべき理由ではなく、構築と購入の判断をよりよく行うための材料である
SaaSに必要な外部APIはクレジットカード処理業者1つだけで、凝るなら2つ程度だ。もちろん1年目を過ぎれば手作業が多く発生し、会計士がばかげたミスを指摘してくれるだろうし、会計についても多く学ぶことになる
それでも今日新しい事業を始めるなら複数のソリューションを比較はするだろうが、自作することがそれほど恐ろしいものではないという確信はある
システム構築はいつも簡単そうに見えるし、初日には実際に簡単だ。だがすぐに、なぜレポートが完全にめちゃくちゃなのかを財務責任者に説明するのに多くの時間を費やすことになり、サポートチームには、なぜインボイスが失敗したのか、なぜサブスクリプション価格を誤って請求したのか、存在すら知らなかったさまざまな例外ケースを説明することになる
その次には、変わった規制に対応しなければならなかったり、選んだゲートウェイが成長中の地域をサポートしていなかったりするかもしれない
「ただもっと上手く作ればいい」と言う前に、それも時間だという点を覚えておくべきだ。製品に使えなかった時間であり、価格モデルの改善にも使えなかった時間であり、事業成長を生み出す仕事の代わりに足踏みに使う時間である
それ以外は無視できるかもしれないが、後で税金を計算できなかったり、本人確認制度の法律に違反することになったりすると本当に大変になる
また、あるシステムが予想より高価で、賢そうに見える多くの会社が使っているからといって、目的に合っているという意味ではない。特に、あなたが望む目的に合っている保証はなおさらない。購入するからといって調査しなくてよいわけではない
こうした請求を扱う人の目標は単純だ。営業チームが契約を締結できるよう、適切な選択肢を提供しなければならない。営業チームと協力して「実装しやすく、契約を締結するのに十分な」範囲がどこかを見つけるべきだ
この点はいくら強調してもしすぎることはない。営業チームは実際に売上を作っている。完璧な請求システムではないからといって文句を言うべきではない。衝撃的かもしれないが、ビジネス上の関係がかかった問題では、ときには腕まくりして手作業で処理しなければならない
できるだけ単純な方法にしつつ、社内の他チームが読んで理解でき、自動化が動いていても簡単に手動調整できるシステムであるべきだ。Stripeが使いやすく感じられる理由の80%はここにある。手動調整は人生の一部であり、事業によってはまれであっても最終的には必要になる
日割り計算、異なる請求スケジュール、トライアル、新価格のテスト、地域別価格、地域別税金、複数通貨でのバンドル商品の列挙、新価格の展開が、突然「6通貨 × X地域 × Y製品 × Z請求スケジュール × L言語」の組み合わせになる
ここに新しいサブスクリプションを追加し、サブスクリプションプランを統合し、古いプランを廃止しながら顧客を新しい代替プランへスムーズに移行させ、顧客ときちんとコミュニケーションしなければならない。SaaSならほぼすべてが十分に自動化・セルフサービス化・テストされている必要があり、そうでなければカスタマーサポートと解約に埋もれて死ぬことになる
価格変更の展開には3日から2か月までかかることがあり、初期のカスタム契約の名残を処理するのは悪夢だ。簡単に自動化できなければ、できない。時間がかかりすぎる
ここで言及されているような製品を請求の基盤にしていたなら、顧客セグメント別のカスタム契約や価格変更の展開をはるかにうまくできていた可能性がある
ここでは扱われていないが、自分で対処したことのある問題が2つある
1つ目は月次・四半期決算だ。記事は勘定元帳について語っているが、数値を報告しなければならない上場企業を相手にし始めると、厳格な締め時点があり、すべてが円滑に進むようにしなければならない
2つ目は移動中の現金会計だ。この記事は決済処理業者が100%正確で、何の問題もないと仮定している。十分に大きくなると、銀行口座に入ってきたすべてのお金を特定のインボイスや請求項目と照合できなければならない。対応する銀行明細行がないインボイスも見つける必要があり、逆にインボイス項目と結び付いていない入金がある場合も処理しなければならない。請求インボイスと結び付いていない銀行口座のクレジットを扱う能力も重要だ
これをすべて経理部門の問題だと言うこともできるが、システムと非常に密接に結合しているため、2つのチームが帳簿間の不一致がないように協力しなければならない
実際の会計士は決算のために繰り返し深夜まで残らなければならず、技術・ビジネス側の人間は会計チームから何かを受け取る必要があるのに、決算期間中は会計チームが地球上から消えたように見える状況を経験する。家族の一員として経験しても同じだ
内部会計と銀行口座が少しずつずれていき、会計士はどこから問題を探せばよいのか分からなくなる
みなさんが権限管理に何を使っているのか気になります。機能フラグシステムを使っているのか、Stigg のような別の SaaS を使っているのか、それとも別途社内システムを持っているのか知りたいです
今朝 HN に来たのも、機能フラグを権限管理に使う記事を書いたからです: https://prefab.cloud/blog/modeling-product-entitlements-with...。Arnon の SKU 形式に関する記事からも着想を得ました
機能フラグが権限管理に完璧な場所に見えるわけではありませんが、経験上、この種の課題に対処するときに手元にあるツールの中で最善であることが多かったです。ほかの意見も聞きたいです
この上限とフラグは「料金プラン」に紐づき、料金プランはアカウントに紐づけられます。料金プランを組み合わせる場合、数値はより大きい値を採用し、タグは和集合としてまとめます。またアカウントごとに値を上書きしたり追加したりできるので、顧客が PlanX は必要だがカスタム API 割り当てが必要な場合、その値だけをアカウントに直接上書きすれば済みます
古臭いと言われても構いませんが、なぜこういうものを第三者に外注しなければならないのか分かりません
基本的な解決策は機能フラグで可能ですが、請求・価格に関連する権限、たとえば料金プランやエディションの整理と変更は、時間が経つにつれて周辺要件が増えて複雑になります。機能、シート、使用量ベース・計量戦略のさまざまな組み合わせ、チームサブスクリプション、料金プランの移行、一回限りのエンタープライズ料金プラン、複数のサブスクリプションを持つ顧客、プロモーション期間と階層型サブスクリプション、使用量集計、自動アップセルなどを考えてみればよいです
記事にあるように数値を持つフラグで上限を表現することはできますが、使用量追跡インフラは依然としてビジネス側が自分で実装する必要があります。代わりに、その使用量を権限サービスへエクスポートし、使用量ベースの権限がチーム間でもリアルタイムに更新されると考えるとよいです。また、その権限に依存するほかの権限も一緒に更新できます。上限に近づいたり超えたりしたら使い続けさせつつ営業チームに通知するソフト制限や、アップグレード案内を表示するハード制限を選べます
元記事の趣旨と同じく、私たちは請求を作り直すのではなく、既存の請求ソリューションと連携して動作します。以前の成功したエグジットを元手にブートストラップしており、初期顧客と取り組んでいます。このテーマについて話してみたいだけの人も trent at planship.io まで連絡してください
ベータ展開、ロールベース認可、請求権限、一回限りの顧客要望まで、すべて機能フラグで作れます。最良の機能フラグは任意で値も付けられるので、API 料金プランの上限も機能フラグにできます
それが最善かと言われれば、各ユースケースごとにはおそらく違うでしょう。しかし一度作ってしまうと、あらゆる場所で使いたくなる誘惑は大きいです
権限は顧客が見る機能と明確に結びついているべきで、概念的にははるかに大きな機能ブロックです。このアプローチの難しさは、それでも請求に関する多くの側面を考慮しなければならない点です。滞納顧客の扱い、特定の上限を超えたときの超過料金、同じ機能に対する複数の価格モデル、料金プラン変更・アップグレード時の使用量カウンターのリセットや繰り越しなどが、時間とともに大きな複雑さを加えます
そのため私たちは Wingback で、請求チェーンと計量に密接に結合した別個の機能権限を提供することにしました。ちなみに私は CTO です。結局のところ、料金プランの複雑さと、すでに機能フラグにどれだけ投資しているかによって、どちらのアプローチもうまく機能し得ると思います。顧客向けの機能ゲーティングがあれば、顧客アカウントのプロビジョニングやカスタムパッケージの提供がずっと簡単になります
「システム X は非常に複雑だから自作せず既製ソリューションを使え」という論理構造全般には納得しにくいです
X の一般解が非常に厄介で複雑であり得るとしても、自分のユースケースにはその複雑さの特定の部分だけが必要です。だから必要な複雑さだけを扱う自前の解決策を作ることができ、それは既製ツールよりずっと単純になり得ます
私はこの立場を日付・時刻については完全に採用しています。私の日付・時刻へのアプローチでは、ライブラリが 2 つの関数呼び出しだけを提供してくれれば十分です。エポック時刻を特定タイムゾーンの ISO 形式の時刻文字列に変換する関数と、その逆関数です。ほかのライブラリコードには一切触れず、残りの時刻操作はその 2 つの関数を基準に自分のコードで処理します
最初から、個人情報処理でやるべきこと・やってはいけないこと、複数の請求オプションの周期とライフサイクル、返金上限、冪等性のサポート、課題に合ったモデルを備えた合理的なデータベーストランザクション管理、請求書発行と顧客への提示などを理解している必要があります
すべてが一度に必要なわけではありませんが、最初の動作する実装にも少なくとも半分は必要です
「道路を渡ることの 14 の苦痛、そしてなぜ私の本を買って読むべきなのか」のような感じがあります
多くの人は目を閉じて歩き始めるのがよいと考え、その結果、早すぎる負傷や死を迎えます
国ごとに、さらには都市ごとに道路を渡るルールは違います。まだ知らないかもしれませんが、左右を見なければなりません。自分が色覚異常だと知らず、赤と緑を区別できなくて死んだりけがをしたりする人も多いです。左右は見ましたが、上も見ましたか? 都市では窓から物が落ちてきますし、田舎では鳥が頭上を飛ぶことがあり、宇宙ごみもますます多く地球に落ちてきています。物体は複数の方向から来る可能性があります
この記事がそこまでひどいというわけではありませんが、方法論の記事として構成されていればもっとよかったでしょう。否定的に組み立てられた記事より、そういう記事のほうがはるかに読みたいです
「どれほど難しいっていうんだ?」というジョークプロジェクトの理想形ですが、問題はすべて事実だという点です
例は数え切れないほどありますが、問題への取り組み方を間違えると、すぐに「顧客はいくら支払うべきか」という問いにぶつかり、続いて「なぜ私たちはこの金額ではなく別の金額を請求したのか」が来ます。こうしたことがあまりに頻繁に起きると、財務チームがやって来て、会社運営のレポート、さらには解雇の可否を決めるレポートまで信頼できなくしたとして、何をしたのかと問うことになります