Pattern: sports prediction
A pre-match prediction game across a tournament. Users pick the outcome, predictions lock at kickoff, scoring runs on the final result, the weekly leaderboard awards prizes. Sponsorable on every screen.
Key takeaways
Quick read- Each match is a contest. Predictions are events with attributes; scoring evaluates after the result is known.
- Kickoff lock is enforced server-side via window.starts_at. Late predictions return 422.
- Weekly leaderboard is a separate contest with a 7-day window; it aggregates the per-match scores.
- Sponsor logos and themes are configured per contest; the SDK reflects them automatically.
- Edge cases (rain, abandonment, retirement) handled via admin endpoints, not by editing the active contest.
Anatomy
What you are building
API
Contests (per-match and weekly) and their scoring rules are configured in the dashboard. Your app submits predictions as events; scoring and leaderboards run server-side. Match results are recorded from the dashboard, after which the contest scores predictions.
SDK
useEngagement renders the prediction form; useLeaderboard renders the bracket and the global top.
User sees
Live match list with countdown to lock. Pre-match: pick the winner. Post-match: score, rank, points to next position.
Step 1: config
Configure one contest per match
Contests and their scoring rules are configured in the dashboard, not via a public API. For each match you set up a contest with:
Per-match contest (dashboard):
Title Qualifier Semi-Final, May 3
Window 2026-05-03 18:00Z -> 22:00Z
Lock at kickoff (predictions close)
Scoring prediction event 'prediction_submitted'
winner correct -> 10 pts
exact score -> 25 pts
Predictions arrive as events from your app; the contest scores them
server-side once you record the result (Step 4).Step 2: aggregate
Weekly leaderboard contest
A second, longer contest aggregates the week’s per-match scores into a leaderboard with a prize structure. Also configured in the dashboard:
Weekly leaderboard contest (dashboard):
Window 2026-05-01 -> 2026-05-07
Aggregates the week's per-match contest scores
Prize structure ranks 1-50 -> voucher 500
Contest scoring and aggregation run inside the contest engine on background
workers; you do not wire the per-match totals together yourself.Step 3: predict
Submit a prediction
"use client";
import { useEngagement } from "@bricqs/sdk-react";
export function PredictionForm({ matchId }: { matchId: string }) {
const { engagement, state, submit } = useEngagement({
engagementId: matchId,
sync: false,
});
async function pick(team: string, score: string) {
await submit({
attributes: { winner: team, score },
attemptId: `prediction:${matchId}:${userId}`,
});
}
if (!engagement) return null;
if (state.locked) return <p>Locked at kickoff.</p>;
return (
<div>
<button onClick={() => pick("home", "2-1")}>Home wins 2-1</button>
<button onClick={() => pick("away", "1-0")}>Away wins 1-0</button>
</div>
);
}Step 4: record result
When the match ends
Record the match result in the dashboard (Contests -> the match -> result):
Outcome winner = home, score = 2-1
What happens next, server-side:
1. The contest moves into scoring.
2. Each prediction is scored against the contest's rules.
3. When scoring completes, the contest.completed.v1 webhook fires and the
weekly leaderboard reflects the new points.Step 5: leaderboard
Bracket and global top
"use client";
import { useLeaderboard } from "@bricqs/sdk-react";
export function PredictionLeaderboard() {
// engagementId inherited from <BricqsProvider>
const { entries, myRank } = useLeaderboard({
code: "week_18_leaderboard",
limit: 10,
});
return (
<div>
{myRank != null && <p className="mb-3 text-sm text-slate-500">You're #{myRank}</p>}
<RankList title="Top 10" rows={entries} myRank={myRank} />
</div>
);
}Step 6: edge cases
Rain, abandonment, walkover
Handle these from the dashboard (Contests -> the match):
Match abandoned -> void the contest; no points are awarded
Walkover -> record the result as a walkover; predictions for the
winning side score normally
Voiding and result-recording are dashboard actions. The contest engine then
cancels or re-scores predictions accordingly.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.
