What you scan
A string beginning withvqr_:
qrToken field.
It is single-use
This is the most important property of the system, and the one most likely to surprise you. The moment a charge against a code commits, that code is retired — in the same instant, as part of the same database write. The pass immediately begins showing a new one. So a409 qr token already used does not mean something went wrong. It usually means the
payment already succeeded and you are looking at a duplicate scan or a retry. Confirm with
GET /v1/transactions before you either hand over goods or charge again.
This is also why you must never cache a scanned code, log it for later replay, or let a cashier
re-submit an old one from a screen history. It will not work, and the attempt is indistinguishable
from fraud.
It also expires
A code stops being accepted 24 hours after the pass created it, whether or not it was ever charged. That is a backstop against an old screenshot, not the main defence — the single-use rule is. In practice a pass refreshes its code well within that window, so an expired code almost always means the customer’s phone has been offline for a long time. The fix is the same either way:TOKEN_EXPIRED → ask the customer to open their Vibepay pass and show it again. Opening the
pass refreshes the code. Then scan and charge afresh — with a new idempotency key, since this
is a new attempt at the same sale only if you kept the original key. See
Idempotency.Scanner requirements
If your scanner appends a carriage return or a configured prefix, strip it in your integration
before sending — an extra byte is a
TOKEN_INVALID.
Errors you will see
Now send the charge
Request fields, amount rules, and the response.

