Skip to content

FAST Rewards Guide ​

Rewards are the bonus/incentive engine. Users receive tangible benefits (bonus balance, discounts, better profit splits) either from achievement links, standalone reward rules, or manual operator grants.

The rewards system operates independently from achievements. See Achievements Guide for the badge system.


Table of Contents ​


Quick Start ​

With Challenges (full mode) ​

  1. Create reward rules in the backoffice (Reward Rules page)
  2. Users earn rewards automatically when criteria are met
  3. Rewards apply on next challenge purchase or funded account creation
  4. Widget shows pending rewards in the Rewards tab

Without Challenges (engagement-only mode) ​

  1. Create reward rules with standalone types (free_bet, bonus_credit, cashback_credit, loyalty_points, custom)
  2. Users earn rewards from bet activity (missions, achievements, rules)
  3. FAST emits reward.granted webhook to your backend
  4. Your backend credits the reward in your sportsbook (free bet, bonus balance, etc.)
  5. Widget shows earned rewards in the Rewards tab

No code changes needed for either mode. No achievement required.


Availability ​

Rewards are available on Growth and Enterprise plans. Independent from achievements - you can have rewards without badges, or both.

achievementsrewardsWhat happens
offoffNothing
onoffBadges only. Achievement-linked rewards are NOT granted.
offonReward rules fire. No badges. Pure bonus engine.
ononFull: badges + reward rules + achievement-linked rewards

How It Works ​

Reward rules are evaluated on every lifecycle event (bet placed, settled, challenge completed, etc.). When a user meets the criteria for a rule, a pending reward is granted and a reward.granted webhook fires.

Pending rewards are consumed automatically at the next relevant action:

  • On challenge purchase: balance bonuses, discounts, and extended duration are applied.
  • On funded account creation: profit split boosts and payout cap boosts are applied.

When rewards are consumed, a reward.applied webhook fires. Reward consumption is atomic - if the purchase or creation fails, rewards remain pending.


Two Ways to Trigger Rewards ​

1. Reward Rules (standalone, no achievement needed) ​

Reward rules have their own criteria. When criteria are met, the reward is granted directly. No badge, no points. Just the bonus.

json
POST /v1/admin/reward-rules
{
  "name": "10 Bets Bonus",
  "criteria": { "type": "bets_placed", "threshold": 10 },
  "rewardType": "balance_bonus",
  "rewardValue": 10,
  "applyMode": "auto",
  "maxGrantsPerUser": 1
}

This means: "When a user places 10 bets, give them 10 EUR bonus on their next challenge. One time only."

2. Achievement-linked rewards ​

Add a reward field to an achievement. When the achievement is earned, the reward is auto-granted.

json
POST /v1/admin/achievements
{
  "code": "streak_7",
  "criteria": { "type": "streak_days", "threshold": 7 },
  "reward": { "type": "balance_bonus", "value": 10, "apply_mode": "auto" }
}

3. Manual grants (promotions, support, campaigns) ​

json
POST /v1/admin/rewards/grant
{ "userId": "player-42", "rewardType": "purchase_discount_percent", "value": 20, "expiresInDays": 7 }

Or bulk:

json
POST /v1/admin/rewards/bulk-grant
{ "userIds": ["p1","p2","p3"], "rewardType": "balance_bonus", "value": 5, "applyMode": "claim" }

Reward Types ​

Challenge-Coupled (require challenges module) ​

TypeEffectValue meaningConsumed when
balance_bonus+EUR to starting balanceEUR (e.g., 10 = +10 EUR)Next challenge purchase
balance_boost_percent+% to current active balance% (e.g., 5 = +5%)Immediately on grant/claim
purchase_discount_percent% off purchase price% (e.g., 15 = 15% off)Next challenge purchase
purchase_discount_fixedFlat EUR off purchaseEUR (e.g., 5 = -5 EUR)Next challenge purchase
profit_split_boostBetter user share on funded account% points (e.g., 2 = 80/20 becomes 82/18)Next funded account
extended_durationExtra days on challengeDays (e.g., 5 = +5 days)Next challenge purchase
payout_cap_boost_percentHigher payout cap% points (e.g., 10 = 50% becomes 60%)Next funded account
payout_bonus_percentBonus on top of a payout, paid by you% of the payout (e.g., 10 = +40 EUR on a 400 EUR payout)Next executed payout (a rejected one leaves it pending)

payout_bonus_percent does not touch the balance or the profit split: the user receives userPayout + ownStakeReturned + rewardBonus, and rewardBonus appears in the payout response, the funded_account.payout webhook and the payout request record.

If challenges are disabled or user has no challenge: these rewards accumulate as pending and apply when/if a challenge is eventually purchased. They never expire (unless expiresInDays is set).

Standalone (no challenge dependency) ​

These work without the challenges module. FAST grants the reward and emits a reward.granted webhook. The operator fulfills it on their side (credits the free bet, adds balance, etc.).

