Gamification architecture
Bricqs is an event-driven engagement engine. Events come in, facts are produced, the rules engine decides what changes — points, tiers, badges, challenge progress, contest scores, webhooks. This page is the working mental model for everything you build on top of the platform.
Key takeaways
Quick read- Everything is tenant-scoped. Tenants own participants, programs, rewards, and API keys.
- Events are the universal input. POST one event, the rules engine fans it out to challenges, contests, points, streaks, and webhooks.
- Facts are the immutable middle layer. They are how progression and contests stay consistent under retries.
- Progression entities (points, tiers, badges, streaks) are passive calculators. They do not emit events; they react to facts.
- The same event can update points, score a contest, and progress a challenge at the same time. You do not need to call three endpoints.
The model
Five core entities
Tenant
The brand or environment. Owns API keys, programs, participants, rewards. Every request is scoped to one tenant.
Participant
An end-user identity. Created automatically on first event or first explicit registration. Carries points, tier, streaks, challenge progress.
Event
Something a participant did. quiz_submitted, purchase_completed, custom.foo. Sent via REST or SDK.
Fact
An internal, deduplicated record of an event after validation. The rules engine reads facts; everything downstream operates on them.
Program
Anything that consumes facts: a challenge, a contest, a points rule, a streak, a leaderboard window. Configured once, evaluated continuously.
Event flow
From POST to progression
Every Bricqs integration moves through this sequence. Knowing the order helps debug everything.
Client (web, mobile, server)
│
│ POST /api/v1/ingest/events
│ { participant_id, event_type, attributes, idempotency_key }
│
▼
Ingestion (the event buffer)
│ Validates schema, rate limits, dedupes by idempotency_key
│
▼
Fact Bridge
│ Persists Fact (immutable). Triggers ChallengeRulesEngine.
│
├──▶ Challenge Rules Engine updates objective progress, completes if threshold met
├──▶ Contest Scoring Service scores entries, updates the in-memory ranked store
├──▶ Points Engine grants points per earn rule
├──▶ Streak Service extends or breaks streak based on grace
└──▶ Outbound Webhooks signs and delivers HMAC-signed payloadA single event can update progression, score a contest, advance a challenge, and trigger a webhook. You do not need to call multiple endpoints.
Separation of concerns
What lives where
The most common mistake is trying to make a passive entity emit events. Keep this table next to your build.
| Entity | Role | Emits events? | Reads facts? |
|---|---|---|---|
| Engagement (quiz, spin, scratch) | Active. The participant performed an action. | Yes (e.g. quiz_submitted) | No |
| Challenge | Reactive. Watches facts to advance objectives. | Sometimes (challenge_completed) | Yes |
| Contest | Reactive. Scores facts inside a window. | Sometimes (contest_completed) | Yes |
| Points | Passive calculator. Earns and spends are derived from facts. | No | Yes |
| Tier | Passive calculator. Computed from cumulative points or value. | No | Yes |
| Badge | Passive calculator. Awarded when condition is met. | No | Yes |
| Streak | Reactive. Advances on each qualifying fact in window. | No | Yes |
| Webhook | Outbound. Delivers signed events to your stack. | No | Yes |
A worked example
One event, four updates
A user finishes a fitness quiz with a perfect score. You POST one event. Behind the scenes, here is what changes.
{
"participant_id": "p_8a3f",
"event_type": "quiz_completed",
"attributes": {
"quiz_id": "q_fit_basics",
"score": 100,
"time_seconds": 42
},
"idempotency_key": "p_8a3f:q_fit_basics:2026-04-30"
}Points engine
Earn rule fires: 'quiz_completed with score=100' grants 50 points. Participant balance updated atomically.
Challenge rules engine
30-day fitness challenge has objective 'finish 5 quizzes'. Counter increments to 3 of 5.
Contest scoring service
Quiz contest is active. Entry created, score 100 added to the ranked store, leaderboard recomputed.
Outbound webhook
If your tenant has a webhook for points.granted, an HMAC-signed POST goes to your endpoint within 60 seconds.
Idempotency
Why every event needs a key
Networks fail. Clients retry. Webhooks redeliver. Without an idempotency key, retries double-credit the user. With one, the second POST short-circuits at ingestion and the participant sees one fact, one points grant, one contest entry.
Recommended format:
participant_id : event_subject : period
Examples:
p_8a3f : q_fit_basics : 2026-04-30
p_8a3f : checkout_complete : order_4271
p_8a3f : streak_tick : 2026-04-30
Rules:
- Same key inside 24 hours = duplicate, ignored.
- Different attributes with same key = first write wins.
- 200 OK with duplicate: true on the response.Developer FAQ
Common questions when integrating gamification with Bricqs.
Ready to ship?
Wire it up with the Bricqs SDK or API
Headless SDK for React UIs, REST API for any backend. Same engine behind both.
