Merit / E-Commerce Solution / Rewards

Digital gift cards and tenant discount, end to end

How a digital gift card gets into the catalogue, how a discount is set for one product and one tenant, and what happens to the money between the order and the settlement report.

Source: Marthino's whiteboard plus the session on 25 August 2026 on discount for the rewards portal.
Status: working draft for review, not a specification. Owner: Brian. Reviewers: Marthino, Habeeb.

Where each half comes from

Sections 1, 2 and 5 come from the recorded session, so they carry what people actually said. Sections 3 and 4, the runtime, come from the whiteboard plus Brian's walkthrough of it. The session never discussed the wallet, OMS, fulfilment or settlement, so treat the runtime half as a reading of the board that needs Marthino to confirm it.

01Setup: how a product and its price get there

This is the configuration path. Nothing moves money here. It answers two separate questions: what is this product, and what does it cost this particular tenant.

Where it comes from System of record What the tenant sees Global Catalog legacy, we leave this Digital Seller Portal gift card vendors self serve gift cards today, offers later Merit commercial people, not a system PIM what the product IS name, brand, image, value, terms, category LiveOps what it COSTS, per tenant discount, markup, transaction fee Rewards Portal one catalogue per tenant, at that tenant's price Effective price base value + discount rule for THIS product, THIS tenant bulk product data product info supplier cost, base value sets the rate per tenant catalogue price rules vendor reads back its own config

Read it left to right. Two independent inputs meet in the middle. PIM holds the product. LiveOps holds the price rule. The Rewards Portal joins the two at display time, so the same gift card can appear at a different price in two different tenant portals.

Input

Digital Seller Portal

The counterpart of the Seller Portal, but for gift card vendors. The vendor owns its own product data and enters it here. Gift cards first, offers later.

Record

PIM

Single source of truth for what a product is. It publishes product.created and product.updated so downstream systems stay in sync.

Record

LiveOps

Where discount, markup and transaction fee are configured. The key is the pair, one product and one tenant, not the product alone.

One correction to the whiteboard

The board shows the Digital Seller Portal writing config into LiveOps directly. A vendor must not set the tenant discount, because that is Merit's margin against Merit's client. The vendor supplies its cost to Merit. Merit commercial sets the tenant rate. Two different writers, and today they share one box.

02The unit of configuration is product times tenant

This is the single hardest thing to hold in your head, and it is why a flat revenue share was rejected in the session.

A tenant gets access to a subset of the global catalogue. Inside that subset, each product carries a discount that belongs to that tenant alone. The same gift card sits at a different rate for Jahez than it does for Al Fursan, because the contracts differ and the volumes differ.

Gift cardTenant A, high volumeTenant B, newTenant C
Brand X, SAR 1005.0%2.0%no access
Brand Y, SAR 503.0%2.0%2.5%
Brand Z, SAR 2001.0%no access1.0%

Every cell is a separate configuration row. A blank cell is catalogue entitlement, which is a different control from price. Two controls, one screen.

Why one flat rate does not work

Brand discount from the supplier already ranges from 1% to 5%. A single Merit-wide share would pay out more than the margin on the 1% brands and leave money on the table on the 5% brands. This was decided in the session on 25 August and it is the reason the granular table above exists.

Volume changes the rate over time

New client
2%
Entry rate. Low volume, no track record.
Volume grows
3%
Incentive step. The tenant earns the better rate.
At scale
5%
Top rate, still inside the supplier margin.
Nobody owns the promotion yet

The ladder implies a job that measures tenant volume on a cycle and moves the rate. That job has no owner, no cycle and no threshold definition. Until it exists, every promotion is a manual edit in LiveOps that someone has to remember to make.

03Runtime, part one: order to fulfilled

Swimlane. Time runs left to right. Each row is the system that does the work.

