API: points economy
Most points work happens via earn rules wired to events. Sometimes you need to grant or deduct directly: bonus campaigns, refunds, manual corrections. This page covers the direct endpoints and how they interact with the rules engine.
Key takeaways
Quick read- Default to events. Earn rules grant points automatically. Direct grants are an escape hatch.
- deduct is atomic and guarded. Insufficient balance returns 422; the points do not partially leave.
- lifetime tracks earnings and never decreases. Used for tier qualification.
- available decreases on deduct, not on lifetime. Treat them as separate counters.
- Idempotency keys are required on grant and deduct. Without them, retries duplicate.
Grant
Issue points directly
curl -X POST https://api.bricqs.co/api/v1/gamify/points/grant \
-H "Authorization: Bearer bq_live_admin_..." \
-H "X-Bricqs-Tenant: tenant_brand_xyz" \
-H "Content-Type: application/json" \
-d '{
"participant_id": "p_8a3f",
"amount": 250,
"reason": "manual_correction",
"memo": "Apology credit, ticket #4271",
"idempotency_key": "manual:ticket:4271"
}'
# response
{
"available": 1500,
"lifetime": 5070,
"delta": 250,
"duplicate": false
}Use direct grants sparingly. Most points should flow through earn rules so the program ledger reads correctly.
Deduct
Atomic, guarded redemption
curl -X POST https://api.bricqs.co/api/v1/gamify/points/deduct \
-H "Authorization: Bearer bq_live_admin_..." \
-H "X-Bricqs-Tenant: tenant_brand_xyz" \
-H "Content-Type: application/json" \
-d '{
"participant_id": "p_8a3f",
"amount": 500,
"reason": "redeem_voucher",
"idempotency_key": "redeem:voucher_91x:p_8a3f"
}'
# success
HTTP/1.1 200 OK
{ "available": 1000, "lifetime": 5070, "delta": -500 }
# insufficient
HTTP/1.1 422 Unprocessable Entity
{ "error": "insufficient_points", "available": 100, "required": 500 }Deduct is atomic. The server uses a guarded UPDATE; concurrent deducts cannot drive the balance negative.
Lifetime vs available
Two counters, different jobs
lifetime
Cumulative earnings. Never decreases. Used for tier qualification (e.g. 'Gold = 10,000 lifetime points'). Grants increase it; deducts do not affect it.
available
Spendable balance. Increases on grant, decreases on deduct. The number you show in the wallet UI.
Expiry
How points age out
Configuration (per tenant in dashboard):
expiry_policy: "fifo" | "lifo" | "none"
default_ttl_days: 365
On expiry:
- available decreases by the expiring batch
- lifetime is unchanged
- participant.points.expired event is fired (subscribe via webhook)
- Points expired in the last 90 days are queryable via GET /points/history
Reminders (configured in dashboard):
- 60 / 30 / 7 / 1 days before expiry
- Sent via webhook; you forward to your ESPMultipliers
Run a 2x weekend without changing the base rate
curl -X POST https://api.bricqs.co/api/v1/admin/points/multipliers \
-H "Authorization: Bearer bq_live_admin_..." \
-d '{
"id": "weekend_2x_apr",
"multiplier": 2,
"starts_at": "2026-04-26T00:00:00Z",
"ends_at": "2026-04-28T23:59:59Z",
"match": {
"event_type": "purchase_completed",
"attributes": { "category": "skincare" }
}
}'Multipliers apply to events that match. They do not affect direct grants or deducts. Stack with care; the dashboard shows the effective rate per cohort.
Common mistakes
What goes wrong
Granting points without idempotency. Retries duplicate balances.
Always pass idempotency_key. Use a deterministic format (reason : subject).
Deducting points before checking available. The 422 returns mid-flow with bad UX.
Read the participant state first if the UI needs to disable a button. The deduct endpoint is the source of truth, but the UI can pre-validate.
Treating lifetime as available. Tier qualification breaks after redemption.
Tier qualification reads lifetime, which is unaffected by spend. Use available for the wallet UI.
Hardcoding the multiplier in earn rules. Rolling back is hard.
Use a multiplier object with starts_at and ends_at. Easy to roll out, easy to roll back, leaves earn rules clean.
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.
