Rewards
Rewards are the tangible prizes users receive for achievements, milestones, and competition victories. Phoenix separates what you give (Reward Items) from when you give it (Reward Configs and feature triggers).
Rewards
Rewards are the tangible prizes users receive for achievements, milestones, and competition victories. Phoenix provides a flexible reward system that separates what you give (Reward Items) from when you give it (Reward Configs and feature triggers).
🛒 Looking for the Rewards Store?
If you want to let users spend their points to purchase prizes, see the Rewards Store Guide. This page covers the reward system for automatic distribution through leaderboards, streaks, and achievements.
1. Core Concepts
Reward Items
Reward Items are standalone, reusable definitions of what a user receives. They live in the reward_items table and can be referenced by:
- Coupons: Each coupon definition links to a
reward_item_id - Reward Configs: Tiers reference items by
item_ids - Leaderboards, Streaks, Achievements: Via attached reward configs
Reward Configs
Reward Configs define the conditions for when rewards are distributed (rank ranges, milestones, thresholds). They contain tiers that reference reward items.
Feature Integration
| Feature | How Rewards Work |
|---|---|
| Coupons | Each coupon definition has a reward_item_id - users get the item when they redeem |
| Leaderboards | Attach a reward_config_id - distribute items when window completes based on rank |
| Streaks | Attach a reward_config_id - distribute items when milestones are reached |
| Achievements | Attach a reward_config_id - distribute items when achievements complete |
2. Reward Items API
Create a Reward Item
Endpoint
POST /v1/reward-items?tenant_id=${tenant_id}Request Body
{
"name": "1000 Gems",
"description": "Premium currency bundle",
"reward_type": "currency",
"payload": {
"currency_id": "gems",
"amount": 1000
}
}Response
{
"item_id": "550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "your-tenant-id",
"name": "1000 Gems",
"description": "Premium currency bundle",
"reward_type": "currency",
"payload": {"currency_id": "gems", "amount": 1000},
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}Save the item_id - you'll use it when creating coupons or reward configs.
Reward Types
The reward_type field is flexible - use any string that makes sense for your fulfillment pipeline:
| Type | Description | Example Payload |
|---|---|---|
currency | In-game currency | {"currency_id": "gems", "amount": 1000} |
item | Virtual item/consumable | {"item_id": "legendary_chest", "quantity": 1} |
xp | Experience points | {"amount": 5000} |
badge | Achievement badge | {"badge_id": "top_player_2025"} |
physical_item | Physical prize | {"model": "iPhone 15 Pro", "shipping_required": true} |
custom | Any custom reward | {"your": "custom", "data": "here"} |
Managing Reward Items
| Action | Endpoint | Method |
|---|---|---|
| List items | /v1/reward-items?tenant_id=${tenant_id} | GET |
| Get item | /v1/reward-items/{item_id}?tenant_id=${tenant_id} | GET |
| Create item | /v1/reward-items?tenant_id=${tenant_id} | POST |
| Update item | /v1/reward-items/{item_id}?tenant_id=${tenant_id} | PUT |
| Delete item | /v1/reward-items/{item_id}?tenant_id=${tenant_id} | DELETE |
3. Using Reward Items with Coupons
The simplest integration is with coupons. Each coupon definition specifies which reward item users receive upon redemption.
Step 1: Create the Reward Item
POST /v1/reward-items?tenant_id=${tenant_id}{
"name": "Welcome Bonus - 500 Coins",
"description": "Coins granted to new users",
"reward_type": "currency",
"payload": {
"currency_id": "coins",
"amount": 500
}
}Response: item_id: "reward-item-001"
Step 2: Create a Coupon Definition
POST /v1/coupons?tenant_id=${tenant_id}{
"name": "Welcome Bonus Coupon",
"description": "New user welcome gift",
"config": {
"reward_item_id": "reward-item-001",
"code_format": "random",
"code_prefix": "WELCOME",
"code_length": 8,
"usage_limit": {
"limit_type": "per_user",
"max_uses": 1
}
}
}Step 3: User Redeems Coupon
When a user redeems the coupon, the response includes the reward item details:
{
"code": "WELCOME8X4F2K9P",
"status": "redeemed",
"reward_item": {
"item_id": "reward-item-001",
"name": "Welcome Bonus - 500 Coins",
"reward_type": "currency",
"payload": {"currency_id": "coins", "amount": 500}
}
}Your application then fulfills the reward (adds 500 coins to the user's account).
4. Reward Configs for Leaderboards
For leaderboards, you create a Reward Config that maps rank ranges to reward items. The config is attached to leaderboard definitions.
Step 1: Create Reward Items
Create items for each prize tier:
# First place prize
POST /v1/reward-items?tenant_id=${tenant_id}
{
"name": "Champion's Crown",
"reward_type": "badge",
"payload": {"badge_id": "weekly_champion"}
}
# Response: item_id: "crown-item-001"
# Top 10 prize
POST /v1/reward-items?tenant_id=${tenant_id}
{
"name": "5000 Gems",
"reward_type": "currency",
"payload": {"currency_id": "gems", "amount": 5000}
}
# Response: item_id: "gems-5000-item"
# Top 100 prize
POST /v1/reward-items?tenant_id=${tenant_id}
{
"name": "1000 Gems",
"reward_type": "currency",
"payload": {"currency_id": "gems", "amount": 1000}
}
# Response: item_id: "gems-1000-item"Step 2: Create Reward Config
For reward catalog entries (store items, etc.), use the rewards catalog. For leaderboard tier configs, the config is typically part of the leaderboard or a dedicated config API:
POST /v1/rewards-catalog?tenant_id=${tenant_id}{
"name": "Weekly Top 100 Rewards",
"description": "Rewards for weekly leaderboard winners",
"tiers": [
{
"condition": {
"type": "rank_range",
"start": 1,
"end": 1
},
"item_ids": ["crown-item-001", "gems-5000-item"]
},
{
"condition": {
"type": "rank_range",
"start": 2,
"end": 10
},
"item_ids": ["gems-5000-item"]
},
{
"condition": {
"type": "rank_range",
"start": 11,
"end": 100
},
"item_ids": ["gems-1000-item"]
}
]
}Response: config_id: "weekly-top100-config"
Step 3: Attach to Leaderboard
POST /v1/leaderboards?tenant_id=${tenant_id}{
"leaderboard_id": "xp-weekly-global",
"name": "Global Weekly XP",
"reward_config_id": "weekly-top100-config",
"config": {
"timeframe": {
"type": "weekly",
"timezone": "UTC",
"reset_day": "monday"
}
}
}Step 4: Window Completion
When the weekly window completes, Phoenix:
- Finalizes standings (top 1000 users)
- Matches each user's rank to reward tiers
- Sends webhook with reward distribution:
{
"event_type": "leaderboard.window_completed",
"tenant_id": "your-tenant-id",
"leaderboard_id": "xp-weekly-global",
"window_key": "2025-W02",
"completed_at": "2025-01-13T00:00:02Z",
"reward_distribution": [
{
"user_id": "user-123",
"rank": 1,
"score": 12850,
"items": [
{
"item_id": "crown-item-001",
"name": "Champion's Crown",
"reward_type": "badge",
"payload": {"badge_id": "weekly_champion"}
},
{
"item_id": "gems-5000-item",
"name": "5000 Gems",
"reward_type": "currency",
"payload": {"currency_id": "gems", "amount": 5000}
}
]
},
{
"user_id": "user-456",
"rank": 2,
"score": 12510,
"items": [
{
"item_id": "gems-5000-item",
"name": "5000 Gems",
"reward_type": "currency",
"payload": {"currency_id": "gems", "amount": 5000}
}
]
}
]
}5. Rank-Specific Rewards
For different prizes at each rank position, use rank_items instead of item_ids:
{
"name": "Top 3 Physical Prizes",
"description": "Different devices for top 3 players",
"tiers": [
{
"condition": {
"type": "rank_range",
"start": 1,
"end": 3
},
"rank_items": {
"1": ["macbook-item"],
"2": ["iphone-item"],
"3": ["samsung-item"]
}
}
]
}Result:
- Rank 1 → MacBook Pro
- Rank 2 → iPhone 15 Pro
- Rank 3 → Samsung Galaxy S24
6. Reward Config Condition Types
| Condition | Works With | Example |
|---|---|---|
rank_range | Leaderboards | Top 10 players get rewards |
threshold_range | Streaks, Scores | 7-14 day streaks get rewards |
milestone | Progression, Levels | Reaching level 20 triggers reward |
custom | Any feature | Advanced JSON-based rules |
Examples
Rank Range (Leaderboards)
{
"type": "rank_range",
"start": 1,
"end": 10
}Threshold Range (Streaks)
{
"type": "threshold_range",
"metric": "streak_days",
"min": 7,
"max": 14
}Milestone (Exact Value)
{
"type": "milestone",
"metric": "streak_days",
"value": 30
}7. Managing Reward Configs
| Action | Endpoint | Method |
|---|---|---|
| List catalog | /v1/rewards-catalog?tenant_id=${tenant_id} | GET |
| Get reward | /v1/rewards-catalog/{reward_id}?tenant_id=${tenant_id} | GET |
| Create | /v1/rewards-catalog?tenant_id=${tenant_id} | POST |
| Update | /v1/rewards-catalog/{reward_id}?tenant_id=${tenant_id} | PUT |
| Delete | /v1/rewards-catalog/{reward_id}?tenant_id=${tenant_id} | DELETE |
8. Best Practices
Create a Reward Item Library
Build a library of reusable reward items:
// Good: Reusable items
{"name": "100 Gems", "reward_type": "currency", ...}
{"name": "500 Gems", "reward_type": "currency", ...}
{"name": "1000 Gems", "reward_type": "currency", ...}
{"name": "Weekly Champion Badge", "reward_type": "badge", ...}Then reference them in multiple configs and coupons.
Use Descriptive Names
{
"name": "Q1 2025 Tournament - Top 10 Rewards",
"description": "Prizes for Winter 2025 tournament top performers"
}Test Before Production
- Create reward items and configs on staging
- Attach to test features (coupons, leaderboards)
- Verify webhook payloads match expectations
- Deploy to production
Monitor Fulfillment
Ensure your webhook endpoint:
- Returns
200 OKquickly (< 5 seconds) - Handles duplicate deliveries (idempotent)
- Logs all reward distributions for audit
9. Webhook Integration
Configure your tenant's webhook URL to receive reward distribution events:
| Event Type | Triggered When |
|---|---|
leaderboard.window_completed | Leaderboard window ends |
streak.milestone_reached | User hits streak milestone |
achievement.completed | User completes achievement |
coupon.redeemed | User redeems coupon |
All events include full reward item details for fulfillment.
Next Steps
- Rewards Store - Let users purchase rewards with points
- Redeeming Coupons - Use reward items with coupons
- Creating Leaderboards - Attach reward configs to leaderboards
- Creating Streaks - Attach reward configs to streaks