Events API
Emit custom events from your application. Events are processed synchronously, persisted as facts, and fed through the rules engine to trigger challenge evaluations, badge unlocks, tier transitions, and outbound webhooks. Use the history endpoint to read back a participant’s emitted events with filters and pagination.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key Emit and read events with any valid API key.
Base URLhttps://YOUR_API_DOMAIN/api/v1/gamify
Endpoint inventory
| Method | Endpoint | Purpose |
|---|
| POST | /gamify/events | Emit a single event. Idempotent. |
| POST | /gamify/events/batch | Emit up to 100 events in one request. Per-item idempotency via body keys. |
| GET | /gamify/participants/{participant_id}/events | Paginated event history with filters. |
POST/api/v1/gamify/events
Participant keyIdempotent
Emit a single custom event for a participant. The event is persisted as a fact, evaluated against active challenges, and may trigger badge unlocks, tier transitions, and outbound webhooks. Safe to retry through the Idempotency-Key header; a second call with the same key returns the original response.
Headers
| Field | Type | Description |
|---|
| Idempotency-Key | str | Optional. 1 to 255 chars matching ^[A-Za-z0-9_\-:.]{1,255}$. Recommended for every call so retries never produce duplicate facts. |
Request body
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. Auto-creates the participant on first interaction. |
| event_namerequired | str | Event name to emit. 1 to 100 characters. Use snake_case (purchase_completed, video_watched). |
| properties | dict[str, Any] | Free-form event payload. Read by challenge evaluators and forwarded to outbound webhooks. Default: {} |
| timestamp | Optional[datetime] | Event occurrence time. Defaults to server time (UTC). Naive datetimes are stored as UTC. |
| idempotency_key | Optional[str] | Legacy body idempotency key (max 255 chars). The Idempotency-Key header is preferred; when both are supplied they must match. |
POST /api/v1/gamify/events
X-API-Key: bq_live_xxxxx
Content-Type: application/json
Idempotency-Key: purchase_ord_001
{
"participant_id": "user_42",
"event_name": "purchase_completed",
"properties": {
"amount": 49.99,
"currency": "USD",
"product_id": "prod_abc"
},
"timestamp": "2026-02-14T10:00:00Z"
}
Response fields
| Field | Type | Description |
|---|
| event_id | Optional[str] | Identifier of the persisted event record. |
| fact_id | Optional[str] | Identifier of the fact emitted into the rules pipeline. |
| status | str | Processing status. Default: "processed" |
| rewards_granted | list[dict[str, Any]] | Rewards triggered by this event (badge unlocks, point awards, reward grants). Empty list when nothing fired. Default: [] |
{
"event_id": "01HZ...",
"fact_id": "01HZ...",
"status": "processed",
"rewards_granted": []
}
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. |
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
| 429 | RATE_LIMIT_PARTICIPANT_EXCEEDED | Per-participant write rate cap exceeded. The Retry-After response header tells you when to retry. |
POST/api/v1/gamify/events/batch
Participant key
Emit up to 100 events in a single request. Each event is processed independently; per-item failures are reported in the results array without failing the whole request. Use the body-level idempotency_key on each event for retry safety (the request-level Idempotency-Key header is not honoured here).
Request body
| Field | Type | Description |
|---|
| eventsrequired | list[EmitEventRequest] | Array of 1 to 100 events. Each entry uses the same shape as POST /events. Set idempotency_key per item for retry safety. |
POST /api/v1/gamify/events/batch
X-API-Key: bq_live_xxxxx
Content-Type: application/json
{
"events": [
{
"participant_id": "user_42",
"event_name": "purchase_completed",
"properties": { "amount": 49.99 },
"idempotency_key": "purchase_ord_001"
},
{
"participant_id": "user_42",
"event_name": "loyalty_signup",
"properties": { "channel": "email" },
"idempotency_key": "signup_user_42"
}
]
}
Response fields
| Field | Type | Description |
|---|
| processed | int | Count of events that completed successfully. |
| failed | int | Count of events that returned an error. |
| results | list[EmitEventResponse] | Per-item results in submission order. Failed items have status="error" and null event_id / fact_id. |
{
"processed": 2,
"failed": 0,
"results": [
{
"event_id": "01HZ...",
"fact_id": "01HZ...",
"status": "processed",
"rewards_granted": []
},
{
"event_id": "01HZ...",
"fact_id": "01HZ...",
"status": "processed",
"rewards_granted": []
}
]
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
| 422 | unprocessable_entity | events array is empty or exceeds 100 entries, or an item fails schema validation. |
GET/api/v1/gamify/participants/{participant_id}/events
Participant key
Paginated event history for a participant, with optional filters by event_name and date range.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. |
Query parameters
| Field | Type | Description |
|---|
| event_name | Optional[str] | Filter to events with this exact name. |
| from_date | Optional[str] | Inclusive lower bound, ISO date (YYYY-MM-DD). |
| to_date | Optional[str] | Inclusive upper bound, ISO date (YYYY-MM-DD). |
| page | int | 1-indexed page number. Default: 1 |
| page_size | int | Items per page. Max 100. Default: 50 |
GET /api/v1/gamify/participants/user_42/events?event_name=purchase_completed&page=1&page_size=20
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| events | list[EventHistoryEntry] | Page of events. Each entry: id, event_name, properties (default {}), occurred_at. |
| total | int | Total events matching the filters across all pages. |
| page | int | Echo of the requested page. |
| page_size | int | Echo of the requested page size. |
{
"participant_id": "user_42",
"events": [
{
"id": "01HZ...",
"event_name": "purchase_completed",
"properties": { "amount": 49.99, "currency": "USD" },
"occurred_at": "2026-02-14T10:00:00Z"
}
],
"total": 156,
"page": 1,
"page_size": 20
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |