はじめに
決済フォームでfincodeの3DS認証を実装していたところ、
都度決済とサブスク登録が実行されるはずが都度決済のみ完了しサブスク登録が実行されないという事象が発生しました。
本記事ではその調査過程と対応策をまとめます。
こんな方におすすめ
- fincodeでこれから実装を考えている人
- fincodeで1度の決済で都度決済とサブスク決済の実装を考えている人
- fincodeで3DS認証を実装していて、コールバックが来ない事象が発生した人
環境
- PHP(7.4.33)
- fincode
構成・処理の流れ
- redirect_url(3DS認証の画面)をフロントに返してexitする
- フロント側で3DS認証画面が表示される
- ユーザーが3DS認証後、return_urlで指定したファイル(今回はPHP)にリダイレクト
- サブスク登録処理が行われる
- 完了画面が表示される
発生した事象
以下は事象発生時のログです。
本来であれば「3DS認証リダイレクト処理」のログの後に「コールバック処理」⇒「サブスク登録」…という流れになるはずです。
他の顧客では発生しない事象でした。
[2026-06-10 00:00:00] 決済実行APIリクエスト
[2026-06-10 00:00:00] 決済実行APIパラメータ{…"customer_id":”✖✖”…}
[2026-06-10 00:00:00]決済実行レスポンス(200): {…"status":"AUTHENTICATED",…,"return_url":"https:”〇〇”,…"redirect_url":"https:□□"…}
[2026-06-10 00:00:00] 3DS認証リダイレクト処理
←ここ以降のログなし
調査過程
-
ログの確認
「発生した事象」に掲載したログを確認したところ、3DS認証リダイレクト処理の後にコールバック処理のログが一切出力されていませんでした。つまり3DS認証後にこちら側のサーバーへの戻りが発生していないことが分かりました。 -
fincode管理画面のステータス確認
この顧客の決済状況をfincode管理画面で確認したところ、以下のステータスが確認できました。- 決済ステータス:売上確定
- 3DS2.0 処理ステータス:AUTHENTICATED
fincodeのドキュメントによるとstatusが売上確定であれば決済完了、tds2_statusがAUTHENTICATEDであれば3DS認証完了を意味することから、ユーザーは3DS認証および決済を完了していたことがわかります。
-
fincodeへの問い合わせ
手元で調べるには1、2までが限界であったため問い合わせを行い以下の回答をいただきました。お問合せの件、恐れ入りますが弊社でも確認できかねます。 リダイレクト時、遷移途中に画面を閉じられた場合や 戻るボタン等の操作があり、正常にリダイレクトが完了されなかった可能性がございます。
原因
「構成・処理の流れ」・「調査過程」セクションの内容と実装から、今回の事象の原因は同期通信による実装にあると考えられます。
// redirect_url(3DS認証画面のURL)が存在する場合
if (!empty($redirectUrl)) {
write_log("3DS認証リダイレクト処理");
echo json_encode([
'success' => true,
'redirect_url' => $redirectUrl,
]);
exit;
}
//フロントの処理へ続く
このコードはreturn_urlをフロントに返して処理を終了しており、サブスク登録はコールバック側に実装されているため
3の「fincodeがreturn_urlにリダイレクトする」という処理を必ず経由しないとサブスク登録が実行されない同期的な構造になっています。
そのため今回のようにリダイレクトが何らかの理由で失敗した場合、それ以降の処理が実行されないという問題が発生しました。
解決策
解決策としてはWebhookを使いリアルタイムで通知を受け取れるようにします。
そもそもWebhookとは何でしょうか?
Webhookは、特定のイベントが発生した際に、事前に設定された他のアプリケーションに通知を自動的に送信する仕組みで「Webコールバック」や「HTTPプッシュAPI」と呼ばれることもあります。
引用元:https://blastengine.jp/blog_content/webhook/
イベントが発生するとリアルタイムで通知を受け取れるとても便利な仕組みです。
Webhookを使うと何が違うのか?を整理すると
- 今回:return_urlにリダイレクトしないとその後の処理は進まない。
- Webhook:ブラウザのreturn_urlのリダイレクトの可否に関係なく、fincodeから直接エンドポイントにPOSTリクエストを送ってくれる
これによりクライアント側の処理とサーバー側の処理が切り離された非同期通信になるため、クライアント側の処理に依存しません。
実装方針
以下のように実装する方針です。
今まで通りの処理と並行してWebhookの処理を追加します。
- Webhookエンドポイント追加
- PHPファイルにWebhookを受け取る処理を追加しfincode管理画面に登録
- イベント判定
- POSTリクエストのstatus(決済ステータス)とevent(Webhook通知 トリガーイベント)の値から、決済が完了していればサブスク登録を実行
- 二重登録防止
- return_urlとWebhookの両方からサブスク登録される可能性もあるため、fincodeのサブスク一覧取得APIで登録済かを確認する
まとめ
長々と書いてきましたが、今回の事象を通じて以下のことを学びました。
- 非同期通信の重要性
- 決済処理のようにユーザーの操作が絡む処理では、クライアント側の処理に依存した同期通信だと意図せず処理が中断されるリスクがある。そのためWebhookを使った非同期通信にすることで確実に処理を実行することができます。
- ログ出力の重要性
- 各処理にログを出力しておくことで、問題発生時にどこまで処理が進んでいてどこから進んでいないかを迅速に特定できます。今回もログがなければ調査に大幅な時間がかかっていたと思います。
参考:https://docs.fincode.jp/api#tag/Webhook_/operation/receiveWebhookOfCardPayment
https://docs.fincode.jp/tutorial/prod_webhook