Cross-channel loyalty
Earn and redeem loyalty points on every channel — online, in-store, and mobile — using VINR's unified commerce and engagement stack.
Loyalty is most powerful when it works the same way whether the customer buys online, taps at the terminal, or orders over the phone. VINR ties payment events to the engagement stack via shopperReference so points accrue and redeem across channels automatically — there is no separate loyalty middleware to maintain and no risk of a customer's in-store balance being invisible at your web checkout. See Engagement for the full loyalty feature set including tier configuration, reward catalogues, and expiry rules.
How it worksAsk
The customer is identified by their shopperReference at checkout on any channel — online, terminal, or phone. The reference is the stable, unique identifier that links every payment to the same loyalty ledger.
When the payment settles, VINR fires a payment.completed webhook that includes the shopperReference alongside the payment amount and currency.
Your backend — or VINR's no-code webhook integration — calls the Engagement API to credit points for the transaction.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
export async function handlePaymentCompleted(event: WebhookEvent) {
const { shopperReference, amount, currency, id: paymentId } = event.data;
if (!shopperReference) return;
await vinr.engagement.loyalty.credit({
shopperReference,
points: Math.floor(amount / 100),
currency,
sourceType: 'payment',
sourceId: paymentId,
metadata: {
channel: event.data.metadata?.channel ?? 'unknown',
},
});
}At the customer's next purchase the accrued balance is available to retrieve and redeem on any channel. The ledger is shared — points earned in store are visible online and vice versa.
Sending shopperReference on every payment is the only prerequisite. Points are credited asynchronously after settlement, so there is no latency impact on checkout.
Earning points at the terminalAsk
Pass shopperReference on every terminal payment request. VINR links the terminal transaction to the shopper profile in the same way as an online payment, and the same payment.completed webhook fires with the reference included.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
const terminalPayment = await vinr.terminal.payments.create({
terminalId: 'term_london_01',
amount: 4200,
currency: 'GBP',
shopperReference: 'cust_abc123',
receiptData: {
pointsEarned: 42,
loyaltyBalanceAfter: 1380,
},
});receiptData.pointsEarned and receiptData.loyaltyBalanceAfter surface on the printed and digital receipts so staff can read the points earned aloud and the customer sees confirmation on their copy. Retrieve the current balance before creating the payment to populate loyaltyBalanceAfter accurately.
For the full terminal payment reference see Shopper recognition.
Redeeming in storeAsk
When a customer mentions their loyalty balance at the counter, staff retrieve it before creating the payment. The redemption value is applied as a discount; any remaining basket value is charged to the customer's card.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
const balance = await vinr.engagement.loyalty.getBalance({
shopperReference: 'cust_abc123',
});
const redeemPoints = 500;
const pointValue = balance.pointValueMinorUnit * redeemPoints;
const remainingAmount = Math.max(0, 6000 - pointValue);
await vinr.engagement.loyalty.redeem({
shopperReference: 'cust_abc123',
points: redeemPoints,
sourceType: 'payment',
metadata: { channel: 'in_store', staffId: 'staff_jsmith' },
});
const payment = await vinr.terminal.payments.create({
terminalId: 'term_london_01',
amount: remainingAmount,
currency: 'GBP',
shopperReference: 'cust_abc123',
metadata: {
loyaltyRedemption: true,
pointsRedeemed: redeemPoints,
pointsValueMinorUnit: pointValue,
},
});Redeem points before creating the payment, not after. If the card payment fails after redemption, reverse the redemption with vinr.engagement.loyalty.reverseRedemption using the same sourceId.
Redemption fieldsAsk
Prop
Type
Redemption via terminal promptAsk
Configure a terminal input prompt to collect the customer's loyalty identifier — their account number, email address, or phone number — without staff manually looking it up. VINR maps the input to a shopperReference and surfaces the balance for staff to confirm before redemption.
import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
const session = await vinr.terminal.sessions.create({
terminalId: 'term_london_01',
prompts: [
{
id: 'loyalty_lookup',
type: 'text_input',
label: 'Loyalty number or email',
optional: true,
keyboardType: 'email_address',
},
],
});import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });
export async function handleSessionPromptResponse(event: WebhookEvent) {
const loyaltyInput = event.data.promptResponses?.loyalty_lookup;
if (!loyaltyInput) return;
const shopperReference = await vinr.engagement.loyalty.resolveIdentifier({
identifier: loyaltyInput,
});
const balance = await vinr.engagement.loyalty.getBalance({ shopperReference });
await vinr.terminal.sessions.update(event.data.sessionId, {
display: {
message: `Balance: ${balance.points} points (worth ${balance.formattedValue})`,
confirmAction: 'Redeem',
dismissAction: 'Skip',
},
});
}See Receipts and engagement for the full terminal prompts and display reference.
Cross-channel point expiryAsk
Points earned online and in store share the same ledger and the same expiry rules. There is no separate expiry clock per channel — a point earned at the terminal and a point earned at web checkout age at the same rate under the same policy.
Configure expiry windows, rolling or fixed, in Loyalty accounts.
When expiry is configured, the expiry date of the soonest-expiring points block appears on digital receipts automatically. No additional integration is required.
Next stepsAsk
Loyalty accounts
Configure expiry rules, tier thresholds, point multipliers, and reward catalogues for your loyalty programme.
Shopper recognition
Understand how shopperReference links payment methods and loyalty data across every channel.
Receipts and engagement
Customise printed and digital receipts with loyalty balances, tier status, and terminal prompts.
Last updated on