Skip to main content

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:

  1. Authenticated with a valid API token
  2. A ValueMapper account with at least one brand set up
  3. 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
FieldDescriptionExample
sessionIdServer-generated unique identifier for this QR session.0196e29a-...
walletUuidThe customer's wallet ID0196e29b-...
accountUuidYour brand/account ID in ValueMapper0196e29c-...
modeWhat kind of transaction this is (see below)IDENTITY, CASH, POINTS, REDEMPTION_CODE
valueAmount or redemption code (empty for identity)25.00, 500, DESSERT-1, or empty
expiresAtISO 8601 timestamp when this QR expires2026-06-09T18:55:00.000Z
kidKey ID for signature verificationv1
signatureServer-signed cryptographic signatureBase64Signature...

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 — including IDENTITY QRs that prove wallet ownership without any value exchange — carries a sessionId. 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.

warning

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
  1. Scan the QR to obtain the raw pipe-delimited string.
  2. Validate the payload by calling the validatePosRedemption GraphQL mutation. The server checks the signature, expiry, brand match, and single-use on your behalf.
  3. If valid is true, use the returned customerIdentity (phone/email) to verify the customer's identity with staff.
  4. The staff member can now proceed with the manual transaction.

What data is in the QR

FieldValue
modeIDENTITY
value(empty)
amountNot included
redemptionCodeUuidNot included
redemptionCodeNot 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.

  1. Scan the QR to obtain the raw pipe-delimited string.
  2. Validate the payload by calling the validatePosRedemption GraphQL mutation.
  3. If valid is true, read mode and value to 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.

FieldValue
modeCASH
valueNumeric 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.

FieldValue
modePOINTS
valueWhole 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.

FieldValue
modeREDEMPTION_CODE
valueThe 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
}
FieldTypeDescription
validBoolean!Whether the payload is valid for the authenticated account.
reasonStringMachine-readable invalid reason, when not valid.
redemptionIdStringOne-time session identifier from the payload.
walletUuidStringWallet UUID from the payload.
accountUuidStringAccount UUID from the payload.
valueTypePosRedemptionValueTypeSelected balance type from value-exchange payloads (CASH or POINTS).
amountFloatSelected cash or points amount from value-exchange payloads.
redemptionCodeUuidStringClaimed reward redemption code UUID from redemption-code payloads.
redemptionCodeStringClaimed reward redemption code value from redemption-code payloads.
expiresAtDateExpiry timestamp from the payload.
customerIdentityPosRedemptionCustomerIdentityMember identity (phone/email) for staff verification when valid.
balancePosRedemptionBalanceCurrent wallet balance for the account when valid.

Note on redemptionId: In the validatePosRedemption response 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
}
}
}
  1. Scan the QR to obtain the raw pipe-delimited string.
  2. Call validatePosRedemption with the full payload string.
  3. Check valid — if false, surface the reason to the staff member and stop.
  4. If valid, use the returned fields to drive the transaction:
    • For IDENTITY payloads, use customerIdentity to verify the customer's identity with staff.
    • For CASH / POINTS payloads, use valueType and amount to apply the discount.
    • For REDEMPTION_CODE payloads, use redemptionCode to validate the claimed reward.

The full mutation reference is available at validatePosRedemption.


Summary

QR TypemodevalueWhat the system should do
IdentityIDENTITY(empty)Call validatePosRedemption; if valid, use customerIdentity to confirm the customer's identity with staff
Credit redemptionCASHAmount (e.g. 25.00)Call validatePosRedemption; if valid, deduct credit from wallet balance and apply the discount
Points redemptionPOINTSPoints (e.g. 500)Call validatePosRedemption; if valid, deduct points from wallet balance and apply the equivalent discount
Reward redemptionREDEMPTION_CODECode (e.g. DESSERT-1)Call validatePosRedemption; if valid, apply the claimed reward to the transaction

Processing checklist

StepRequired?Notes
Scan the QRRequiredUse any QR scanner that returns the raw text.
Pass the full payload to your backendRequiredYour backend calls validatePosRedemption and acts on the result.
Call the validatePosRedemption GraphQL mutationRequired (recommended)Validates signature, expiry, brand match, and single-use in one server call.
Look up the customer's identityOptionalOnly required for IDENTITY mode — the mutation returns customerIdentity when valid.
Apply the discount or rewardRequiredOnly 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.