TypeEffectValue meaningFulfillment
free_betFree bet creditEUR amount (e.g., 5 = 5 EUR free bet)Operator via webhook
bonus_creditBonus added to sportsbook balanceEUR cents (e.g., 1000 = 10 EUR)Operator via webhook
cashback_creditCashback returned to playerEUR cents (e.g., 500 = 5 EUR)Operator via webhook
loyalty_pointsPoints added to loyalty balancePoints count (e.g., 500 = +500 pts)FAST loyalty engine
customOperator-defined (merch, VIP, etc.)Operator-defined meaningOperator via webhook

Example webhook for standalone reward:

json
{
  "eventType": "reward.granted",
  "userId": "player-42",
  "data": {
    "rewardId": "uuid",
    "rewardType": "free_bet",
    "rewardValue": 500,
    "applyMode": "auto",
    "achievementId": null
  }
}

The operator receives this and credits the free bet in their sportsbook. FAST marks the reward as consumed immediately (auto mode) since fulfillment is external.


Apply Modes ​

ModeBehaviorBest for
autoSilent. Applies on next action. For balance_boost_percent, applies immediately.Background loyalty perks
claimUser sees it in widget, must click "Claim".Engagement, visible incentives

Expiry and Stacking ​

Expiry: Set expiresInDays (or expires_in_days in rule). null = never expires.

Stacking: Multiple rewards of the same type accumulate. Two purchase_discount_percent rewards (10% + 15%) = 25% off. Total discount capped at purchase price.


How Rewards Are Consumed ​

During challenge purchase (atomic, same transaction):

  1. Pending rewards are loaded and locked
  2. Applied: add to balance, subtract from price, extend duration
  3. Each reward is marked as consumed (with reference to the challenge)
  4. reward.applied webhook fires

During funded account creation (atomic, same transaction):

  1. Pending rewards are loaded and locked
  2. Applied: boost profit split, boost payout cap
  3. Each reward is marked as consumed
  4. reward.applied webhook fires

If the purchase or creation fails (rollback), rewards are NOT consumed. The operation is atomic.


Criteria Types (for Reward Rules) ​

Same as achievements. Full list:

TypeMeasuresThresholdTriggered by
bets_placedTotal accepted betsCountEvery bet
bets_wonWon betsCountSettlement
streak_daysCurrent consecutive daysDaysBet placement
longest_streakBest-ever streakDaysBet placement
challenges_completedCompleted challengesCountCompletion
challenges_failedFailed challengesCountFailure
first_withdrawalHas withdrawn1Withdrawal
total_wageredCumulative stake (cents)CentsEvery bet
odds_aboveHighest odds placedDecimalEvery bet
odds_won_aboveHighest odds of a winning slipDecimalSettlement
win_streakWinning slips in a row, in the order FAST recorded the results; a loss resets it, a void is skippedCountSettlement
clean_daysDistinct betting days after the day whose losses last triggered a cooldown (all betting days if there never was one)DaysEvery bet
active_daysDistinct active daysCountEvery bet
funded_accountHas funded account1Creation
win_rateWin % (min 10 bets)0-100Settlement
total_profitTotal EUR withdrawnEURWithdrawal
comebackFailed N then completedFailuresCompletion

API Reference ​

Reward Rules (operator) ​

MethodEndpointPurpose
GET/v1/admin/reward-rulesList all reward rules
POST/v1/admin/reward-rulesCreate a rule
PUT/v1/admin/reward-rules/:idUpdate a rule
DELETE/v1/admin/reward-rules/:idDelete a rule

Reward Management (operator) ​

MethodEndpointPurpose
GET/v1/admin/rewards?userId=XPending rewards for user
GET/v1/admin/rewards/history?userId=XApplied reward history
POST/v1/admin/rewards/grantGrant single reward
POST/v1/admin/rewards/bulk-grantGrant to multiple users (max 500)
DELETE/v1/admin/rewards/:idRevoke pending reward

Public (widget key) ​

MethodEndpointPurpose
GET/v1/users/:userId/rewardsPending + claimable rewards
POST/v1/users/:userId/rewards/:id/claimClaim a claim-mode reward

Widget Display ​

"Rewards" tab (gift icon):

  • Claimable - gold border, claim button, expiry countdown
  • Active - auto-mode rewards pending next action, "Auto" badge
  • Rewards you can earn - enabled rules the user has not yet earned, with progress (e.g. 3/5)

When a reward is granted while the widget is open, it announces it: confetti and a card naming the reward, with a button to the Rewards tab (above the closed launcher, or at the top of the open panel). It listens for the reward.granted SSE event, so nothing needs wiring; onEvent also receives reward.granted with rewardType and rewardValue.

The funded account card says what rewards did there: "Includes +3% from a reward" when a profit_split_boost raised its split, "+10% reward bonus on the next payout" while a payout_bonus_percent waits, and the bonus amount on a pending and an executed payout. The progress endpoint carries these as profitSplitRewardBoost, payoutBonusPercent and lastPayoutRequest.rewardBonus.


