BricqsBricqs
Documentation

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.

Bricqs Gamify vs Bricqs Engage: The Gamification API (Bricqs Gamify) is for developers who want full control over the UI and need server-to-server integration. Bricqs Engage uses the visual builder and hosted runtime. Both share the same backend infrastructure.

Authentication

All Gamification API endpoints use API key authentication. Pass your key in the X-API-Key header.

curl -X POST https://YOUR_API_DOMAIN/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.

1. Award points for an action
curl -X POST https://YOUR_API_DOMAIN/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
}
2. Award a badge
curl -X POST https://YOUR_API_DOMAIN/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
}
3. Record a streak activity
curl -X POST https://YOUR_API_DOMAIN/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
}
4. Get unified participant state
curl https://YOUR_API_DOMAIN/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 }
}

API Resources

Explore each resource for full endpoint details, request/response schemas, and examples.

Common 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 result

Participant 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
ScenarioStatusDetail
Deduct more than available400Insufficient points. Available: 30, requested: 50
Unknown badge code404Badge definition not found: unknown_badge
Missing admin scope403API key requires 'admin' scope
No reward codes left400No available reward codes
Max claims exceeded400Maximum claims per participant exceeded

Integration Example

A typical server-side integration that awards points on purchase and checks for tier upgrades.

Node.js / Express
const BRICQS_API = 'https://YOUR_API_DOMAIN/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,
  });
});
Python / FastAPI
import httpx

BRICQS_API = "https://YOUR_API_DOMAIN/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"),
    }

Next Steps