Automating Events and Rewards - Rules and Webhooks
Gamification is based on two "motors": events (what the user did) and rules (what is supposed to be for it). For this to work on a large scale and without errors, you need a reliable event bus, a rules engine, a delivery/award mechanism and strict protection against fraud. Below are practical architecture, templates and checklists.
1) Event → rule → reward flow architecture
1. Ingest (event input): SDK/web, server webhooks from payment/game provider → API Gateway → queue/bus (Kafka/Rabbit/Cloud Pub/Sub).
2. Normalizer: validation, enrichment (geo, device, payer_flag), scheme version.
3. Rules Engine: scoring/XP, checking missions/quests, reward/notification triggers.
4. Reward Orchestrator: calculating rewards, budget check, RG/KYC gates, creating a "issuance task," logging.
5. Payout/Bonus Service: cache/bonus cache/freespins/coupons, external webhooks (wallet, providers).
6. Notifier: push/in-app/email/instant messengers with frequency limits.
7. Storage/Analytics: raw events, storefronts, A/B, alerts.
8. Anti-Fraud/RG: mouthguards, heuristics/ML, hold-and-review big prizes.
2) Event model (minimum set)
json
{
"event_id": "d9e8-...-5c2", "event_name": "bet", "version": "1. 2. 0", "ts": "2025-10-24T11:37:21Z", "user": {
"id": "u_123", "geo": "TR", "platform": "android", "payer_flag": true, "risk_flags": ["vp_nightly"]
}, "context": {
"session_id": "s_789", "device_fp": "fp_...", "ip": "203. 0. 113. 24"
}, "payload": {
"game_id": "slot_wolf", "bet": 0. 5, "win": 1. 25, "currency": "EUR", "provider": "GameCo"
}
}
Базовые типы: `login`, `session_start/end`, `bet/spin`, `win`, `deposit`, `withdraw_request`, `kyc_status_changed`, `mission_view/join/progress/complete`, `tournament_join/score/update/reward`, `reward_issued`, `rg_event`.
3) Rule engine: how to describe logic
Concepts: rules (if/then), segments, time windows, mouthpieces, priorities, versioning.
An example of a declarative rule (YAML style):yaml rule_id: r_points_winmult_v2 when:
event_name: bet filters:
- payload. bet >= 0. 2
- user. geo in ["TR","BR","PE"]
- now between "2025-11-01" and "2025-11-30"
score:
formula: "floor((payload. win / payload. bet) 3)"
caps:
per_bet: 50 per_minute: 200 per_day: 1500 reward_trigger:
on_progress:
threshold: [100, 300, 800]
reward: [{type: "fs", value: 10}, {type: "bonus_cash", value: 2}, {type: "loot", rarity: "rare"}]
guardrails:
kyc_min_level: 2 rg_limits_ok: true budget_pool: "nov_season"
budget_soft_cap: 80000 meta:
version: "2. 0"
experiment: "scoring_ab_2025w45"
4) Webhooks: server-server integration
4. 1. Outbound webhooks (from you to providers/wallet)
Method: 'POST https ://partner. example/payouts`
Подпись: `X-Signature: HMAC-SHA256(secret, body)` + `X-Request-Id` (idempotency).
Retrai: exponential backoff, 'max _ retries = 8', jitter, DLQ.
Idempotency: repeat the same 'X-Request-Id' → the partner must respond with the same 'payout _ id/status'.
Example of payload:json
{
"request_id": "rid_7f5...", "user_id": "u_123", "reward": {"type":"cash","amount":10. 00,"currency":"EUR"}, "reason": "milestone_300_points", "kyc_level": 2, "constraints": {"wagering": 0, "expiry_at": "2025-12-01T00:00:00Z"}
}
4. 2. Incoming webhooks (to you)
Allow only IP/MTLS lists, check HMAC and signature lifetime ('X-Timestamp', ± 5 minutes).
Store "raw" body + headers in the Audit Store (WORM).
Any double/repeat → check the idempotency key against the log.
5) Reliability: "even" flow without double payments
At-least-once on ingest + idempotent handlers → the gold standard.
Idempotency key: 'hash (event_id + user_id + rule_id)' for scoring; separate key for issuing reward 'reward _ task _ id'.
Exactly-once semantics are only logically realistic (through idempotence), not transport.
Order of events: store 'event _ ts' and 'ingest _ ts'; use reordering window (for example, 60 seconds) and replay from the queue by the 'user _ id' key.
Dead Letter Queue (DLQ):- We write messages there with a permanent error (the temporary scheme did not pass, the signature is invalid, the budget is closed).
- DLQ review service with reprocess/drop/fix schema buttons.
6) Budgets and margin protection
Budget pools: 'nov _ season', 'daily _ sprint', 'vip _ weekend'.
Quotas: soft/hard cap, "circuit breaker" - when reaching 90% of the budget, transfer large prizes to hold-state.
Single cost: 'Prize & Bonus Cost per Active/Payor', Net Uplift.
Priorities: RG and compliance are more important than promo - in case of conflict, the reward is postponed.
Example of budget check (SQL sketch):sql
SELECT pool_id, SUM(amount) AS spent, budget AS limit, SUM(amount)/budget AS fill
FROM reward_ledger
WHERE pool_id =:pool AND date(ts) = current_date
GROUP BY pool_id, budget;
7) RG/KYC/Geo gates (player safety and compliance)
KYC: L2 minimum for cache/big prizes; freespins are valid with L1.
RG: checking deposit limits, self-exclusion, cool-off → awards are frozen until the restrictions are lifted.
Geo: list of allowed countries for each award rule/pool.
Threshold alerts: sharp growth "almost reached" in individual accounts = a reason to hold & review.
8) Anti-fraud rules and telemetry
Caps of points at a rate/min/hour/day, minimum variance of bets, prohibition of "ideal" patterns.
Technical signals: headless, repeated device_fp, proxy subnets.
Anomalies: "points/bets" and "points/min" - long "tails" on the 99-percentile.
Hold-and-review for top winners: automatic KYC check + manual review.
9) Monitoring, metrics and alerts
SLO/SLA:- Ingest p95 ≤ 250 ms; rule processing p95 ≤ 150 ms; leadership board update ≤ 2 s; award issue ≤ 60 s.
- Error budget < 0. 1% events/day.
- SRM on experiments (traffic skew), DLQ growth, HMAC validation signature drop, budget overrun, idempotent duplicate surge.
- Events/s, lag, fault tolerance;
- Funnel: event → rule → reward_task → reward_issued;
- Cost: Prize/Bonus per Active, Net Uplift;
- Quality: fraud flags, KYC blocks, RG triggers.
10) Versioning and migrations
Each rule is versioned ('rules. version`).
You cannot edit the active rule without a new version; use ficheflag and "smooth heating" (10% → 50% → 100%).
Diagram of events via schema registry; incompatible changes - major version only.
11) A/B automation tests (short)
Unit - user; sticky-assignment; stratification (payer/geo/platform).
Separate leadboards or normalization of points to eliminate interference.
Primary: participation_net, completion, Net ARPPU; Guardrails: complaints/1k, fraud flags, RG triggers.
CUPED and covariates for variance reduction.
12) Examples: from rule to issue
12. 1. Micro-reward progress trigger
json
{
"type": "reward_task. created", "reward_task_id": "rt_456", "user_id": "u_123", "origin": {"rule_id":"r_points_winmult_v2","threshold":300}, "reward": {"type": "bonus_cash", "amount": 2, "currency":"EUR", "wagering": 15}, "pool_id": "nov_season", "status": "pending", "created_at": "2025-10-24T11:38:30Z"
}
12. 2. Outgoing webhook for wallet
POST /wallet/credit
X-Request-Id: rid_7f5...
X-Timestamp: 1730061700
X-Signature: sha256=7b9a...
{ "user_id":"u_123", "amount":2. 00, "currency":"EUR", "reason":"rule:r_points_winmult_v2" }
Success → 'reward _ task' = 'succeeded' and writing to 'reward _ ledger'.
Failure (5xx/timeout) → retray with the same 'X-Request-Id'.
Dip (4xx) → DLQ + manual parsing.
13) Vaults and tables (sketch)
sql
-- awards magazine
CREATE TABLE reward_ledger (
id BIGSERIAL PRIMARY KEY, reward_task_id TEXT UNIQUE, user_id TEXT, pool_id TEXT, type TEXT, value NUMERIC(18,2), currency TEXT, cost NUMERIC(18,2) DEFAULT 0, -- реальная стоимость для P&L status TEXT, -- succeeded/failed/held created_at TIMESTAMPTZ, updated_at TIMESTAMPTZ
);
-- indempotency
CREATE UNIQUE INDEX uniq_reward_task ON reward_ledger (reward_task_id);
-- budget
CREATE TABLE reward_budget (
pool_id TEXT PRIMARY KEY, budget NUMERIC(18,2), spent NUMERIC(18,2), period DATE
);
14) Security and privacy
HMAC signatures, MTLS, allow-list IP.
Encryption in transit/rest, key rotation, secrets in vault.
Minimizing data in payload (PII separately, by token link, TTL).
Audit logs immutable (WORM).
Retention and disposition policy (right to be forgotten, deduplication-safe).
15) Launch checklist
- Event schemas and registry, webhook contracts (signatures, TTL).
- Queues, retrays, DLQ, idempotent handlers.
- Caps/guardrails in the rules, KYC/RG gates.
- Budget-pools, circuit-breakers, overflow alerts.
- SLO dashboards + reward funnel.
- A/B filters and SRM monitoring.
- Runbook of incidents (replay, freeze, manual issue).
16) Mini Case (Synthetic)
Connected events from game providers and wallet; included "win/bet" scoring with mouth guards.
Webhooks signed HMAC, retrays up to 8 attempts, DLQ with review every 2 h.
For 4 weeks: processing lag p95 180 ms; DLQ < 0,06%; duplicate payments 0; fraud flags − 0.4 pp; ΔParticipation_net +6,3 п.п.; ΔARPPU (net) +€2,1 при Prize&Bonus/Active +€0,7.
Conclusion: scaling rules to new geo with local budget pools.
Automating rewards is not "send push with freespins." This is an engineering system: reliable delivery of events, strict versioning of rules, idempotency and signatures, budget privateers, KYC/RG gates, anti-fraud and monitoring. Build this framework one day - and any missions, tournaments and "loot moments" will work predictably, on time and with a positive net effect.