Till flow
The customer opens their loyalty card in the Mekante Wallet app on their phone and presents a QR code. Your POS reads that code and follows the steps below.
Scan QR ──► POST /scan ──► (preview points) ──► POST /earn award points/stamps
└──────────────────────► POST /redeem redeem reward
Earning points or stamps
- Scan the QR code. The QR payload is an opaque token string. Send it to
POST /scan. The response includesscanIdand member details (name, masked phone, balances, tier) that you can display on the cashier screen. - Preview (optional). Call
POST /earn/previewto calculate how many points and stamps a purchase amount will award without writing to the ledger. - Commit the earn. Call
POST /earnwithscanIdand the purchase amount (or stamp count). TheIdempotency-Keyheader is required.
Redeeming a reward
There are two ways to redeem a reward:
- Cashier chooses. Scan the customer's standard QR code with
POST /scan. The response'srewardsarray lists all rewards the member can (or cannot, withreasonandmissing) redeem. After the cashier picks one, sendscanIdand the chosenrewardIdtoPOST /redeem. - Customer chooses. The customer selects a reward in the Wallet app and generates a dedicated redeem QR code for that reward. Scan it with
POST /scan: the response hasintent: "redeem"and populatesreward. You do not need to passrewardIdtoPOST /redeem; if you do, it must match the scanned reward (400 REWARD_MISMATCH).
The response returns a 6-character confirmation code. The customer receives an instant push notification that their reward was redeemed, and the cashier/API key is recorded on the ledger entry. A cashier or API key can redeem at most the daily limit configured by the business (429 CASHIER_DAILY_LIMIT).
Important rules
QR codes expire after 30 seconds. An expired code returns 400 QR_EXPIRED. Ask the customer to refresh their screen.
Each QR code can only be scanned once. A second scan returns 409 QR_ALREADY_USED. This prevents replay via screenshots or photos.
A scan is valid for 5 minutes. After POST /scan succeeds, you have 5 minutes to call POST /earn or POST /redeem with that scanId. Once consumed or expired, it returns 409 SCAN_INVALID and you must scan a fresh QR code. If your POS UI reloads, you can re-fetch an active scan with GET /scans/:id.
Amounts are integer kuruş. 15000 = 150 TL. Decimal, zero, or negative values are rejected. The hard ceiling is 100000000 kuruş; the business's own per-transaction limit is usually lower (Limits).
Idempotency-Key: never double-count a sale
If the network drops mid-request, you won't know whether the server committed the transaction. Retrying the same request with the same Idempotency-Key guarantees points are not awarded twice; the server replays the original response with "replayed": true.
- Generate one key per sale and tie it to the sale (for example from the receipt ID:
pos-2026-000123). - Must be between 8 and 100 characters long.
- Reusing the same key for a different operation or payload returns
409 DUPLICATE_REQUEST. - Passing
receiptNoadds a second layer of protection: the same receipt number cannot be recorded twice (409 DUPLICATE_RECEIPT).
First request → 201 Created "replayed": false
Retry → 200 OK "replayed": true (same entry, no duplicate points)
Voiding a mistaken entry
POST /ledger/:id/void reverses an earn or redeem ledger entry. Because an API key operates with cashier privileges, it can only void its own entries and only within 15 minutes of creation. If earned points have already been spent in the meantime, the entry cannot be voided (409 POINTS_ALREADY_SPENT).