Merit · E-Commerce Solution · Internal

The service map

Every service the E-Commerce Solution owns, every system it has to call to complete an order, and the contract at each seam between them. The green band is ours. Everything above it is a caller and everything below it is a dependency, which is why most of what blocks us is not code.

Owner: Brian Arfi Faridhi, Product Director · 11 September 2026 · Companion to How Merit moves an order, which covers the Old World in the same notation

00Read this first

What this page is, and what it deliberately is not.

This is the New World view. The E-Commerce Solution is a B2B SaaS stack: loyalty programmes and brands, called tenants, run their own branded commerce experience on it and pay a subscription plus a take rate. The target every dated commitment traces back to is sixteen large tenants producing 869,200 dollars a month by December 2026.

Old World and New World are not phases. They are two live stacks.

The Old World earns the revenue today, across eight live client instances, and it runs on the legacy Online Catalogue, MGC and the Platform services. The New World is a parity chase beside it. A number from one stack does not describe the other. When somebody says "the platform", they almost always mean an Old World thing.

Green

Ours

The E-Commerce Solution. Boards MSP and STOR, delivered with Tintash.

Violet

Shared services

Called by us, owned by somebody else, and not by one team. Payments hold the Payment Service and the tax rules, Marthino holds the Exchange Hub, the Communication Hub and LiveOps, Bilal holds Identity. A few of them are Akshay's Old World services that the new stack still has to call. None carry a deprecation date.

Amber

Old World commerce

MGC and the Online Catalogue. Being replaced, and a supplier behind our own pipeline until they are.

Three things this page does not do. It does not specify any service, because each one has its own PRD. It does not describe the Old World order path, which is covered in the companion page. And it is not a deployment or infrastructure diagram: every box is a responsibility, not a container.

01The map

Every part, and the fifteen places work crosses from one part to another. Each numbered badge on the diagram is a seam listed underneath.

Demand · every channel that asks the E-Commerce Solution for somethingchannelsB2C Super AppMerit's own consumer app, AndroidliveTenant storefrontwhite label template, one pertenantClient shops, Old WorldAl Fursan, Nielsen, Kantar, MCMRewards Portaltenant facing redemption, giftcardsClient API and bulkcorporate orders placed straight inThe E-Commerce Solution · what we own · boards MSP and STORsupply andchannelsSeller Portalmerchandise sellers, self serve. Upload,price and stock, warehouses, fulfilment.Plus the cross-tenant Merit Ops consoleDigital Seller Portalgift card merchants. Phase 0 is a store ofcommercial termsStorefront Buildertenant provisioning, template, basic CMSSearchadvanced search across the tenant catalogue,untunedPIMwhat the product is. MedusaJS. No price, everE-commerce Corethe front door for demand. Offers, inventory, sales channels and marketsproduct andofferthe order,and after itSettlement Servicethe final calculation once the order isfinal. It hangs off OMSOMS Corethe order state machine, SLA engine,settlement hooksFulfillment Serviceone interface, provider adapters behindit. Warehouses mirrored hereTMS on OTOlabels, AWB and tracking. It runsbehind the Fulfillment ServiceShared services · owned outside the E-Commerce Solution, and not by one team · the owner is on each boxthe moneyPayment ServicePayments, Tamer. Holds the Platform TaxService and every TaxRuleWallet and LedgerPayments. Tenant balance and the immutabletransaction proofPayout ServiceAkshay, Old World. Pays the seller. No NewWorld counterpartMerit Exchange HubMarthino. FX rates, refresh and the requotetoleranceidentity,place andmessagesIdentity ServiceBilal. Login, and the structured addressmodule. Every seller warehouse is storedhere, not in the Seller PortalCommunication HubMarthino. Email and SMS under the tenantbrandTenant Context ServiceAkshay, Old World. Tenant details and MGCcredentialsPoints ExchangeAkshay, Old World. Merit points to a partnercurrencyoperate andmeasureLiveOps consoleMarthino. Tenants, catalogue approval, seller onboarding. It has no market screen yetETL and the datalakeEvery service ships its own tables nightly. Metabase and Mixpanel read it, neverproductionOld World commerce · Akshay · being replaced, and a supplier behind us until it islegacyMGCorders, inventory, client float, gift cardissuingOnline Cataloguethe catalog source of truth todayMerchandise Serviceevery supplier integration, wired one by oneOps panelsthe manual steps nobody has removed yetOutside MeritvendorsOTO200 plus GCC carriers on one APISalasa and SPLfulfilment partner, and Saudi PostMoyasarcard rail, Saudi ArabiaHERE Mapsaddress validation at checkoutSuppliers and brandsAleph, Jasani, GoldenScent, STC1every read and every order arrives at Core2the product goes to PIM, the offer goes to Core34655789101112131415

