Limit hierarchy
A limit is a formalized limitation of an operation in time/volume/value. In iGaming and fintech, limits are the basis for safety, regulatory compliance and risk management. The limit hierarchy specifies whose rule is most important and where it is executed in order to prevent double spending, exceeding bets/deposits, abuse of bonuses and violations of responsible play.
1) Classification of limits
By application strength
Hard - insurmountable (operation prohibition).
Soft - warning/friction (captcha, confirmation), escalation to hard when repeated.
By nature
Cash: deposit amount/rates/payments; daily/weekly/monthly limits.
Time: session duration, breaks, "cooling," timeouts.
Quantitative: the number of transactions, spins, API requests.
Rate limits: RPS/competition.
Quotas: budget of actions per window (N per day/week).
Contextual: by game/provider/payment method/device/country.
By Owner
Regulatory/Brand (Tenant/Region)
System (platform, infrastructure protection)
User-defined (self-limits within RG)
2) Measurements and keys (scoping)
Each limit is bound to a context (key):
tenant_id · region · license · currency · channel · brand player_id · kyc_tier · rg_state · age game_id · provider_id · product (casino/sports/live)
payment_method · device_fingerprint · ip_asn
The more accurate the key, the higher the priority (see hierarchy below).
3) Hierarchy and priorities (most specific wins)
Let's arrange the levels from general to particular:
GLOBAL_DEFAULT
< TENANT/BRAND
< REGION/LICENCE
< PRODUCT/PROVIDER/GAME
< CURRENCY/CHANNEL/PAYMENT_METHOD
< PLAYER (KYC/RG)
< SESSION/DEVICE
<REQUEST (idempotency-key operation)
Rules:
- A narrower context overlaps a wide: player> region.
- Any explicit deny wins allow.
- Soft/hard conflicts are resolved in favor of hard.
- With the merge of quotas/windows, the minimum allowable value (min-cap) wins.
4) Data model (simplified)
sql
CREATE TABLE limits (
id bigserial primary key,
scope jsonb, -- context keys (tenant, region, player_id,...)
kind text, -- bet_amount, deposit_daily, rps_api, payout_single, session_duration type text, -- HARD SOFT QUOTA RATE value numeric, -- sum/qty/seconds/ops window_sec int, -- for QUOTA/RATE, else null burst int, -- for RATE token-bucket currency text, -- if applicable reason_code text, -- regulator/product/security valid_from timestamptz,
valid_to timestamptz,
priority int default 0, -- manual specificity overlide created_by text,
created_at timestamptz default now()
);
CREATE TABLE limit_counters (
key_hash text primary key, -- hash(scope,kinda,window_start)
window_start timestamptz,
consumed numeric, -- money/pcs/sec updated_at timestamptz
);
Idempotence: all operations carry 'operation _ id'; the counter increment is performed once (inbox/outbox or compare-and-swap according to the version).
5) Evaluation algorithm
1. Collecting candidates by 'kind' and crossing 'scope'.
2. Ranking by specificity (number of matched measurements) and 'priority'.
3. Parameter range: hardness (hard> soft), min-cap, min-window.
4. Check quotas/rate limit: token-bucket (RATE) + fix/sliding window (QUOTA).
5. Решение: `ALLOW | SOFT_WARN | DENY` + `retry_after`/`remaining`.
6. Trace record: audit event and metrics.
json
{
"decision":"DENY",
"kind":"deposit_daily",
"remaining":0,
"window_reset_at":"2025-10-31T21:00:00Z",
"matched_limit_id":12345,
"policy":"REGULATORY",
"reason":"DAILY_CAP_REACHED"
}
6) Enforcement points
API Gateway - infrastructure protection: RATE (RPS), CONCURRENCY, burst.
Domain services - semantic limits: deposits, rates, payments, sessions.
Provider adapters - duplicate/local provider limits (validate before calling).
Client UX - preventive prompts (SOFT), "N left," timers.
Rule: write off the quota/tokens once - where the operation becomes irreversible (after backing up the wallet/valid authenticated step).
7) Cash limits: deposit/rate/payout
Per currency: Store limits in the transaction currency, not through FX on the fly.
Min/Max: `min_bet`, `max_bet`, `max_payout_single`.
Windows: 'deposit _ daily/weekly/monthly' with fixed boundaries (for example, in the license timezone).
Composition: final allowed range = intersection (regional ∩ brand ∩ custom).
8) Responsible Play (RG)
Self-limits (the player asked himself) are always tougher than branded ones.
Time limits: 'session _ duration', 'cool _ off', 'self _ exclusion'.
Escalation: exceeding the soft limit → warning, repeating the hard → (within the window).
Audit: Each RG change is recorded non-laterally (who/when/why).
9) Rate limit vs Quota: when what
Rate limit (token-bucket/leaky): surge protection; apply on gateway/adapters.
Quota (fixed/sliding window): managing the total budget of actions/money; apply in domain (deposit_daily, bet_count_hourly).
Often used together: 'RATE' (instant peaks) + 'QUOTA' (daily budget).
10) Multi-tenant and multi-region
Limits always contain 'tenant _ id' and 'region/license'.
Residency: counters and storage - in the "home" region.
Fairness: Separate RATE/QUOTA per tenant pools so "noisy" doesn't disrupt others' SLOs
11) Idempotency and consistency
Commands with 'operation _ id'; repeat should not increase 'consumed'.
For money - strict path: wallet reserve and increment counters in one transaction/saga (TCC).
For RATE - use atomic increments/warehouses current window.
12) Observability
Metrics:- `limit_eval_p95_ms`, `decision_rate{ALLOW,DENY,SOFT}`,
- 'quota _ remaining _ percent'by main species,
- `rate_throttled`, `burst_dropped`,
- `rg_self_limit_hits`, `regulatory_hits`.
Логи/трейсинг: `matched_limit_id`, `scope_hash`, `operation_id`, `window_start/reset`, `remaining`.
Alerts: growth of'DENY '/' 429' over the threshold, frequent achievement of regulatory caps, "hot key" by player/device.
13) Versioning and auditing
Each rule is with 'valid _ from/valid _ to', 'created _ by', 'reason _ code'.
События: `LimitCreated/Updated/Deleted`, `LimitHit`, `LimitDenied`.
Keep a "snapshot" of active rules to reproduce historical decisions (dispute-ready).
14) Testing
Contract tests: scheme and range of specificities/priorities.
Property-based: "most specific wins," "deny wins allow," "min-cap."
Golden cases: a set of reference conflicts (tenant vs region, RG vs brand).
Chaos: Request spikes (RATE), count races, repeat commands (idempotency).
E2E: limit matches on the check lists of the regulator (deposit/week/month).
15) Playbooks
1. Storm 429/throttling on gateway
Reduce concurrency, increase token-bucket temporarily, enable prioritization of critical paths, analyze sources (ASN/IP).
2. Mass failures by regulatory limit
Check window schedule and timezone; prolong soft-UX (explanations), notify compliance.
3. False positive failures due to racing
Enable serialization by the 'player _ id/kind' key, switch to CAS/dedup by 'operation _ id'.
4. Discrepancy with provider limit
Synchronize min/max per game, add pre-validation to the adapter, temporarily lower the game catalog/placement.
16) Typical errors
Lack of hierarchy → tug-of-war between rules.
Calculation of limits in UI without server validation.
Substitution of quotas with rate limits (and vice versa).
Ignoring currencies/steps with monetary limits (CLP/JPY).
No idempotency → double quota write-off.
A single RATE pool for all tenants → shearing problems.
No audit → failure cannot be explained.
17) Quick recipes
Bid acceptance: 'max _ bet' = min (region, game, provider, user RG); RATE on '/bets. place '= 20 rps/player, QUOTA = 500 bets/day.
Deposits: 'deposit _ daily/monthly' + 'deposit _ single'; pre-validate PSP limits.
Sessions: 'session _ duration' hard + reminders every N minutes (soft).
API protection: global RATE by the keys' ip _ asn'and' tenant _ id '; canary windows for releases.
18) Pre-sale checklist
- Most specific wins, deny> allow.
- Data model with 'scope', 'kind', 'type', windows, currencies and priorities.
- Application points: gateway (RATE), domain (QUOTA/money), adapters (provider).
- Idempotency ('operation _ id') and serialization by keys; the counters are atomic.
- Observability: solution metrics, window lags, alerts; trace with 'matched _ limit _ id'.
- Versioning and unalterable auditing of changes and actuations.
- Test Pack: contract/property/golden/chaos/E2E.
- Multi-tenant fairness and data residency met.
- UX for SOFT limits: friendly messages, 'remaining/retry _ after'.
- Incident playbooks are aligned with compliance and support.
Conclusion
The limit hierarchy is a decision system, not a set of disparate numbers. Clear specificity and order of priorities, a single data model, the right application points, idempotence and observability turn limits into a robust safety and compliance loop that scales across tenants, regions and products - and doesn't hinder growth.