💸

これから決済システムを開発させる人・開発する人に読んで欲しいこと

に公開

はじめに

決済システムは単なるWebアプリとはまったく性質が違う。お金を預かり、それを正しく流す仕組みだからこそ、法律・セキュリティ・運用体制のどれか一つでも欠けるとサービス自体が立ち行かなくなる。普通のWebサービスなら多少の障害は「不便」で済むが、決済システムは「損害」につながる。その重さを実感するには一度でも金融系の現場を経験すればわかるはずだ。

自分はこれまで金融SIerとして銀行システムに関わり、さらにキャッシュレス決済事業を展開する会社でサービス開発を担当してきた。その中で何度も「決済システムは動けばいいわけじゃない」と痛感している。冪等性の担保を怠った結果、二重決済が発生して大量の返金処理が必要になった案件もあったし、監査用のログを残していなかったせいで、過去の取引を遡れずに顧客や監査法人に頭を下げ続けたこともあった。どれも「技術的には簡単に直せる」ことだったが、実際には信用や運用コストに大きな傷を残すことにつながる危険性を秘めている。

この記事では、発注者と開発者の両方に向けて、決済システムを設計・開発・運用するときに絶対に意識しておくべきことを整理した。資金決済法や割販法といった法律面から、DB設計やインフラ構成、APIの認証方式や冪等性の扱いまで幅広く掘り下げる。ポイントは「教科書的な理屈」ではなく、現場で実際に問題になったり、見落とされやすい部分を具体的に示すことだ。

もしこれから新しい決済サービスを企画する立場にあるなら、「資金決済法ってなに?」という基本的な疑問から始まると思う。あるいは開発者であれば「DBのテーブルはどこまで冪等性を考慮すればいいのか」「APIキーはどう分離すれば安全なのか」といった技術的な疑問が出てくるだろう。この記事はそういった問いに対して、一通りの答えや判断材料を提供できるように書いたつもりだ。

決済システムはユーザーからすれば「正常に動いて当たり前」だが、裏側には数多くの落とし穴が潜んでいる。その落とし穴を事前に知って避けられるかどうかで、サービスの信用と寿命は大きく変わる。

1. 法律面の注意点

資金決済法と前払式支払手段

資金決済法における規制の段階
資金決済法における規制の段階

プリペイドカードや電子マネー、ポイントといった“前払いで利用する残高”を扱うと、必ず資金決済法の規制を受ける。これは単に役所に届け出るだけの話ではなく、利用者が「預けたのに残高が消えた」という事態を防ぐための安全網だ。

まず押さえるべきラインは発行残高1,000万円。これを超えた時点で金融庁への届出が必要になる。届出を怠れば「無登録営業」として指導対象となり、公開処分を受けるリスクがある。そしてさらに1億円を超えると供託金(発行保証金)を積まなければならない。これは利用者が返金を求めた際に発行者が倒産していても資金を守れるようにするための仕組みで、現金供託や保証契約といった方法がある。小規模のスタートアップが一気に成長したとき、この1億円ラインで一気に資金繰りが苦しくなることは珍しくない。

もう一つ重要なのが有効期限の設定。資金決済法では「無期限のポイントや残高」は原則認められていない。理由はシンプルで、発行者が無限に返還義務を負うことになるからだ。一般的には「発行日から5年」や「最後の利用から1年」といった期限が設けられている。開発の現場では、この期限切れ処理をバッチや定期ジョブで無効化する仕組みを作っておかないと、後で法令違反が発覚し、大改修が必要になる。

発注者が勘違いしがちなのは「残高を自社で持った方がユーザーの囲い込みになる」と考えること。確かに自社ブランドの電子マネーは強力だが、その分、金融庁への届出、供託、定期報告といった手間を背負うことになる。立ち上げ期には決済代行会社と組み、自社で残高を持たない方式を選ぶ方が現実的だ。

https://www.s-kessai.jp/pdf/shikin/shikin2021-01.pdf

割賦販売法(クレジットカード)

どの決済代行会社を選ぶべきか?
どの決済代行会社を選ぶべきか

