Core concepts
Rewards & Redemptions
Rewards are items that customers can purchase with their accumulated loyalty points. When a customer spends points on a reward, a redemption is created with a unique confirmation code.
Reward types
Discount
A monetary discount applied to a future purchase:
| Field | Description |
|---|---|
discount_value | The discount amount |
discount_type | percent (e.g., 10% off) or fixed (e.g., EUR 5.00 off) |
Free product
A complimentary product or service:
| Field | Description |
|---|---|
product_reference | Reference to the free product (vendor-defined) |
Reward properties
| Field | Type | Description |
|---|---|---|
id | integer | Unique reward ID |
name | string | Reward name |
description | string | Reward description |
type | string | discount or free_product |
point_cost | integer | Number of points required to redeem |
total_stock | integer | Total available stock (null = unlimited) |
remaining_stock | integer | Remaining stock |
status | string | active or inactive |
available_from | datetime | Start of availability window (optional) |
available_until | datetime | End of availability window (optional) |
image_path | string | Uploaded reward image |
code_valid_for_hours | integer | Hours the confirmation code is valid (optional) |
branches | array|null | The branches this reward may be redeemed at, each { "external_id", "name", "type" }. null means every branch |
Availability
Rewards can have a limited availability window defined by available_from and available_until. The API only returns rewards that are currently within their availability window and have remaining stock.
Redemption flow
1. Customer selects a reward
The POS system lists available rewards and the customer chooses one. Use the list rewards endpoint to fetch active rewards.
2. Submit a redemption
POST /api/v1/redemptions
{
"identifier": "CARD-001",
"reward_id": 5,
"idempotency_key": "redeem-2024-0042"
}
The API validates:
- The customer has sufficient wallet balance
- The reward is active and available
- The reward has remaining stock
- The reward allows the branch the redemption is recorded at
The idempotency_key makes the call safe to retry: re-sending the same key
returns the original redemption instead of deducting points twice.
Where the redemption happened
branch is your own key for the shop: the external_id you gave it. It follows the same chain a
transaction's branch does: the key in the payload wins, otherwise the API credential's default branch,
otherwise none. A key matching none of your branches is refused with BRANCH_NOT_FOUND (422), so
a typo cannot pass for an unattributed redemption.
A reward that names branches may only be redeemed at one of them. Send no branch, or a branch
outside its set, and the call is refused with BRANCH_REQUIRED (422). One code for both, because
both have the same fix: name a branch the reward allows.
The branch is recorded once. A replay of the same idempotency_key returns the original
redemption with the branch the first call recorded, even when the replay names a different one.
3. Confirmation code issued
On success, the API deducts points from the customer's wallet and returns a redemption with a confirmation code:
{
"data": {
"redemption_id": 12,
"confirmation_code": "PNTJ-K4MP7QRS",
"reward": {
"name": "Free Coffee",
"type": "free_product"
},
"points_deducted": 500,
"remaining_balance": 1000,
"redeemed_at": "2024-03-15T12:30:00+00:00",
"expires_at": "2024-03-15T14:30:00+00:00"
}
}
4. Verify the redemption
When the customer presents their confirmation code, verify it:
POST /api/v1/redemptions/{code}/verify
This transitions the redemption status from pending to verified.
Redemption status
| Status | Description |
|---|---|
| pending | Code issued, awaiting verification at POS |
| verified | Code verified and reward delivered |
Confirmation code expiration
If code_valid_for_hours is set on a reward, the confirmation code expires after that duration. Expired codes cannot be verified. The expires_at field in the redemption response indicates when the code will expire.
Looking up a redemption
You can look up a redemption by its confirmation code:
GET /api/v1/redemptions/{code}
This is useful for POS systems that need to display redemption details before verifying.
See Redemption endpoints for the complete API reference.