Loyalty Earn & Redeem
Earning Points (POS)
Points are earned when a basket is finalized. Call the earn endpoint after POST .../finalize:
POST
/pos/api/v1/loyalty/earncurl -X POST "http://localhost:5003/pos/api/v1/loyalty/earn" \
-H "X-Api-Key: rsa_live_..." \
-H "Content-Type: application/json" \
-d '{
"memberId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"basketId": "b1c2d3e4-...",
"referenceId": "TXN-2026-001234",
"points": 125,
"storeId": "s1t2u3v4-..."
}'
Response (201 Created):
{
"transactionId": "t1u2v3w4-...",
"pointsAwarded": 125,
"newBalance": 1375,
"referenceId": "TXN-2026-001234"
}
referenceId is the idempotency key. Resubmitting the same referenceId returns the original transaction — no double-crediting.
Redeeming Points at POS
POST
/pos/api/v1/loyalty/redeemcurl -X POST "http://localhost:5003/pos/api/v1/loyalty/redeem" \
-H "X-Api-Key: rsa_live_..." \
-H "Content-Type: application/json" \
-d '{
"memberId": "3fa85f64-...",
"basketId": "b1c2d3e4-...",
"referenceId": "REDEEM-TXN-001",
"points": 500
}'
Response:
{
"transactionId": "...",
"pointsRedeemed": 500,
"dollarValue": 5.00,
"newBalance": 875
}
Shopper Self-Service Redeem
Members redeem points in their app via the Shopper API:
POST
/api/v1/loyalty/redeemcurl -X POST "http://localhost:5001/api/v1/loyalty/redeem" \
-H "Authorization: Bearer SHOPPER_JWT" \
-H "Content-Type: application/json" \
-d '{
"points": 500,
"referenceId": "app-redemption-uuid-abc123"
}'
Insufficient balance returns 422 Unprocessable Entity:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.23",
"title": "Insufficient loyalty balance",
"status": 422,
"detail": "Member has 250 points, requested 500",
"traceId": "00-4bf5122f344..."
}
Checking Balance
# Shopper
GET /api/v1/loyalty/balance → { "points": 875, "tier": "Silver" }
# POS
GET /pos/api/v1/members/{id}/balance → { "points": 875, "tier": "Silver" }
Viewing Transaction History (Shopper)
GET
/api/v1/loyalty/transactionsReturns paginated list of all earn and redeem transactions for the authenticated member.