クレジットカード決済を受け入れる事業者は、割賦販売法の規制対象になる。ユーザーにとってカード情報は最もセンシティブなデータであり、漏洩すれば即サービス終了レベルの事故になるからだ。

法律上、加盟店はカード会社や決済代行会社の審査を受ける必要がある。その際に必ず確認されるのがPCI DSS準拠だ。PCI DSSは国際的なカード情報保護の基準で、カード番号をどのように保存・処理・伝送するかを細かく定めている。

開発者の立場でまず大前提なのは「カード番号をDBに保存しない」ことだ。どうしても保存が必要なら暗号化やトークン化をする必要があるが、実務的には決済代行会社のトークン決済を利用するのが一般的だ。これならシステム側ではトークン(乱数文字列)しか扱わず、カード番号は一切保持しない。

もしここを軽視して情報漏洩が起きれば、被害額は数億〜数十億円単位に膨らむ。さらにカード会社から加盟店契約を打ち切られ、事業そのものが継続できなくなる可能性もある。実際に海外では、セキュリティ事故をきっかけに会社が倒産した事例も少なくない。

発注者側は「どの決済代行会社を使うか」を選定する時点で、その会社がPCI DSSに準拠しているかどうかを必ず確認すべきだ。見積金額や手数料だけを基準に選ぶと、後から大きなリスクを背負うことになる。

https://www.meti.go.jp/policy/economy/consumer/credit/index.html
https://www.pcisecuritystandards.org/

犯罪収益移転防止法(AML/KYC)

AML/KYCコンプライアンスサイクル
AML/KYCコンプライアンスサイクル

もう一つ避けて通れないのが犯罪収益移転防止法だ。送金やウォレットのように「人から人へお金を動かす機能」を持つと、マネーロンダリング防止のために**本人確認(KYC)**が義務化される。

具体的には、年間100万円を超える送金を扱う場合、eKYC(オンライン本人確認)の導入が義務付けられる。これは顔写真付きの身分証をスマホで撮影させ、顔認証と突き合わせる方式が一般的だ。最近では外部KYCベンダーが提供するAPIを利用するケースが多く、開発者はそのAPIをどう組み込むか、失敗時のリカバリをどう設計するかを考える必要がある。

ここで厄介なのは「サービスがどこまで資金移動業に該当するか」の線引きだ。例えば「自社内のポイントを別ユーザーに譲渡できる」仕組みを入れるだけで資金移動業者とみなされる可能性がある。資金移動業者として登録するには、最低資本金1,000万円、供託義務、定期的な監査対応など重い要件を満たす必要がある。スタートアップが軽い気持ちで「残高を送れるようにしたい」と実装すると、一気に法規制の沼にハマる。

無登録営業が発覚すると、金融庁からの業務停止命令だけでなく、刑事罰の対象になる。開発者としては、仕様を鵜呑みにせず「これは資金移動業に当たらないか」を常にチェックし、疑わしい場合は専門家に相談する必要がある。

https://www.fsa.go.jp/news/r6/sonota/20250625/20250625.html

2. DB設計の注意点

取引履歴は更新ではなく追記

取引履歴管理プロセス
取引履歴管理プロセス

決済システムにおいてDB設計は単なるデータ格納の問題ではなく、「お金の流れをどう記録し、どう追跡するか」を左右する最重要ポイントになる。ECサイトの商品DBのように「とりあえず更新できればいい」では済まない。履歴の正確さや改ざん防止が担保できなければ、ユーザーからのクレームや監査対応で一気に詰む。

まず大前提として、取引履歴は更新ではなく追記で管理することが基本になる。たとえば transactions テーブルには「最新の状態」を1レコードで保持しつつ、別に transaction_logs テーブルを作り、状態の遷移(pending → succeeded → refunded など)を時系列で残す。これをやらずに「取引テーブルのステータスを更新するだけ」にすると、後から「この取引は一度成功してからキャンセルされたのか? それとも最初から失敗だったのか?」といった問いに答えられなくなる。金融監査では必ず過去の履歴を遡られるので、追記方式での履歴管理は必須だ。

