POS integration.
Build a point-of-sale integration for member lookup, balance checks, purchases, rewards, stamps, and vouchers.
This guide shows the typical cashier workflow: identify the member, inspect their current loyalty state, record the sale, then redeem a reward, stamp card, or voucher when the member asks.
Use this guide for:
- in-store POS systems
- kiosk terminals
- cashier tablets
- back-office terminals that behave like a POS
Recommended scopes
Start with:
readwrite:transactionswrite:rewards
Add these only if you need them:
write:stampswrite:vouchers
Core flow
- Find or search the member.
- Check the member's balance on the active card.
- Record the purchase.
- If the member asks, redeem a reward, add stamps, or process a voucher.
- Persist the external order or ticket reference on your side for reconciliation.
For a brand-new member, step 1 answers not-found by design. See First-time customers.
Member lookup
The partner API supports multiple member identifier formats. This is useful because different POS systems know different identifiers at checkout time.
Accepted forms:
- member UUID
- member number
- unique identifier
Examples:
{ "member_identifier": "[email protected]" }
{ "member_identifier": "MEM-2024-00001" }
{ "member_identifier": "550e8400-e29b-41d4-a716-446655440000" }
{ "member_identifier": "344-319-665-971" }
Exact lookup:
GET /api/agent/v1/partner/members/[email protected] HTTP/1.1
Host: your-domain.com
Accept: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
Search fallback:
GET /api/agent/v1/partner/members?search=jane&per_page=25 HTTP/1.1
Host: your-domain.com
Accept: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
First-time customers
Lookup and search return only members who have already interacted with your business: earned points, collected a stamp, redeemed a voucher, or used a pass. A member who joined a card seconds ago, for example by scanning its QR code, has no interaction yet, so lookup answers not-found even though the member exists.
The transaction endpoints resolve member_identifier without the interaction requirement, so skip the lookup and record the purchase with the identifier the customer presents: their email, their member number, or the 12-digit identifier shown with the QR code in the member app. The QR code carries a rotating code for the built-in staff scanner, so ask for one of the three identifiers above instead of scanning it into your POS.
That first purchase completes everything on its own. It enrolls the member on the card if they had not joined it yet and credits any initial bonus points the card offers on top of the points for the sale. From then on, lookup and search find the member.
This gives you the fastest flow at a busy counter: the customer joins by scanning the card's QR code on their own phone, with no POS work, and their first order activates the membership. To mirror new members into your POS customer records as they appear, subscribe to webhooks and upsert from whichever event arrives first. See member synchronization.
Balance check
Once you know the member and the active card, fetch the live balance:
GET /api/agent/v1/partner/members/550e8400-e29b-41d4-a716-446655440000/balance/3598a5db-f008-477c-ac4d-5365c662ad62 HTTP/1.1
Host: your-domain.com
Accept: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"error": false,
"data": {
"member_id": "550e8400-e29b-41d4-a716-446655440000",
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"balance": 420,
"currency": "USD"
}
}
Record the purchase
Use POST /partner/transactions/purchase to award points for the sale.
POST /api/agent/v1/partner/transactions/purchase HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"member_identifier": "[email protected]",
"purchase_amount": 24.50,
"staff_id": "9a126c5f-8737-4f0a-83b2-11a6b7e8f901",
"note": "Order #12345"
}
{
"error": false,
"data": {
"transaction_id": "019cce5d-c950-71d7-8f6f-731f06c3cf56",
"points_awarded": 2450,
"member_balance": 2870,
"purchase_amount": 24.5,
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"member_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
staff_id delegation
- Without
staff_id, Reward Loyalty records the operation as an agent or system transaction. - With
staff_id, it attributes the operation to that staff member. - The
staff_idmust belong to the same partner.
Use staff_id when the terminal knows which cashier is signed in.
Points-only adjustments
If your POS needs to grant a manual point amount instead of calculating from a purchase amount, send points.
POST /api/agent/v1/partner/transactions/purchase HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"member_identifier": "MEM-2024-00001",
"points": 500,
"note": "Manual goodwill adjustment"
}
Redeem a reward
Use POST /partner/transactions/redeem when the member spends points at checkout.
POST /api/agent/v1/partner/transactions/redeem HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"reward_id": "7f1335c0-b6f1-4c82-8655-c5148d3fd3be",
"member_identifier": "[email protected]",
"staff_id": "9a126c5f-8737-4f0a-83b2-11a6b7e8f901",
"note": "Redeemed on POS ticket #12345"
}
{
"error": false,
"data": {
"transaction_id": "019cce5d-cae0-70b8-9af1-7158fca5bcdb",
"points_deducted": 100,
"member_balance": 2770,
"new_balance": 2770,
"reward_id": "7f1335c0-b6f1-4c82-8655-c5148d3fd3be",
"reward": {
"id": "7f1335c0-b6f1-4c82-8655-c5148d3fd3be",
"title": "Free Coffee"
},
"card_id": "3598a5db-f008-477c-ac4d-5365c662ad62",
"member_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
Typical failure branch:
{
"error": true,
"code": "INSUFFICIENT_POINTS",
"message": "Member does not have enough points for this reward.",
"retry_strategy": "no_retry",
"details": {
"required": 100,
"available": 20
}
}
Stamp cards
Add stamps:
POST /api/agent/v1/partner/stamp-cards/{stampCardId}/stamps HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"member_identifier": "[email protected]",
"stamps": 1,
"purchase_amount": 12.00,
"note": "POS ticket #12345"
}
Redeem a completed stamp reward:
POST /api/agent/v1/partner/stamp-cards/{stampCardId}/redeem HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"member_identifier": "[email protected]",
"note": "POS redemption"
}
Vouchers
Validate the code before you finalize the order:
POST /api/agent/v1/partner/vouchers/validate HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"code": "WELCOME10",
"member_identifier": "[email protected]",
"club_id": "019cce5d-bd81-7096-9118-9cb360ab9008",
"order_amount": 2450
}
Then redeem the voucher:
POST /api/agent/v1/partner/vouchers/{voucherId}/redeem HTTP/1.1
Host: your-domain.com
Accept: application/json
Content-Type: application/json
X-Agent-Key: rl_agent_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0
{
"member_identifier": "[email protected]",
"order_amount": 2450,
"order_reference": "12345"
}
Safe retry behavior
Do not retry purchase or redemption requests without checking what happened first. These flows are not idempotent.
- Use your own external order reference tracking.
- Pass the order or ticket ID in
notewhere available. - Reconcile ambiguous failures before replaying.
If you hit a rate limit:
{
"error": true,
"code": "RATE_LIMITED",
"message": "Too many requests. Please slow down.",
"retry_strategy": "backoff"
}
Honor Retry-After.