Phoenix Gamification
Rewards

Reward Grants API

Phoenix tracks all reward grants across features in ClickHouse for analytics and user-facing queries. Users can see their complete reward history regardless of source (coupons, leaderboards, streaks, achievements, purchases).

Reward Grants API

Phoenix tracks all reward grants across features in ClickHouse for analytics and user-facing queries. This allows users to see their complete reward history regardless of the source (coupons, leaderboards, streaks, achievements, purchases).

Overview

When a reward is granted to a user, Phoenix records it in ClickHouse with full details:

  • Source tracking: Which feature granted the reward (coupon, leaderboard, streak, achievement, purchase)
  • Item details: The actual reward item with its payload
  • Context: Additional information like coupon code, leaderboard window, streak milestone, achievement ID
  • Timing: When the reward was granted

Achievement Rewards: When an achievement is completed, if it has a reward_id configured, the reward is automatically granted through the rewards service. The reward order is created immediately upon completion, and fulfillment (wallet currency, badges, manual, or API) is handled automatically. See Achievement Types and Configuration for details.

Client Endpoints

Query Gateway uses JWT only; paths do not include tenant_id. User-facing reward/order history is available via the orders API.

Get User's Order History (Reward / Grant History)

Retrieve orders and reward history for a user:

GET /v1/orders/user/{user_id}
Authorization: Bearer <JWT>

For a single order: GET /v1/orders/user/{user_id}/{order_id}.

Query Parameters:

ParameterTypeDescription
source_typestringFilter by source: coupon, leaderboard, streak, achievement, wheel
source_idstringFilter by specific source ID (e.g., leaderboard_id)
fromISO 8601 datetimeFilter grants after this time
toISO 8601 datetimeFilter grants before this time
limitintegerPage size (default: 50, max: 100)
offsetintegerPage offset (default: 0)

Response:

{
  "grants": [
    {
      "grant_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "grant_time": "2025-01-04T10:30:00Z",
      "user_id": "user_123",
      "source_type": "leaderboard",
      "source_id": "weekly-leaderboard",
      "source_name": "Weekly Top Players",
      "source_context": "2025-W01",
      "item_id": "item_gems_1000",
      "item_name": "1000 Gems",
      "reward_type": "currency",
      "payload": {
        "currency": "gems",
        "amount": 1000
      },
      "metadata": {
        "rank": 1,
        "score": 50000,
        "tier_name": "gold"
      }
    },
    {
      "grant_id": "b2c3d4e5-6789-01bc-def2-3456789012bc",
      "grant_time": "2025-01-03T15:45:00Z",
      "user_id": "user_123",
      "source_type": "coupon",
      "source_id": "def_abc123",
      "source_name": "New Year Bonus",
      "source_context": "NEWYEAR2025",
      "item_id": "item_coins_500",
      "item_name": "500 Coins",
      "reward_type": "currency",
      "payload": {
        "currency": "coins",
        "amount": 500
      },
      "metadata": {
        "coupon_id": "coupon_xyz",
        "redeemed_at": "2025-01-03T15:45:00Z"
      }
    }
  ],
  "total": 25,
  "limit": 50,
  "offset": 0
}

Get User's Grant Summary

If your deployment exposes a grants summary endpoint (e.g. GET /v1/rewards/user/{user_id}/summary), it returns a quick summary by source type. Otherwise derive summary from order history (GET /v1/orders/user/{user_id}).

Response:

{
  "total_grants": 25,
  "by_source": [
    { "source_type": "leaderboard", "count": 12 },
    { "source_type": "coupon", "count": 8 },
    { "source_type": "streak", "count": 5 }
  ]
}

Get Grants by Source Type

If available, filter grants to a specific source type (e.g. GET /v1/rewards/user/{user_id}?source_type=wheel). Otherwise filter order history client-side by order metadata. source_type may be one of: coupon, leaderboard, streak, achievement, wheel.

Response: Same shape as order/grants list (order_id, status, reward details, etc.).

JavaScript Example

// Fetch user's order/reward history (Query Gateway)
async function getUserOrders(userId, options = {}) {
  const params = new URLSearchParams(options);
  
  const response = await fetch(
    `${QUERY_API_URL}/v1/orders/user/${userId}?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${jwt}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return response.json();
}

// Get single order
async function getUserOrder(userId, orderId) {
  const response = await fetch(
    `${QUERY_API_URL}/v1/orders/user/${userId}/${orderId}`,
    {
      headers: {
        'Authorization': `Bearer ${jwt}`,
        'Content-Type': 'application/json'
      }
    }
  );
  return response.json();
}

// Example: Display order/reward history in UI
const ordersResponse = await getUserOrders('user_123', { limit: 20 });

ordersResponse.orders?.forEach(order => {
  console.log(`${order.created_at}: Order ${order.id} — ${order.status}`);
});

Source Types

SourceDescriptionContext Field Contains
couponReward from coupon redemptionCoupon code
leaderboardReward from leaderboard placementWindow key (e.g., "2025-W01")
streakReward from streak milestoneMilestone threshold
achievementReward from achievement completionAchievement definition ID
wheelReward from spin-the-wheelWheel name
purchaseReward bought from storeOrder ID
adminReward granted by adminGrant reference
promotionReward from promotional campaignCampaign ID

Admin / Analytics Endpoints

Analytics or grant-listing endpoints (e.g. GET /v1/analytics/grants?tenant_id=${tenant_id}) may be available on the Admin Gateway or a separate analytics service depending on deployment. Use Admin JWT or API key; paths include tenant_id where applicable.

Grant statistics and per-tenant analytics (e.g. GET /v1/analytics/grants/stats?tenant_id=${tenant_id} or per-user grant lists) depend on your deployment. Use the Admin API or analytics service documentation for exact paths and response shapes.

Best Practices

  1. Pagination: Always use limit and offset for large result sets
  2. Filtering: Use source_type to reduce result sets when showing specific reward categories
  3. Caching: Consider caching the summary endpoint as it's commonly used for UI badges
  4. Time range: For recent rewards, use from parameter to limit the query scope

Next Steps

On this page