Read it downward. Everything above the green band asks for something, everything below it is asked for something, and the E-Commerce Solution holds both ends together. The lanes at the edges carry the six routes that skip a band, and the catalog bridge on the right runs in both directions. Each badge is a seam, listed below.

1Every channel arrives at Core. The B2C app, a tenant storefront, an Old World client shop, the Rewards Portal and a bulk API client all read the catalogue and place the order through E-commerce Core. Before that, the shopper signs in through the client app, and the points are read and burned at the client's own loyalty system. Merit never holds the points.
2The upload writes two things, to two services. A seller uploading in the Seller Portal creates or matches the master product in PIM, and creates the offer in E-commerce Core. Those are two different writes to two different services, and the distinction is the whole data model. The Digital Seller Portal writes commercial terms to Core only. The Storefront Builder configures the tenant channel, and Search reads.
3Product against offer. A product is what an item is: iPhone 15, 128GB, black. An offer is one seller listing it at a price, with stock, on a channel. Two sellers, one product, two offers, and the Buy Box picks which one the shopper sees. Offers reference products and never the reverse.
4Core creates the order. Core hands the confirmed basket to OMS. From that moment only OMS moves the state, and no other service writes it.
5OMS, then fulfilment, then the carrier. The chain runs in one direction. OMS tells the Fulfillment Service to fulfil the line, the Fulfillment Service picks the provider, and TMS books the carrier through OTO. TMS sits behind the Fulfillment Service and Core never calls it.
6Settlement hangs off OMS, not off Core. Settlement runs after the order is final, which is a state only OMS knows. It turns the wallet hold into a permanent charge and works out the split: discount, markup, transaction fee and the tenant revenue share.
7Tax and payment. Core resolves the tax against the Platform Tax Service, which is a module inside the Payment Service and holds every TaxRule. We resolve and display. We never compute a rate and we never store a second copy of one. The same service then takes the money.
8Wallet and payout. Settlement writes the charge against the Wallet and the Ledger, and the Payout Service pays the seller on delivery. Payout is an Old World service and has no New World counterpart, so the new stack settles into an old rail.
9Notifications. OMS and the Fulfillment Service raise the event, the Communication Hub sends it under the tenant brand. Gift cards use lazy fulfilment, so Merit sends the mail and the code is minted when the customer clicks.
10A seller warehouse is written to the Identity Service. Warehouse addresses do not live in the Seller Portal. The portal proxies every seller write to the Identity Service, which is the source of truth, and publishes a snapshot only after identity answers 2xx. OTO needs contact name, contact email, mobile, city and country, and identity holds all five as optional today, which is why freshly mirrored rows park as BLOCKED. The grain is per warehouse, not per seller.
11The Fulfillment Service mirrors it, and pushes it to OTO. The Fulfillment Service subscribes to that snapshot, mirrors the address into its own warehouses table, and registers it with OTO as a pickup location. One identity address is one warehouse row is one OTO pickup location, and the order item carries that same id. The per-seller fallback in the dispatcher is a leftover and collects from the wrong warehouse, so it is deleted before the import.
12The catalog bridge, and it runs both ways. Signed webhooks push product and stock out to the Online Catalogue, which syncs onward to MGC on a pipeline that was already nine months old when we reused it. The stock decrement comes back synchronously at order time. This is the seam that breaks most often, and today a supplier SKU conflict is stopping it.
13Legacy issues the gift card. For gift cards and catalogue sourced items the Fulfillment Service calls MGC. The dependency is inverted on purpose: legacy is a supplier sitting behind our own pipeline rather than the system the order is handed to.
14TMS books the carrier. OTO reaches more than 200 GCC carriers on one API. Until TMS is built, the Fulfillment Service proxies MGC and the label comes out of the legacy system.
15Suppliers, and the manual steps nobody removed. The Merchandise Service and MGC hold every supplier integration, wired one at a time with no adapter to reuse. Ops still copies catalogue data into client panels, moves order statuses by hand and distributes gift cards by mail. If a change moves a manual step, tell Ops before it ships.
The shape to hold in your head