Rewards Portal OMS MeritFulfilment Svc Wallet MGC ornew channel 123 456 789 Customer places order Order created tenant id attached Price snapshot MISSING TODAY see gap 1 Fulfilment record created Balance checked Funds held not captured Card allocated code, PIN, link fulfilled = true Order FULFILLED order created approve, forward check tenant wallet execute fulfilment callback status update

The important beat is step 6. Funds are held, not taken. Nothing is charged to the tenant until the card actually exists. That is what makes the settlement step in part two necessary at all.

Order path Fulfilment Money Gap, proposed

04Runtime, part two: fulfilled to settled

The second half is where the discount is actually applied to money. Same swimlane grammar, different cast.

OMS SettlementService LiveOps Wallet Finance andtenant 123 456 Order FULFILLED event published Settlement triggered Discount and fee config read read late, see gap 1 Net amount computed Hold captured at the net amount Reconciled statement issued order is complete what rate applies rate returned capture instruction ledger line

The Settlement Service does not decide anything about the order. It reads the completed state from OMS, reads the rate from LiveOps, does the arithmetic, and tells the Wallet what to take. Three reads and one write.

This service does not exist yet

Two drafts overlap with it and neither is built. The OMS Payment Settlement Integration covers escrow and payout batches. The Pricing Commission Engine covers rate resolution and the pricing ledger. Whether the rewards settlement path is a third service or a mode of one of those two is an unmade decision, and it is the largest single risk in this design.

05Two discount models, and they are not interchangeable

The session settled this. Gift cards and merchandise are priced by different mechanics, so one engine cannot serve both without a mode switch.

Gift cards

Per product, per tenant

The card has a base value. Merit takes a discount off it or adds a markup. The rate is set for each product and tenant pair, and it moves with volume. Configured in LiveOps, applied at settlement.

Typical range: 1% to 5%, driven by what the supplier gives Merit on that brand.

Merchandise

Client level profit share

No per-product discount. The tenant contract carries a share of profit across the whole basket. Simpler to administer, and it is the right shape for enterprise deals.

Marthino's diagram does not cover this path. It is a gift card diagram.

Revenue share is the third mechanic, and it was not rejected outright

Two ways exist to share a gift card: share the discount, or share a percentage of the money. The revenue share version was described in the room like this. Merit gets 3% from the brand, is transparent about it, and splits that 3% with the tenant on an agreed ratio, 80/20 or 40/60. That is workable for one deal.

What was rejected is doing it globally, across the whole catalogue, because brands give 1%, 2%, 3% and 5% and an averaged single rate pays out wrong at both ends. Revenue share stays a fair shape for enterprise deals. The rewards portal needs the granular table instead.

One thing the room did not settle

The question was raised that the same product-and-tenant discount logic should also apply in the new e-commerce architecture, using three different bank clients as the example. The answer given was that e-commerce will share gross margin instead, and the discussion moved on. So whether this logic gets built once or twice is still open, and it is the reason question 1 below matters.

The supplier side is the other half of the same number

The tenant rate cannot be set without knowing what the supplier gives Merit, otherwise the deal can go negative without anyone noticing. The Online Catalogue holds this today, by hand, with a Finance double check before anything goes live. The rule in use is one conditional:

client_rate = IF( supplier_rate < -1% , supplier_rate x revenue_share , supplier_rate + 2.5% )

So there are two chained margins, supplier to Merit and Merit to tenant, and the tenant-facing rate in LiveOps is only safe while it stays inside the supplier-facing one. That guard is a manual check today.

06Where this differs from the whiteboard

Four deltas. Two are things Brian said out loud that the board does not draw. Two are lines on the board that nobody explained.

#On the boardHere, and why
1Settlement is triggered by the fulfilment channel, arrow labelled If Fulfilled = True from MGC to Settlement ServiceHere it is triggered by OMS after the order reaches FULFILLED, which is how Brian described it. The two are not the same design. Triggering from the channel skips the order state, so a bulk order with one failed item would settle anyway. Needs Marthino to confirm which one is intended.
2No return arrow from the Fulfilment Service to OMSAdded here as step 8 to 9. Without it, OMS never learns the order is complete and cannot be the trigger in delta 1.
3A line from LiveOps to WalletNot drawn here, because nothing in the walkthrough explains it. If the Wallet reads the rate directly, then two systems compute the same number and they will disagree. See question 7.
4A line from the Rewards Portal to WalletNot drawn here. Most likely a balance display at checkout, which is reasonable, but it is a read the board does not label. See question 8.
Everything else matches

