V-REC Webhook 通知・送信タイミング仕様
会員登録、KYC、テナント資金割当・組戻しと、MatchMove 3Dセキュアをそれぞれの責任範囲で説明します。
1. 誰が何を通知するのか
V-REC → 加盟店:加盟店が設定したHTTPS Webhook URLに、署名付きの非同期業務イベントを送信します。
SAKURA → V-REC:KYC更新を署名付きで通知し、V-RECがSAKURAから最新の正式な状態を再取得します。
V-REC → パートナー:Payoutのライフサイクルを別のパートナーWebhook経路で通知します。
MatchMove → カード会員・決済画面:発行会社側の3Dセキュア認証。加盟店向けV-REC Webhookとは別の経路です。
2. イベント名と通知される状態
| 加盟店向けイベント | 発火条件 | 送信する状態 |
|---|---|---|
user.registered | 加盟店API・管理画面・一般会員登録・既存ユーザーの同意確定時 | membership_status(通常 ACTIVE)、access_mode(FULL / READONLY)、kyc_status の処理時点の値 |
user.kyc.updated | SAKURAからの通知処理後、現在のKYC状態を再取得 | NOT_STARTED, PENDING, REVIEW, CORRECTION_REQUIRED, APPROVED, REJECTED |
tenant.funding.allocation.updated | 直接資金割当の結果が保存された時 | COMPLETED, REJECTED, FAILED, UNKNOWN, RECONCILE_REQUIRED, MISMATCH |
tenant.funding.return.updated | 組戻し・返還処理の結果が確定した時 | COMPLETED, FAILED, RECONCILE_REQUIRED |
webhook.test | 加盟店画面でテスト送信を操作した時 | 接続確認専用 |
イベントには共通フィールド id, type, occurred_at およびイベント別データ data が含まれます。statusなどのフィールド値はプログラム上の値であり、大文字・小文字を含め翻訳せずに処理してください。V-RECから加盟店への3DS Webhookは現状ありません。
3. 会員登録APIとWebhookの関係
GET /api/merchant/v1/profile-options
POST /api/merchant/v1/users + HMAC + Idempotency-Key
→ SAKURAで本人情報を登録・既存情報を照合
→ V-REC会員所属・ログイン情報を保存
→ 該当時にV-REC / SAKURAの案内メールを送信
→ user.registered を加盟店の送信待ちキューに登録
← HTTP 201 { user, notifications, activation_url(該当時) }
次の定期実行 → 加盟店のHTTPS通知先にPOST
加盟店 → GET /api/merchant/v1/users/{id} で状態を再確認
HTTP 201はAPIの同期応答です。一方、 user.registered は非同期通知で、加盟店・ユーザー単位で重複登録を抑止します。通常の公開会員登録には加盟店向けPOST/201はありません。既存会員の同意リンクは、リンクを発行した時点ではなく、本人が同意を確定した時点で通知されます。会員登録の完了はKYC承認を意味しません。パスワード設定用URLはWebhookに含まれません。
4. テナント資金割当APIとWebhookの関係
GET /api/merchant/v1/tenant-funding/balance
GET /api/merchant/v1/tenant-funding/users/{id}/capacity
POST /api/merchant/v1/tenant-funding/allocations
+ Idempotency-Key + tenant_funding.write
→ ACTIVE / FULL / KYC APPROVED、同一Merchantか確認
→ SAKURAでテナント管理・/fund 処理を確認
→ COMPLETED の時は有効期限付きのV-REC資金ロットを記録
→ tenant.funding.allocation.updated をキュー登録
← HTTP 201 COMPLETED
← HTTP 409 REJECTED(残高不足など。資金は動いていない・確定)
← HTTP 202 UNKNOWN 等(同じIdempotency-Keyで再送して確定させる)
GET /api/merchant/v1/tenant-funding/allocations?updated_since=…(Cronで一覧取得)
GET /api/merchant/v1/tenant-funding/allocations/{id}
POST /api/merchant/v1/tenant-funding/allocations/{id}/reverse
POST /api/merchant/v1/tenant-funding/users/{id}/return
→ tenant.funding.return.updated
直接資金割当が残高へ反映されたと確認できる状態は COMPLETED のみです。 UNKNOWN, RECONCILE_REQUIRED, MISMATCH は利用可能残高と見なさないでください。REJECTED は資金が動いていない確定状態で、同じIdempotency-Keyで再送しても結果は変わりません(条件を見直して新しいキーで実行してください)。Webhookを受け取れない場合は GET /api/merchant/v1/tenant-funding/allocations?updated_since=… で一覧取得できます。結果が不明の場合は同一Idempotency-Keyを使って照合し、新しい送金を安易に再実行しないでください。テナント残高と元ロットの有効期限(180日ルール適用の可能性を含む)はSAKURA側が正です。READONLY所属は資金割当を実行できず、MatchMove上のユーザー間送金も行いません。
パートナー向け payout.credited は別経路の通知です。直接資金割当のWebhookの代わりにはなりません。
5. KYC状態の通知
MatchMove / SAKURA でKYC状態が変化
→ SAKURAから署名付き通知 → V-REC
→ V-RECがSAKURAの最新状態を再取得
→ V-RECが user.kyc.updated をキュー登録
→ 加盟店がGET /api/merchant/v1/users/{id}/kyc で再確認
Webhookは更新を知るための通知です。最新状態の確認にはGET APIを使用してください。重複または遅延したプロバイダー通知によって、より新しいKYC状態を上書きしないでください。
6. V-RECはいつ通知を送るか
対象処理の結果が保存されると、イベントが配信キューへ登録されます。送信ワーカー gateway/bin/deliver-merchant-webhooks.php は1分ごとに実行する必要があります。初回送信は次のワーカー起動時であり、何秒後といった厳密な時刻は保証されません。イベント発生前にHTTPS URLとシークレットが設定されている必要があります。設定前のイベントは自動的には過去にさかのぼって配信されません。
配信状態: PENDING → SENDING → DELIVERED(HTTP 2xx)、失敗すると RETRY、最大8回の試行後に FAILED となります。再送間隔は1回目から順に60秒、5分、30分、2時間、6時間、12時間、24時間で、ワーカー実行時刻による遅れが加わります。加盟店管理画面の「加盟店API → Webhook配信履歴」で確認できます。受信側はイベントIDで重複排除し、少なくとも1回の配信を前提に実装してください。
7. 署名付き通知の検証
X-VREC-Event: user.registered
X-VREC-Delivery: mwd_...
X-VREC-Timestamp: 1791532800
X-VREC-Signature: lowercase hex HMAC-SHA256
body_hash = hex(SHA256(raw_body))
message = timestamp + "\n" + delivery + "\n" + event + "\n" + body_hash
signature = hex(HMAC-SHA256(message, MerchantWebhookSecret))
受信したraw bodyを変更せずに署名を計算してください。定数時間比較、リプレイ防止期間、冪等な処理を実装してください。Webhook Secretは加盟店APIの認証シークレットとは別です。パートナーWebhookはDelivery IDを含まない別の署名仕様です。
7b. Partner Webhook(Corporate Payout)
V-REC管理者がPartner設定に登録したWebhook URL(HTTPS)へ、Payoutの作成と入金完了を通知します。加盟店Webhookとは別の署名仕様で、Delivery IDとイベントIDはありません。
X-VREC-Event: payout.created | payout.credited
X-VREC-Timestamp: 1792540800
X-VREC-Signature: lowercase hex HMAC-SHA256
body_hash = hex(SHA256(raw_body))
message = timestamp + "\n" + event + "\n" + body_hash
signature = hex(HMAC-SHA256(message, PartnerWebhookSecret))
{
"event_version": "1.0",
"payout": {
"id": "po_...", "beneficiary_id": "VREC-...",
"amount": "100.00000000", "currency": "USD",
"external_reference": "INVOICE-2026-10-001", "purpose": "corporate_payout",
"funding_mode": "MERCHANT_BALANCE",
"source_asset": "MATCHMOVEUSD", "destination_asset": "MATCHMOVEUSD",
"status": "PENDING_FUNDS", "underlying_fund_confirmed": false,
"created_at": "2026-10-21 01:00:00", "credited_at": null
}
}
- 送信されるイベントは payout.created と payout.credited の2種類だけです。取消、RETRYABLE、RECONCILE_REQUIRED、承認待ちは通知されません。状態はGET /api/v1/payouts/{id} で確認してください。
- 各イベントはPayoutごとに1回だけ発生します。再送時もbodyは同一(タイムスタンプと署名のみ変化)のため、X-VREC-Event と payout.id の組で重複排除してください。
- 過去のLEGACY_REFERENCE PayoutがTenant Fundingで入金された場合の payout.credited は、payout に id / status / amount / currency だけを含む短い形式です。
- HTTP 2xx以外は再送します。再送間隔は60秒、5分、30分、2時間、6時間、12時間、24時間で、最大8回の試行後に停止します。タイムスタンプは受信時刻と比較し、古すぎる通知は拒否してください。
8. MatchMove 3Dセキュア:発行会社側の認証フロー
カード会員 → オンライン決済画面/アクワイアラ
→ カードネットワーク → MatchMove発行会社/ACS
→ 本人にOTP・アプリ・ブラウザー等の追加認証
→ カード会員が認証を完了
→ ACSが結果を決済画面/アクワイアラへ返信
→ カードネットワーク/発行会社によるオーソリ
3Dセキュアの認証通知・チャレンジは、実際のカードプログラムに従ってMatchMoveまたは発行会社の認証プロバイダーが送付・制御します。V-RECはカード会員に3DS OTPを送付せず、現バージョンで 3ds.* の加盟店向けWebhookも公開していません。発行会社固有のコールバックURLやステータスは、MatchMoveの契約仕様と受信テストが確認できるまでは実装済みと扱いません。