We own one band. The order cannot complete without the two bands underneath it, and neither of them is on our roadmap or our sprint. That is the whole reason the recurring shape of a problem here is a sync that fails on bad data, a contract nobody signed, a budget nobody approved, or a design review nobody scheduled.

02The five rules that decide where a thing lives

Most architecture arguments on this stack are one of these five, restated.

1

PIM owns the product, Core owns the offer

A product is what an item is: iPhone 15, 128GB, black. An offer is one seller's listing of it, with their price and their stock. Two sellers, one product, two offers, and the Buy Box picks which one the shopper sees. Offers reference products and never the reverse. PIM stores no price at all.

2

Core is the front door for demand. Supply writes to both

Every storefront, the B2C app and every order come through E-commerce Core, and they never reach PIM directly. Supply is the exception that matters: a seller uploading in the Seller Portal writes the master product into PIM and the offer into Core, because they are two different objects with two different owners. Reading that as one write is how the catalogue and the offer drift apart.

3

Once an order exists, only OMS moves it, and everything after it hangs off OMS

OMS Core is the state machine, and it belongs to the E-Commerce Solution. Fulfilment and Settlement are both called by OMS, not by Core: Core has no business knowing that an order shipped or that it became final. Platform's own team page still lists "order lifecycle infrastructure" among its components, and that page was never corrected.

4

The Fulfillment Service is the only thing that talks to a carrier

One interface, provider adapters behind it, and TMS sits behind it rather than beside it. Core never calls TMS and neither does OMS. Phase one proxies MGC, which inverts the dependency on purpose: legacy becomes a supplier behind our pipeline rather than the system the order is handed to. Warehouses are mirrored here too, from the Identity Service, and pushed to OTO as pickup locations.

5

We connect to a rule engine, we never keep a second copy of its rules

The Platform Tax Service already holds every TaxRule. So a market stores no rates: it names the categories it sells and resolves them against that service at configuration time, shows the result read only, and turns a missing rule into a request rather than a field to type into. The same reasoning applies to FX, which belongs to the Merit Exchange Hub.

The trap

One word, two meanings

Storefront is a running client shop, which is Marketplace, and it is also the builder product, which is ours. Catalog is the Online Catalogue, which is Old World, and it is also PIM plus Core. Naming a client means the first. Saying builder, template or tenant means the second.

03The services, one row each

What each one owns, who it depends on, and where it actually stands this week. The state column goes stale fastest; the live answer is the dashboard and journal/todo.md.