整合性と二重決済防止

決済システムの整合性と二重決済をどのように確保するか?
決済システムの整合性と二重決済をどのように確保するか

次に重要なのが整合性と二重決済の防止。APIの世界では、同じリクエストが複数回飛んでくるのは当たり前に起こる。ユーザーが決済完了画面をリロードしただけでも、バックエンドにとっては「もう一度課金してほしいリクエスト」に見えることがある。そのため、DBには transaction_id にユニーク制約を設け、アプリケーションレベルでは Idempotency-Key を使って同じ処理を1回しか通さない仕組みを作る必要がある。これを入れていないと、ユーザーに二重請求をしてしまい、返金作業でオペレーションが崩壊する。StripeやPayPalが必ず冪等性キーを推奨しているのは、このトラブルがいかに頻発するかを示している。

さらに考慮すべきは削除方針だ。金融データを物理削除するのは基本的にNG。少なくとも7年程度は保存するのが会計・税務的に求められることが多い。そのため「論理削除(削除フラグ)」で管理し、物理的に消さずに残す方が無難だ。監査が入ったときに「過去のデータが一切残っていない」という状態は絶対に避けたい。

もう一つ地味に効いてくるのが整合性レベルの設計だ。外部キーを厳密に設定しすぎると、障害時に復旧が難しくなるケースがある。決済システムでは「データの一部が欠けている状態」でとりあえず記録し、後からリカバリする方が現実的なことも多い。そのため、アプリケーションレベルで整合性を担保し、DBにはある程度の柔軟性を持たせる設計が好まれる。

最後に監査ログとの関係も忘れてはいけない。アプリケーションのログとDBのトランザクション履歴が一致しているかどうかを確認できるようにしておくこと。たとえば「ユーザーAが10:32に支払いを試み、結果は失敗した」という事実がDBとログの両方で追跡できることが求められる。監査の現場では「システムログとDBの履歴を照合させて矛盾がないか」を見られるので、ここが崩れていると信用を失う。

要するに、決済システムのDBは「最新状態を保持するテーブル」「全履歴を残すテーブル」「監査と照合できるログ」の三層で構成するのが理想だ。発注者にとっては「監査に耐える履歴が残る仕組み」が重要であり、開発者にとっては「二重決済を防ぐ整合性設計」と「監査で突っ込まれない保存方針」が生命線になる。ここを軽視すると、後から必ず大きなツケを払うことになる。

https://stripe.com/docs/idempotency

3. インフラ構成の注意点

冗長化

決済が数分止まるだけで売上に直結する。例えばECサイトでは、たった数分の障害で数百万円規模の売上が吹き飛ぶこともある。一般的なWebサービスなら「アクセスできないので後で使おう」と済むことも、決済では「買えなかったから別のサービスに行く」につながる。だからこそ冗長化は必須だ。

インフラをAWSで組むなら、マルチAZ構成は前提条件。アプリケーションサーバーもDBも、単一のAZに閉じ込めるとAZ障害がそのままサービス停止につながる。DBについてはフェイルオーバー対応を必ず入れる。Auroraのように自動で切り替えられる仕組みを選ぶか、RDS Multi-AZでプライマリ障害に備える。

また、キャッシュサーバーも冗長化しておく必要がある。RedisやMemcachedを1台だけで運用すると、そのノードが落ちた瞬間にアプリ全体が遅延する。決済のトラフィックは集中する時間帯があるので、スパイクに耐えられるようクラスタリングやリードレプリカ構成を考えておくべきだ。

さらに忘れがちなのはネットワーク。インターネットゲートウェイやNATゲートウェイもシングルAZに置くと、そこで詰まる。可用性を確保するなら各AZに分散配置して、ルーティングを組むのが基本だ。

冗長化をきちんと設計すれば、AZ障害が起きても「ユーザーから見て気付かれない」レベルで切り替えができる。逆にこれを怠ると、たった一度の障害で「このサービスは信用できない」と烙印を押される。

ログの保存

ログをどのように保存し管理するか?
ログをどのように保存し管理するか

