Skip to content

Product authentication flow ​

A shopper points the camera at the code on a label, the app proves the product is genuine, and the points and collectible behind that code are claimed. This is product authentication — unrelated to signing a user in, which is the other thing "authentication" means in this app.

Play the flow ​

Three paths: a signed-in scan, a scan by someone who has not logged in yet — who gets sent to the login screen before anything can be claimed — and the branch where the reward is held until a receipt is checked.

1 / 6
4:4713
authenticate
point the camera at the code on the label

Screen not designed yet — drawn from what the documented flow requires.

Space plays and pauses, ← and → step. These screens have no design yet, so they are drawn from what the documented calls require — the step list and the endpoints are what to build against.

Verifying and claiming are different things ​

The shape that surprises people is that a verified scan is not a claimed scan. verify/product/:authCode proves the code is real and returns the product; nothing has been granted at that point. Claiming is a separate call against the same authCode, and points and collectibles are two separate calls again:

StepEndpointWhat it does
Verifyverify/product/:authCodeProves the code, logs the view, returns the product plus brl_id / pvl_id
Post-verifypost_verify/product/:brl_idThe side effects of a successful scan. Customer-only
Claim pointsredeem-point/productGrants the points on that code
Claim collectibleredeem-collectible/productGrants the collectible, if the code carries one

So a product can carry points, a collectible, both or neither, and the UI has to handle a code that verifies but has nothing left to give.

Three ways a code reaches the app ​

The journey above starts with an authCode in hand. There are three ways to get one, and only the first is a camera:

  • A scanned or typed code — straight into verify/product/:authCode.
  • An NFC tap — same endpoint, with nfc_identifier in the payload (lowercased server-side). event_count rides along for devices that count puffs.
  • A photo of the label — verify/authcode-by-ocr takes multipart/form-data with a single file field, max 10 MB, runs OCR and resolves the code. It is the one call in this flow that is not JSON.

There is also verify/authcode/:authCode — a lightweight validity check that writes no view log. Use it when you want to know whether a code is real without recording a scan against it.

Scanning without an account: verify yes, claim no ​

The verify call has a guest mount and a customer mount on one handler. The difference is attribution: /user/mobile/verify/... records the scan against the caller, /brand/mobile/verify/... does not.

So anyone holding the product can prove it is genuine. Claiming is where the app stops them. There is no inline claim screen: tapping claim while signed out sends the user into login or sign up, and the claim runs afterwards with a session behind it. post_verify is customer-only too, so a signed-out scan skips it entirely.

A field that looks like a guest claim, but is not one

redeem-point/product accepts an optional customer object — email or phoneNumber, a name, even a password — and the endpoint reference describes it as the standalone claim path. The app does not use it. It forces a login instead, which is consistent with the endpoint being marked Customer. Whatever that object serves, it is not this flow — do not build a guest claim screen on the strength of the field existing.

The hold / release branch ​

When a reward depends on something being checked — a receipt, a manual verification — the scan does not grant it outright:

  1. hold/points-collectible reserves the points and collectible against the authCode.
  2. The receipt goes through its own review.
  3. release/points-collectible takes the same authCode plus an optional receiptId and turns the held reward into a granted one.

Nothing in the mobile API set says what happens to a hold that is never released — no expiry endpoint, no list-my-holds call. That is worth settling before the screen is built.

A scan is also a loyalty event ​

The last thing a successful scan does is move campaigns. Sending campaigns/almost-completed with event_item.event_type: "scan-auth" returns the campaigns this scan just pushed closer to completing — which is the hand-off into the rewards flow.

Batch platform, Shopify app and API documentation