"10 bets = 10 EUR bonus" (no achievement needed) ​

json
POST /v1/admin/reward-rules
{
  "name": "10 Bets Welcome Bonus",
  "criteria": { "type": "bets_placed", "threshold": 10 },
  "rewardType": "balance_bonus",
  "rewardValue": 10,
  "applyMode": "auto",
  "maxGrantsPerUser": 1
}

User places 10th bet. Next challenge purchase: starts with 60 EUR instead of 50 EUR.

"7-day streak = 15% off next purchase" ​

json
POST /v1/admin/reward-rules
{
  "name": "Streak Discount",
  "criteria": { "type": "streak_days", "threshold": 7 },
  "rewardType": "purchase_discount_percent",
  "rewardValue": 15,
  "applyMode": "claim",
  "expiresInDays": 14,
  "maxGrantsPerUser": null
}

maxGrantsPerUser: null = repeatable. Every time user hits a 7-day streak, they get 15% off. Must claim within 14 days.

"Complete a challenge = better profit split" ​

json
POST /v1/admin/reward-rules
{
  "name": "Champion Split",
  "criteria": { "type": "challenges_completed", "threshold": 1 },
  "rewardType": "profit_split_boost",
  "rewardValue": 2,
  "applyMode": "auto",
  "maxGrantsPerUser": 1
}

First challenge completion: funded account gets 82/18 instead of 80/20.

"High roller bonus" ​

json
POST /v1/admin/reward-rules
{
  "name": "High Roller Boost",
  "criteria": { "type": "total_wagered", "threshold": 100000 },
  "rewardType": "balance_boost_percent",
  "rewardValue": 10,
  "applyMode": "auto",
  "maxGrantsPerUser": 1
}

1000 EUR wagered total: immediate +10% boost to current balance.

"Comeback kid bonus" ​

json
POST /v1/admin/reward-rules
{
  "name": "Comeback Bonus",
  "criteria": { "type": "comeback", "threshold": 2 },
  "rewardType": "purchase_discount_fixed",
  "rewardValue": 25,
  "applyMode": "claim",
  "expiresInDays": 30,
  "maxGrantsPerUser": 1
}

Failed 2 challenges but completed one: 25 EUR off next purchase. Rewards persistence.

"Sharpshooter bonus" ​

json
POST /v1/admin/reward-rules
{
  "name": "Sharpshooter Perk",
  "criteria": { "type": "win_rate", "threshold": 65 },
  "rewardType": "extended_duration",
  "rewardValue": 5,
  "applyMode": "auto",
  "maxGrantsPerUser": 1
}

65%+ win rate (after 10+ bets): +5 extra days on next challenge. Rewards skill.

"Summer promo for all users" (manual, no criteria) ​

json
POST /v1/admin/rewards/bulk-grant
{
  "userIds": ["player-1", "player-2", "player-3"],
  "rewardType": "purchase_discount_percent",
  "value": 20,
  "applyMode": "claim",
  "expiresInDays": 7
}

20% off for 7 days. Claim required. No rule, no achievement - just a campaign.


Webhooks ​

reward.granted ​

Fires when a reward is created (rule trigger, achievement link, or manual):

json
{
  "eventType": "reward.granted",
  "userId": "player-42",
  "data": {
    "rewardId": "uuid",
    "rewardType": "balance_bonus",
    "rewardValue": 10,
    "applyMode": "auto",
    "expiresAt": "2026-07-03T14:30:00Z"
  }
}

reward.applied ​

Fires when rewards are consumed during purchase/creation:

json
{
  "eventType": "reward.applied",
  "userId": "player-42",
  "data": {
    "appliedTo": "challenge-uuid",
    "context": "challenge_purchase",
    "rewards": [
      { "rewardType": "balance_bonus", "rewardValue": 10, "effect": "+10 EUR starting balance" }
    ],
    "adjustedStartingBalance": 60,
    "adjustedDurationDays": 25
  }
}

Use reward.granted to notify users ("You earned a bonus!"). Use reward.applied to adjust your payment collection if discounts were applied.


Limitations ​

  • Reward rules evaluate on every lifecycle event. With unlimited maxGrantsPerUser, a rule fires on every event once criteria are met. Use maxGrantsPerUser: 1 for one-time bonuses.
  • payout_cap_boost_percent is NOT consumed if the funded account has no cap. It stays pending.
  • balance_boost_percent in auto mode applies immediately if there's an active account. If not, stays pending.
  • Consumed rewards cannot be revoked. Only pending (unconsumed) rewards can be deleted.
  • Total discount (percent + fixed) is capped at the purchase price. No negative prices.
  • win_rate requires 10+ bets before it fires. Prevents false positives on 2/2 wins.

Support ​

BLACKLINE CONSULTING d.o.o.