Skip to main content

Rewards Block

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

ConceptDescription
PointsVirtual currency users earn through actions
TiersLoyalty levels with escalating benefits
BadgesVisual achievements for milestones
CouponsDiscount codes with rules and limits
ReferralsTracking and rewarding user invitations
RewardsRedeemable items in your reward catalog

API Endpoint

ServiceURL
Rewardshttps://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 Staging
  • pk_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:

ParameterTypeDescription
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 20, max: 100)
filter[type]stringFilter by transaction type: credit, debit
filter[action]stringFilter by action type
filter[from]datetimeStart date for range
filter[to]datetimeEnd 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:

ParameterTypeDescription
filter[category]stringFilter by category
filter[rarity]stringFilter 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:

TypeDescriptionExample
percentagePercentage off25% off
fixedFixed amount off$10 off
free_shippingFree shipping-
buy_x_get_yBuy X get Y freeBuy 2 get 1 free

List Coupons

Retrieve all coupons.

GET /v1/rewards/coupons

Query Parameters:

ParameterTypeDescription
filter[active]booleanFilter by active status
filter[expires-after]datetimeFilter by expiration date
searchstringSearch 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:

ParameterTypeDescription
filter[status]stringFilter 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:

ParameterTypeDescription
filter[category]stringFilter by category
filter[max-points]integerFilter by maximum points cost
filter[available]booleanOnly show in-stock rewards
sortstringSort 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:

ParameterTypeDescription
limitintegerNumber of entries (default: 10, max: 100)
periodstringSpecific 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:

ParameterTypeDescription
filter[active]booleanShow only active challenges
filter[user-id]stringInclude 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

EventDescription
points.awardedPoints credited to a user
points.deductedPoints deducted from a user
points.expiredPoints expired
tier.upgradedUser upgraded to a new tier
tier.downgradedUser downgraded to a lower tier
badge.awardedBadge awarded to a user
coupon.redeemedCoupon was used
coupon.expiredCoupon expired
referral.trackedNew referral tracked
referral.completedReferral completed and rewards issued
reward.redeemedReward redeemed from catalog
streak.milestoneStreak milestone reached
streak.brokenStreak was broken
challenge.completedChallenge completed
leaderboard.rank_changedUser'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

CodeDescription
insufficient_pointsUser doesn't have enough points
invalid_couponCoupon code is invalid
coupon_expiredCoupon has expired
coupon_usage_limitCoupon usage limit reached
coupon_already_usedUser already used this coupon
reward_out_of_stockReward is not available
reward_limit_reachedUser reached redemption limit
tier_not_foundTier doesn't exist
badge_already_awardedUser already has this badge
referral_invalidInvalid referral code
referral_selfCannot refer yourself
streak_not_activeNo active streak for this type
challenge_endedChallenge has ended
challenge_not_enrolledUser not enrolled in challenge

Rate Limits

EndpointRate Limit
Points operations100/min per user
Badge awards50/min per user
Coupon validation200/min per user
Leaderboard reads60/min
Webhook deliveries10,000/hour