Turn receipts in loyalty points - Hashting integration

You can now set up a receipt / proof-of-purchase cashback flow powered by our partner Hashting: a member uploads a receipt through a Qualifio campaign, Hashting runs OCR and validates it, and the result is shown back to the member in the portal — with points granted automatically once the receipt is accepted.

This article explains how the pieces fit together, how to configure the flow for a client, what the receipt statuses mean, and how to troubleshoot a receipt that isn't updating.

What's new?

This ships on top of three building blocks that already exist in the platform — nothing receipt-specific was hardcoded:

  • An Interaction — a generic loyalty-profile record used to show a member the current + historical status of something happening outside Qualifio (here, a receipt). It's rendered through a Handlebars detail template inside an Interaction widget in the portal.
  • An incoming event — the generic endpoint + JSONata mapping Qualifio already uses to receive any partner's webhook. For Hashting, one mapping feeds the earning rule (the points side), and a second mapping (the "Interaction JSONata") writes the Interaction record the member sees.
  • A Hashting Cashback integration on the campaign — the campaign that collects the receipt image pushes it to Hashting, and a push rule on that campaign keeps it wired to the flow.

Because it's built on generic Interaction + incoming-event mechanics, this isn't limited to Hashting — the same pattern works for any partner that reports back an asynchronous status.

How does a receipt flow from upload to points?

  1. The member opens the portal and clicks Upload a receipt, which opens the embedded Qualifio campaign pre-filled with their first name, last name and email.
  2. They upload the receipt image (mapped to the campaign's invoice field) and submit.
  3. The campaign pushes the submission to Hashting via the Hashting Cashback Flow push rule.
  4. Hashting calls back the incoming event as it processes the receipt — first with a Pending update, then a final Accepted (with the line items and amount) or Refused (with a reason) update.
  5. Each callback is mapped twice: the event-mapping JSONata feeds the earning rule, and the Interaction JSONata upserts the Interaction record shown in the portal.
  6. Once a receipt is Accepted, the earning rule (configured to trigger on this event, using Total Amount (VAT Included)) grants the points.

Interaction vs. incoming event vs. Transaction — what's the difference?

These three concepts sit next to each other in this flow, so here's a quick comparison:

ConceptWhat it isWhere it's configuredMember-facing?
Incoming eventThe generic endpoint + JSONata mapping that receives a partner's webhook (Hashting or any other)Once per integration, in the incoming-event admin❌ No — plumbing only
InteractionA record showing a member the current + historical status of an external process, rendered via a Handlebars templateCreated once per use case (e.g. "Store receipt"), populated by the incoming event's Interaction JSONata✅ Yes — shown in an Interaction widget
TransactionThe record created by the earning rule when points are actually grantedCreated automatically by the earn flowIndirectly — it's what moves the points balance

An incoming event can exist without an active interaction (points only, no status display); an Interaction always depends on an incoming event to feed it.

How do I set up the Hashting Cashback flow for a client?

Our internal Professional Services team takes care of the technical configuration (steps 1 to 6 below) on your behalf. If interested in this service, please get in touch with Professional Services (integrations@qualifio.com) to set it up.

  1. Create the Interaction (type "Store receipt"), using the standard Handlebars detail template — it renders the current status, the refusal reason when present, the itemised amount, a link to view the receipt, and the status history.
  2. Create the incoming event: link it to the Hashting integration and to that Interaction, set the authentication (currently a token in a query parameter), and set Source = Ecommerce / Action = Purchase. Add the two JSONata mappings — the earn mapping and the Interaction mapping (Qualifio provisions the standard Interaction snippet; it isn't exposed to the client).
  3. Subscribe the webhook on Hashting's side — a one-off API call to Hashting registering your incoming event's URL as the callback for cashback_entry_status_update_with_data.
  4. Create a Hashting Cashback integration in the campaign module.
  5. Build the campaign that pushes to Hashting, mapping firstname, lastname, email, and the receipt upload to the invoice field.
  6. Activate the "Hashting Cashback Flow" push rule on that campaign.
  7. Add the widgets to the portal: a Campaign widget embedding the upload campaign, and an Interaction widget pointing at the receipt Interaction.
  8. Create the earning rule that grants points when a receipt is accepted, using Total Amount (VAT Included) as the awarded amount.

Pricing:

  • Technological fee for feature activation: €2,000
  • Setup fee on the Qualifio side: €3,000

What do the receipt statuses mean?

  • Pending — the receipt was submitted and Hashting hasn't returned a final result yet.
  • Accepted — Hashting validated the receipt and sent back the detailed line items and amount. This is also the trigger point for the earning rule to grant points.
  • Refused — Hashting rejected the receipt. When Hashting provides a reason, it's shown directly in the Interaction's title and history — no separate lookup needed.

Why is a receipt stuck on "Pending", or not earning points?

Check, in order:

  • The webhook subscription on Hashting's side points at the right incoming-event URL and token — a stale or mistyped one means Hashting has nothing to call back.
  • The push rule ("Hashting Cashback Flow") is active on the campaign — if it's off, the receipt image never reaches Hashting in the first place.
  • The Interaction JSONata still outputs the required externalId, label, status, and data keys — a broken mapping updates nothing, but never blocks or mis-grants points, since the points path is gated in code, not in the mapping.
  • The earning rule is active and correctly reads the amount from the Accepted payload (Total Amount (VAT Included)).
  • Hashting's own processing — if neither the itemised payload nor a rejected status has come back yet, the receipt legitimately stays Pending until Hashting finishes reviewing it.

Can I reuse this for another partner or event type?

Yes. Nothing in the Interaction or incoming-event configuration is Hashting-specific — the same pattern (incoming event + Interaction JSONata + Interaction widget) applies to any partner that reports an asynchronous status back to a member-facing process.

 

Was this article helpful?

Can’t find the answer you need?

Send us a question and connect with an expert to get personal assistance.

Contact support

Vous ne trouvez pas les réponses que vous cherchez ?

Nous sommes là pour vous aider. Envoyez-nous une demande en direct !

Contacter le support