Webhooks
Bricqs delivers progression events (badges, tiers, points, streaks, milestones, challenges, contests, referrals, rewards) and engagement activity events to HTTPS endpoints you register. Every delivery is HMAC-signed, retried on failure, logged, and manually replayable. The machine-readable list of subscribable events and their payload schemas is published at https://api.bricqs.co/.well-known/events.json.
X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.https://api.bricqs.co/api/v1/gamifyEndpoint inventory
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /gamify/webhooks | List destinations. |
| POST | /gamify/webhooks | Create a destination. Returns the signing secret. |
| GET | /gamify/webhooks/{destination_id} | Read one destination. |
| PATCH | /gamify/webhooks/{destination_id} | Update url, events, retries, timeout, active state. The URL is re-validated against SSRF rules. |
| DELETE | /gamify/webhooks/{destination_id} | Delete a destination. |
| POST | /gamify/webhooks/{destination_id}/test | Send a signed test delivery (X-Bricqs-Event: ping). |
| GET | /gamify/webhooks/{destination_id}/logs | Delivery history (status, attempts, response codes). |
| POST | /gamify/webhooks/{destination_id}/deliveries/{log_id}/replay | Replay one delivery. |
| POST | /gamify/webhooks/{destination_id}/replay | Bulk replay; returns a job id. |
| GET | /gamify/webhooks/{destination_id}/replay-jobs/{job_id} | Bulk replay job status. |
/api/v1/gamify/webhooksRegister an HTTPS endpoint for event delivery. The response includes the generated signing secret: store it server-side. There is no secret-rotation endpoint; to rotate, delete the destination and create a new one.
| Field | Type | Description |
|---|---|---|
| namerequired | str | Display name, 1 to 100 characters. Names prefixed [system] are reserved and rejected. |
| urlrequired | str | HTTPS endpoint URL. Validated against SSRF rules (no private ranges). |
| eventsrequired | list[str] | Event types to subscribe to. Every entry must exist in the published catalog (events.json); unknown names are rejected. |
| engagement_id | Optional[str] | Scope delivery to one engagement. Omit for all. |
| custom_headers | dict | Extra headers added to every delivery (for your own auth). Default: {} |
| retry_count | int | Retries after the initial attempt, 0 to 5. Default: 3 |
| timeout_seconds | int | Per-attempt response timeout, 3 to 60. Default: 10 |
# Standard bq_live_... key carrying the admin (or gamify:admin) scope.
curl -X POST https://api.bricqs.co/api/v1/gamify/webhooks \
-H "X-API-Key: bq_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "crm-progression-sink",
"url": "https://api.your-app.com/bricqs/webhooks",
"events": ["badge.earned.v1", "tier.changed.v1", "reward.claimed.v1"]
}'| Status | Code | When it fires |
|---|---|---|
| 401 | AUTH_UNAUTHENTICATED | No admin credential supplied. |
| 403 | AUTH_FORBIDDEN | Credential lacks the admin / gamify:admin scope. |
| 422 | VALIDATION_INVALID_VALUE | Unknown event name, non-HTTPS or SSRF-blocked URL, reserved [system] name prefix, or out-of-range retry/timeout. |
Delivery contract
Every delivery is an HTTPS POST to your destination URL with these headers and a canonical JSON envelope. The same envelope (same id) also appears on the participant’s live SSE stream, so the two transports are correlatable.
| Field | Type | Description |
|---|---|---|
| X-Bricqs-Signature | str | t={unix_timestamp},v1={hex}. HMAC-SHA256 over the string "{timestamp}.{raw_body}" with the destination secret. |
| X-Bricqs-Event | str | Event name (ping for test deliveries). |
| X-Bricqs-Timestamp | str | Unix timestamp used in the signature. |
| X-Bricqs-Delivery-Id | str | Stable across retries of the same delivery. Use this as your dedupe key. |
| Field | Type | Description |
|---|---|---|
| id | str | evt_-prefixed event id. Equals X-Bricqs-Delivery-Id. |
| event | str | Event name, exactly as in the catalog. |
| timestamp | str | ISO 8601 emission time (UTC). |
| tenant_id | str | Your tenant id. |
| engagement_id | Optional[str] | Set when the event is engagement-scoped. |
| participant_id | Optional[str] | The affected participant. |
| data | dict | Event payload. Schema per event in events.json. Can be {} on retries/replays (see non-guarantees). |
Retry schedule
A delivery succeeds only on an HTTP 2xx response within timeout_seconds. Anything else (timeout, 4xx, 5xx) schedules a retry with this backoff:
attempt 1 immediate
attempt 2 +30 seconds
attempt 3 +5 minutes
attempt 4 +30 minutes
(total attempts = retry_count + 1; retry_count default 3, max 5)
After the final attempt the delivery is EXHAUSTED (terminal).
Recovery is manual: the replay endpoints above.Subscribable events
The catalog at https://api.bricqs.co/.well-known/events.json is the contract: 25 events with JSON payload schemas. Versioned progression events (badge.earned.v1, tier.changed.v1, points.awarded.v1, streak.continued.v1, challenge.completed.v1, contest.prize_allocated.v1, referral.converted.v1, reward.claimed.v1, reward.points_expired.v1, and more) plus legacy engagement activity events (activity.completed, quiz.completed, ...).
Each catalog entry carries a status: active events fire today; deferred events (currently reward.expired.v1 and game.completed) are subscribable and schema-published but have no emitter yet. Do not block an integration waiting on a deferred event.
Non-guarantees
- No ordering. Deliveries are not ordered, within or across participants. Retries make out-of-order arrival normal; process idempotently and order on the envelope
timestampif you need a sequence. - Replay payloads can be redacted. Retried and replayed deliveries can carry
"data": {}. Treat the envelope as a trigger and re-fetch state viaGET /api/v1/gamify/state/{participant_id}. - No secret rotation endpoint. Rotate by deleting and recreating the destination (two destinations can point at the same URL during the cutover).
- Exhausted is terminal. Nothing re-sends automatically after the retry schedule; use the replay endpoints.
