Streaks API
Track consecutive activity streaks such as daily logins or weekly workouts. Bricqs handles period calculation, grace periods, and automatic resets. Read a participant’s status with the participant endpoints; create and manage streak definitions through the admin endpoints.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key Read streak status and record ticks with any valid API key.
Admin scope Manage streak 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}/streaks | All streak statuses for a participant. |
| POST | /gamify/streaks/record | Record a streak tick. Period-based dedup. |
| GET | /gamify/admin/streaks | List streak definitions. Admin scope. |
| POST | /gamify/admin/streaks | Create a streak definition. Admin scope. |
| GET | /gamify/admin/streaks/{streak_id} | Get one streak definition. Admin scope. |
| PATCH | /gamify/admin/streaks/{streak_id} | Update a streak definition. Admin scope. |
| DELETE | /gamify/admin/streaks/{streak_id} | Deactivate (soft-delete) a streak. Admin scope. |
GET/api/v1/gamify/participants/{participant_id}/streaks
Participant key
Returns the current and longest counts for every active streak the participant has touched, plus an at-risk flag for streaks whose grace window is about to close.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
GET /api/v1/gamify/participants/user_42/streaks
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| streaks | list[StreakStatusEntry] | One entry per streak the participant has touched. Fields: code, name, current_count (default 0), longest_count (default 0), last_recorded_at (optional), is_at_risk (default false), period (default "daily"). |
{
"participant_id": "user_42",
"streaks": [
{
"code": "daily_login",
"name": "Daily Login",
"current_count": 7,
"longest_count": 21,
"last_recorded_at": "2026-02-14T08:15:00Z",
"is_at_risk": false,
"period": "daily"
}
]
}
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/streaks/record
Participant key
Record a streak tick for the participant. Period-based idempotency: a second tick in the same period returns already_recorded: true with the count unchanged. No Idempotency-Key header needed.
Request body
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
| streak_coderequired | str | Code of the streak definition to record against. 1 to 50 characters. Must match an existing streak for the tenant. |
| timestamp | Optional[datetime] | ISO-8601 timestamp for the tick. Defaults to server time when omitted. |
POST /api/v1/gamify/streaks/record
X-API-Key: bq_live_xxxxx
Content-Type: application/json
{
"participant_id": "user_42",
"streak_code": "daily_login",
"timestamp": "2026-02-14T08:15:00Z"
}
Response fields
| Field | Type | Description |
|---|
| streak_code | str | Echo of the recorded streak code. |
| new_count | int | Current streak length after this tick. |
| is_new_record | bool | True when new_count exceeds the participant's previous longest_count for this streak. Default: false |
| longest_count | int | Longest streak length the participant has ever reached for this streak. |
| already_recorded | bool | True when a tick has already been recorded in the current period; new_count is unchanged in that case. Default: false |
// First tick of the period
{
"streak_code": "daily_login",
"new_count": 1,
"is_new_record": true,
"longest_count": 1,
"already_recorded": false
}
// Same period again, idempotent no-op
{
"streak_code": "daily_login",
"new_count": 1,
"is_new_record": false,
"longest_count": 1,
"already_recorded": true
}
// Next period, increments
{
"streak_code": "daily_login",
"new_count": 2,
"is_new_record": true,
"longest_count": 2,
"already_recorded": false
}
Errors
| Status | Code | When it fires |
|---|
| 404 | streak_not_found | No streak definition exists for the supplied streak_code ("Streak '{streak_code}' not found"). |
| 429 | RATE_LIMIT_PARTICIPANT_EXCEEDED | Per-participant write rate cap exceeded. The Retry-After response header tells you when to retry. |
Query parameters
| Field | Type | Description |
|---|
| is_active | Optional[bool] | When set, filters to definitions where is_active matches. |
| page | int | 1-indexed page number. Default: 1 |
| page_size | int | Items per page. Max 100. Default: 50 |
GET /api/v1/gamify/admin/streaks?is_active=true&page=1&page_size=50
X-API-Key: bq_live_xxxxx # must carry admin or gamify:admin scope
Response fields
| Field | Type | Description |
|---|
| items | list[StreakResponse] | Page of streak definitions. Each item: id (UUID), tenant_id (UUID), code, name, description (optional), fact_type, fact_filter (optional dict), period, grace_periods, reset_on_miss, icon_url (optional), color (optional), is_active, display_order, created_at, updated_at. |
| total | int | Total number of definitions matching the filter. |
| page | int | Current page number. |
| page_size | int | Items per page used for the response. |
{
"items": [
{
"id": "01HZ...",
"tenant_id": "01HZ...",
"code": "daily_login",
"name": "Daily Login",
"description": "One tick per calendar day for logging in.",
"fact_type": "login",
"fact_filter": null,
"period": "daily",
"grace_periods": 0,
"reset_on_miss": true,
"icon_url": "https://cdn.example.com/streaks/login.png",
"color": "#0891B2",
"is_active": true,
"display_order": 0,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-02-12T15:30:00Z"
}
],
"total": 3,
"page": 1,
"page_size": 50
}
POST/api/v1/gamify/admin/streaks
Admin scope
Create a streak definition. Returns 201 on success.
Request body
| Field | Type | Description |
|---|
| coderequired | str | Unique streak code for the tenant. 1 to 50 chars. Cannot be changed after creation; downstream ticks reference it. |
| namerequired | str | Display name. 1 to 100 chars. |
| description | Optional[str] | Optional long-form description. |
| fact_typerequired | str | Fact type that increments the streak (for example login, activity_completed). |
| fact_filter | Optional[dict] | Optional payload filter applied to incoming facts before they count toward the streak. |
| period | str | Cadence used for the dedup window. One of daily, weekly, monthly. Default: "daily" |
| grace_periods | int | Number of consecutive missed periods tolerated before the streak resets. Must be >= 0. Default: 0 |
| reset_on_miss | bool | When true, missing more than grace_periods periods resets current_count to 0. Default: true |
| icon_url | Optional[str] | Optional URL for a streak icon shown in the SDK or dashboards. |
| color | Optional[str] | Optional hex color. Max 20 chars. |
| display_order | int | Sort order in admin and SDK listings. Default: 0 |
POST /api/v1/gamify/admin/streaks
X-API-Key: bq_live_xxxxx # admin or gamify:admin scope
Content-Type: application/json
{
"code": "daily_login",
"name": "Daily Login",
"fact_type": "login",
"period": "daily",
"grace_periods": 1,
"reset_on_miss": true,
"color": "#0891B2"
}
Errors
| Status | Code | When it fires |
|---|
| 400 | streak_code_conflict | Another streak definition already uses that code for this tenant ("Streak with code '{code}' already exists"). |
| 403 | forbidden | API key is missing the admin or gamify:admin scope. |
GET/api/v1/gamify/admin/streaks/{streak_id}
Admin scope
Retrieve one streak definition by its UUID. Response shape matches the items in the list endpoint.
Errors
| Status | Code | When it fires |
|---|
| 404 | streak_not_found | No streak exists for the supplied streak_id ("Streak not found"). |
PATCH/api/v1/gamify/admin/streaks/{streak_id}
Admin scope
Partial update of a streak definition. All body fields are optional; only supplied fields are changed.
Request body (all optional)
| Field | Type | Description |
|---|
| name | Optional[str] | 1 to 100 chars. |
| description | Optional[str] | Long-form description. |
| fact_type | Optional[str] | Switches which fact type increments the streak. |
| fact_filter | Optional[dict] | Replaces fact filter entirely. |
| period | Optional[str] | daily, weekly, or monthly. |
| grace_periods | Optional[int] | Missed periods tolerated before reset. Must be >= 0. |
| reset_on_miss | Optional[bool] | Toggle reset-on-miss behaviour. |
| icon_url | Optional[str] | |
| color | Optional[str] | Hex color, max 20 chars. |
| display_order | Optional[int] | Sort order in listings. |
| is_active | Optional[bool] | Set false to pause the streak without deleting it. |
Errors
| Status | Code | When it fires |
|---|
| 404 | streak_not_found | No streak exists for the supplied streak_id ("Streak not found"). |
DELETE/api/v1/gamify/admin/streaks/{streak_id}
Admin scope
Soft-delete the streak definition by setting is_active to false. Existing participant counts are preserved; new ticks against the streak are rejected.
{ "message": "Streak deactivated" }
Errors
| Status | Code | When it fires |
|---|
| 404 | streak_not_found | No streak exists for the supplied streak_id ("Streak not found"). |