WinUpGo
Search
CASWINO
SKYSLOTS
BRAMA
TETHERPAY
777 FREE SPINS + 300%
Cryptocurrency casino Crypto Casino Torrent Gear is your all-purpose torrent search! Torrent Gear

Managing promotions and bonuses at the backend level

Full article

💡 18+. Engineering and practical material for platforms/operators and providers. Not a call to play. By "wallet" we mean Ledger/Wallet with ACID guarantees, by "bonuses" - promoters that affect the balance and conditions of the game.

1) Why take the promo to a separate backend

Monetary invariants. Bonus ≠ "added balance": this is a contract with conditions (vager, contribution to games, maximum bet/win).

Rate of change. Marketing teams release campaigns daily - you need a declarative rules engine and rollback.

Anti-abuse/compliance. KYC/RG/AML, velocity, segmentation, four-eye tasks for expensive offers.

Observability and reporting. SLO, promo cost, impact on GGR/NGR/LTV.

Principle: the promo core is a separate service with its own status machines, and money moves only through the wallet, idempotently.


2) Bonus typology and invariants

Deposit match (100% before X): accrued after capture deposit, vager X ×.

Cashback: calculated by time window/games, can be sticky/non-sticky.

Free Spins/Free Bets: coupons/tokens with a price per spin/bet, fixed RTP pool.

Quests/missions: task → progress → reward.

Tournaments/flight events: contribution of events, rating, prize money.

Invariants:
  • Sticky: cannot be output until conditions are met.
  • Max bet/Max win: limits on the bet/payout from bonus funds.
  • Contribution: contribution by game (e.g. slots = 100%, live = 10%).
  • Expiry: Bonus validity period and vager window.

3) Bonus service architecture


Admin ─Promo ─Rules Engine API/Eligibility
│
├─Bonus Ledger (status of offers)
├─Wagering Engine (progress)
├─Anti -Abuse (limits/fraud/velocity)
└─Outbox (events) ─Kafka/Pulsar ─BI/DWH/CRM

Wallet/Ledger── Idempotent Commands ───┘

Rules Engine - declarative conditions (segments, geo/license, channels, KYC/RG).

Wagering Engine - counts contributions from 'bet. settled`/`wallet. debitcredit`.
Bonus Ledger is a source of truth on bonus/mission states.
Outbox/CDC - reliable publication 'bonus. issuedprogress. updated

4) Data model (simplified)

`bonus_grant`

`grant_id, player_id, offer_id, type, currency, amount_minor, sticky, wager_x, max_bet_minor, max_win_minor, contribution_schema_id, status (issuedactivepausedcompletedexpiredrevoked), issued_at, expires_at, brand_id, region, idempotency_key`
`wager_progress`
  • `grant_id, required_minor, contributed_minor, remaining_minor, last_update_at`
`contribution_schema`
  • `schema_id, rules: [{game_type:"slot", pct:100},{game_type:"live", pct:10}]`

'bonus _ ledger _ entry '(audit)

`entry_id, grant_id, action (issueconsumerevokeexpireadjust), amount_minor, reason, occurred_at, trace_id`

5) Status machines and sagas

5. 1 Issue - Saga

1. eligibility. check (segment, RG/KYC, velocity)

2. grant. create (status=`issued`)

3. wallet. credit [bonus] (idempotent; at sticky - to bonus sub-balance)

4. activate (status=`active`)

5. emit `bonus. issued`

Rollback: when falling at step 3 → 'grant. cancel '+ event' bonus. revoked`.

5. 2 Vager progress

Na'bet. settled 'count contribution =' stake _ minor contribution_pct' (or according to win/loss rules).

Update'wager _ progress' atomically; when 100% is reached - 'complete'.

5. 3 Finish (consume)

complete → `wallet. convert_bonus_to_cash' (if non-sticky) or remove output restrictions.

emit `bonus. consumed`.

5. 4 Expiration/Recall

By'expires _ at'or the fraud rule → 'revoke' (idempotent), compensation according to policy is possible.


6) Purse contracts (only via API, always idempotent)

Accrue bonus


POST /v1/wallet/credit
Headers: X-Idempotency-Key: bonus_grant_123
{
"player_id":"p_001",  "amount":{"minor_units":100000,"currency":"EUR"},  "balance_type":"bonus",  "reference":{"grant_id":"gr_123","offer_id":"of_777"}
}
→ 200 {"status":"credited","entry_id":"e_9001"}

Convert to cache when conditions are met


POST /v1/wallet/convert
Headers: X-Idempotency-Key: bonus_convert_gr_123
{
"player_id":"p_001",  "from_balance":"bonus",  "to_balance":"cash",  "amount_minor":100000,  "reference":{"grant_id":"gr_123"}
}
→ 200 {"status":"converted","entry_id":"e_9010"}
Check max bet/max win - on the RGS/Wallet Guard side:
  • request 'bets. authorize 'is rejected by code'BONUS _ MAX _ BET _ EXCEEDED'.

7) API of promo service (templates)

Create an offer (admin)


POST /v1/offers
{
"name":"Welcome 100% up to 100€",  "type":"deposit_match",  "params":{"match_pct":100,"cap_minor":10000,"wager_x":20,"sticky":true,       "max_bet_minor":200,"max_win_minor":50000,"contribution_schema_id":"c_slot100_live10"},  "eligibility":{"brands":["A"],"regions":["EU"],"segment":"new_depositors"},  "schedule":{"start":"2025-10-20T00:00:00Z","end":"2025-11-30T23:59:59Z"}
}
→ 201 {"offer_id":"of_777"}

Issue a bonus (runtime)


POST /v1/bonus/grants
Headers: X-Idempotency-Key: grant_p001_of777
{
"player_id":"p_001","offer_id":"of_777","trigger":"deposit_captured","amount_minor":10000
}
→ 200 {"grant_id":"gr_123","status":"active"}

Wager progress (read)


GET /v1/bonus/grants/gr_123/progress
→ 200 {"required_minor":200000,"contributed_minor":45000,"remaining_minor":155000,"pct":0. 225}

Void/Revoke


POST /v1/bonus/grants/gr_123/revoke
Headers: X-Idempotency-Key: revoke_gr_123
{ "reason":"fraud_velocity" }
→ 200 {"status":"revoked"}

All write calls are with 'X-Idempotency-Key' and 'X-Trace-Id'.


8) Anti-abuse and compliance

Velocity limits: issues/conversions/deposit attempts (Redis counters + TTL + Lua).

Trigger dedup: one deposit → one grant by rule.

Segmentation and RG: exclude self-excluded/limit; per brand/region license.

Block of conflict of offers: only one welcome bonus is active at a time; priorities.

Anomaly detector: multiple accounts/devices/ASN, fast "zeroing" of the vager.

"Four eyes" on large grants and manual adjustments.

WORM audit of all rule/grant/conversion changes.


9) Observability, metrics and SLO

SLO (landmarks):
  • `grant. issue p95` (issue→credited) ≤ 300–500 мс.
  • Update 'wager _ progress p95' ≤ 200ms since 'bet. settled`.
  • Events' bonus. 'In the p95 bus ≤ 2 minutes from what happened.
  • "Lost/duplicated grants/conversions" = 0.
Metrics:
  • Rate/latency по `issue/convert/revoke`, error-rate (business/4xx/5xx), `IDEMPOTENCY_MISMATCH`.
  • Vager conversion, average 'time-to-complete', proportion overdue.
  • Promo cost: 'promo _ cost' (minor) and 'promo _ roi' on cohorts.
  • Anti-abuse: velocity triggers rejected by max bet/win.

Tracking: OpenTelemetry on the chain'trigger → grant → wallet. credit → progress. update → convert`.


10) Integration with RGS/games

Free Spins/Free Bets coupons - via'entitlements' API: issuing tokens, scrapping in runtime, telemetry by use.

Max bet/win - rules in 'bets. authorize` и `bets. settle`; return codes' BONUS _ RULE _ VIOLATION '.

Contribution - scheme at the 'bet level. settled '(by' game _ type/provider _ id '), schema version.


11) DWH/BI and reports

Outbox events → Lake (bronze) → Silver (dedup, SCD2) → Gold showcases:
  • `fact_bonus_grants`, `fact_wager_progress`, `fact_bonus_cost`, `fact_promo_roi`.
  • SLA freshness: Silver ≤ 15 min, Gold ≤ 30-60 min.
  • Panels: conversion by offers/segments, time-to-complete, contribution by games, abuse incidents.

12) Safety and residency

mTLS + OAuth2 CC; scope’ы `promo:issue`, `promo:convert`, `promo:revoke`.

Keys/tokens - per brand/region, short-lived; secrets in Vault/HSM.

PII isolation: 'player _ id' - alias; RLS по `brand/region`.

Rate limits and issuance quotas; protection from retray storms.


13) Checklists

Platform/Operator

  • All monetary transactions go through Wallet with'Idempotency-Key '.
  • Rules/Eligibility are versioned; "double letter" of events on migrations.
  • Contribution schemes are centralized, covered with tests.
  • Velocity and anti-fraud enabled; "four eyes" on large sums.
  • Outbox/CDC, DLQ and managed replay for 'bonus.'.
  • SLO dashboards, OpenTelemetry, WORM audit.
  • DWH storefronts for ROI and compliance (RG/AML).

Integrations (RGS/wallet/CRM)

  • Checking max bet/win; returning the business error code.
  • I throw 'trace _ id' and 'idempotency _ key'.
  • Deadup triggers and delivery guarantees (webhooks signed).

14) Red flags (anti-patterns)

Charging the bonus "manually" directly into the balance, bypassing Wallet.

Lack of idempotency → double grants/conversions.

The wager is considered by 'bet. placed ', and not according to the results of' bet. settled`.

There are no contribution schemes or they are "protected" in the code of providers.

Conflicting offers are activated simultaneously.

There is no velocity/anti-fraud and WORM audit.

'bonus. 'events are posted bypassing outbox/CDC.

Promo metrics don't add up to Ledger/BI (no ROI showcases).


15) The bottom line

Reliable backend promos are contracts and invariants, not "add balance." It separates rules from money, considers progress according to actual outcomes, guarantees idempotency and observability, protects against abuse and ensures compliance. With such a core, marketing moves quickly, the player sees honest conditions, and finances and regulators get an accurate picture of the cost and effect of each offer.

× Search by games
Enter at least 3 characters to start the search.