Cashback Programs
A cashback program pays members real money based on the items they buy. Members upload a receipt, the platform recognises line items via OCR, matches them against your catalogue, and accrues a cashback amount that's paid out via Bizum or bank transfer (SEPA) — either at the end of the campaign, on demand, or in scheduled batches.
When to use it
- FMCG / pharma activations where the brand wants to reimburse a portion of the purchase price for specific SKUs.
- Promotional campaigns ("buy two, get €5 back") that require monetary payout rather than loyalty points.
- Markets where points have lower perceived value than cash.
How it works (the four phases)
Cashback ships across four phases and you can adopt them incrementally:
Phase 1 — Provider abstraction
The platform separates what a member earns (a cashback amount in euros) from how it's paid out. Disbursements are routed to a provider via a registry — local Manual payouts are always available; Bizum and SEPA are pluggable. The dispatcher polls due rows in batches and retries failed sends up to three times with backoff [1, 5, 15] minutes.
Phase 2 — Bizum
Bizum is a Spanish instant-transfer scheme tied to the recipient's phone number. When a member's preferred cashback method is Bizum and they've registered a valid Spanish mobile, the platform dispatches the payout to the Bizum provider.
Phase 3 — SEPA bank transfer
For larger amounts or members who prefer it, the platform supports SEPA pain.001 XML batch exports. The admin approves a batch of disbursements and downloads the file to upload into the bank's portal. The platform marks each line as Sent after export.
Phase 4 — Admin disbursement UI
A full back-office UI for inspecting, approving, completing, and rejecting disbursements:
- Approve moves a Pending row to Processing.
- Complete marks it Completed (after the bank confirms).
- Reject cancels it with a reason — the member is notified.
Plus a bank-PII backfill CLI for tenants that already have member IBANs/Bizum phones in plaintext and need them re-encrypted under the platform's IPiiProtector.
Step-by-step
Configure cashback on a product
- Go to Loyalty → Products and open the SKU you want to incentivise.
- Set either:
- Cashback amount — a fixed € per unit (e.g. €0.50 per box), or
- Cashback percentage — a % of the line total (e.g. 10%).
- Save. The platform picks the amount path if both are set.
Set the member's payout method
- On the member's profile, open the Payments tab.
- Pick Preferred cashback method: Bizum, Bank transfer, or Manual.
- For Bizum: enter the Spanish mobile.
- For Bank transfer: enter IBAN and holder name. The platform encrypts both at rest (last 4 digits are kept visible for UI confirmation).
Members can self-edit this on the member portal under their profile.
Process a receipt
When a member uploads a receipt:
- OCR extracts line items (barcode and product name).
- The platform matches each line to your catalogue — first by barcode (exact), then by name (substring, ≥80% confidence).
- For every matched product, cashback is computed and a
CashbackDisbursementis created in Pending.
Approve and pay
- Go to Loyalty → Cashback → Disbursements.
- Filter to Pending. Review each row (member, amount, evidence, line items).
- Click Approve — the row moves to Processing and the dispatcher takes over (Bizum is automatic; SEPA waits for a batch export).
- After the bank/provider confirms, the row goes to Completed.
To reject: click Reject, enter a reason. The row is cancelled and the member is notified.
Export a SEPA batch
- From Disbursements, filter to Processing + method Bank transfer.
- Click Export SEPA batch. The platform produces a SEPA pain.001 XML file with the selected disbursements.
- Upload the file to your bank.
- Once confirmed, mark each row Completed.
Backfill encrypted PII (one-time)
If you have legacy member rows with plaintext IBAN or Bizum phone, run the CLI to encrypt them under the platform's PII protector. See the Cashback bank-PII backfill runbook (P3012) for the exact command and rollback plan.
Budget guardrails
Each cashback-enabled campaign can have a budget with Auto-pause on budget. When a new disbursement would push projected spend over the budget, the campaign is automatically paused (BudgetPausedAt is recorded) and the disbursement is rejected with BudgetExhausted. A warning notification fires once when spend crosses the configured warning percentage.
Reference format
Each disbursement has a human-readable reference: CB-{tenant-slug}-{yyyyMMdd}-{evidenceId}. Use it when communicating with the bank or with the member.
Limits and gotchas
- OCR confidence threshold defaults to 80%. Below that the line item is not matched. Tune in
Ocr:ConfidenceThresholdif needed. - Encrypted IBAN/Bizum. Plaintext is never stored after F2 lands. Last-4 digits are visible in the UI only.
- Retry policy: 3 retries with
[1, 5, 15]minute backoff. After that the row stays in Failed until an admin retries manually. - Manual method bypasses providers. The platform marks the disbursement as Pending and leaves payout entirely to the operator (cheque, in-store, gift card, whatever). Use it as a fallback.
- Member-side disbursement UI: members see status per disbursement (Pending → Processing → Completed / Cancelled) on the member portal cashback page.
- Permission:
Pages.Loyalty.Products. Requires theCashbackcapability on the tenant.