Gamification API
Server-to-server REST API for adding gamification to any application. Award points, unlock badges, manage tiers, track streaks, and run leaderboards — all via API key authentication.
Authentication
All Gamification API endpoints use API key authentication. Pass your key in the X-API-Key header.
curl -X POST https://api.bricqs.ai/api/v1/gamify/points/award \
-H "X-API-Key: bq_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"participant_id": "user_123", "amount": 100, "reason": "Purchase completed"}'Standard API Key
Used for participant-facing operations (awarding points, recording streaks, querying state). Any active API key works.
Admin API Key
Used for definition management (creating badges, tiers, leaderboards). Requires admin or gamify:admin scope on the API key.
Quick Start
A complete gamification flow in four API calls. Participants are auto-created on first interaction — no registration step needed.
curl -X POST https://api.bricqs.ai/api/v1/gamify/points/award \
-H "X-API-Key: bq_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"participant_id": "user_123",
"amount": 250,
"reason": "Completed onboarding",
"idempotency_key": "onboarding_user123"
}'
# Response
{
"transaction_id": "a1b2c3d4-...",
"participant_id": "user_123",
"amount": 250,
"new_balance": 250,
"tier_upgrade": null
}curl -X POST https://api.bricqs.ai/api/v1/gamify/badges/award \
-H "X-API-Key: bq_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"participant_id": "user_123",
"badge_code": "first_steps"
}'
# Response
{
"participant_id": "user_123",
"badge_code": "first_steps",
"badge_name": "First Steps",
"rarity": "common",
"earned_at": "2026-02-14T10:00:00Z",
"already_earned": false
}curl -X POST https://api.bricqs.ai/api/v1/gamify/streaks/record \
-H "X-API-Key: bq_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"participant_id": "user_123",
"streak_code": "daily_login"
}'
# Response
{
"streak_code": "daily_login",
"new_count": 3,
"longest_count": 14,
"is_new_record": false,
"already_recorded": false
}curl https://api.bricqs.ai/api/v1/gamify/participants/user_123/state \
-H "X-API-Key: bq_live_your_key"
# Response
{
"participant_id": "user_123",
"points": { "balance": 250, "total_earned": 250, "total_spent": 0 },
"tier": { "code": "bronze", "name": "Bronze", "level": 1 },
"badges": [{ "code": "first_steps", "name": "First Steps", "earned": true }],
"streaks": { "current": 3, "longest": 14 },
"challenges": { "active": 0, "completed": 0 },
"rewards": { "total_claimed": 0 }
}Points5 endpoints
Award and deduct points, query balances, and view transaction history. Points trigger automatic tier evaluation — if a participant crosses a tier threshold, the tier upgrade is included in the response.
| Method | Endpoint | Description |
|---|---|---|
| POST | /gamify/points/award | Award points. Returns new balance and any tier upgrade. |
| POST | /gamify/points/deduct | Deduct points. Returns 400 if insufficient balance. |
| POST | /gamify/points/award-batch | Batch award up to 100 participants at once. |
| GET | /gamify/participants/{pid}/points | Get current balance, total earned, and total spent. |
| GET | /gamify/participants/{pid}/points/transactions | Paginated transaction history. |
Award Points
POST /api/v1/gamify/points/award
{
"participant_id": "user_123", // Required, 1-255 chars
"amount": 100, // Required, 1-1,000,000
"reason": "Purchase completed", // Optional, max 500 chars
"metadata": { // Optional, custom data
"order_id": "ord_abc",
"amount_usd": 49.99
},
"idempotency_key": "purchase_ord_abc" // Optional, prevents duplicates
}{
"transaction_id": "a1b2c3d4-e5f6-...",
"participant_id": "user_123",
"amount": 100,
"new_balance": 1500,
"tier_upgrade": { // null if no tier change
"code": "gold",
"name": "Gold Tier",
"level": 3,
"previous_code": "silver",
"previous_level": 2
}
}Deduct Points
POST /api/v1/gamify/points/deduct
{
"participant_id": "user_123",
"amount": 50,
"reason": "Reward redemption"
}
// Response
{
"transaction_id": "...",
"participant_id": "user_123",
"amount": 50,
"new_balance": 1450
}
// Error: insufficient balance
// 400 Bad Request
{ "detail": "Insufficient points. Available: 30, requested: 50" }Batch Award
POST /api/v1/gamify/points/award-batch
{
"awards": [
{ "participant_id": "user_1", "amount": 100, "reason": "Weekly bonus" },
{ "participant_id": "user_2", "amount": 100, "reason": "Weekly bonus" },
{ "participant_id": "user_3", "amount": 50, "reason": "Referral bonus" }
]
}
// Response
{
"processed": 3,
"failed": 0,
"results": [
{ "participant_id": "user_1", "transaction_id": "...", "new_balance": 500, "error": null },
{ "participant_id": "user_2", "transaction_id": "...", "new_balance": 350, "error": null },
{ "participant_id": "user_3", "transaction_id": "...", "new_balance": 200, "error": null }
]
}Badges2 endpoints
Award badges to participants and query earned status. Badge awards are idempotent — awarding the same badge twice returns already_earned: true instead of an error.
| Method | Endpoint | Description |
|---|---|---|
| POST | /gamify/badges/award | Award a badge (idempotent). |
| GET | /gamify/participants/{pid}/badges | List all badges with earned/unearned status. |
// Award a badge
POST /api/v1/gamify/badges/award
{
"participant_id": "user_123",
"badge_code": "power_user",
"metadata": { "trigger": "10th_login" }
}
// Response
{
"participant_id": "user_123",
"badge_code": "power_user",
"badge_name": "Power User",
"icon": "https://cdn.example.com/badges/power.png",
"rarity": "rare",
"earned_at": "2026-02-14T10:00:00Z",
"already_earned": false
}
// Award same badge again → idempotent
{
"already_earned": true,
"badge_code": "power_user",
"earned_at": "2026-02-14T10:00:00Z",
...
}// All badges (earned and unearned)
GET /api/v1/gamify/participants/user_123/badges
// Only earned badges
GET /api/v1/gamify/participants/user_123/badges?earned_only=true
// Specific badges by code
GET /api/v1/gamify/participants/user_123/badges?badge_codes=power_user,first_steps
// Response
{
"participant_id": "user_123",
"badges": [
{
"code": "power_user",
"name": "Power User",
"description": "Log in 10 times",
"icon": "https://...",
"rarity": "rare",
"earned": true,
"earned_at": "2026-02-14T10:00:00Z"
}
],
"total": 8,
"earned_count": 3
}Tiers2 endpoints
Query the current tier for a participant and manually assign tiers. Automatic tiers are evaluated on every points award — when a participant crosses a threshold, the tier upgrade is returned in the points response.
| Method | Endpoint | Description |
|---|---|---|
| GET | /gamify/participants/{pid}/tier | Current tier, next tier, and tier history. |
| POST | /gamify/tiers/assign | Manually assign a tier (overrides automatic). |
// Get current tier
GET /api/v1/gamify/participants/user_123/tier
{
"participant_id": "user_123",
"current_tier": {
"code": "gold",
"name": "Gold",
"level": 3,
"color": "#FFD700",
"achieved_at": "2026-02-01T10:00:00Z"
},
"next_tier": {
"code": "platinum",
"name": "Platinum",
"points_required": 10000,
"points_remaining": 8500
},
"tier_history": [
{ "code": "bronze", "achieved_at": "2026-01-01T..." },
{ "code": "silver", "achieved_at": "2026-01-15T..." },
{ "code": "gold", "achieved_at": "2026-02-01T..." }
]
}
// Manual tier assignment
POST /api/v1/gamify/tiers/assign
{
"participant_id": "user_123",
"tier_code": "platinum",
"reason": "VIP promotion"
}Leaderboards2 endpoints
Query leaderboard rankings and individual participant positions. Rankings are computed on-the-fly from the points/scoring data.
| Method | Endpoint | Description |
|---|---|---|
| GET | /gamify/leaderboards/{code} | Top rankings with optional time period filter. |
| GET | /gamify/leaderboards/{code}/rank/{pid} | Individual rank, score, and percentile. |
// Get top 10 rankings
GET /api/v1/gamify/leaderboards/top_scorers?limit=10&period=monthly
{
"leaderboard_code": "top_scorers",
"period": "monthly",
"entries": [
{ "rank": 1, "participant_id": "user_456", "score": 5000, "change": "up" },
{ "rank": 2, "participant_id": "user_123", "score": 4500, "change": "same" },
{ "rank": 3, "participant_id": "user_789", "score": 4200, "change": "new" }
],
"total_participants": 1250
}
// Get individual rank
GET /api/v1/gamify/leaderboards/top_scorers/rank/user_123
{
"participant_id": "user_123",
"rank": 2,
"score": 4500,
"total_participants": 1250,
"percentile": 99.8
}all_time, yearly, monthly, weekly, daily. If omitted, uses the leaderboard definition's default time window.Streaks2 endpoints
Track consecutive activity streaks (daily logins, weekly workouts, etc.). The API handles period calculation, grace periods, and automatic resets.
| Method | Endpoint | Description |
|---|---|---|
| POST | /gamify/streaks/record | Record streak activity. Auto-increment or reset based on period. |
| GET | /gamify/participants/{pid}/streaks | All streak statuses for a participant. |
// Record a streak activity
POST /api/v1/gamify/streaks/record
{
"participant_id": "user_123",
"streak_code": "daily_login",
"timestamp": "2026-02-14T08:15:00Z" // Optional, defaults to now
}
// Day 1 response
{ "streak_code": "daily_login", "new_count": 1, "longest_count": 1,
"is_new_record": true, "already_recorded": false }
// Same day again → idempotent
{ "streak_code": "daily_login", "new_count": 1, "longest_count": 1,
"is_new_record": false, "already_recorded": true }
// Next day → increments
{ "streak_code": "daily_login", "new_count": 2, "longest_count": 2,
"is_new_record": true, "already_recorded": false }
// Get all streaks
GET /api/v1/gamify/participants/user_123/streaks
{
"participant_id": "user_123",
"streaks": [
{
"code": "daily_login",
"name": "Daily Login",
"current_count": 7,
"longest_count": 21,
"last_recorded_at": "2026-02-14T08:15:00Z",
"period": "daily"
}
]
}Rewards3 endpoints
List available rewards, claim them, and query claimed history. Rewards can optionally deduct points as a cost.
| Method | Endpoint | Description |
|---|---|---|
| GET | /gamify/rewards | List available rewards. Filter by ?reward_type=coupon. |
| POST | /gamify/rewards/{reward_id}/claim | Claim a reward. Optionally deduct points. |
| GET | /gamify/participants/{pid}/rewards | List all rewards claimed by participant. |
// List available rewards
GET /api/v1/gamify/rewards?reward_type=coupon
{
"rewards": [
{
"id": "rwd_uuid",
"name": "10% Off Coupon",
"type": "coupon",
"description": "10% discount on next purchase",
"points_cost": 500,
"available_codes": 45,
"max_claims_per_user": 1
}
],
"total": 1
}
// Claim a reward (with points deduction)
POST /api/v1/gamify/rewards/rwd_uuid/claim
{
"participant_id": "user_123",
"points_deduction": true
}
// Response
{
"claim_id": "claim_uuid",
"participant_id": "user_123",
"reward_name": "10% Off Coupon",
"reward_type": "coupon",
"code_value": "SAVE10-ABC123",
"points_deducted": 500,
"new_balance": 1000
}coupon, voucher, physical, digital, points_multiplierEvents3 endpoints
Emit custom events from your application. Events are processed synchronously and can trigger challenge evaluations, badge unlocks, and other automated actions based on your configured rules.
| Method | Endpoint | Description |
|---|---|---|
| POST | /gamify/events | Emit a single event (synchronous processing). |
| POST | /gamify/events/batch | Batch emit up to 100 events. |
| GET | /gamify/participants/{pid}/events | Query event history with filters. |
// Emit a custom event
POST /api/v1/gamify/events
{
"participant_id": "user_123",
"event_name": "purchase_completed",
"properties": {
"amount": 49.99,
"currency": "USD",
"product_id": "prod_abc"
},
"timestamp": "2026-02-14T10:00:00Z",
"idempotency_key": "purchase_ord_001"
}
// Response
{
"event_id": "evt_uuid",
"fact_id": "fact_uuid",
"status": "processed"
}
// Query event history with filters
GET /api/v1/gamify/participants/user_123/events?event_name=purchase_completed&page=1&page_size=20
{
"participant_id": "user_123",
"events": [
{
"id": "evt_uuid",
"event_name": "purchase_completed",
"properties": { "amount": 49.99, "currency": "USD" },
"occurred_at": "2026-02-14T10:00:00Z"
}
],
"total": 156,
"page": 1,
"page_size": 20
}Participants4 endpoints
Register participants explicitly, get rich profiles with all gamification data, update profile attributes, and query unified state. Participants are also auto-created on first interaction with any other endpoint.
| Method | Endpoint | Description |
|---|---|---|
| POST | /gamify/participants | Create/register a participant with profile data. Idempotent. |
| GET | /gamify/participants/{pid} | Rich profile with points, tier, badges, streaks, rewards. |
| PATCH | /gamify/participants/{pid} | Update display name, avatar, or custom attributes. |
| GET | /gamify/participants/{pid}/state | Unified state with selectable sections. |
Create Participant
POST /api/v1/gamify/participants
{
"participant_id": "user_123", // Required, your app's user ID
"display_name": "Jane Doe", // Optional
"avatar_url": "https://example.com/avatar.png", // Optional
"attributes": { // Optional, custom metadata
"plan": "premium",
"signup_source": "referral"
}
}
// Response (201 Created)
{
"participant_id": "user_123",
"display_name": "Jane Doe",
"avatar_url": "https://example.com/avatar.png",
"attributes": { "plan": "premium", "signup_source": "referral" },
"points": { "balance": 0, "total_earned": 0, "total_spent": 0 },
"tier": null,
"badges": [],
"streaks": null,
"rewards_claimed": 0,
"total_events": 0,
"is_active": true,
"created_at": "2026-02-14T10:00:00Z"
}
// Idempotent — calling again updates display_name/avatar/attributesGet Participant Profile
Returns a rich profile with points breakdown, current tier with next-tier progress, earned badges, best streak, and rewards count.
GET /api/v1/gamify/participants/user_123
{
"participant_id": "user_123",
"display_name": "Jane Doe",
"avatar_url": "https://example.com/avatar.png",
"attributes": { "plan": "premium" },
"points": { "balance": 1500, "total_earned": 5000, "total_spent": 3500 },
"tier": {
"code": "gold", "name": "Gold", "level": 3, "color": "#FFD700",
"achieved_at": "2026-02-01T10:00:00Z",
"next_tier": { "code": "platinum", "name": "Platinum",
"points_required": 10000, "points_remaining": 8500 }
},
"badges": [
{ "code": "first_steps", "name": "First Steps", "rarity": "common",
"earned": true, "earned_at": "2026-01-15T..." }
],
"streaks": { "current": 7, "longest": 21, "last_activity_at": "2026-02-14T..." },
"rewards_claimed": 3,
"total_events": 156,
"first_seen_at": "2026-01-01T...",
"last_seen_at": "2026-02-14T...",
"is_active": true
}Update Participant
PATCH /api/v1/gamify/participants/user_123
{
"display_name": "Jane Smith",
"attributes": { "plan": "enterprise", "team_id": "team_42" }
}
// Returns full profile (same shape as GET)Unified State
Lightweight endpoint that returns selected gamification sections without full profile data.
// Full state
GET /api/v1/gamify/participants/user_123/state
// Partial state (only specific sections)
GET /api/v1/gamify/participants/user_123/state?include=points,tier,badges
// Response
{
"participant_id": "user_123",
"points": { "balance": 1500, "total_earned": 5000, "total_spent": 3500 },
"tier": { "code": "gold", "name": "Gold", "level": 3 },
"badges": [
{ "code": "first_steps", "earned": true, "earned_at": "..." },
{ "code": "power_user", "earned": false, "earned_at": null }
],
"streaks": { "current": 7, "longest": 21 },
"challenges": { "active": 2, "completed": 5 },
"rewards": { "total_claimed": 3 }
}points, tier, badges, streaks, challenges, rewards. Omit to return all sections.Admin EndpointsAdmin Key Required
Create, update, and delete gamification definitions (badges, tiers, leaderboards, streaks, rewards). These endpoints require an API key with admin or gamify:admin scope.
| Resource | Endpoints | Operations |
|---|---|---|
| Badges | /gamify/admin/badges | List, Create, Get, Update, Delete |
| Tiers | /gamify/admin/tiers | List, Create, Get, Update, Delete |
| Leaderboards | /gamify/admin/leaderboards | List, Create, Get, Update, Delete |
| Streaks | /gamify/admin/streaks | List, Create, Get, Update, Delete |
| Rewards | /gamify/admin/rewards | List, Create, Get, Update, Delete |
| Participants | /gamify/admin/participants | List (search/filter/sort), Delete/Anonymize |
All admin resources follow the same CRUD pattern:
# List with pagination and filters
GET /api/v1/gamify/admin/badges?page=1&page_size=50&is_active=true
# Create
POST /api/v1/gamify/admin/badges
{
"code": "streak_master",
"name": "Streak Master",
"description": "Maintain a 30-day streak",
"icon_url": "https://cdn.example.com/badges/streak.png",
"category": "achievement",
"rarity": "epic",
"display_order": 10
}
# Get by ID
GET /api/v1/gamify/admin/badges/{badge_id}
# Update (partial)
PATCH /api/v1/gamify/admin/badges/{badge_id}
{ "name": "Updated Name", "rarity": "legendary" }
# Delete (soft-delete)
DELETE /api/v1/gamify/admin/badges/{badge_id}Tier Definition Example
POST /api/v1/gamify/admin/tiers
{
"code": "platinum",
"name": "Platinum",
"level": 4,
"color": "#E5E4E2",
"criteria_config": { "min_points": 10000 },
"award_type": "automatic",
"benefits": ["priority_support", "2x_points"],
"display_order": 4
}Streak Definition Example
POST /api/v1/gamify/admin/streaks
{
"code": "daily_login",
"name": "Daily Login Streak",
"description": "Log in every day to build your streak",
"period": "daily",
"grace_period_hours": 24,
"display_order": 1
}Reward Definition Example
POST /api/v1/gamify/admin/rewards
{
"name": "Premium Gift Card",
"type": "voucher",
"description": "Redeemable for premium items",
"points_cost": 1000,
"max_claims_per_user": 1,
"total_inventory": 100,
"is_active": true
}Participant Management
# List participants with search, filter, and sort
GET /api/v1/gamify/admin/participants?search=jane&sort_by=total_points&sort_order=desc
{
"items": [
{
"participant_id": "user_123",
"display_name": "Jane Doe",
"total_points": 5000,
"available_points": 1500,
"current_tier": "gold",
"total_events": 156,
"is_active": true
}
],
"total": 1, "page": 1, "page_size": 50
}
# Anonymize a participant (soft-delete, clears PII)
DELETE /api/v1/gamify/admin/participants/user_123?anonymize=true
# Hard delete a participant and all their data
DELETE /api/v1/gamify/admin/participants/user_123Common Patterns
Idempotency
Points awards and events support idempotency_key to prevent duplicate processing. Badge awards and streak recordings are naturally idempotent (same badge/period returns success without duplication).
// First call — processes normally
POST /api/v1/gamify/points/award
{ "participant_id": "user_123", "amount": 100,
"idempotency_key": "purchase_ord_001" }
→ { "transaction_id": "txn_abc", "new_balance": 100 }
// Second call with same key — returns cached result
POST /api/v1/gamify/points/award
{ "participant_id": "user_123", "amount": 100,
"idempotency_key": "purchase_ord_001" }
→ { "transaction_id": "txn_abc", "new_balance": 100 } // Same resultParticipant Registration
Participants are automatically created on their first interaction with any endpoint — no registration step required. Optionally, use POST /gamify/participants to pre-register participants with a display name, avatar, and custom attributes. The participant_id is your application's user identifier (string, 1-255 chars).
Pagination
List endpoints support pagination via page and page_size query parameters.
GET /api/v1/gamify/participants/user_123/points/transactions?page=2&page_size=20
{
"transactions": [...],
"total": 156, // Total across all pages
"page": 2, // Current page
"page_size": 20 // Items per page (max 100)
}Automatic Tier Evaluation
Every points award automatically evaluates tier thresholds. If the participant qualifies for a higher tier, the tier_upgrade field is populated in the response. No separate API call needed.
Error Handling
All errors return a consistent JSON format with an appropriate HTTP status code.
// Error response format
{
"detail": "Human-readable error message"
}
// Common status codes
401 Unauthorized — Missing or invalid API key
403 Forbidden — API key lacks required scope (admin endpoints)
404 Not Found — Badge code, tier code, or participant not found
400 Bad Request — Insufficient points, invalid parameters
422 Unprocessable — Request validation failed (missing required fields)
429 Too Many Requests — Rate limit exceeded| Scenario | Status | Detail |
|---|---|---|
| Deduct more than available | 400 | Insufficient points. Available: 30, requested: 50 |
| Unknown badge code | 404 | Badge definition not found: unknown_badge |
| Missing admin scope | 403 | API key requires 'admin' scope |
| No reward codes left | 400 | No available reward codes |
| Max claims exceeded | 400 | Maximum claims per participant exceeded |
Integration Example
A typical server-side integration that awards points on purchase and checks for tier upgrades.
const BRICQS_API = 'https://api.bricqs.ai/api/v1/gamify';
const API_KEY = process.env.BRICQS_API_KEY;
const headers = {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
};
// After a purchase is completed
app.post('/api/purchase/complete', async (req, res) => {
const { userId, orderId, amount } = req.body;
// 1. Award points based on purchase amount
const pointsRes = await fetch(`${BRICQS_API}/points/award`, {
method: 'POST',
headers,
body: JSON.stringify({
participant_id: userId,
amount: Math.floor(amount), // 1 point per dollar
reason: `Purchase #${orderId}`,
metadata: { order_id: orderId, amount },
idempotency_key: `purchase_${orderId}`,
}),
});
const points = await pointsRes.json();
// 2. Record daily activity streak
await fetch(`${BRICQS_API}/streaks/record`, {
method: 'POST',
headers,
body: JSON.stringify({
participant_id: userId,
streak_code: 'daily_purchase',
}),
});
// 3. Check for tier upgrade
if (points.tier_upgrade) {
// Trigger your own notification
await sendPushNotification(userId,
`Congratulations! You've reached ${points.tier_upgrade.name}!`
);
}
res.json({
points_earned: points.amount,
new_balance: points.new_balance,
tier_upgrade: points.tier_upgrade,
});
});import httpx
BRICQS_API = "https://api.bricqs.ai/api/v1/gamify"
HEADERS = {
"X-API-Key": os.environ["BRICQS_API_KEY"],
"Content-Type": "application/json",
}
@app.post("/api/purchase/complete")
async def complete_purchase(order: Order):
async with httpx.AsyncClient() as client:
# Award points
resp = await client.post(
f"{BRICQS_API}/points/award",
headers=HEADERS,
json={
"participant_id": order.user_id,
"amount": int(order.total),
"reason": f"Purchase #{order.id}",
"idempotency_key": f"purchase_{order.id}",
},
)
result = resp.json()
# Record streak
await client.post(
f"{BRICQS_API}/streaks/record",
headers=HEADERS,
json={
"participant_id": order.user_id,
"streak_code": "daily_purchase",
},
)
return {
"points_earned": result["amount"],
"new_balance": result["new_balance"],
"tier_upgrade": result.get("tier_upgrade"),
}