QR Code Integration
ValueMapper uses QR codes at the point of sale so your customers can prove their wallet identity, redeem wallet credit, redeem loyalty points, or redeem a claimed reward. This guide explains how the codes work and how to validate them through the API.
Every QR code scanned from a customer's ValueMapper app is server-signed, time-limited, and single-use. You should validate it server-side before applying any value to the transaction.
Prerequisites
Before integrating QR code validation, ensure you have:
- Authenticated with a valid API token
- A ValueMapper account with at least one brand set up
- A POS or checkout system capable of scanning QR codes and forwarding the raw text to your backend
Payload format
When your POS scanner reads the QR code, it receives a plain text string separated by pipe characters (|):
sessionId|walletUuid|accountUuid|mode|value|expiresAt|kid|signature
| Field | Description | Example |
|---|---|---|
sessionId | Server-generated unique identifier for this QR session. | 0196e29a-... |
walletUuid | The customer's wallet ID | 0196e29b-... |
accountUuid | Your brand/account ID in ValueMapper | 0196e29c-... |
mode | What kind of transaction this is (see below) | IDENTITY, CASH, POINTS, REDEMPTION_CODE |
value | Amount or redemption code (empty for identity) | 25.00, 500, DESSERT-1, or empty |
expiresAt | ISO 8601 timestamp when this QR expires | 2026-06-09T18:55:00.000Z |
kid | Key ID for signature verification | v1 |
signature | Server-signed cryptographic signature | Base64Signature... |
Note on
sessionId: This is a one-time identifier for the QR session itself, not a confirmation that a value exchange has occurred. Every QR — includingIDENTITYQRs that prove wallet ownership without any value exchange — carries asessionId. The server uses it to enforce single-use and to maintain an audit trail. POS systems do not need to interpret, store, or de-duplicate this field; the server handles single-use enforcement automatically.
Every QR code is signed, time-limited, and single-use. Validate it immediately. Do not accept the same QR code twice.
Identity QR code
The customer wants to prove that their ValueMapper wallet belongs to them so your staff can perform a manual transaction (e.g. a staff-initiated credit redemption that does not go through the automated POS integration).
How to identify it
The mode field is IDENTITY and the value field is empty.
sessionId|walletUuid|accountUuid|IDENTITY||expiresAt|kid|signature
Recommended flow
- Scan the QR to obtain the raw pipe-delimited string.
- Validate the payload by calling the
validatePosRedemptionGraphQL mutation. The server checks the signature, expiry, brand match, and single-use on your behalf. - If
validistrue, use the returnedcustomerIdentity(phone/email) to verify the customer's identity with staff. - The staff member can now proceed with the manual transaction.
What data is in the QR
| Field | Value |
|---|---|
mode | IDENTITY |
value | (empty) |
amount | Not included |
redemptionCodeUuid | Not included |
redemptionCode | Not included |
Redemption QR codes
The customer wants to automatically redeem wallet credit, loyalty points, or a claimed reward through your POS integration.
How to identify it
The mode field is one of: CASH, POINTS, or REDEMPTION_CODE.
Recommended flow
- Scan the QR to obtain the raw pipe-delimited string.
- Validate the payload by calling the
validatePosRedemptionGraphQL mutation. - If
validistrue, readmodeandvalueto determine the action and apply the discount or reward.
Redemption modes in detail
CASH — Redeem wallet credit
The customer wants to redeem an amount of credit from their wallet balance.
| Field | Value |
|---|---|
mode | CASH |
value | Numeric amount (e.g. 25.00) |
POS action: Deduct the specified amount from the customer's wallet credit balance. This is usually applied as a discount or credit note on the current transaction.
POINTS — Redeem loyalty points
The customer wants to redeem a number of loyalty points from their wallet balance.
| Field | Value |
|---|---|
mode | POINTS |
value | Whole number of points (e.g. 500) |
POS action: Deduct the specified number of points from the customer's loyalty point balance. Your system should map this to the equivalent discount or reward value.
REDEMPTION_CODE — Redeem a specific reward
The customer wants to redeem a specific reward they previously claimed in the app.
| Field | Value |
|---|---|
mode | REDEMPTION_CODE |
value | The human-readable redemption code (e.g. DESSERT-1) |
POS action: Validate that the customer has an active claim for this redemption code, then apply the reward to the transaction.
Server-side validation
ValueMapper exposes a public validatePosRedemption mutation that POS systems call to validate a scanned payload. This is the recommended approach for POS integrations because it performs signature verification, expiry checks, single-use enforcement, and brand matching on the server in one call.
Mutation
validatePosRedemption(payload: String!): ValidatePosRedemptionResult!
payload(required) — the full pipe-delimited string scanned from the QR.
Result type
type ValidatePosRedemptionResult {
valid: Boolean!
reason: String
redemptionId: String
walletUuid: String
accountUuid: String
valueType: PosRedemptionValueType
amount: Float
redemptionCodeUuid: String
redemptionCode: String
expiresAt: Date
customerIdentity: PosRedemptionCustomerIdentity
balance: PosRedemptionBalance
}
| Field | Type | Description |
|---|---|---|
valid | Boolean! | Whether the payload is valid for the authenticated account. |
reason | String | Machine-readable invalid reason, when not valid. |
redemptionId | String | One-time session identifier from the payload. |
walletUuid | String | Wallet UUID from the payload. |
accountUuid | String | Account UUID from the payload. |
valueType | PosRedemptionValueType | Selected balance type from value-exchange payloads (CASH or POINTS). |
amount | Float | Selected cash or points amount from value-exchange payloads. |
redemptionCodeUuid | String | Claimed reward redemption code UUID from redemption-code payloads. |
redemptionCode | String | Claimed reward redemption code value from redemption-code payloads. |
expiresAt | Date | Expiry timestamp from the payload. |
customerIdentity | PosRedemptionCustomerIdentity | Member identity (phone/email) for staff verification when valid. |
balance | PosRedemptionBalance | Current wallet balance for the account when valid. |
Note on
redemptionId: In thevalidatePosRedemptionresponse this field is the same one-time session identifier that appears in the QR payload. It is surfaced for traceability only — you do not need to interpret, store, or de-duplicate it.
Example: Validate a scanned QR
mutation ValidatePosRedemption {
validatePosRedemption(
payload: "0196e29a-...|0196e29b-...|0196e29c-...|CASH|25.00|2026-06-09T18:55:00.000Z|v1|Base64Signature..."
) {
valid
reason
valueType
amount
customerIdentity {
phone
email
}
balance {
globalCreditBalance
localCreditBalance
}
}
}
Recommended validation flow
- Scan the QR to obtain the raw pipe-delimited string.
- Call
validatePosRedemptionwith the full payload string. - Check
valid— iffalse, surface thereasonto the staff member and stop. - If
valid, use the returned fields to drive the transaction:- For
IDENTITYpayloads, usecustomerIdentityto verify the customer's identity with staff. - For
CASH/POINTSpayloads, usevalueTypeandamountto apply the discount. - For
REDEMPTION_CODEpayloads, useredemptionCodeto validate the claimed reward.
- For
The full mutation reference is available at validatePosRedemption.
Summary
| QR Type | mode | value | What the system should do |
|---|---|---|---|
| Identity | IDENTITY | (empty) | Call validatePosRedemption; if valid, use customerIdentity to confirm the customer's identity with staff |
| Credit redemption | CASH | Amount (e.g. 25.00) | Call validatePosRedemption; if valid, deduct credit from wallet balance and apply the discount |
| Points redemption | POINTS | Points (e.g. 500) | Call validatePosRedemption; if valid, deduct points from wallet balance and apply the equivalent discount |
| Reward redemption | REDEMPTION_CODE | Code (e.g. DESSERT-1) | Call validatePosRedemption; if valid, apply the claimed reward to the transaction |
Processing checklist
| Step | Required? | Notes |
|---|---|---|
| Scan the QR | Required | Use any QR scanner that returns the raw text. |
| Pass the full payload to your backend | Required | Your backend calls validatePosRedemption and acts on the result. |
Call the validatePosRedemption GraphQL mutation | Required (recommended) | Validates signature, expiry, brand match, and single-use in one server call. |
| Look up the customer's identity | Optional | Only required for IDENTITY mode — the mutation returns customerIdentity when valid. |
| Apply the discount or reward | Required | Only for CASH, POINTS, and REDEMPTION_CODE modes, after validation passes. |
POS systems do not need to parse the payload fields themselves or perform local signature verification. The recommended path is to forward the raw scanned string to your backend, which calls validatePosRedemption and returns the structured result.
Related documentation
validatePosRedemption— GraphQL mutation reference for validating scanned QR payloads- Authentication — Set up API access for your POS backend
- Connected Services — Configure your ValueMapper account