Rewards Block

Loyalty, Gamification & Engagement API
The Rewards Block provides a complete loyalty and gamification infrastructure for your applications. Build points systems, loyalty tiers, badge achievements, coupon campaigns, referral programs, and reward redemption - all through a simple, unified API.
Why Rewards Block?
Building engagement and loyalty features from scratch requires:
- Complex points accounting with transaction history
- Flexible tier progression algorithms
- Badge unlock conditions and achievement tracking
- Coupon generation with usage limits and expiration
- Referral attribution and multi-level tracking
- Secure reward redemption with inventory management
The Rewards Block handles all of this, letting you focus on creating engaging user experiences.
Core Concepts
| Concept | Description |
|---|---|
| Points | Virtual currency users earn through actions |
| Tiers | Loyalty levels with escalating benefits |
| Badges | Visual achievements for milestones |
| Coupons | Discount codes with rules and limits |
| Referrals | Tracking and rewarding user invitations |
| Rewards | Redeemable items in your reward catalog |
API Endpoint
| Service | URL |
|---|---|
| Rewards | https://rewards.api.us.23blocks.com |
Environment Routing: Use the same URL for all environments. Your API key determines the environment:
pk_test_*/sk_test_*→ Routes to Stagingpk_live_*/sk_live_*→ Routes to Production
Quick Start
npm install @23blocks/sdk
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { rewards: 'https://rewards.api.us.23blocks.com' },
apiKey: 'your-api-key', // Use pk_test_* for staging, pk_live_* for production
});
// Award points for a purchase
await client.rewards.awardPoints({
userId: 'user-123',
amount: 150,
action: 'purchase',
metadata: { orderId: 'order-456' }
});
// Get user's points balance
const balance = await client.rewards.getBalance('user-123');
console.log(`User has ${balance.data.attributes.available} points`);
// Redeem a reward
await client.rewards.redeem({
userId: 'user-123',
rewardId: 'reward-789',
pointsCost: 500
});
Points API
Points are the foundation of your loyalty program. Users earn points through actions and redeem them for rewards.
Points Object
{
"data": {
"id": "points-txn-abc123",
"type": "points-transaction",
"attributes": {
"user-id": "user-123",
"amount": 150,
"type": "credit",
"action": "purchase",
"balance-after": 1250,
"description": "Points earned from order #456",
"metadata": {
"order-id": "order-456",
"amount": 75.00
},
"expires-at": "2027-01-01T00:00:00Z",
"created-at": "2026-01-02T10:30:00Z"
}
}
}
Award Points
Award points to a user for completing an action.
POST /v1/rewards/points/award
Request Body:
{
"data": {
"type": "points-award",
"attributes": {
"user-id": "user-123",
"amount": 150,
"action": "purchase",
"description": "Points for order #456",
"metadata": {
"order-id": "order-456"
},
"expires-in-days": 365
}
}
}
Response: 201 Created
{
"data": {
"id": "points-txn-abc123",
"type": "points-transaction",
"attributes": {
"user-id": "user-123",
"amount": 150,
"type": "credit",
"action": "purchase",
"balance-after": 1250,
"expires-at": "2027-01-02T10:30:00Z",
"created-at": "2026-01-02T10:30:00Z"
}
}
}
Deduct Points
Deduct points from a user's balance (for redemptions or adjustments).
POST /v1/rewards/points/deduct
Request Body:
{
"data": {
"type": "points-deduction",
"attributes": {
"user-id": "user-123",
"amount": 500,
"reason": "reward_redemption",
"description": "Redeemed for $5 discount",
"reference-id": "redemption-789"
}
}
}
Get Points Balance
Retrieve a user's current points balance.
GET /v1/rewards/points/balance/{user_id}
Response: 200 OK
{
"data": {
"id": "balance-user-123",
"type": "points-balance",
"attributes": {
"user-id": "user-123",
"total-earned": 5000,
"total-spent": 2500,
"total-expired": 250,
"available": 2250,
"pending": 100,
"expiring-soon": 500,
"expiring-soon-date": "2026-02-01T00:00:00Z",
"lifetime-value": 5000,
"updated-at": "2026-01-02T10:30:00Z"
}
}
}
List Points History
Get a user's points transaction history.
GET /v1/rewards/points/history/{user_id}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page[number] | integer | Page number (default: 1) |
page[size] | integer | Items per page (default: 20, max: 100) |
filter[type] | string | Filter by transaction type: credit, debit |
filter[action] | string | Filter by action type |
filter[from] | datetime | Start date for range |
filter[to] | datetime | End date for range |
Response: 200 OK
{
"data": [
{
"id": "points-txn-abc123",
"type": "points-transaction",
"attributes": {
"amount": 150,
"type": "credit",
"action": "purchase",
"balance-after": 1250,
"created-at": "2026-01-02T10:30:00Z"
}
}
],
"meta": {
"total-count": 45,
"page-count": 3
}
}
Configure Points Rules
Set up earning rules for automatic points awards.
POST /v1/rewards/points/rules
Request Body:
{
"data": {
"type": "points-rule",
"attributes": {
"name": "Purchase Points",
"action": "purchase",
"points-formula": "amount * 2",
"description": "Earn 2 points per dollar spent",
"conditions": {
"min-amount": 10,
"max-points": 1000
},
"multipliers": {
"weekend": 1.5,
"holiday": 2.0
},
"active": true
}
}
}
Tiers API
Loyalty tiers reward your most engaged customers with escalating benefits.
Tier Object
{
"data": {
"id": "tier-gold",
"type": "loyalty-tier",
"attributes": {
"name": "Gold",
"slug": "gold",
"level": 2,
"points-required": 5000,
"points-multiplier": 1.5,
"benefits": [
"15% bonus points on all purchases",
"Early access to sales",
"Free shipping on orders over $25"
],
"badge-image-url": "https://cdn.23blocks.com/badges/gold-tier.png",
"color": "#FFD700",
"member-count": 1250,
"created-at": "2025-01-01T00:00:00Z"
}
}
}
List Tiers
Retrieve all loyalty tiers.
GET /v1/rewards/tiers
Response: 200 OK
{
"data": [
{
"id": "tier-bronze",
"type": "loyalty-tier",
"attributes": {
"name": "Bronze",
"level": 0,
"points-required": 0,
"points-multiplier": 1.0
}
},
{
"id": "tier-silver",
"type": "loyalty-tier",
"attributes": {
"name": "Silver",
"level": 1,
"points-required": 1000,
"points-multiplier": 1.25
}
},
{
"id": "tier-gold",
"type": "loyalty-tier",
"attributes": {
"name": "Gold",
"level": 2,
"points-required": 5000,
"points-multiplier": 1.5
}
},
{
"id": "tier-platinum",
"type": "loyalty-tier",
"attributes": {
"name": "Platinum",
"level": 3,
"points-required": 15000,
"points-multiplier": 2.0
}
}
]
}
Create Tier
Create a new loyalty tier.
POST /v1/rewards/tiers
Request Body:
{
"data": {
"type": "loyalty-tier",
"attributes": {
"name": "Diamond",
"slug": "diamond",
"level": 4,
"points-required": 50000,
"points-multiplier": 3.0,
"benefits": [
"Triple points on all purchases",
"Personal account manager",
"Exclusive products access",
"Free express shipping"
],
"color": "#B9F2FF"
}
}
}
Get User Tier
Get a user's current tier and progress.
GET /v1/rewards/tiers/user/{user_id}
Response: 200 OK
{
"data": {
"id": "user-tier-123",
"type": "user-tier-status",
"attributes": {
"user-id": "user-123",
"current-tier": {
"id": "tier-gold",
"name": "Gold",
"level": 2
},
"next-tier": {
"id": "tier-platinum",
"name": "Platinum",
"level": 3,
"points-required": 15000
},
"qualifying-points": 8500,
"points-to-next-tier": 6500,
"progress-percentage": 56.67,
"tier-expires-at": "2026-12-31T23:59:59Z",
"points-to-maintain": 5000,
"tier-since": "2025-06-15T00:00:00Z"
}
}
}
Update User Tier
Manually upgrade or adjust a user's tier.
PATCH /v1/rewards/tiers/user/{user_id}
Request Body:
{
"data": {
"type": "user-tier-update",
"attributes": {
"tier-id": "tier-platinum",
"reason": "vip_promotion",
"expires-at": "2027-01-01T00:00:00Z"
}
}
}
Badges API
Badges are visual achievements that recognize user milestones and behaviors.
Badge Object
{
"data": {
"id": "badge-first-purchase",
"type": "badge",
"attributes": {
"name": "First Purchase",
"slug": "first-purchase",
"description": "Made your first purchase",
"category": "milestones",
"image-url": "https://cdn.23blocks.com/badges/first-purchase.png",
"points-reward": 50,
"rarity": "common",
"unlock-count": 15000,
"conditions": {
"action": "purchase",
"count": 1
},
"created-at": "2025-01-01T00:00:00Z"
}
}
}
List Badges
Retrieve all available badges.
GET /v1/rewards/badges
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
filter[category] | string | Filter by category |
filter[rarity] | string | Filter by rarity: common, uncommon, rare, epic, legendary |
Response: 200 OK
{
"data": [
{
"id": "badge-first-purchase",
"type": "badge",
"attributes": {
"name": "First Purchase",
"category": "milestones",
"rarity": "common",
"points-reward": 50
}
},
{
"id": "badge-streak-7",
"type": "badge",
"attributes": {
"name": "Week Warrior",
"category": "streaks",
"rarity": "uncommon",
"points-reward": 100
}
}
]
}
Create Badge
Create a new badge definition.
POST /v1/rewards/badges
Request Body:
{
"data": {
"type": "badge",
"attributes": {
"name": "Super Shopper",
"slug": "super-shopper",
"description": "Made 50 purchases",
"category": "milestones",
"image-url": "https://cdn.23blocks.com/badges/super-shopper.png",
"points-reward": 500,
"rarity": "rare",
"conditions": {
"action": "purchase",
"count": 50
}
}
}
}
Award Badge
Award a badge to a user.
POST /v1/rewards/badges/award
Request Body:
{
"data": {
"type": "badge-award",
"attributes": {
"user-id": "user-123",
"badge-id": "badge-super-shopper",
"reason": "Completed 50th purchase"
}
}
}
Response: 201 Created
{
"data": {
"id": "user-badge-abc123",
"type": "user-badge",
"attributes": {
"user-id": "user-123",
"badge-id": "badge-super-shopper",
"badge-name": "Super Shopper",
"points-awarded": 500,
"awarded-at": "2026-01-02T10:30:00Z"
}
}
}
Get User Badges
Retrieve badges earned by a user.
GET /v1/rewards/badges/user/{user_id}
Response: 200 OK
{
"data": [
{
"id": "user-badge-001",
"type": "user-badge",
"attributes": {
"badge-id": "badge-first-purchase",
"badge-name": "First Purchase",
"badge-image": "https://cdn.23blocks.com/badges/first-purchase.png",
"points-awarded": 50,
"awarded-at": "2025-06-01T10:00:00Z"
}
},
{
"id": "user-badge-002",
"type": "user-badge",
"attributes": {
"badge-id": "badge-streak-7",
"badge-name": "Week Warrior",
"badge-image": "https://cdn.23blocks.com/badges/week-warrior.png",
"points-awarded": 100,
"awarded-at": "2025-07-15T10:00:00Z"
}
}
],
"meta": {
"total-badges": 2,
"total-points-from-badges": 150
}
}
Get Badge Progress
Check a user's progress toward a specific badge.
GET /v1/rewards/badges/{badge_id}/progress/{user_id}
Response: 200 OK
{
"data": {
"id": "progress-badge-123-user-456",
"type": "badge-progress",
"attributes": {
"badge-id": "badge-super-shopper",
"badge-name": "Super Shopper",
"user-id": "user-456",
"target-count": 50,
"current-count": 32,
"progress-percentage": 64.0,
"earned": false,
"estimated-completion": "2026-04-15T00:00:00Z"
}
}
}
Coupons API
Create and manage discount coupons with flexible rules and usage limits.
Coupon Object
{
"data": {
"id": "coupon-summer25",
"type": "coupon",
"attributes": {
"code": "SUMMER25",
"name": "Summer Sale 25% Off",
"description": "25% off your entire order",
"discount-type": "percentage",
"discount-value": 25,
"min-order-amount": 50.00,
"max-discount-amount": 100.00,
"usage-limit": 1000,
"usage-count": 456,
"per-user-limit": 1,
"starts-at": "2026-06-01T00:00:00Z",
"expires-at": "2026-08-31T23:59:59Z",
"conditions": {
"categories": ["summer-collection"],
"new-customers-only": false
},
"active": true,
"created-at": "2026-05-15T00:00:00Z"
}
}
}
Create Coupon
Create a new coupon.
POST /v1/rewards/coupons
Request Body:
{
"data": {
"type": "coupon",
"attributes": {
"code": "NEWUSER20",
"name": "New User Welcome",
"description": "20% off your first order",
"discount-type": "percentage",
"discount-value": 20,
"min-order-amount": 25.00,
"usage-limit": null,
"per-user-limit": 1,
"expires-at": "2026-12-31T23:59:59Z",
"conditions": {
"new-customers-only": true
}
}
}
}
Discount Types:
| Type | Description | Example |
|---|---|---|
percentage | Percentage off | 25% off |
fixed | Fixed amount off | $10 off |
free_shipping | Free shipping | - |
buy_x_get_y | Buy X get Y free | Buy 2 get 1 free |
List Coupons
Retrieve all coupons.
GET /v1/rewards/coupons
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
filter[active] | boolean | Filter by active status |
filter[expires-after] | datetime | Filter by expiration date |
search | string | Search by code or name |
Get Coupon
Retrieve a specific coupon by ID or code.
GET /v1/rewards/coupons/{id_or_code}
Validate Coupon
Check if a coupon is valid for a specific user and order.
POST /v1/rewards/coupons/validate
Request Body:
{
"data": {
"type": "coupon-validation",
"attributes": {
"code": "SUMMER25",
"user-id": "user-123",
"order-amount": 75.00,
"items": [
{
"product-id": "prod-001",
"category": "summer-collection",
"quantity": 2,
"price": 37.50
}
]
}
}
}
Response: 200 OK
{
"data": {
"type": "coupon-validation-result",
"attributes": {
"valid": true,
"coupon-code": "SUMMER25",
"discount-type": "percentage",
"discount-value": 25,
"discount-amount": 18.75,
"final-amount": 56.25,
"message": "Coupon applied successfully"
}
}
}
Validation Errors:
{
"data": {
"type": "coupon-validation-result",
"attributes": {
"valid": false,
"coupon-code": "SUMMER25",
"error-code": "usage_limit_reached",
"message": "This coupon has reached its usage limit"
}
}
}
Redeem Coupon
Record a coupon usage.
POST /v1/rewards/coupons/redeem
Request Body:
{
"data": {
"type": "coupon-redemption",
"attributes": {
"code": "SUMMER25",
"user-id": "user-123",
"order-id": "order-456",
"discount-amount": 18.75
}
}
}
Generate Unique Codes
Generate a batch of unique coupon codes.
POST /v1/rewards/coupons/generate
Request Body:
{
"data": {
"type": "coupon-generation",
"attributes": {
"campaign-id": "summer-2026",
"count": 1000,
"prefix": "SUM26",
"discount-type": "percentage",
"discount-value": 15,
"per-user-limit": 1,
"expires-at": "2026-08-31T23:59:59Z"
}
}
}
Response: 201 Created
{
"data": {
"type": "coupon-generation-result",
"attributes": {
"campaign-id": "summer-2026",
"codes-generated": 1000,
"sample-codes": [
"SUM26-A7X9K2",
"SUM26-B3M4P8",
"SUM26-C5N7Q1"
],
"download-url": "https://api.23blocks.com/v1/rewards/coupons/download/summer-2026"
}
}
}
Referrals API
Track referrals and reward users for bringing in new customers.
Referral Object
{
"data": {
"id": "referral-abc123",
"type": "referral",
"attributes": {
"referrer-id": "user-123",
"referee-id": "user-456",
"referral-code": "JOHN25",
"status": "completed",
"referrer-reward": {
"type": "points",
"amount": 500,
"status": "paid"
},
"referee-reward": {
"type": "discount",
"value": 25,
"status": "paid"
},
"qualifying-action": "first_purchase",
"qualifying-amount": 75.00,
"created-at": "2026-01-01T10:00:00Z",
"completed-at": "2026-01-02T15:30:00Z"
}
}
}
Get Referral Code
Get or create a user's referral code.
GET /v1/rewards/referrals/code/{user_id}
Response: 200 OK
{
"data": {
"id": "ref-code-123",
"type": "referral-code",
"attributes": {
"user-id": "user-123",
"code": "JOHN25",
"share-url": "https://yourapp.com/invite/JOHN25",
"total-referrals": 12,
"successful-referrals": 8,
"pending-referrals": 2,
"total-rewards-earned": 4000,
"created-at": "2025-01-15T00:00:00Z"
}
}
}
Track Referral
Record when a new user signs up with a referral code.
POST /v1/rewards/referrals/track
Request Body:
{
"data": {
"type": "referral-tracking",
"attributes": {
"referral-code": "JOHN25",
"referee-id": "user-789",
"referee-email": "newuser@example.com"
}
}
}
Complete Referral
Mark a referral as completed when the qualifying action occurs.
POST /v1/rewards/referrals/complete
Request Body:
{
"data": {
"type": "referral-completion",
"attributes": {
"referral-id": "referral-abc123",
"qualifying-action": "first_purchase",
"qualifying-amount": 75.00,
"order-id": "order-456"
}
}
}
List User Referrals
Get all referrals made by a user.
GET /v1/rewards/referrals/user/{user_id}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
filter[status] | string | Filter by status: pending, completed, expired |
Response: 200 OK
{
"data": [
{
"id": "referral-001",
"type": "referral",
"attributes": {
"referee-email": "friend1@example.com",
"status": "completed",
"reward-amount": 500,
"completed-at": "2026-01-02T15:30:00Z"
}
},
{
"id": "referral-002",
"type": "referral",
"attributes": {
"referee-email": "friend2@example.com",
"status": "pending",
"created-at": "2026-01-05T10:00:00Z"
}
}
],
"meta": {
"total-referrals": 12,
"successful": 8,
"pending": 2,
"expired": 2,
"total-rewards": 4000
}
}
Configure Referral Program
Set up referral program rules.
POST /v1/rewards/referrals/config
Request Body:
{
"data": {
"type": "referral-config",
"attributes": {
"referrer-reward": {
"type": "points",
"amount": 500
},
"referee-reward": {
"type": "percentage_discount",
"value": 25,
"max-discount": 50
},
"qualifying-action": "first_purchase",
"min-qualifying-amount": 25.00,
"expiration-days": 30,
"max-referrals-per-user": null,
"double-sided": true
}
}
}
Rewards Catalog API
Manage redeemable rewards in your catalog.
Reward Object
{
"data": {
"id": "reward-free-shipping",
"type": "reward",
"attributes": {
"name": "Free Shipping",
"slug": "free-shipping",
"description": "Get free shipping on your next order",
"category": "discounts",
"points-cost": 250,
"type": "free_shipping",
"value": null,
"image-url": "https://cdn.23blocks.com/rewards/free-shipping.png",
"inventory": null,
"redemption-limit": 1,
"active": true,
"redemption-count": 5420,
"created-at": "2025-01-01T00:00:00Z"
}
}
}
List Rewards
Retrieve all available rewards.
GET /v1/rewards/catalog
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
filter[category] | string | Filter by category |
filter[max-points] | integer | Filter by maximum points cost |
filter[available] | boolean | Only show in-stock rewards |
sort | string | Sort by: points-cost, -points-cost, popular |
Response: 200 OK
{
"data": [
{
"id": "reward-5-off",
"type": "reward",
"attributes": {
"name": "$5 Off Coupon",
"points-cost": 500,
"category": "discounts",
"type": "fixed_discount",
"value": 5.00
}
},
{
"id": "reward-free-shipping",
"type": "reward",
"attributes": {
"name": "Free Shipping",
"points-cost": 250,
"category": "discounts",
"type": "free_shipping"
}
},
{
"id": "reward-tshirt",
"type": "reward",
"attributes": {
"name": "Branded T-Shirt",
"points-cost": 2500,
"category": "merchandise",
"type": "physical_product",
"inventory": 50
}
}
]
}
Create Reward
Add a new reward to the catalog.
POST /v1/rewards/catalog
Request Body:
{
"data": {
"type": "reward",
"attributes": {
"name": "VIP Event Access",
"slug": "vip-event",
"description": "Exclusive access to our annual VIP event",
"category": "experiences",
"points-cost": 10000,
"type": "experience",
"image-url": "https://cdn.23blocks.com/rewards/vip-event.png",
"inventory": 100,
"redemption-limit": 1,
"available-from": "2026-06-01T00:00:00Z",
"available-until": "2026-09-01T00:00:00Z"
}
}
}
Redeem Reward
Redeem a reward for a user.
POST /v1/rewards/catalog/redeem
Request Body:
{
"data": {
"type": "reward-redemption",
"attributes": {
"user-id": "user-123",
"reward-id": "reward-5-off",
"metadata": {
"size": "L",
"color": "blue"
}
}
}
}
Response: 201 Created
{
"data": {
"id": "redemption-xyz789",
"type": "reward-redemption",
"attributes": {
"user-id": "user-123",
"reward-id": "reward-5-off",
"reward-name": "$5 Off Coupon",
"points-spent": 500,
"status": "fulfilled",
"fulfillment": {
"type": "coupon_code",
"code": "REWARD-XYZ789",
"expires-at": "2026-02-01T23:59:59Z"
},
"created-at": "2026-01-02T10:30:00Z"
}
}
}
Get User Redemptions
List a user's reward redemption history.
GET /v1/rewards/catalog/redemptions/{user_id}
Response: 200 OK
{
"data": [
{
"id": "redemption-001",
"type": "reward-redemption",
"attributes": {
"reward-name": "Free Shipping",
"points-spent": 250,
"status": "used",
"created-at": "2025-12-15T10:00:00Z",
"used-at": "2025-12-18T14:30:00Z"
}
}
],
"meta": {
"total-redemptions": 5,
"total-points-spent": 2750
}
}
Leaderboards API
Create competitive engagement with leaderboards.
Leaderboard Object
{
"data": {
"id": "leaderboard-monthly-points",
"type": "leaderboard",
"attributes": {
"name": "Monthly Top Earners",
"slug": "monthly-top-earners",
"metric": "points-earned",
"period": "monthly",
"reset-day": 1,
"max-entries": 100,
"rewards": [
{ "rank": 1, "prize": "1000 bonus points" },
{ "rank": 2, "prize": "500 bonus points" },
{ "rank": 3, "prize": "250 bonus points" }
],
"active": true
}
}
}
Get Leaderboard
Retrieve leaderboard rankings.
GET /v1/rewards/leaderboards/{leaderboard_id}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit | integer | Number of entries (default: 10, max: 100) |
period | string | Specific period: current, previous, 2026-01 |
Response: 200 OK
{
"data": {
"id": "leaderboard-monthly-points",
"type": "leaderboard",
"attributes": {
"name": "Monthly Top Earners",
"period": "2026-01",
"entries": [
{
"rank": 1,
"user-id": "user-456",
"display-name": "Sarah M.",
"avatar-url": "https://cdn.23blocks.com/avatars/user-456.jpg",
"score": 15000,
"prize": "1000 bonus points"
},
{
"rank": 2,
"user-id": "user-789",
"display-name": "John D.",
"avatar-url": "https://cdn.23blocks.com/avatars/user-789.jpg",
"score": 12500,
"prize": "500 bonus points"
},
{
"rank": 3,
"user-id": "user-123",
"display-name": "Emma L.",
"avatar-url": "https://cdn.23blocks.com/avatars/user-123.jpg",
"score": 10200,
"prize": "250 bonus points"
}
],
"updated-at": "2026-01-02T12:00:00Z"
}
}
}
Get User Rank
Get a specific user's rank on a leaderboard.
GET /v1/rewards/leaderboards/{leaderboard_id}/rank/{user_id}
Response: 200 OK
{
"data": {
"type": "user-leaderboard-rank",
"attributes": {
"user-id": "user-123",
"leaderboard-id": "leaderboard-monthly-points",
"rank": 3,
"score": 10200,
"percentile": 97.5,
"users-above": 2,
"users-below": 78,
"distance-to-next-rank": 2300,
"updated-at": "2026-01-02T12:00:00Z"
}
}
}
Create Leaderboard
Create a new leaderboard.
POST /v1/rewards/leaderboards
Request Body:
{
"data": {
"type": "leaderboard",
"attributes": {
"name": "Top Referrers",
"slug": "top-referrers",
"metric": "referral-count",
"period": "all-time",
"max-entries": 50,
"rewards": [
{ "rank": 1, "prize": "5000 bonus points" }
]
}
}
}
Streaks API
Encourage consistent engagement with streak tracking.
Streak Object
{
"data": {
"id": "streak-user-123-daily-login",
"type": "user-streak",
"attributes": {
"user-id": "user-123",
"streak-type": "daily-login",
"current-streak": 15,
"longest-streak": 45,
"last-action-at": "2026-01-02T08:30:00Z",
"streak-expires-at": "2026-01-03T23:59:59Z",
"milestones-reached": [7, 14],
"next-milestone": 30,
"rewards-earned": 150
}
}
}
Get User Streak
Get a user's streak status.
GET /v1/rewards/streaks/{user_id}/{streak_type}
Response: 200 OK
{
"data": {
"id": "streak-user-123-daily-login",
"type": "user-streak",
"attributes": {
"current-streak": 15,
"longest-streak": 45,
"next-milestone": 30,
"days-to-milestone": 15,
"streak-expires-at": "2026-01-03T23:59:59Z",
"time-remaining": "15:29:32"
}
}
}
Record Streak Action
Record an action that extends a streak.
POST /v1/rewards/streaks/record
Request Body:
{
"data": {
"type": "streak-action",
"attributes": {
"user-id": "user-123",
"streak-type": "daily-login"
}
}
}
Response: 200 OK
{
"data": {
"type": "streak-update",
"attributes": {
"previous-streak": 14,
"current-streak": 15,
"milestone-reached": null,
"bonus-points": 0,
"streak-expires-at": "2026-01-03T23:59:59Z"
}
}
}
Configure Streak
Set up a streak type with milestones and rewards.
POST /v1/rewards/streaks/config
Request Body:
{
"data": {
"type": "streak-config",
"attributes": {
"streak-type": "daily-purchase",
"name": "Daily Purchase Streak",
"period": "daily",
"grace-period-hours": 0,
"milestones": [
{ "days": 3, "points": 25 },
{ "days": 7, "points": 100 },
{ "days": 14, "points": 250 },
{ "days": 30, "points": 1000 }
]
}
}
}
Challenges API
Create time-limited challenges to drive specific behaviors.
Challenge Object
{
"data": {
"id": "challenge-winter-2026",
"type": "challenge",
"attributes": {
"name": "Winter Challenge",
"description": "Complete 5 purchases in January to earn 500 bonus points",
"type": "action_count",
"action": "purchase",
"target": 5,
"reward": {
"type": "points",
"amount": 500
},
"starts-at": "2026-01-01T00:00:00Z",
"ends-at": "2026-01-31T23:59:59Z",
"participants-count": 2500,
"completions-count": 450,
"active": true
}
}
}
List Challenges
Get all active challenges.
GET /v1/rewards/challenges
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
filter[active] | boolean | Show only active challenges |
filter[user-id] | string | Include user's progress |
Join Challenge
Enroll a user in a challenge.
POST /v1/rewards/challenges/{challenge_id}/join
Request Body:
{
"data": {
"type": "challenge-enrollment",
"attributes": {
"user-id": "user-123"
}
}
}
Get Challenge Progress
Get a user's progress in a challenge.
GET /v1/rewards/challenges/{challenge_id}/progress/{user_id}
Response: 200 OK
{
"data": {
"type": "challenge-progress",
"attributes": {
"challenge-id": "challenge-winter-2026",
"user-id": "user-123",
"target": 5,
"current": 3,
"progress-percentage": 60.0,
"completed": false,
"time-remaining": "23 days 14:30:00",
"enrolled-at": "2026-01-02T10:00:00Z"
}
}
}
Webhooks
Subscribe to reward events for real-time updates.
Available Events
| Event | Description |
|---|---|
points.awarded | Points credited to a user |
points.deducted | Points deducted from a user |
points.expired | Points expired |
tier.upgraded | User upgraded to a new tier |
tier.downgraded | User downgraded to a lower tier |
badge.awarded | Badge awarded to a user |
coupon.redeemed | Coupon was used |
coupon.expired | Coupon expired |
referral.tracked | New referral tracked |
referral.completed | Referral completed and rewards issued |
reward.redeemed | Reward redeemed from catalog |
streak.milestone | Streak milestone reached |
streak.broken | Streak was broken |
challenge.completed | Challenge completed |
leaderboard.rank_changed | User's leaderboard rank changed |
Webhook Payload Example
{
"id": "evt_abc123",
"type": "tier.upgraded",
"created_at": "2026-01-02T10:30:00Z",
"data": {
"user_id": "user-123",
"previous_tier": {
"id": "tier-silver",
"name": "Silver",
"level": 1
},
"new_tier": {
"id": "tier-gold",
"name": "Gold",
"level": 2
},
"qualifying_points": 5250
}
}
Register Webhook
POST /v1/rewards/webhooks
Request Body:
{
"data": {
"type": "webhook",
"attributes": {
"url": "https://yourapp.com/webhooks/rewards",
"events": [
"tier.upgraded",
"badge.awarded",
"reward.redeemed"
],
"secret": "whsec_your_secret_key"
}
}
}
SDK Examples
JavaScript/TypeScript
import { create23BlocksClient } from '@23blocks/sdk';
const client = create23BlocksClient({
urls: { rewards: 'https://rewards.api.us.23blocks.com' },
appId: process.env.BLOCKS_APP_ID,
});
// Award points for a purchase
async function handlePurchase(userId: string, orderTotal: number) {
const pointsEarned = Math.floor(orderTotal * 2); // 2 points per dollar
const result = await client.rewards.points.award({
userId,
amount: pointsEarned,
action: 'purchase',
metadata: { orderTotal }
});
// Check for tier upgrade
const tierStatus = await client.rewards.tiers.getUserStatus(userId);
if (tierStatus.data.attributes['tier-upgraded']) {
// Notify user of tier upgrade
}
return result;
}
// Get user's complete rewards profile
async function getRewardsProfile(userId: string) {
const [balance, tier, badges, streaks] = await Promise.all([
client.rewards.points.getBalance(userId),
client.rewards.tiers.getUserStatus(userId),
client.rewards.badges.getUserBadges(userId),
client.rewards.streaks.getAll(userId)
]);
return {
points: balance.data.attributes,
tier: tier.data.attributes,
badges: badges.data,
streaks: streaks.data
};
}
// Apply a referral code
async function applyReferralCode(code: string, newUserId: string) {
try {
await client.rewards.referrals.track({
referralCode: code,
refereeId: newUserId
});
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}
React Hook Example
import { useRewards } from '@23blocks/react';
function LoyaltyDashboard({ userId }: { userId: string }) {
const {
balance,
tier,
badges,
isLoading,
refetch
} = useRewards(userId);
if (isLoading) return <LoadingSpinner />;
return (
<div className="loyalty-dashboard">
<div className="points-card">
<h2>{balance.available} Points</h2>
<p>Lifetime: {balance.totalEarned} earned</p>
</div>
<div className="tier-card">
<img src={tier.badgeImageUrl} alt={tier.name} />
<h3>{tier.name} Member</h3>
<div className="progress-bar">
<div
className="progress"
style={{ width: `${tier.progressPercentage}%` }}
/>
</div>
<p>{tier.pointsToNextTier} points to {tier.nextTier.name}</p>
</div>
<div className="badges-grid">
{badges.map(badge => (
<div key={badge.id} className="badge">
<img src={badge.imageUrl} alt={badge.name} />
<span>{badge.name}</span>
</div>
))}
</div>
</div>
);
}
Error Codes
| Code | Description |
|---|---|
insufficient_points | User doesn't have enough points |
invalid_coupon | Coupon code is invalid |
coupon_expired | Coupon has expired |
coupon_usage_limit | Coupon usage limit reached |
coupon_already_used | User already used this coupon |
reward_out_of_stock | Reward is not available |
reward_limit_reached | User reached redemption limit |
tier_not_found | Tier doesn't exist |
badge_already_awarded | User already has this badge |
referral_invalid | Invalid referral code |
referral_self | Cannot refer yourself |
streak_not_active | No active streak for this type |
challenge_ended | Challenge has ended |
challenge_not_enrolled | User not enrolled in challenge |
Rate Limits
| Endpoint | Rate Limit |
|---|---|
| Points operations | 100/min per user |
| Badge awards | 50/min per user |
| Coupon validation | 200/min per user |
| Leaderboard reads | 60/min |
| Webhook deliveries | 10,000/hour |
Related Resources
- Auth Block - User authentication and management
- Onboarding Block - User journey tracking
- Sales Block - Payments and subscriptions
- Frontend SDK - Client-side integration