Reference/Webhook events
Webhook events
Boss Hub reports important events to your registered address with a POST. You manage endpoints and the events they listen to on the Webhook deliveries card of the portal. Webhooks depend on the api module.
Events
| Event | When | data |
|---|---|---|
| round.big_win | The round’s win reached a multiple of the bet (50× by default); once per round. Not sent for free round or promotional rounds | round_id, bet, win, currency |
| round.stuck | A round became stuck | round_id |
| round.resolved | A stuck round was resolved | round_id |
| jackpot.won | A Boss Hub jackpot drop was paid. Not sent for EGT’s own jackpots | pool_id, level, amount, currency, site_id, player_id, game_id, round_id, won_at |
| invoice.issued | An invoice was issued. Live address only. On a manual invoice the period fields are null and total_usd and credited are absent | invoice_no, period_start, period_end, total, currency, total_usd, credited, issued_at, due_date |
| invoice.overdue | An invoice is past its due date. Live address only | invoice_no, balance, currency, due_date |
| payment.confirmed | A payment was confirmed. Live address only | invoice_no, payment_id, amount, currency, paid_amount, paid_currency, value_date, status |
| campaign.finished | A free round campaign finished (status: finished) or was cancelled (status: cancelled) | campaign_id, name, status, won_total, currency (only the first three when cancelled) |
| tournament.finished | A tournament ended and its leaderboard froze | below |
| tournament.prize_approved | A tournament prize was approved (wallet or manual payment) | below |
| game.released | A new game was released. To your Live address if the provider was taken live, otherwise to Test | game_id, name, version, release_at |
| game.retiring | A retirement was planned, moved or cancelled for a game in your library | below |
| game.availability_changed | The on/off state of a game or provider changed | changes[]: scope, target, provider_id, game_id, site_id, state, source; truncated |
| limits.changed | Effective bet limits changed | changes[]: scope, target, provider_id, game_id, site_id, currency, inherit, min_bet, max_bet, default_bet, removed; truncated |
| market_rule.changed | A market rule changed. To your Live address unless the market is Test-only | market_id, market, rules[]: key, value |
| wallet.degraded | Callback performance dropped; only on the transition into degraded | since, metrics |
| alert.triggered | An alert rule fired | alert_id, rule, metric, severity, value, label, started_at |
| key.revoked | An API key was revoked or rotated | name, prefix, rotated (true on rotation) |
Jackpot: Only a drop paid from a Boss Hub pool is reported (jackpot.won), when it is paid rather than when it drops. No event is sent for the jackpot contribution of each bet.
Tournaments: tournament.finished arrives once when the period ends: data holds tournament_id, name, scoring, currency, starts_at, ends_at, ended_at, participants and leaderboard (the top 10 and every prize rank: rank, player_id, score, prize). Prizes are decided in the portal. tournament.prize_approved arrives separately for each approved prize: tournament_id, name, rank, player_id, method (wallet or manual), prize and currency (in the tournament currency), decided_at. With wallet the prize reaches you as promotional credit through a /win call (promo.type: tournament); the event carries paid_amount, paid_currency, transaction_id and round_id. With manual these fields are null: you pay the prize from your own system. No event is sent for a rejected prize.
Game retirement: game.retiring arrives at least 7 days ahead: data holds game_id, name, provider, status (planned or cancelled), retire_at (null when cancelled) and note. On the date the game closes and game.availability_changed arrives with source: retired. /v1/games retire_at and /v1/releases show the plan too.
Rule changes: One save is one event, a bulk edit too: game.availability_changed and limits.changed carry their changes in data.changes, cut after 100 rows (data.truncated); read the current state from /v1. Rules are not per environment: an event about your operator or site rule reaches your Test and Live addresses separately; an event about a platform rule for a provider or game reaches both if the provider is live for you, or only Test while it is in testing; a platform rule for all games reaches both. wallet.degraded fires only on the transition into degraded, not on every measurement.
Signature
| Header | Description |
|---|---|
| X-Timestamp | Unix seconds |
| X-Signature | hex(HMAC_SHA256(webhook_secret, ts + "." + body)) |
Each webhook endpoint has its own secret (whsec_…), shown once when you add the endpoint. There is no secret rotation: add a new endpoint and delete the old one. Because the address is fixed, the signature covers only the timestamp and the raw body; this is where it differs from the API signature. The timestamp and the signature are renewed on every attempt; you may reject a request with an old timestamp.
Delivery
- Response: a 2xx counts as delivered. Any other response or a timeout (5 s) is retried.
- Attempts: at most 5 attempts by default: within about 15 s after the event, then 1, 2, 4 and 8 minutes apart. There is no automatic retry after the last attempt.
- Resending: in the Webhook deliveries table of the portal, you can send any event again with Resend; the id stays the same and created_at is the time of the resend.
- Duplicates: the same event can arrive more than once. Deduplicate by id.
- Environment: webhooks are per environment; a Test event never reaches a Live address. Invoice and payment events go to your Live endpoints only.
- Setup: add an endpoint on the Webhook deliveries card of the portal: an address of at most 500 characters, HTTPS required (Test included), private and internal network addresses rejected; 1-30 events per endpoint; the api module is required. A Live endpoint can be added after production approval.