Rewards API
List the rewards a participant can claim, claim one (optionally spending points in the same call), and read the participant’s claim history. Reward definitions and code inventory are managed through admin endpoints. Reward types: coupon, voucher, physical, digital, points_multiplier.
AuthAll endpoints require an X-API-Key header. Production keys are prefixed bq_live_; sandbox keys bq_test_.
ScopesParticipant key List, claim, and read claimed rewards with any valid API key.
Admin scope Manage reward definitions and inventory: requires admin or gamify:admin scope.
Base URLhttps://YOUR_API_DOMAIN/api/v1/gamify
Endpoint inventory
| Method | Endpoint | Purpose |
|---|
| GET | /gamify/rewards | List active rewards available to claim. Optional reward_type filter. |
| GET | /gamify/participants/{participant_id}/rewards | List rewards already claimed by a participant. |
| POST | /gamify/rewards/{reward_id}/claim | Claim a reward. Idempotent. |
| GET | /gamify/admin/rewards | List reward definitions. Admin scope. |
| POST | /gamify/admin/rewards | Create a reward definition. Admin scope. |
| GET | /gamify/admin/rewards/{reward_id} | Get one reward definition. Admin scope. |
| PATCH | /gamify/admin/rewards/{reward_id} | Update a reward definition. Admin scope. |
| DELETE | /gamify/admin/rewards/{reward_id} | Deactivate (soft-delete) a reward. Admin scope. |
GET/api/v1/gamify/rewards
Participant key
List active rewards available to claim for the tenant. Each entry includes the points cost (if any), remaining code inventory, and per-user claim cap.
Query parameters
| Field | Type | Description |
|---|
| reward_type | Optional[str] | Filter by reward type: coupon, voucher, physical, digital, points_multiplier. |
GET /api/v1/gamify/rewards?reward_type=coupon
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| rewards | list[AvailableRewardResponse] | Array of available rewards. Each entry has: id, name, type, optional description, optional points_cost, optional available_codes (remaining inventory), max_claims_per_user (default 1), optional expires_at. |
| total | int | Total number of rewards in the response. |
{
"rewards": [
{
"id": "rwd_uuid",
"name": "10% Off Coupon",
"type": "coupon",
"description": "10% discount on next purchase",
"points_cost": 500,
"available_codes": 45,
"max_claims_per_user": 1,
"expires_at": "2026-12-31T23:59:59Z"
}
],
"total": 1
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
GET/api/v1/gamify/participants/{participant_id}/rewards
Participant key
List every reward the participant has claimed. Use this to render a wallet or rewards inbox in your app.
Path parameters
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
GET /api/v1/gamify/participants/user_42/rewards
X-API-Key: bq_live_xxxxx
Response fields
| Field | Type | Description |
|---|
| participant_id | str | Echo of the requested participant id. |
| rewards | list[ClaimedRewardEntry] | Array of claims. Each entry has: claim_id, reward_name, reward_type, optional code_value (the redeemable code, when applicable), claimed_at, optional expires_at. |
| total | int | Total number of claims for this participant. |
{
"participant_id": "user_42",
"rewards": [
{
"claim_id": "claim_uuid",
"reward_name": "10% Off Coupon",
"reward_type": "coupon",
"code_value": "SAVE10-ABC123",
"claimed_at": "2026-04-12T10:14:00Z",
"expires_at": "2026-12-31T23:59:59Z"
}
],
"total": 1
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | Tenant is disabled. |
POST/api/v1/gamify/rewards/{reward_id}/claim
Participant keyIdempotent
Claim a reward on behalf of a participant. Optionally deducts the reward's points_cost from the participant's balance in the same call. Safe to retry through the Idempotency-Key header; a second call with the same key returns the original claim without double-issuing a code or double-deducting points.
Path parameters
| Field | Type | Description |
|---|
| reward_idrequired | UUID | The reward definition to claim. Returned from GET /rewards as id. |
Headers
| Field | Type | Description |
|---|
| Idempotency-Key | str | Optional. 1 to 255 chars matching ^[A-Za-z0-9_\-:.]{1,255}$. Recommended for every call so retries are safe. |
Request body
| Field | Type | Description |
|---|
| participant_idrequired | str | Your participant identifier. 1 to 255 characters. |
| points_deduction | bool | When true, the participant's available_points balance is decremented by the reward's points_cost as part of the same claim. When false, the reward is issued without touching the points balance. Default: false |
POST /api/v1/gamify/rewards/rwd_uuid/claim
X-API-Key: bq_live_xxxxx
Content-Type: application/json
Idempotency-Key: claim-user_42-rwd_uuid-1
{
"participant_id": "user_42",
"points_deduction": true
}
Response fields
| Field | Type | Description |
|---|
| claim_id | str | Unique identifier for this claim. Use this when reconciling with your downstream order or fulfilment system. |
| participant_id | str | Echo of the claiming participant. |
| reward_name | str | Display name of the claimed reward. |
| reward_type | str | coupon, voucher, physical, digital, or points_multiplier. |
| code_value | Optional[str] | Redeemable code allocated from inventory (coupon / voucher) or null when the reward type does not use codes. |
| expires_at | Optional[datetime] | When the issued code expires. null when the reward never expires. |
| points_deducted | Optional[int] | Points removed from the participant's available balance. null when points_deduction was false. |
| new_balance | Optional[int] | Participant's available_points after the deduction. null when points_deduction was false. |
{
"claim_id": "claim_uuid",
"participant_id": "user_42",
"reward_name": "10% Off Coupon",
"reward_type": "coupon",
"code_value": "SAVE10-ABC123",
"expires_at": "2026-12-31T23:59:59Z",
"points_deducted": 500,
"new_balance": 1000
}
Errors
| Status | Code | When it fires |
|---|
| 400 | IDEMPOTENCY_KEY_INVALID | Idempotency-Key header is empty, longer than 255 chars, or contains characters outside [A-Za-z0-9_\-:.]. |
| 400 | IDEMPOTENCY_KEY_MISMATCH | Both the Idempotency-Key header AND a body idempotency_key were provided and they differ. |
| 400 | insufficient_points | points_deduction is true and the participant's available balance is below points_cost. Message format: "Insufficient points. Available: X, requested: N". |
| 400 | reward_not_available | The reward is configured with a future availability date and has not opened yet ("Reward not yet available"). |
| 400 | reward_expired | The reward's expires_at has already passed ("Reward has expired"). |
| 400 | reward_out_of_stock | No unallocated codes remain in inventory ("Reward is out of stock"). |
| 400 | max_claims_reached | The participant has already claimed this reward up to its max_claims_per_user cap ("Maximum claims reached for this reward"). |
| 404 | reward_not_found | No reward exists for the supplied reward_id, or it has been deactivated. |
| 429 | RATE_LIMIT_PARTICIPANT_EXCEEDED | Per-participant write rate cap exceeded. The Retry-After response header tells you when to retry. |
GET/api/v1/gamify/admin/rewards
Admin scope
List every reward definition for the tenant, including inactive ones. Supports filtering by status and type plus paginated reads.
Query parameters
| Field | Type | Description |
|---|
| is_active | Optional[bool] | When set, filters to definitions where is_active matches. |
| reward_type | Optional[str] | Filter by reward type: coupon, voucher, physical, digital, points_multiplier. |
| page | int | 1-indexed page number. Default: 1 |
| page_size | int | Items per page. Max 100. Default: 50 |
GET /api/v1/gamify/admin/rewards?is_active=true&reward_type=coupon&page=1&page_size=50
X-API-Key: bq_live_xxxxx # must carry admin or gamify:admin scope
Response fields
| Field | Type | Description |
|---|
| items | list[AdminRewardResponse] | Reward definitions. Each entry has: id, name, type, optional description, optional points_cost, max_claims_per_user (default 1), optional total_inventory, optional config (free-form), is_active, created_at, optional updated_at. |
| total | int | Total matching definitions. |
| page | int | Current page. |
| page_size | int | Items per page used. |
{
"items": [
{
"id": "rwd_uuid",
"name": "10% Off Coupon",
"type": "coupon",
"description": "10% discount on next purchase",
"points_cost": 500,
"max_claims_per_user": 1,
"total_inventory": 100,
"config": { "code_prefix": "SAVE10-" },
"is_active": true,
"created_at": "2026-03-01T08:00:00Z",
"updated_at": "2026-04-12T15:30:00Z"
}
],
"total": 4,
"page": 1,
"page_size": 50
}
POST/api/v1/gamify/admin/rewards
Admin scope
Create a reward definition. Returns 201 on success. The reward's lookup code is auto-generated server-side as gamify_<8 hex>; you do not supply it.
Request body
| Field | Type | Description |
|---|
| namerequired | str | Display name. 1 to 200 chars. |
| typerequired | str | Reward type: coupon, voucher, physical, digital, or points_multiplier. |
| description | Optional[str] | Free-form description shown to participants. |
| points_cost | Optional[int] | Cost in points when claimed with points_deduction=true. Must be >= 0. Omit (or null) for free rewards. |
| max_claims_per_user | int | Maximum number of times a single participant may claim this reward. Must be >= 1. Default: 1 |
| total_inventory | Optional[int] | Total redeemable codes seeded into inventory. Must be >= 0. Omit for unlimited or non-code rewards. |
| config | Optional[dict[str, Any]] | Free-form configuration (e.g. code_prefix, fulfilment metadata) consumed by your downstream systems. |
| is_active | bool | Whether the reward is claimable immediately on creation. Default: true |
POST /api/v1/gamify/admin/rewards
X-API-Key: bq_live_xxxxx # admin or gamify:admin scope
Content-Type: application/json
{
"name": "10% Off Coupon",
"type": "coupon",
"description": "10% discount on next purchase",
"points_cost": 500,
"max_claims_per_user": 1,
"total_inventory": 100,
"config": { "code_prefix": "SAVE10-" },
"is_active": true
}
Errors
| Status | Code | When it fires |
|---|
| 401 | unauthorized | X-API-Key header missing, invalid, expired, or revoked. |
| 403 | forbidden | API key is missing the admin or gamify:admin scope. |
GET/api/v1/gamify/admin/rewards/{reward_id}
Admin scope
Retrieve one reward definition by its UUID. Response shape matches the items in the list endpoint.
Errors
| Status | Code | When it fires |
|---|
| 404 | reward_not_found | No reward exists for the supplied reward_id. |
PATCH/api/v1/gamify/admin/rewards/{reward_id}
Admin scope
Partial update of a reward definition. All body fields are optional; only supplied fields are changed. The reward type cannot be changed after creation.
Request body (all optional)
| Field | Type | Description |
|---|
| name | Optional[str] | 1 to 200 chars. |
| description | Optional[str] | Free-form description. |
| points_cost | Optional[int] | Must be >= 0. Set to null to make the reward free. |
| max_claims_per_user | Optional[int] | Must be >= 1. |
| total_inventory | Optional[int] | Must be >= 0. Affects newly seeded codes; already issued codes are not revoked. |
| config | Optional[dict[str, Any]] | Replaces the config payload entirely. |
| is_active | Optional[bool] | Set false to pause the reward without deleting it. Existing claims are preserved; participants can no longer claim new copies. |
Errors
| Status | Code | When it fires |
|---|
| 404 | reward_not_found | No reward exists for the supplied reward_id. |
DELETE/api/v1/gamify/admin/rewards/{reward_id}
Admin scope
Soft-delete the reward by setting is_active to false. Existing claims and issued codes are preserved; the reward stops appearing in GET /rewards.
{ "message": "Reward deactivated" }
Errors
| Status | Code | When it fires |
|---|
| 404 | reward_not_found | No reward exists for the supplied reward_id. |