The catalogue path, the config path, the order path through OMS to the Fulfilment Service, the wallet check and hold, and the fulfilment channel are all drawn the same way here as on the board.

07What the whiteboard does not answer

Twelve things. Ordered by how much they hurt. The first four can lose money quietly, which is worse than failing loudly.

#GapWhy it matters, and what to do
1Rate is read at settlement, not at orderIf someone edits the discount in LiveOps between the order and the settlement, the tenant is charged a rate they never saw at checkout. Fix: write a price snapshot on the order at creation, and settle from the snapshot. This is step 3 in part one.
2No hold release pathThe diagram only draws the happy path. If MGC fails to allocate, the hold sits on the tenant wallet forever. Every hold needs a time to live and an explicit void on failure.
3No insufficient balance branchWhat does the customer see, does the order fail or queue, and who is told. Undefined.
4No margin guard at config timeNothing stops a tenant rate being set above the supplier margin on that brand. That is a loss per transaction and it will not surface until reconciliation.
5Refund and cancellation are absentA gift card is delivered and then disputed. Reverse the capture, reverse the settlement line, and mark the card. None of this is drawn.
6Partial fulfilment on bulk ordersMGC takes 5 items per call at 1 order per second. A 200 card order is many calls, some of which fail. One hold against a partly fulfilled order needs a defined capture rule.
7Transaction fee appears once and never againThe board lists it beside discount and markup, then it does not enter the settlement arithmetic. Is it charged per order or per item, and does it sit inside or outside the discount.
8Volume tier promotion has no ownerThe 2 to 3 to 5 percent ladder implies a periodic job. No cycle, no threshold, no owner. Today it is a manual edit someone must remember.
9No effective dating or audit on the configRate changes need a start date, an end date and a record of who changed what. Finance will ask which rate was live on a given day, and there is no answer.
10Idempotency is not shownA retried order must not hold funds twice. The Fulfilment Service already takes an idempotency key. The Wallet path does not say it does.
11VAT, FX and roundingMulti market means more than one currency and a tax treatment per market. The net amount cannot be computed without them.
12Global Catalog retirement has no dateThe board marks it "we will leave this eventually". Until it goes, supplier cost lives in one system and tenant price lives in another, which is exactly how the two margins drift apart.
What the room did agree on

Discount is keyed on the product and tenant pair, not the product alone. Merchandise is client level profit share, not per product. A single flat revenue share across the whole catalogue does not work. Tenant discount data is specific to the brand and the tenant, so it stays in the rewards portal domain. All four from the session on 25 August 2026.

08Questions for Marthino and Habeeb

Eight. Each one blocks something concrete. The first two are the ones that change the build.

#QuestionBlocks
1Is the Settlement Service a new service, or a mode of the OMS settlement engine, or the Pricing Commission Engine.Ownership, sequencing, and which backlog it lands in
2Do we snapshot the rate on the order at creation. Yes or no.The whole settlement design. Answer this first
3Who is allowed to write the tenant rate in LiveOps: Merit commercial only, or the vendor too.Permissions, and whether vendor and tenant config split into two screens
4Hold time to live, and the void rule on fulfilment failure.Wallet build, which is not started
5Transaction fee: per order or per item, inside or outside the discount.The net amount formula
6Is merchandise in scope for this flow at all, or does it stay on client level profit share.Scope of the first build
7What is the LiveOps to Wallet line on the board for.Whether the Wallet computes the net amount or is only told it
8What is the Rewards Portal to Wallet line for. Balance display at checkout, or something else.Checkout behaviour when the tenant balance is low