ServiceWhat it ownsIt callsIt is called byState, 11 Sep
E-commerce Core
np-core
The offer: price, stock context, condition, channel assignment. Sales channels and markets.PIM, the Platform Tax Service, the Online Catalogue, OMSEvery storefront, the B2C app, the Seller Portal, LiveOpspartialIn progress. Blocked on catalogue sync automation, and carrying about one engineer
PIM
np-core
What a product is. Canonical identity and enrichment, on MedusaJS. It stores no price at all.Nothing outwardE-commerce Core, and the Seller Portal upload, which writes the master product straight inliveLive and multi-tenant. A supplier SKU conflict is stopping one sync
OMS Core
np-oms
The order state machine, the SLA engine and the settlement hooks. Everything after the order is called from here, not from Core.The Fulfillment Service, the Settlement Service, the Communication Hub, PaymentE-commerce Core, support tooling, the B2C order webhookpartialIn testing and migration. It slipped July and it gates most of Q3, so it is the critical path
Seller Portal
np-sp
Self service for third party merchandise sellers: upload, price and stock, warehouses, fulfilment, payout view. Plus the cross-tenant Merit Ops console, which is the only planned replacement for operating a physical order in MGC.PIM and E-commerce Core on upload, the Identity Service on every address writeSellers directly, and Merit Ops staff on the admin consolepartialLive and expanding. Blocked mainly on the Online Catalogue two way sync. The admin console is P0 for the Al Fursan cutover and is still a draft
Digital Seller Portal
np-dsp
The same idea for gift card merchants. Phase 0 is not a portal: it is a store of commercial terms plus two APIs, at the grain of tenant and product.E-commerce Core, which is the single source of truth for the termsLiveOps writes, the Rewards Portal reads and cachesnot builtPhase 0 designed on 8 Sep and not yet estimated
Storefront and Builder
np-sf
The multi-tenant white label template, the builder, tenant provisioning and a basic CMS.E-commerce Core, the Identity ServiceTenants configuring their own shoppartialIn progress, about half way through its sprint and flagged at risk
Fulfillment Service
np-ffs
Everything that happens to a reward after the order. Provider adapters behind one interface, and the mirror of every seller warehouse.TMS on OTO, MGC, the Communication Hub. It subscribes to the Identity address snapshotOMSpartialPhase one proxies MGC. The warehouse sync is built end to end and parks every row as BLOCKED, because OTO needs contact fields identity holds as optional
TMS on OTO
np-ffs
Carrier orchestration: labels, AWB, tracking, more than 200 GCC carriers on one API. It runs behind the Fulfillment Service and nothing else calls it.OTO, and SPL for Saudi Post branchesThe Fulfillment Service onlynot builtPlanning. Gated on OTO budget approval and a solution design review open since mid August
Settlement Service
np-settle
The final calculation once the order is done: turns a hold into a charge and writes the revenue line. It is triggered by OMS, because only OMS knows the order is final.The Wallet and Ledger, the Payout ServiceOMS, Finance reportingnot builtDraft v0.4. Product says a new service, engineering may overrule it on technical grounds
Search
np-core
Advanced product search across the tenant catalogue.E-commerce CoreStorefronts and the B2C apppartialIn progress and untuned. The Old World search has years of tuning behind it
Read the state column as a dependency chain, not a list

OMS gates most of Q3. Core is blocked on catalogue sync automation, the Seller Portal is blocked on the same sync from the other side, and PIM is where the sync actually fails, on a supplier SKU conflict. Four rows, one root cause.

04An order, end to end

Six lanes carry it. Only two of them are ours.

Storefrontor B2C appE-commerce Coreoffers and channelsOMS Corethe state machinePayment and TaxPayments, TamerFulfillment Serviceafter the orderOTO or MGCwho actually shipsBrowsecatalogue and offersthe Buy Box picks one offer per productprice in the market currencythe market decides currency, payment providers and fulfilmentCheckoutresolve the taxby product category and market, from the Platform Tax Servicerate and amountfrozen on the order line at confirmation and never repricedpoints burn at the clientMerit reads the balance and asks for the debit. It holds nothingtake the moneycard through Moyasar, or a hold on the tenant walletOrdercreate the orderfrom here only OMS may move the statefulfil this linephysical: book a carrierTMS on OTO. Until TMS exists, MGC does itgift card: issue the codelegacy is a supplier sitting behind our own pipelinestatus callbacksAfter the order is finalSettlement runs here, not at checkout. It is aseparate service and a separate clock: theclient is charged at purchase, revenue isrecognised on reveal.

An order in the New World. Compare step "create the order" with the Old World, where the shop forwards the order to MGC and MGC becomes the source of truth for sales and inventory.

The market decides more than the currency

A market holds the country, the pricing currency, the settlement currency, the delivery fee, the payment providers and the fulfilment profile. Today Core assigns one hardcoded Saudi market to every sales channel created from LiveOps, because LiveOps has no field for it. That is acceptable for the first multi-currency launch and not after it: Jordan is next, and it currently needs an engineer and a database write.

05Catalog and stock, the live bridge

The one seam where the two stacks touch continuously rather than at cutover.

