Tiers API
Query a participant’s current tier with next-tier progress and history. Manually override automatic evaluation when you need to promote a participant outside the points criteria (VIP, support escalation). Tier definitions are managed through admin endpoints.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key Read tier state and call POST /tiers/assign with any valid API key.
Admin scope Manage tier definitions: requires admin or gamify:admin scope.
Base URLhttps://YOUR_API_DOMAIN/api/v1/gamify
Endpoint inventory
| Method | Endpoint | Purpose |
|---|
| GET | /gamify/participants/{participant_id}/tier | Current tier + next-tier progress + history. |
| POST | /gamify/tiers/assign | Manually assign a tier. Idempotent. |
| GET | /gamify/admin/tiers | List tier definitions. Admin scope. |
| POST | /gamify/admin/tiers | Create a tier definition. Admin scope. |
| GET | /gamify/admin/tiers/{tier_id} | Get one tier definition. Admin scope. |
| PATCH | /gamify/admin/tiers/{tier_id} | Update a tier definition. Admin scope. |
| DELETE | /gamify/admin/tiers/{tier_id} | Deactivate (soft-delete) a tier. Admin scope. |
GET/api/v1/gamify/participants/{participant_id}/tier
Participant key
Returns the participant's current tier, the next-tier delta (points required and remaining), and recent tier history.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
GET /api/v1/gamify/participants/user_42/tier
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| current_tier | TierState | null | Current placement: code, name, level, optional color, achieved_at, plus next_tier delta. null when the participant has no tier yet. |
| next_tier | NextTierInfo | null | Top-level convenience: code, name, points_required, points_remaining. null when at the top tier. |
| tier_history | list[TierHistoryEntry] | Best-effort recent transitions. Each entry: code, name (optional), achieved_at (optional). Last few transitions only; use the tier-change fact stream for an audit trail when outbound progression webhooks ship. |
{
"participant_id": "user_42",
"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", "name": "Bronze", "achieved_at": "2026-01-01T..." },
{ "code": "silver", "name": "Silver", "achieved_at": "2026-01-15T..." },
{ "code": "gold", "name": "Gold", "achieved_at": "2026-02-01T..." }
]
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
POST/api/v1/gamify/tiers/assign
Participant keyIdempotent
Override automatic tier evaluation and pin a participant to a specific tier. Safe to retry through the Idempotency-Key header; a second call with the same key returns the original response without re-emitting the tier-change fact.
Headers
| Field | Type | Description |
|---|
| Idempotency-Key | str | Optional. 1 to 255 chars matching ^[A-Za-z0-9_\-:.]{1,255}$. Recommended for every call; descriptive keys ("enterprise-contract-1234") give clean audit trails. |
Request body
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
| tier_coderequired | str | Code of the tier to assign. Must match an active tier definition for the tenant. 1 to 50 characters. |
| reason | Optional[str] | Free-form audit note (max 500 chars). Surfaced in tier-change fact payloads. |
POST /api/v1/gamify/tiers/assign
X-API-Key: bq_live_xxxxx
Content-Type: application/json
Idempotency-Key: enterprise-contract-1234
{
"participant_id": "user_42",
"tier_code": "platinum",
"reason": "Enterprise contract signed (Q2 2026)"
}
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the assigned participant. |
| tier_code | str | Code of the now-current tier. |
| tier_name | str | Display name of the now-current tier. |
| level | int | Ordered level of the now-current tier. Use this for comparisons (codes can be renamed; levels are stable). |
| previous_tier_code | Optional[str] | Code of the tier the participant was at before this call. null if they had no tier. |
{
"participant_id": "user_42",
"tier_code": "platinum",
"tier_name": "Platinum",
"level": 4,
"previous_tier_code": "gold"
}
Errors
| Status | Code | When it fires |
|---|
| 400 | IDEMPOTENCY_KEY_INVALID | Idempotency-Key header is empty, longer than 255 chars, or contains characters outside [A-Za-z0-9_\-:.]. |
| 400 | IDEMPOTENCY_KEY_MISMATCH | Both the Idempotency-Key header AND a body idempotency_key were provided and they differ. |
| 404 | tier_not_found | No active tier definition exists for the supplied tier_code. |
| 409 | TIER_ASSIGN_CONFLICT | Concurrent modification raced the assignment. Retry the call (the Idempotency-Key keeps the retry safe). |
| 429 | RATE_LIMIT_PARTICIPANT_EXCEEDED | Per-participant write rate cap exceeded. The Retry-After response header tells you when to retry. |
GET/api/v1/gamify/admin/tiers
Admin scope
List all tier definitions for the tenant. Tiers are global only on this endpoint (engagement-scoped tiers are not exposed here).
Query parameters
| Field | Type | Description |
|---|
| is_active | Optional[bool] | When set, filters to definitions where is_active matches. |
| award_type | Optional[str] | Filter by award_type: automatic or manual. |
| page | int | 1-indexed page number. Default: 1 |
| page_size | int | Items per page. Max 100. Default: 50 |
GET /api/v1/gamify/admin/tiers?is_active=true&page=1&page_size=50
X-API-Key: bq_live_xxxxx # must carry admin or gamify:admin scope
{
"items": [
{
"id": "01HZ...",
"tenant_id": "01HZ...",
"engagement_id": null,
"code": "gold",
"name": "Gold",
"description": "Premium status with extra benefits.",
"level": 3,
"criteria_type": "points",
"criteria_config": { "min_points": 5000 },
"benefits": { "support_sla_hours": 4, "discount_pct": 10 },
"point_multiplier": 1.5,
"icon_url": "https://cdn.example.com/tiers/gold.png",
"color": "#FFD700",
"badge_url": null,
"is_active": true,
"award_type": "automatic",
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-02-12T15:30:00Z"
}
],
"total": 4,
"page": 1,
"page_size": 50
}
POST/api/v1/gamify/admin/tiers
Admin scope
Create a tier definition. Always scoped globally; engagement_id is ignored if supplied.
Request body
| Field | Type | Description |
|---|
| coderequired | str | Unique tier code for the tenant. 1 to 50 chars. Cannot be changed after creation; downstream awards reference it. |
| namerequired | str | Display name. 1 to 100 chars. |
| description | Optional[str] | Optional long-form description. |
| levelrequired | int | Ordered integer used for comparison and progress math. Must be >= 1. Number with gaps (10, 20, 30) so future tiers can be inserted without renumbering downstream code. |
| criteria_type | str | How tier eligibility is evaluated. Default: "points" |
| criteria_config | dict | Configuration for the chosen criteria_type. For points: { min_points: int }. Default: {} |
| benefits | dict | Free-form benefits payload shown alongside the tier in your UI. Default: {} |
| point_multiplier | Optional[float] | Optional multiplier applied to subsequent points awards while the participant is at this tier. Must be >= 1.0. |
| icon_url | Optional[str] | Optional URL for a tier icon shown in the SDK / dashboards. |
| color | Optional[str] | Optional hex color. Max 20 chars. |
| badge_url | Optional[str] | Optional URL for a tier badge image. |
| award_type | str | automatic (evaluator picks the tier from criteria) or manual (must be assigned via /tiers/assign). Default: "automatic" |
POST /api/v1/gamify/admin/tiers
X-API-Key: bq_live_xxxxx # admin or gamify:admin scope
Content-Type: application/json
{
"code": "platinum",
"name": "Platinum",
"level": 4,
"criteria_type": "points",
"criteria_config": { "min_points": 10000 },
"benefits": { "support_sla_hours": 1, "discount_pct": 15, "exclusive_access": true },
"color": "#E5E4E2"
}
Errors
| Status | Code | When it fires |
|---|
| 400 | tier_code_conflict | Another tier definition already uses that code for this tenant. |
| 400 | tier_level_conflict | Another tier definition already uses that level for this tenant. |
| 403 | forbidden | API key is missing the admin or gamify:admin scope. |
GET/api/v1/gamify/admin/tiers/{tier_id}
Admin scope
Retrieve one tier definition by its UUID. Response shape matches the items in the list endpoint.
Errors
| Status | Code | When it fires |
|---|
| 404 | tier_not_found | No tier exists for the supplied tier_id. |
PATCH/api/v1/gamify/admin/tiers/{tier_id}
Admin scope
Partial update of a tier definition. All body fields are optional; only supplied fields are changed. engagement_id cannot be set through this endpoint.
Request body (all optional)
| Field | Type | Description |
|---|
| name | Optional[str] | 1 to 100 chars. |
| description | Optional[str] | Long-form description. |
| level | Optional[int] | New ordered level. Must remain unique within the tenant. |
| criteria_type | Optional[str] | Switches the evaluation strategy. |
| criteria_config | Optional[dict] | Replaces criteria configuration entirely. |
| benefits | Optional[dict] | Replaces benefits payload entirely. |
| point_multiplier | Optional[float] | >= 1.0. |
| icon_url | Optional[str] | |
| color | Optional[str] | Hex color, max 20 chars. |
| badge_url | Optional[str] | |
| is_active | Optional[bool] | Set false to pause the tier without losing existing placements. |
| award_type | Optional[str] | automatic or manual. |
Errors
| Status | Code | When it fires |
|---|
| 400 | tier_level_conflict | The supplied level is already in use by another tier. |
| 404 | tier_not_found | No tier exists for the supplied tier_id. |
DELETE/api/v1/gamify/admin/tiers/{tier_id}
Admin scope
Soft-delete the tier definition by setting is_active to false. Existing placements are preserved; the evaluator stops picking the tier for new evaluations.
{ "message": "Tier deactivated" }
Errors
| Status | Code | When it fires |
|---|
| 404 | tier_not_found | No tier exists for the supplied tier_id. |