冗長化と並んで重要なのが「ログを残すこと」。不正アクセスや二重請求、システム障害が起きたとき、ログがなければ証拠を示せない。ユーザーから「二重決済された」と言われたときに、DBの状態だけでは不十分で、APIリクエストや内部処理のログを突き合わせて「どの段階で何が起きたか」を説明できなければならない。

ログは単に保存するだけでは意味がない。改ざんできない形で残す必要がある。AWSなら S3 + Object Lock を使うと、書き込んだログを変更不可にできる。監査対応を想定すると、これは必須に近い。セキュリティ事故の調査では「本当にそのログが当時のままなのか?」が問われるからだ。

また、保存期間も考えなければならない。税務や会計監査を意識すると、最低7年間はログを保持するケースが多い。決済サービスでは、5年後に「当時の取引を確認させてほしい」と言われることは普通にある。ストレージコストを理由に短期保存にしてしまうと、いざ必要なときに「証跡がない」という最悪の状況になる。

さらに、ログをどう検索できる状態にするかも設計に含めるべきだ。単なるS3保存では探し出せないので、Athenaでクエリできるようにしたり、CloudWatch LogsやElasticsearchで一定期間は検索可能にしておくと運用が楽になる。

ログを正しく残していれば、訴訟や監査でも「この時刻にこのリクエストが来て、こう処理され、結果がこうなった」という一貫した説明ができる。逆にログがなければ、全てがサービス側の過失扱いになる。

https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html
https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html

4. API開発の注意点

API開発の注意点
API開発の注意点

決済システムにおけるAPIは、外部と直接やり取りする最前線になる。ユーザーや加盟店からのリクエストが最初に通る場所だから、ここが甘いと一気に不正利用や二重決済につながる。インフラやDBがどれだけ堅牢でも、APIの設計がずさんならすべてが台無しになる。

認証・認可の設計

API開発でまず重要なのが認証と認可の分離だ。多くのシステムでありがちなミスは「APIキー1つですべての操作ができる」状態にしてしまうこと。これでは万一キーが流出した際に全機能が不正利用される。理想は権限を分けること。たとえば「読み取り専用キー」と「書き込み可能キー」を分ける。加盟店が残高参照だけしたい場合に、誤って返金処理までできるキーを渡すべきではない。

さらにセキュリティを強化するなら、OAuth2.0やJWTのようなトークンベースの仕組みを導入する。これによりアクセス権限を細かく制御でき、トークンに有効期限を持たせることで流出リスクも抑えられる。セッションの無期限化やトークンの長期利用は禁物で、短期トークン+リフレッシュ方式を基本にする。

シークレット管理

決済代行会社から渡されるAPIキーやシークレットをソースコードに直書きするのは論外だ。GitHubに誤ってコミットされれば、その瞬間から攻撃者に抜かれてしまう。必ずSecrets ManagerやVaultのような専用サービスに格納し、アプリからは動的に参照する形を取るべきだ。環境変数にすらベタ書きせず、権限の分離と暗号化を徹底する。

冪等性の担保

決済APIで特に重要なのが冪等性だ。ユーザーの画面がフリーズして「決済できたか不安だからもう一度ボタンを押す」という状況は日常的に起きる。もしそのたびに新しい取引として処理すれば、ユーザーは二重請求を受けることになる。

これを防ぐには、クライアントからリクエストを送る際にIdempotency-Keyをヘッダに付けさせ、サーバー側では同じキーを持つリクエストは1回しか処理しない仕組みを作る。DBでも transaction_id にユニーク制約を設けて「同じ取引は1つまで」と保証する。こうした仕組みがないと、リクエスト再送で事故が起こるのは時間の問題だ。StripeやSquareがこの方式を採用しているのは、決済の世界では冪等性が必須だからだ。

エラーハンドリングとリトライ

APIは常に外部ネットワークを経由するため、通信エラーやタイムアウトは避けられない。そのためリトライ戦略をどう設計するかが重要になる。単純な即時リトライではスパイク的にリクエストが殺到してシステムを落とす原因になる。指数バックオフやジッタを入れてリトライのタイミングを分散させるべきだ。

