Errors & response format
Envelope
Every response is JSON with the same three keys:
{ "success": true, "message": "Transaction committed successfully", "data": { "...": "..." } }
{ "success": false, "message": "Customer not found" }
success— act on this, not only on the HTTP status.message— plain English, safe to show to a cashier.data— the payload; absent ornullon failure.- Some endpoints add top-level fields:
is_duplicate(commit, redeem, void),already_member(members/add),errors(validation),code(PIN errors).
HTTP status
| Status | When | What to do |
|---|---|---|
200 |
Success, including safe duplicates (is_duplicate: true). |
Continue. |
202 |
Cashier redemption created, waiting for the customer to approve it in the app (confirmation_status: awaiting). |
Wait for the approval. See Redeem without the phone. |
400 |
Business rule blocked the call: QR used/expired, wrong merchant, reward unavailable. | Show message to the cashier. Do not retry. |
401 |
Missing, unknown, revoked or expired API key. | Fix the key. See Account & API keys. |
403 |
Key lacks the scope, key mode does not match the merchant, developer inactive, voiding another developer's transaction. | Configuration problem. Do not retry. |
404 |
Customer / transaction / redemption not found, or belongs to another merchant. | Show message. |
409 |
Conflict: same Idempotency-Key still in flight, a void refused because the points were already spent, or transactions/redeem of a cashier redemption the customer has not approved yet. |
Idempotency: retry after a moment. Void: give up. Redeem: wait for the approval, then retry. |
422 |
Validation failed, or a business precondition (void window passed, PIN_INVALID, APPROVAL_UNAVAILABLE, Code not found.). |
Read errors / code. Fix the request. |
429 |
Rate limit hit, PIN_LOCKED, or 30 codes within 10 minutes that name nothing at this merchant — typed RDM- codes on qr/validate, any code on the packages, item-deals and birthday-gift redeem / preview calls (redeem.code_attempts, one counter per integration and merchant). |
Honour Retry-After. |
500 |
Our fault. | Retry with the same Idempotency-Key; contact us if it persists. |
Validation errors
{
"success": false,
"message": "Validation failed",
"errors": {
"amount": ["The amount field is required."],
"branch_id": ["The selected branch id is invalid."]
}
}
errors is keyed by field. Common causes: branch_id from another merchant, amount of 0 on commit, missing user_id.
Duplicate handling, not errors
These are 200 responses that tell you the work was already done:
| Endpoint | Signal | Cause |
|---|---|---|
transactions/commit |
"is_duplicate": true |
Same qr_scan_id already committed. |
transactions/redeem |
message: "Redemption already processed" |
Same qr_scan_id already redeemed. |
transactions/{id}/void |
"is_duplicate": true |
Already voided. |
members/add |
"already_member": true |
Already a member. |
any with Idempotency-Key |
header Idempotency-Replayed: true |
Retried request; stored response returned. |
Messages you will meet
| Message | Endpoint | Meaning |
|---|---|---|
Invalid or unsupported QR |
qr/validate | Not a Reward Networks QR. |
QR already used or expired |
qr/validate, redeem | Redemption is no longer PENDING. |
QR code expired |
qr/validate, redeem | Redemption's expires_at passed. |
Campaign has expired |
qr/validate, redeem | The voucher/points campaign ended. |
Redemption code not found |
qr/validate | Typed RDM- code has a typo, or belongs to another store. |
Waiting for the customer to approve this redemption in the Rewards app. |
qr/validate, redeem (409) |
Cashier redemption awaiting the customer's approval. |
This redemption was not approved in time. |
qr/validate, redeem | The customer did not answer within 60 seconds; it is cancelled. |
Ask the customer for the redemption code shown under their QR (RDM-…), or scan the QR, and send it as redemption_code. |
redeem | error_code: redeem.code_required. Customer approval is on and the customer made this redemption in the app: send its redemption_code (from qr/validate or read out by the customer). Nothing was deducted. |
This redemption code does not match the redemption. |
redeem | error_code: redeem.code_mismatch. Ask the customer for the code again; send the retry with a new Idempotency-Key. |
This reward can only be claimed at Owner Cafe. |
qr/validate, rewards/claim | Merchant-owned network reward at the wrong merchant. |
Merchant has not configured any active loyalty or stamp campaigns… |
preview | data.reason = NO_ACTIVE_RULES; nothing to earn. |
No loyalty or stamp campaign is valid at this branch. |
preview, commit | data.reason = BRANCH_NOT_IN_CAMPAIGN; the merchant's campaigns are limited to other branches. Send the right branch_id. |
This customer is not a member yet. Add them as a member first, then give points. |
commit | data.reason = NOT_A_MEMBER; call members/add first. |
This qr_scan_id already belongs to another transaction. Send a new one. |
commit, redeem | data.reason = QR_SCAN_ID_REUSED; the id names another transaction of this merchant (e.g. the sale's commit). Nothing was awarded or deducted; resend with a new qr_scan_id. |
Code not found. |
packages/* | Unknown package voucher code. |
A request with this Idempotency-Key is already being processed. |
any mutating | Retry after a moment. |
Idempotency-Key was reused with a different request payload. |
any mutating | Bug in your client: keys must be unique per distinct request. |
Reward Networks