Skip to main content

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

  1. Go to Loyalty → Products and open the SKU you want to incentivise.
  2. 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%).
  3. Save. The platform picks the amount path if both are set.

Set the member's payout method

  1. On the member's profile, open the Payments tab.
  2. Pick Preferred cashback method: Bizum, Bank transfer, or Manual.
  3. For Bizum: enter the Spanish mobile.
  4. 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:

  1. OCR extracts line items (barcode and product name).
  2. The platform matches each line to your catalogue — first by barcode (exact), then by name (substring, ≥80% confidence).
  3. For every matched product, cashback is computed and a CashbackDisbursement is created in Pending.

Approve and pay

  1. Go to Loyalty → Cashback → Disbursements.
  2. Filter to Pending. Review each row (member, amount, evidence, line items).
  3. Click Approve — the row moves to Processing and the dispatcher takes over (Bizum is automatic; SEPA waits for a batch export).
  4. 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

  1. From Disbursements, filter to Processing + method Bank transfer.
  2. Click Export SEPA batch. The platform produces a SEPA pain.001 XML file with the selected disbursements.
  3. Upload the file to your bank.
  4. 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:ConfidenceThreshold if 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 the Cashback capability on the tenant.