Offline / Balance Reclaim Callback
When a player exits a game, is force-kicked, or switches to another game in the same currency, VCT notifies the Agent to close the session and reconcile the final balance.
Environment URLs
| Environment | Base URL |
|---|---|
| Production | https://hub-panel-api.v7stech.com |
| Staging | https://hub-panel-api-dev.v7stech.com |
Acknowledgement is required
The Agent must return a JSON response with status: "success". A missing status, any other status, or an unparsable response is recorded by VCT as a failed offline callback.
Endpoint
| Property | Value |
|---|---|
| Path | POST /api/v1/callback/offline |
| Caller | VCT Platform → Agent |
| Content-Type | application/json |
Authentication and Signature
See Authentication for the common Header Token rule. This endpoint's Body sign is HMAC-SHA256(username + "." + timestamp, agent_api_secret); the Header and Body timestamps must match exactly.
Request Parameters (from VCT)
| Parameter | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Player username |
currency | string | Yes | Currency code |
session_id | string | Yes | The VCT session ID created at game launch |
game_id | string | No | Game GUID |
game_code | string | No | Game code |
game_name | string | No | Game name |
game_type | string | No | Game type |
provider | string | No | Provider code |
reclaimed_amount | decimal | Yes | Amount snapshot captured when Hub cleared its local wallet at cleared_at; for this Offline reconciliation only. It must not reapply a master-wallet transaction and is not the final master-wallet balance after all late logs are processed |
wallet_cleared_total | decimal | Normal reclaim | Physical total cleared from every same-currency Hub wallet |
mirrored_delta_total | decimal | Normal reclaim | Adjustment total still present in both source and active wallets, capped by each source wallet's cleared amount |
net_balance_to_reconcile | decimal | Normal reclaim | wallet_cleared_total - mirrored_delta_total |
wallet_breakdown | array | Normal reclaim | Per-wallet amount plus session, game, Provider, and Brand snapshot |
mirrored_adjustments | array | Normal reclaim | Mirrored events with event ID, source/target identity, and delta |
cleared_at | string | No* | Time when Hub actually cleared the local wallet, in RFC3339/RFC3339Nano format. New normal exit/kick/switch-game reclaims include it; historical records and launch_failed may omit it |
action | string | Yes | exit_game, api_kick_exit, switch_game, or launch failure compensation launch_failed |
sign | string | Yes | Request signature |
timestamp | long | Yes | Request timestamp |
Success Response (required)
{
"status": "success",
"message": "received",
"username": "player001",
"currency": "MYR",
"session_id": "vct-session-uuid-001",
"reclaimed_amount": 125.50,
"cleared_at": "2026-10-04T23:30:12.123Z"
}status must be exactly success. This confirms that the Agent processed the notification, marks the reclaim complete, and stops retries. Callback failure does not block the player from launching another game after Hub has atomically cleared the wallets.
Failure Response
{
"status": "error",
"message": "player not found"
}Any failure response or non-2xx HTTP response is recorded by VCT as a failed callback. The Agent should verify sign, timestamp, and username, and implement idempotency.
When the Agent returns a failure, VCT marks the reclaim as callback_failed. VCT may resend the same Offline request, or an administrator may retry it manually. The Agent must process retries idempotently by session_id + action; the failed callback does not block a new game launch.
For normal Offline callbacks, VCT automatically retries failed deliveries up to 15 times with increasing backoff intervals: 1 minute, 5 minutes, 15 minutes, 30 minutes, 1 hour, and 2 hours. Automatic retries stop after the limit, but an administrator may still retry manually. Every actual HTTP attempt is recorded separately; the Agent must never apply the same wallet effect twice.
Notes
- In Seamless mode, master-wallet debits, credits, and reversals are processed through
/bet-push;reclaimed_amountis the amount snapshot captured when Hub cleared its local wallet, for this Offline reconciliation only, and must not cause duplicate wallet changes. wallet_cleared_totalmay contain both a source wallet amount and the same event mirrored into the active wallet. Matchmirrored_adjustments.event_idagainst the Agent ledger and reconcile withnet_balance_to_reconcile; never credit the physical total directly.cleared_atis the time Hub cleared the local wallet. It is not the Offline delivery time and does not mean that all late logs have finished processing. Logs received by Hub after this time may still exist; the Agent should continue applying/bet-pushidempotently and usesession_idpluscleared_atfor audit.- VCT records both the request and response for reconciliation.
- Use
session_id + action(and the request signature when available) as the idempotency key to prevent duplicate credits.
Launch Failure Compensation (launch_failed)
If /balance succeeds but the game provider fails to launch the game, VCT calls this endpoint with the original session and amount:
{
"username": "player001",
"currency": "MYR",
"session_id": "vct-session-uuid-001",
"reclaimed_amount": 100.00,
"action": "launch_failed",
"sign": "9a2f64d0bcfa829...",
"timestamp": 1783324700
}The Agent must:
- Preserve and match
session_idexactly. - Release only the temporary launch session, balance lock, or pending record.
- Keep
launch_failedout of the normalenter_gameand offline settlement flow. - Enforce a unique key for the same player, currency, and
session_id. - Process duplicate
launch_failedrequests idempotently without duplicate credit or release. - Use the normal offline settlement flow only for actions such as
exit_game,api_kick_exit, andswitch_game.
AI Implementation Prompt (Copy Ready)
Implement the Agent endpoint POST /api/v1/callback/offline for VCT session closure and reconciliation.
Requirements:
1. Verify the three-part Authorization Token, require Header timestamp == Body timestamp, and verify Body sign as lowercase hex HMAC-SHA256(username + "." + timestamp, agent_api_secret) using constant-time comparison.
2. Enforce idempotency by Agent + username + currency + session_id + action because VCT may retry automatically or manually.
3. For exit_game, api_kick_exit, and switch_game, close the matching session and store wallet_breakdown plus mirrored_adjustments. Reconcile mirrored events by event_id; switch_game aggregates every Provider wallet for the currency.
4. Seamless funds are already processed by bet-push. wallet_cleared_total is the physical Hub total and net_balance_to_reconcile removes mirrored deltas; neither field should trigger another master-wallet credit or debit.
5. cleared_at is the Hub wallet-clear time, not callback-send time. Late bet-push records must still be processed idempotently.
6. launch_failed releases only that launch_pending state/lock. It must not create enter_game, run normal exit settlement, or move funds twice.
7. Return HTTP 2xx and {"status":"success"} only after the database transaction commits. Already-processed duplicates should return idempotent success.
8. Return non-2xx or status=error for transient failures so VCT retries. Redact Secret, Token, and sign from logs.
9. Test all normal actions, launch_failed, duplicates, out-of-order delivery, invalid/expired signatures, rollback, and no double wallet mutation after bet-push.
Reuse existing sessions, wallet ledger, transactions, locks, and authentication. Deliver route, service, idempotency constraint, and tests.