Rewards Club — Program
Access prerequisites
- Permission (module):
viewRewardsProgram(to read) /manageRewardsProgram(to save) - License/Feature:
REWARDS_CLUB - Menu container: GENERAL → group Rewards Club
What it is / when to use
The Program screen is the singleton configuration of the Rewards Club (RCS) for the tenant. Here you define the club's identity, how the user's level (tier) is calculated (metric + window), global anti-fraud caps, payment pools (house wallets per asset), and manual quotes used when there is no automatic price feed.
Use it when setting up the club for the first time and whenever you need to change the macro rule (e.g.: switch from "deposit volume" to "mission points", pause payouts in an emergency, fund/monitor the payment pool).
Prerequisites
- Permission:
viewRewardsProgramto open;manageRewardsProgramfor the controls to be editable and Save to work (dual permission: CPM enum + dynamic module in the DB). - License/Feature:
REWARDS_CLUBenabled in the tenant license (Vault). If disabled, the group does not even appear in the menu. - Dependencies from other screens: levels are created in Levels and missions in Missions. When the tier metric is
POINTS, missions that grant points must exist.
Step by step
- Go to the menu Rewards Club → Program (
/rewards-club/program). - Set Status (Active/Paused) and the program name.
- Choose the Tier metric (deposit volume, traded volume, or mission points) by clicking the corresponding card.
- Choose the Tier window (lifetime, last 90 days, or current year).
- Configure the default reward asset and the reference fiat.
- Adjust the anti-fraud caps (per day, per user/day).
- Register the payment pools (one house wallet per asset) and, if needed, the manual quotes.
- Click Save — the mutation requires step-up (see below).
Fields
| Field | What it is | Required? | System/backend effect |
|---|---|---|---|
Status (status) | ACTIVE or PAUSED | Yes | Active: events trigger payouts and the tier engine recomputes on cycle. Paused: events continue to be audited, but missions do not pay; the tier engine keeps running. Use Paused in emergencies. |
Tier metric (tierMetric) | How the level is calculated | Yes | DEPOSIT_VOLUME (sum of confirmed deposits in fiat), TRADE_VOLUME (traded volume in fiat), or POINTS (mission points). Canonical values from rcs-lib — define what the engine sums to position the user in a tier. |
Tier window (tierWindow) | Period considered in the metric | Yes | LIFETIME (cumulative lifetime — never drops a level), ROLLING_90D (rolling 90-day window — can lose the level), CALENDAR_YEAR (resets on January 1st). |
Default reward asset (defaultRewardAsset) | Token/asset used when the mission does not define one | No | When a mission has no rewardAssetId, the payout uses this asset. Makes the reward token configurable and modular (e.g.: tBRL, MID, USDC) — without locking into fiat. |
Reference fiat (referenceFiat) | Display currency for the financial metric | Conditional | Used to display the metric when it is DEPOSIT_VOLUME/TRADE_VOLUME. When the metric is POINTS, the UI displays in "pts" and ignores this field. Replaces the legacy fiatRef (mirrored for backward compatibility). |
Global cap per day (globalMaxPayoutsPerDay) | Anti-bot payout limit per 24h for the entire program | No | 0 = no limit. |
Cap per user/day (globalMaxPayoutsPerUserPerDay) | Anti-bot payout limit per 24h per user (all missions) | No | 0 = no limit. Independent protection layer from the per-mission cap. |
Payment pools (pools[]) | House wallets holding the payout balance per asset | Yes (to pay) | Each pool has assetId, walletAddress, balance (balance), and minBalanceAlert (alert threshold). The balance bar turns red when balance ≤ minBalanceAlert. Without a pool with balance, the asset cannot pay. |
Manual quotes (manualQuotes) | Quote override asset → reference fiat | No | Map ASSET → value (1 unit of the asset = N of fiat). Used by the RCS QuoteService when there is no automatic price feed for that pair. Blank lines are ignored on save. |
The NFTs by tier map (
tierNftAssets) appears here only as read-only (backward compatibility with legacy programs). NFT generation for each level has moved to the Levels screen (inline "Generate NFT" button per row).
Actions and modals
- Save: persists the program via
PUT /v1/rewards-club/admin/program. Requires step-up (X-Step-Up-Token: password + MFA re-authentication, 5-minute window). If the token expires, the gateway responds428 Step-up requiredand the interceptor requests new verification. - Add/Remove pool and Add/Remove manual quote: manipulate the lists locally; only persisted on Save.
Business rules / cautions
Caution
- Pausing the program does not stop event capture (audit continues) — it only suspends payments. Useful for containing an incident without losing history.
- The choice between
LIFETIMEand rolling windows deeply changes behavior: inLIFETIMEthe user never drops a level; inROLLING_90D/CALENDAR_YEARthey can lose the tier. - Switching the metric to
POINTSwithout point-awarding missions configured leaves everyone at the base level. Ensure missions withmissionPoints > 0are in place first. - Keep pools funded: a balance below the alert signals risk of payouts failing due to lack of funds in the house wallet.
- Financial values: balances, alerts, and quotes are transmitted as BigNumber strings — no rounding; treat as BigNumber before any arithmetic.
- Idempotency: underlying payouts pass through FinLib, which is idempotent by
externalId. Error codeE00021("already processed") means success (already settled), not failure.
Examples
Scenario 1 — Fundraising club by deposit volume (lifetime)
Objective: reward those who deposit the most, without ever downgrading.
- Status = Active.
- Metric = "Deposit volume".
- Window = "Lifetime".
- Reference fiat = BRL.
- Default reward asset = tBRL.
- Register a tBRL pool with the house wallet and a comfortable
minBalanceAlert. - Save (step-up). The thresholds for each level (in BRL) are defined in Levels.
Scenario 2 — Engagement club by points (rolling 90 days)
Objective: reward continuous activity; those who stop, drop.
Scenario 3 — Containing an incident without losing history
Suspected abuse/bot triggering payouts:
- Open Program and change Status to Paused, save (step-up).
- Events continue to be captured and audited, but no mission pays out.
- Adjust the anti-fraud caps (
globalMaxPayoutsPerUserPerDay > 0) and review suspicious missions. - Return the status to Active when safe.