Participants API
Register participants explicitly, fetch a rich profile with points, tier, badges, streaks, and rewards in one call, patch profile attributes, and query a unified state object scoped to the sections you need. Participants are also auto-created on first interaction with any other Gamify endpoint, so explicit registration is optional.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key All participant endpoints work with any valid API key. No admin scope is required for this resource.
Base URLhttps://YOUR_API_DOMAIN/api/v1/gamify
Endpoint inventory
| Method | Endpoint | Purpose |
|---|
| POST | /gamify/participants | Create or upsert a participant with profile data. Idempotent. |
| GET | /gamify/participants/{participant_id} | Rich profile with points, tier, badges, streaks, rewards counts. |
| PATCH | /gamify/participants/{participant_id} | Update display name, avatar, or custom attributes. |
| GET | /gamify/participants/{participant_id}/state | Unified state with selectable sections via the include query. |
POST/api/v1/gamify/participants
Participant keyIdempotent
Create a participant, or upsert profile fields when one already exists for the supplied participant_id. Returns the full profile (same shape as GET) with a 201 status code. Because it is an upsert, calling again with the same participant_id safely updates display_name, avatar_url, and attributes without creating duplicates.
Request body
| Field | Type | Description |
|---|
| participant_idrequired | str | Your app's user identifier. 1 to 255 characters. Used as the stable external key for every other endpoint. |
| display_name | Optional[str] | Human-readable name shown in dashboards, leaderboards, and the SDK. Max 255 characters. |
| avatar_url | Optional[str] | URL to a profile image. Max 500 characters. |
| attributes | Optional[dict[str, Any]] | Free-form JSON metadata stored verbatim on the participant. Useful for plan tier, signup source, segments. |
POST /api/v1/gamify/participants
X-API-Key: bq_live_xxxxx
Content-Type: application/json
{
"participant_id": "user_123",
"display_name": "Jane Doe",
"avatar_url": "https://example.com/avatar.png",
"attributes": {
"plan": "premium",
"signup_source": "referral"
}
}
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the supplied participant identifier. |
| display_name | Optional[str] | Display name as stored after the upsert. |
| avatar_url | Optional[str] | Avatar URL as stored after the upsert. |
| attributes | Optional[dict[str, Any]] | Free-form attributes as stored. |
| points | Optional[PointsState] | Points snapshot: balance, total_earned, total_spent. Zeroed for new participants. |
| tier | Optional[TierState] | Current tier placement: code, name, level, optional color, achieved_at, plus a next_tier delta. null when the participant has no tier yet. |
| badges | list[BadgeSummary] | Earned badges. Each entry: code, name, optional icon, rarity (default common), earned flag, optional earned_at. Empty list for new participants. |
| streaks | Optional[StreakSummary] | Streak summary: current, longest, optional last_activity_at. |
| rewards_claimed | int | Lifetime count of rewards claimed. Default: 0 |
| first_seen_at | Optional[datetime] | First time this participant was observed. |
| last_seen_at | Optional[datetime] | Most recent activity timestamp. |
| total_events | int | Lifetime count of behavioural events observed for this participant. Default: 0 |
| is_active | bool | Whether the participant is currently active. Default: true |
| created_at | Optional[datetime] | Server-side creation timestamp. |
{
"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,
"first_seen_at": null,
"last_seen_at": null,
"total_events": 0,
"is_active": true,
"created_at": "2026-02-14T10:00:00Z"
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
GET/api/v1/gamify/participants/{participant_id}
Participant key
Returns the full participant profile: identity fields, points snapshot, current tier with next-tier delta, earned badges, streak summary, lifetime rewards and event counts, and seen-at timestamps.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier as supplied at creation. 1 to 255 characters. |
GET /api/v1/gamify/participants/user_123
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| display_name | Optional[str] | Display name. null when never set. |
| avatar_url | Optional[str] | Avatar URL. null when never set. |
| attributes | Optional[dict[str, Any]] | Free-form attributes JSON. |
| points | Optional[PointsState] | balance, total_earned, total_spent integers (all default 0). |
| tier | Optional[TierState] | code, name, level, optional color, optional achieved_at, optional next_tier { code, name, points_required, points_remaining }. |
| badges | list[BadgeSummary] | Each entry: code, name, optional icon, rarity (default common), earned (default false), optional earned_at. |
| streaks | Optional[StreakSummary] | current (default 0), longest (default 0), optional last_activity_at. |
| rewards_claimed | int | Lifetime rewards claimed count. Default: 0 |
| first_seen_at | Optional[datetime] | First observation timestamp. |
| last_seen_at | Optional[datetime] | Latest observation timestamp. |
| total_events | int | Lifetime event count. Default: 0 |
| is_active | bool | Active flag. Default: true |
| created_at | Optional[datetime] | Creation timestamp. |
{
"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",
"icon": "https://cdn.example.com/badges/first_steps.png",
"rarity": "common",
"earned": true,
"earned_at": "2026-01-15T12:30:00Z"
}
],
"streaks": { "current": 7, "longest": 21, "last_activity_at": "2026-02-14T08:15:00Z" },
"rewards_claimed": 3,
"first_seen_at": "2026-01-01T10:00:00Z",
"last_seen_at": "2026-02-14T08:15:00Z",
"total_events": 156,
"is_active": true,
"created_at": "2026-01-01T10:00:00Z"
}
Errors
| Status | Code | When it fires |
|---|
| 404 | participant_not_found | No participant exists for the supplied participant_id under this tenant. |
PATCH/api/v1/gamify/participants/{participant_id}
Participant key
Partial update of a participant's profile fields. All body fields are optional; only supplied fields are changed. Returns the full profile with the same shape as GET. At least one field must be supplied.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
Request body (all optional, at least one required)
| Field | Type | Description |
|---|
| display_name | Optional[str] | New display name. Max 255 characters. |
| avatar_url | Optional[str] | New avatar URL. Max 500 characters. |
| attributes | Optional[dict[str, Any]] | Replaces the attributes JSON entirely. |
PATCH /api/v1/gamify/participants/user_123
X-API-Key: bq_live_xxxxx
Content-Type: application/json
{
"display_name": "Jane Smith",
"attributes": { "plan": "enterprise", "team_id": "team_42" }
}
{
"participant_id": "user_123",
"display_name": "Jane Smith",
"avatar_url": "https://example.com/avatar.png",
"attributes": { "plan": "enterprise", "team_id": "team_42" },
"points": { "balance": 1500, "total_earned": 5000, "total_spent": 3500 },
"tier": { "code": "gold", "name": "Gold", "level": 3 },
"badges": [],
"streaks": { "current": 7, "longest": 21 },
"rewards_claimed": 3,
"first_seen_at": "2026-01-01T10:00:00Z",
"last_seen_at": "2026-02-14T08:15:00Z",
"total_events": 156,
"is_active": true,
"created_at": "2026-01-01T10:00:00Z"
}
Errors
| Status | Code | When it fires |
|---|
| 400 | no_fields_to_update | Request body was empty or contained no recognised fields. |
| 404 | participant_not_found | No participant exists for the supplied participant_id under this tenant. |
GET/api/v1/gamify/participants/{participant_id}/state
Participant key
Lightweight unified state endpoint that returns one or more gamification sections. Use the include query to scope the payload to the sections you need; omit it to return every section.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
Query parameters
| Field | Type | Description |
|---|
| include | Optional[str] | Comma-separated subset of points, tier, badges, streaks, challenges, rewards. Omit to return every section. |
GET /api/v1/gamify/participants/user_123/state?include=points,tier,badges
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| points | Optional[PointsState] | Present when points was included (or include was omitted). balance, total_earned, total_spent. |
| tier | Optional[TierState] | Present when tier was included. code, name, level, optional color, optional achieved_at, optional next_tier. |
| badges | Optional[list[BadgeSummary]] | Present when badges was included. Each entry: code, name, optional icon, rarity, earned, optional earned_at. |
| streaks | Optional[StreakSummary] | Present when streaks was included. current, longest, optional last_activity_at. |
| challenges | Optional[dict] | Present when challenges was included. Shape: { active: int, completed: int }. |
| rewards | Optional[dict] | Present when rewards was included. Shape: { total_claimed: int }. |
{
"participant_id": "user_123",
"points": { "balance": 1500, "total_earned": 5000, "total_spent": 3500 },
"tier": { "code": "gold", "name": "Gold", "level": 3 },
"badges": [
{ "code": "first_steps", "name": "First Steps", "rarity": "common",
"earned": true, "earned_at": "2026-01-15T12:30:00Z" },
{ "code": "power_user", "name": "Power User", "rarity": "rare",
"earned": false, "earned_at": null }
]
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |