UPSIDER Tech Blog

決済を止めないために。バーチャルカードの有効期限を自動更新する仕組み

はじめに

はじめまして。UPSIDER でクレジットカードの決済処理を担う Processor チームのバックエンド開発を担当している Tomohiro Saito です。

普段カードを使うなかで、利用者が有効期限を強く意識する機会は多くありません。一方、カード発行会社にとって、期限切れを迎えるカードを安全に更新し、決済を継続できる状態を保つことは欠かせません。

オンライン決済で使われるバーチャルカードでは、物理カードのような郵送が不要です。しかし、カードの再発行や新旧カードの切り替え、加盟店に登録したカード情報の更新案内など、システムとユーザー体験の両面から設計すべき課題があります。

この記事では、UPSIDER が開発した バーチャルカードの有効期限切れに伴う自動再発行機能について、次の3つの観点から紹介します。

  • 利用者から見て何が変わるのか
  • 「有効期限を更新する」裏側で、システムが何をしているのか
  • Processor チームがどの領域を担当したのか

決済ドメインに詳しくない方にも伝わるよう、社内固有のサービス名や細かな仕様はできるだけ一般的な言葉に置き換えています。

この記事の要点

先に全体像をまとめると、今回実現したのは次の仕組みです。

  1. 有効期限が近いバーチャルカードを定期処理で抽出する
  2. カード番号と名義を維持しつつ、有効期限とセキュリティコードが新しいカードを発行する
  3. 新カードをシステム側で有効化する
  4. 旧カードは新カード発行後も元の有効期限まで利用可能にし、急な決済停止を避ける
  5. カード詳細画面のバナーを通じて、利用者へ更新を知らせる

バーチャルカード自動再発行の全体の流れ

そもそも「カードの再発行」とは

クレジットカードには有効期限があります。有効期限を迎えるカードをそのままにすると、そのカード情報を使った決済はできなくなります。そのためカード発行会社は、期限が切れる前に新しいカードを用意する必要があります。

今回のバーチャルカード再発行では、利用者が使い慣れたカード番号と名義は維持しながら、次の情報を更新します。

維持する情報 更新する情報
カード番号 有効期限
カード名義 セキュリティコード(CVV)

ここで重要なのは、データベース上の有効期限を書き換えるだけではないという点です。システム内部では、旧カードとは別の「新しい世代のカード」として発行し、一定期間は新旧どちらのカードも扱えるようにします。

この併存期間があることで、新カードの発行直後に旧カードが使えなくなることを避け、急な決済停止を防ぎやすくなります。

利用者から見た変化

利用者から見た変化は、大きく「決済面」と「表示面」の2つに分けられます。

  • 決済面:新カードの発行後も、旧カードの有効期限内であればそのまま決済に利用できます。
  • 表示面:カード詳細画面のバナーで、カードが更新されたことと新しい有効期限を確認するよう案内します。

新カードを発行しても、利用者がその変化に気づけなければ、加盟店に登録したカード情報の更新が遅れてしまいます。そこで、システム内部での再発行に加え、カード詳細画面のバナーで更新を案内する仕組みを用意しました。

カード詳細画面で更新を知らせる

再発行されたカードの詳細画面には、カードが更新されたことを伝えるバナーを表示します。

バナー表示

この機能のゴールは、単に新しいカードデータを作ることではありません。決済が止まる前に、利用者が必要な情報へ迷わずたどり着ける状態をつくることです。

システム全体の構成

社内の細かなサービス名を省き、役割単位で表すと次の構成になります。

システム全体の構成

大きく分けると、Processor チームの対応は次の5点です。

  1. 新旧カードを区別して管理できるデータモデルの整備
  2. 既存カードデータを上記の新しいデータモデルへ反映するためのバックフィル
  3. 対象カードを発行・有効化する月次バッチの新規開発
  4. 新旧カードの併存期間を成立させる決済判定ロジックの変更
  5. 画面表示に必要な再発行情報を提供する API の整備

以下、それぞれを説明します。

1. 「カード番号」ではなく「カードの世代」を管理する

今回の再発行ではカード番号を維持します。しかし、カード番号が同じでも、旧カードと新カードでは有効期限やセキュリティコードが異なります。

そこでシステム内部では、カード番号とは別に「カードの世代」を識別できる単位を持たせています。これにより、同じカード番号に対して複数世代のカードが存在しても、次の状態を区別できます。

  • 現在利用できる最新のカードはどれか
  • どのカードが再発行によって作られたものか
  • 旧カードの有効期限はいつか
  • 画面で、どのカードを更新済みとして案内するか

カード世代の管理

このモデルを導入したことで、カード番号を中心に考えるだけでは表現できなかった「新旧カードの併存」を扱えるようになりました。

2. 稼働中のカードを新しいデータモデルへ移す

新しいデータモデルを導入するだけでは、それ以前に発行されたカードを正しく扱えません。そこで、既存データを新しいデータモデルへ移行する バックフィル処理を用意しました。既存システムからカード情報と有効化状態を取得し、新しいテーブルへ反映する処理です。

今回は Kubernetes Job として実装し、既存システムの API を通じて次の情報を補完しました。

  • 既存カードに対応するカード世代のレコード
  • 各カードの有効期限
  • 現在有効なカードであることを示す状態

このとき重要なのは、移行処理が途中で失敗しても再実行できることと、反映済みのデータを壊さないことです。稼働中の決済基盤へデータモデルを追加するため、通常の決済処理に影響を与えず、段階的に移行できる構成にしました。