加えて、レスポンスには明確なステータスコードとエラーメッセージを返す。開発者にとって「200なのに失敗している」「500だけ返ってくる」では調査に膨大な時間がかかる。クライアントが正しくリカバリできるように、エラーの種類(認証失敗、残高不足、システム障害など)を判別できるレスポンス設計にしておくことが求められる。

監査と可観測性

APIは取引の入り口なので、誰がいつどのリクエストを送ったかを監査ログとして必ず残す必要がある。API GatewayやWAFログをS3に保存し、改ざんできない形にする。さらにPrometheusやCloudWatchなどを用いて、エラー率やレスポンスタイムをモニタリングし、異常を早期に検知する。

https://docs.aws.amazon.com/secretsmanager/
https://oauth.net/2/
https://jwt.io/

5. 発注者が意識すべきリスク回避

決済システムの開発を発注する立場では、「使いやすいUIにしたい」「導入コストを抑えたい」といった観点に目が行きがちだが、実際に重要なのは法律に抵触しないことと障害時の対応をどうするかだ。これを軽視すると、サービスリリース後に行政処分や炎上に直結する。

ライセンス要否の確認

最初に押さえるべきは、自社の仕組みが「資金移動業」や「前払式支払手段発行者」に該当するかどうかだ。例えば「ユーザーにチャージさせて残高を保持する」時点で、ほとんどの場合は資金決済法の適用を受ける。発行残高が1,000万円を超えると金融庁への届出義務、1億円を超えると供託義務が発生する。さらに「ユーザー間で残高を送れる仕組み」を入れると資金移動業者としての登録が必要になる。登録には最低資本金1,000万円以上や供託金、監査対応など重い要件が課される。

発注者がよくやりがちな失敗は「小規模だから大丈夫だろう」と考えてしまうこと。残高や利用者数は事業が伸びれば一気に膨らむ。サービスが好調に成長してから法的要件に気づいても、手遅れになるケースが多い。発注時点で「自社が残高を持つのか、それとも代行会社を使って残高を持たないのか」を明確にしておくことが重要になる。もし無登録のままサービスを続ければ、**刑事罰(懲役3年以下または300万円以下の罰金)**の対象になる。

障害対応体制

障害対応体制の重要性
障害対応体制の重要性

もう一つ重要なのが障害時の体制だ。決済システムでは必ず「決済済みなのに反映されていない」という問い合わせが発生する。これはユーザーからすると「お金を取られただけでサービスが使えない」状態であり、最も不満が爆発しやすい。こうしたケースに備えて、返金までのリードタイムをあらかじめ決め、利用規約やFAQに明記しておく必要がある。

さらに、開発ベンダーとの契約にも注意が必要だ。障害が起きたときに「監査ログを提供してもらえるのか」「復旧作業は誰の責任範囲か」を契約段階で詰めておかないと、いざトラブルが発生したときに「これは開発側の責任ではない」と言われて対応が止まる。監査対応や返金処理を発注者だけで背負うと、サポートコストと信用失墜で事業継続が危うくなる。

まとめ

決済システムは「正常に動いて当たり前」と思われがちだが、その裏側では法律、DB設計、インフラ、API、そして発注者側の体制まで、細かい要素が噛み合って初めて安全に回る。資金決済法や割販法、AMLといった法律は単なる縛りではなく、利用者のお金と信頼を守るための仕組みだ。DBは追記型で履歴を残し、二重決済を防ぐ設計が必須になる。インフラは冗長化とWORMログで「止めない・改ざんさせない」を実現する。APIは冪等性と権限分離で、不正利用や事故を防ぐ。さらに発注者は、ライセンス要否や障害対応体制を事前に固めておかないと、成長後に大きな落とし穴にハマる。

つまり決済システムは、派手さの裏にある「地味で当たり前の対策」をどれだけ徹底できるかで寿命が決まる。サービスを伸ばすなら、UIや機能以上にこの基盤部分を丁寧に作り込むことが、結局はユーザーの信頼を最も強く支える。

Discussion