Skip to content

POS integration.

Build a point-of-sale integration for member lookup, balance checks, purchases, rewards, stamps, and vouchers.

Jul 20, 2026

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

Start with:

  • read
  • write:transactions
  • write:rewards

Add these only if you need them:

  • write:stamps
  • write:vouchers

Core flow

  1. Find or search the member.
  2. Check the member's balance on the active card.
  3. Record the purchase.
  4. If the member asks, redeem a reward, add stamps, or process a voucher.
  5. 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
  • email
  • 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_id must 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 note where 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.

Cookies on this site.

Google Analytics runs only if you allow it. It counts visits so we can fix the pages that do not help. No advertising tags run here, and you can change this any time. Cookie policy