Pattern: spin campaign
A 10-day sale spin wheel with email gate, server-side prize draw, one spin per identity per day, and one-tap redeem. The whole campaign ships in a working day if your auth and ESP are already wired.
Key takeaways
Quick read- Configure the spin engagement once. Prize segments and odds live server-side.
- Email gate runs before the spin, not after. Capture rate halves if you wait.
- Server-side prize draw. The client animates to the predetermined outcome; never decides.
- One spin per identity per day enforced server-side via idempotency keys.
- Auto-apply the reward at checkout via API; no copy-paste codes.
Anatomy
What you are building
API
POST /admin/engagements creates the spin. POST /events submits each spin. The server runs the draw.
SDK
useSpinWheel({ engagementId, activityId, config }) returns the segments and a spin() that resolves to the server-drawn prize.
User sees
Email field, then a spinning wheel that lands on a prize. Reveal moment, then a one-tap claim button.
Step 1: config
Define the spin
curl -X POST https://api.bricqs.co/api/v1/admin/engagements \
-d '{
"id": "diwali_spin_2026",
"type": "spin_wheel",
"window": { "start": "2026-10-25", "end": "2026-11-05" },
"rate_limit": { "per_identity_per_day": 1 },
"segments": [
{ "id": "jackpot", "label": "Free outfit (jackpot)", "weight": 1,
"reward": { "type": "voucher", "value": 5000 } },
{ "id": "mid_voucher","label": "500 INR off", "weight": 15,
"reward": { "type": "voucher", "value": 500 } },
{ "id": "shipping", "label": "Free shipping", "weight": 35,
"reward": { "type": "perk", "id": "free_shipping_one_order" } },
{ "id": "small_off", "label": "5% off", "weight": 49,
"reward": { "type": "coupon", "value_percent": 5 } }
],
"max_reward_liability": 500000
}'Step 2: email gate
Capture before the spin
"use client";
import { useState } from "react";
export function SpinGate({ onPass }: { onPass: () => void }) {
const [email, setEmail] = useState("");
return (
<form
onSubmit={async (e) => {
e.preventDefault();
await fetch("/api/bricqs/identify", {
method: "POST",
body: JSON.stringify({ email }),
});
onPass();
}}
>
<h2>Spin to win up to 5,000 INR off</h2>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@email.com"
/>
<button>Spin to reveal</button>
</form>
);
}The /api/bricqs/identify route on your server creates or upserts the participant via the admin API and returns a participant token.
Step 3: spin
Server-determined draw
"use client";
import { useSpinWheel } from "@bricqs/sdk-react";
export function SpinWheel() {
const { isSpinning, result, rotation, spin, confirmResult } = useSpinWheel({
engagementId: "diwali_spin_2026",
activityId: "spin_wheel_1",
config: { segments: SEGMENTS },
});
async function onSpin() {
// Server draws the result first — the client only animates to it.
const outcome = await spin();
await animateToRotation(rotation);
// Records completion + applies the reward's onCompletion actions.
await confirmResult();
if (outcome) setRevealedReward(outcome.segment.label);
}
return (
<button onClick={onSpin} disabled={isSpinning}>
{result ? "Spin again" : "Spin"}
</button>
);
}The server draws before the wheel moves, so the animation always lands on the real prize. confirmResult() applies the reward once the animation completes.
Step 4: claim
Auto-apply the reward
async function claimAndCheckout(rewardId: string) {
const res = await fetch("/api/bricqs/claim-reward", {
method: "POST",
body: JSON.stringify({ rewardId }),
});
const { code } = await res.json();
// Apply to the cart server-side, route to checkout
await applyDiscountCode(code);
router.push("/checkout");
}Step 5: anti-fraud
What runs automatically
Bricqs enforces:
- One spin per identity per day (configured rate_limit)
- max_reward_liability cap; jackpot allocation halts when exceeded
- Server-side draw (segment is decided on the server, never on the client)
- Disposable email pattern detection
- IP and device velocity caps (cross-day attempts from same fingerprint)
You should add:
- hCaptcha or Turnstile on the email gate for cold traffic
- Email confirmation step before claiming high-value prizes
- Manual review for jackpot wins above a thresholdDeveloper 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.