Seller Portalsupply sideE-commerce Coreowns the offerPIMowns the productOnline CatalogueAkshay, Old WorldMGClegacy commercematch or create the master productthe upload writes the product into PIMcreate the offer against itprice, stock, condition, channel. Offers reference products, never the reverseA supplier SKU conflict halts the stop onerror sync. That is what blocks merchandisereaching the Seller Portal today.Outward, livesigned webhook: product and stockpush, not polling. Changed from a direct MGC bridge in April 2026the OC's own syncnine months old and already automated, which is why it was reusedInward, livesynchronous decrement at orderan Old World order still has to take stock off a New World offerAgreed, not builta new variant on an existing productwaiting on the Online Catalogue side to replicate it

Physical merchandise only. Gift cards, digital codes and vouchers are excluded from this bridge. Two routes run today and one is agreed and not built.

Why it runs through the Online Catalogue at all

The original plan was a direct bridge from the Seller Portal to MGC. In April 2026 that was dropped, because the Online Catalogue already had an automated sync into MGC that had been running for nine months. The method changed at the same time, from pull based polling to bi-directional webhook push.

06Where a warehouse lives

The newest seam, and the one most likely to be got wrong, because the obvious answer is wrong: a seller warehouse is not stored in the Seller Portal.

Sellerin the portalSeller Portalproxies, never storesIdentity Servicethe source of truthFulfillment Servicemirrors itOTOpickup locationadd or edit a warehouseone component, used on the warehouses page and inside the offer formproxy the writethe address lives in identity. The portal keeps no copy2xxpublish a full snapshotonly after the 2xx, so nothing is announced that was not committedthe eventmirror it into warehousesone address, one warehouse row, one pickup locationregister the pickup locationsynchronous, outside any transactionIt parks as BLOCKED today. OTO requirescontact name, contact email, mobile, city andcountry, and identity holds all five asoptional while the seller form asks for noneof them.At dispatchcollect from sellerLocationIdthe same id the order item carriesA leftover fallback picks the newest warehousefor the seller when that id is missing. For aseller with two warehouses it collects fromthe wrong one, so it is deleted before theimport.

The grain is per warehouse, not per seller. Every leg of this is built and in review, and the thing stopping it is five fields nobody asks the seller for.

The pattern is settled. The data is not

Synchronous proxy write, then an event after the 2xx, then a synchronous call to OTO. That was decided on 1 September and it is built on all three services. What is open is smaller and harder: the fields OTO demands are optional in identity and absent from the seller form, so the pipeline runs end to end and every row parks as BLOCKED. Validating at capture puts the correction in front of the seller who knows the answer. Validating at sync time puts it in front of Ops, weeks later, on an address nobody can chase.

One consequence worth carrying: a bulk import written straight into identity emits no event, so it would land the addresses and leave the mirror empty. The import goes through the seller portal address API instead.

07The money

Tax at checkout, settlement after the order, payout on delivery. Three services, and only one of them is ours.

Order lineprice, tax, commissionWallet and LedgerPaymentsSettlement Serviceours, triggered by OMSPayout ServiceAkshay, Old WorldFinancethe peopleAt purchasehold the tenant balanceexposure is bounded by what the tenant fundedThe rate in force at the order is the ratebilled. Redemption never reprices it.When the order is finalturn the hold into a chargecompute the splitdiscount, markup, transaction fee, tenant revenue sharewhat the seller is owedpayout on delivery, batchedAt month end, gift cards onlyreverse the unclaimed partit returns as revenue when the customer reveals the cardreconcile against the supplier invoiceTwelve months with no reveal and it becomesbreakage revenue. Merit keeps all of it, andcarries the supplier cost risk in exchange.

Two clocks. The client is charged at purchase, and revenue is recognised on reveal. Any settlement design that assumes one money event per order is wrong for gift cards.

Charging and recognising are different events

The client is charged at purchase, at the rate in force when the order was placed. Revenue is recognised when the customer reveals the card, so the unclaimed part is reversed to contract liability at every month end and returns as revenue on reveal. Reading the first rule as "revenue lands at purchase and stays there" is the mistake Finance already corrected once.

08What we depend on and do not own

This table is the honest risk register of the migration. Every red row is a capability that is live in the Old World and has no counterpart in ours.

