Appearance
Scan-to-claim flow (web)
A customer types the code from a label, or opens the link its QR code carries, and the storefront proves the product is genuine. Proving is not claiming: points and the collectible are separate calls against the same code, and a code can instead be held until a receipt shows the customer bought it.
Play the flow
shop.example.com/scan
shop · rewards · scan
check a product
type the code printed on the label, or open the link from its QR code
7K2Q-9XPA
Page not designed yet — drawn from what the documented flow requires.
States
What the code itself records at each step — and what refuses a second claim — is the scanned code's lifecycle on Product scanning.
API calls by stage
| Stage | Action | API call | Access |
|---|---|---|---|
| 1 | Check the code | POST /api/v1/user/verify/product/:authCode — returns the product and brl_id | Origin + Customer |
| 1′ | Check without signing in | POST /api/v1/brand/verify/product/:authCode — same handler, scan not attributed | Origin + Brand key |
| 2 | Scan side effects | POST /api/v1/user/post_verify/product/:brl_id — returns the campaigns moved | Origin + Brand key + Customer |
| 3 | Claim points | POST /api/v1/user/redeem-point/product — authCode | Origin + Brand key + Customer |
| 4 | Claim collectible | POST /api/v1/user/redeem-collectible/product — authCode | Origin + Brand key + Customer |
| 3h | Hold instead | POST /api/v1/user/hold/points-collectible — authCode | Origin + Brand key + Customer |
| 4h | Upload the receipt image | POST /api/v1/user/uploadImage — returns a /api/v1/files/… link | Origin + Brand key + Customer |
| 5h | Submit the receipt | POST /api/v1/user/receipt — userReceipt (the link), source, brl_id | Origin + Brand key + Customer |
| 6h | Release | POST /api/v1/user/release/points-collectible — authCode, receiptId | Origin + Brand key + Customer |
What the API forces onto this page
- Upload with POST, not PUT.
/api/v1/user/uploadImageexists twice. The POST stores the file and returns a/api/v1/files/link, which is the only kind of link the receipt check can read; the PUT goes to Cloudinary. - A receipt is judged on submission. It is stored only if it passes — this customer's hold on
brl_id, the product and a date found on the receipt, and a scan campaign covering that date with claims left — and it is storedAPPROVED. A failed receipt stores nothing, so there is no "pending review" state for the page to show. See Receipts. - Release without a
receiptIdsucceeds. The service treats it as a gift and grants the hold; the code carries a TODO to gate that path. A storefront should always send the approvedreceiptId. - Age-restricted codes refuse every claim and release until the customer's identity is verified — see Government ID and age verification.
- The QR link is a redirect. The printed link points at the backend, which sends the browser to the URL the authenticity service returns for that code; that page then runs step 1.