3. 毎月、新カードを発行・有効化する

この機能の中心となるのが、月次で動く再発行バッチです。バッチでは、次の処理を順番に実行します。

  1. 次に有効期限を迎えるバーチャルカードを抽出する
  2. 再発行の対象外となる状態を除外する
  3. 新しい有効期限とセキュリティコードを持つカードを発行する
  4. 発行したカードをシステム側で有効化する
  5. 新しいカード世代の情報を保存する
  6. 結果を記録し、異常があれば通知する

バーチャルカード自動再発行の流れ

定期処理で重視したこと

決済基盤のバッチでは、正常に完了することだけでなく、途中で止まった場合にどう復旧するかまで先に考える必要があります。

  • 冪等性:同じ処理を再実行しても、カードが重複発行されないこと
  • 部分失敗への対応:一部のカードで失敗しても、原因と対象を追跡できること
  • 処理量の増加への備え:対象カードが増えても、決められた時間内に処理できること
  • 可観測性:対象件数、成功件数、スキップ件数、失敗件数、処理時間を確認できること
  • 手動リカバリー:異常時に対象を確認し、安全に再実行できること

初回の件数だけに合わせるのではなく、将来のカード増加を前提に性能を検証し、監視とリカバリーの運用も同時に設計しました。

4. 新カードを作っても、旧カードをすぐ無効にしない

実装上の重要なポイントは、新旧カードを一定期間併存させることです。

新カードを発行した直後に旧カードを無効化すると、加盟店の登録情報を変更する前に決済の失敗を招くおそれがあります。そこで、旧カードは元の有効期限まで利用可能とし、その間に新カードへ移行できるようにしました。

既存の決済判定は「最新のカード世代であるか」を重視していたため、そのままでは新カード発行後に旧カードの決済を拒否してしまいます。今回、バーチャルカードの再発行に限り、次の条件を満たす旧カードを正しく扱えるよう判定ロジックを変更しました。

  • 正規の再発行によって新カードが作られている
  • 旧カードがまだ有効期限内である
  • カード自体が利用可能な状態である

一方で、有効期限を過ぎた旧カードは拒否しなければなりません。つまり「新カードがあるか」だけではなく、カードの世代、有効期限、状態を組み合わせて判断しています

5. 画面へ、必要最小限の情報を渡す

カード詳細画面のバナーを実現するためには、「このカードは自動再発行されたカードか」「旧カードの有効期限はいつか」といった情報が必要です。

そこで Processor 側へ参照 API を設け、画面向け API が必要なときだけ取得できる形にしました。

API のインターフェースは、カードの内部データをそのまま公開するのではなく、利用側が必要とする情報だけに絞りました。これにより、カード発行ロジックの詳細を UI 側から隠しつつ、チーム間の責務を明確に分離できます。

リリース後まで含めて機能をつくる

決済基盤では、コードを本番へ反映した時点がゴールではありません。今回も次の準備を進めました。

  • バッチの実行結果を確認する監視項目の整備
  • 失敗時のアラートと原因調査方法の整理
  • 部分失敗・全体失敗それぞれの再実行手順
  • 初回実行時の確認体制
  • カード更新を希望しない場合など、例外ケースの運用整理
  • CS を含む関係チームへの周知

開発者自身が運用や障害対応にも関わるため、実装の段階から「失敗したときに、誰が、何を確認し、どう復旧するか」まで設計します。実装から運用・障害対応までを一気通貫で担うのが、Processor チームの特徴です。

開発を通じて感じた、決済基盤づくりの面白さ

一見すると「有効期限を新しくする」というシンプルな機能ですが、実際には次の課題が含まれていました。

  • 同じカード番号に複数世代のカードが存在するデータモデル
  • 新旧カードを安全に併存させる決済判定
  • 稼働中データを止めずに移行するバックフィル
  • 将来の処理量を見据えた定期バッチ
  • UI を担当するチームとの API 設計
  • 障害時の再実行まで含む運用設計

Processor チームの開発では、単に API やバッチを実装するだけではなく、利用者の決済体験から逆算して、データ、決済判定、性能、監視、運用まで一貫して考えることが求められます。

今回、私はデータモデル、API、既存データのバックフィル、月次バッチ、決済判定、運用整備まで、複数の工程に関わりました。ひとつの機能が利用者へ届くまでの全体像を見渡しながら、異なる専門性を持つチームと協力して開発できることは、この仕事の面白さのひとつです。

おわりに

この記事では、バーチャルカードの有効期限切れに対応する自動再発行機能を題材に、Processor チームの開発内容を紹介しました。

利用者から見ると、カード決済はわずか数秒で終わる体験です。しかし、その裏側では、カードの状態管理、決済可否の判定、データの整合性、定期処理、監視、画面上の案内など、多くの仕組みが連携して動いています。

We Are Hiring

UPSIDER の Processor チームでは、こうしたミッションクリティカルな決済基盤を開発しています。

  • ユーザー体験とシステム設計をつなげて考えたい方
  • 正確性と可用性が求められる分散システムに興味がある方
  • 機能開発だけでなく、データ移行、性能、監視、運用までオーナーシップを持ちたい方
  • 複数チームと協力し、プロダクト全体を通した開発をしたい方

このような開発に興味を持っていただけた方は、ぜひ UPSIDER のエンジニアリングや採用情報をご覧ください。

herp.careers

herp.careers

UPSIDER Engineering Deck はこちら📣

speakerdeck.com