What we depend onWhoseWhat it does for usState, 11 Sep
Platform Tax ServicePayments, Tamer. Hamd built itHolds every TaxRule and computes at runtime. We resolve a category against it and display the result read only. A market stores no rate.partialTwo questions open: who applies the origin rule, and whether there is a lookup call or only a calculation call
Wallet, Payment and LedgerPaymentsPer tenant prepaid balance, the debit, and the immutable per transaction proof that reconciliation and billing are built on.partialThe Ledger is the reconciliation source of truth and a go live blocker
Identity ServiceBilal owns the address moduleLogin, and the structured address module. Every seller warehouse is stored here, not in the Seller Portal, and the portal proxies each write to it before publishing a snapshot.partialThe fields OTO requires are optional in the identity DTO and absent from the seller form, so every mirrored warehouse parks as BLOCKED until that is fixed
Merit Exchange HubMarthinoFX rates, rate refresh and the requote tolerance for multi-currency. It wraps Fixer so that no other service re-integrates it.liveOwnership settled in DEC-0289. Core reads it and must not rebuild it
Communication HubMarthinoEmail, SMS, and the tenant branded templates. WhatsApp still runs through the client side.partialWhatsApp has to move to Merit and no team is assigned to it
LiveOps consoleMarthinoThe operator front end for tenants, catalogue approval, seller onboarding and market management.partialMarket management does not exist, so every market other than Saudi needs an engineer and a database write
Points ExchangeAkshay, Old WorldConverts Merit points into a partner currency and back. Six partner programmes live.not builtNo New World counterpart at all, and burning points is the reason Al Fursan exists
Payout ServiceAkshay, Old WorldPays the seller and the partner. PayPal, Revolut and THUNES are live.not builtNo New World counterpart. Rebuilding it is the largest uncosted item on the migration
Online Catalogue, MGC and the Merchandise ServiceAkshay, Old WorldThe catalog source of truth today, the order and inventory engine today, the gift card issuer for as long as it lives, and every supplier integration.partialFull deprecation is targeted for November 2026 in the migration plan and December in the older strategy documents. Work to November
OTOVendorLogistics aggregation. One API to more than 200 GCC carriers, and the pickup locations every warehouse is registered against.partialCommercial agreement signed on 30 June 2026. The integration budget is still not approved
Salasa and SPLVendorFulfilment partner for Al Fursan and Apple Store, and Saudi Post for parcels.not builtThe Salasa contract was still unsigned on 8 September and is a live escalation. The SPL branch creation API is an open dependency
MoyasarVendorCard and settlement rail in Saudi Arabia.liveLive
HERE MapsVendor, Marketplace sideAddress validation and geocoding at checkout.liveLive on the Al Fursan storefront. It belongs to Marketplace, not to us
The two that decide the cutover

Points Exchange and Payout have no New World counterpart, and both are live, partner integrated Platform services whose integrations took years to build. Rebuilding them inside the E-Commerce Solution is the largest uncosted item on this page. Calling the existing services instead is the cheaper answer and it has not been decided.

09What goes stale here, and where the live answer is

Ranked by how fast it moves.

  1. The state columns, sections 03 and 07
    A week, at most. The live answer is the dashboard at http://localhost:3737 and journal/todo.md, not this page.
  2. Anything with a date on it
    MGC deprecation, the Al Fursan cutover, the tenant count. The migration plan says November 2026 and the older strategy documents say December. Work to November.
  3. The seams
    Slower. A seam changes when a design review lands, and each one is recorded in a PRD or a decision record first.
  4. The five rules, section 02
    Slowest, and the part worth memorising. Several of them were settled after an argument, and re-opening one costs a sprint.

Built from

The E-Commerce Solution orientation pack of 9 September 2026, the Merit E-Commerce Solutions strategic overview v2.0, the LiveOps market management requirement v0.3 of 11 September, the Settlement Service PRD v0.4 of 3 September, the Wallet and Fulfillment alignment document v1.2, the team onboarding guide, and the system topography page of 25 August. No source code was read.

Where this page disagrees with a PRD, the PRD wins and the fix belongs in this file. Regenerate with python3 "Clients/Merit/assets/build_ecom_service_map.py".