Lighthouse · Merchant · Metric dictionary / for sign-off

Merchant Metrics & Definitions

Every metric, its exact source, and its definition across the Merchant dashboard's two tabs — for line-by-line sign-off with the data owners. All figures are live (as of 2026-08-24).

Basic info · source

Fabric DW “Merchant Operations” (Power BI dataset 2eab80d2…, owner Marco.Bertetti). Fact fact_trans_merchant_paymentsSuccess (settled) transactions only, 148M rows. Read via DAX.

Bad merchants · source

PayBy TiDB-DW (Grafana ds-query MMMimfg7z). Tables aml.t_risk_case · acquireii.t_acquire_order · merchant.*. Carries failed / rejected / risk — the Fabric fact does not.

Defined clear, direct pull ⚠ To confirm a choice/assumption — needs owner sign-off Source column: table[column] / DAX / SQL predicate

A · Basic info (operations — Fabric)

GMV / revenue / card & channel mix / onboarding time on settled transactions. Filtered by the selected period (3m / 6m / 12m / YTD) on snapshot_date.

Headline KPIs /api/merchant/ops-summary

MetricDefinitionSource / formulaStatus
GMVTotal settled transaction amount in the periodSUM(fact[order_amount])
Fee incomeFee revenue incl. VAT (payee + payer fees)SUM(fact[total_fee_income_incl_vat])
also _excl_vat, interchange_fee
TransactionsCount of successful transactions (1 row = 1 txn)COUNTROWS(fact)
Active merchantsDistinct merchants with a transaction in the periodDISTINCTCOUNT(fact[merchant_id])
TAT signup→onboardAvg days from sign-up to onboardingmeasure [Avg Days Sign Up to Onboarding]
= AVG(fact[days_signup_to_onboarding])
TAT onboard→1st txnAvg days from onboarding to first transactionmeasure [Avg Days Onboarding to First Txn]
= AVG(fact[days_onboarding_to_first_txn])

⚠ GMV is dominated by settlement accounts (Remittance / PPC / Fuze) — should settlement-type accounts be excluded to reflect real merchants? ⓘ The two TAT measures are currently averaged per transaction row (weights large merchants) — should they be per merchant instead? To confirm.

Trends /api/merchant/ops-trend

MetricDefinitionSource / formulaStatus
GMV by monthMonthly GMV trendSUM(order_amount) group by dim_lkup_date[year_month_num]
Fee by monthMonthly fee-revenue trendSUM(total_fee_income_incl_vat) group by year_month

Breakdowns (GMV by …) /api/merchant/ops-breakdown

DimensionDefinition / valuesSource columnStatus
AcquisitionOnboarding channel: PORTAL / BASIS / AGENT / BOTIM / Referredfact[acquired_via]
≈ TiDB create_source
Card brandCard scheme: VISA / MASTERCARD / Wallet / VAM TopUp / ITC / N Afact[card_brand]
Payment methodPayment methodfact[payment_method]
Merchant categoryMerchant main categoryfact[merchant_main_category]
also sub_category / mcc / merchant_type_category
ProductProductfact[product_name] (+product_code)
Pay channelPayment channelfact[calculated_pay_channel]
also calculated_terminal_type / channel_type

⚠ Card brand is mostly N/A (wallet / top-up / settlement rails, not card) — flag or exclude separately?

Top merchants /api/merchant/ops-top

ColumnDefinitionSource
Merchant / MIDMerchant name / merchant idfact[merchant_name] / [merchant_id]
SourceOnboarding channelfact[acquired_via]
GMV / Fee / TxnsPeriod totals; top-N by GMV descTOPN(N, …, SUM(order_amount) DESC)

📎 Fields present in the model but not yet on the dashboard (add on request): card_type / card_level / card_bin / card_area / bank_area, interchange_fee, referrer_mid/name, the rates dim dim_lkup_merchant_rates (FIX_RATE / MIN·MAX·FIX_CHARGE / validity), and the merchant & product hierarchies grp_1..5.

B · Bad merchants (risk — TiDB)

Bad merchant = the union of four family definitions. A merchant is “bad” on a day if it trips any active definition. Counts across definitions are always de-duplicated by merchant (never summed). Default period 60 days, up to yesterday (today excluded).

Definitions (4 families · 7 variants) /api/merchant/bad-trend · bad-table

Family / variantDefinitionSource table / SQL predicateObserved levelStatus
Risk · allMerchants with any valid risk/fraud case that dayaml.t_risk_case
WHERE status='Valid'
median 6/daydefault
Risk · chargebackChargeback cases only (fraud + service)AND case_type LIKE '%Chargeback fraud/service%'median 2/daycaution
High-reject · count≥10 declined transactions that day (absolute)acquireii.t_acquire_order
HAVING reject_count ≥ 10
median 79/daycaution · volume-biased
High-reject · rateReject rate ≥50% on ≥20 transactions that dayHAVING txns ≥ 20 AND reject/txns ≥ 0.5median 7/daydefault · recommended
App-rejected · statusOnboarding creation-order final status = REJECTEDmerchant.t_merchant_creation_order
WHERE status='REJECTED'
median 1/daydefault
App-rejected · auditA review step returned REJECT (per step)merchant.t_audit_history
WHERE result='REJECT' (join creation_order)
median 2/daycaution
DisabledMerchants moved to DISABLED that daymerchant.t_merchant_status_history
WHERE merchant_status='DISABLED'
5 total / 90ddefault

Metrics

MetricDefinitionFormula / denominatorStatus
CountDistinct bad merchants per day (union of active definitions, de-duped)COUNT(DISTINCT merchant_id) / day
Bad rate %Share of bad merchants — each family uses its own denominatorsee denominators below
↳ risk denomMerchants transacting that day (≥1 txn)DISTINCT partner_id · acquire_order (~782/day)
↳ high-reject denomMerchants with ≥20 txns that day (matches the rate floor)≥20 txn/day merchants (~209/day)
↳ app-rejected denomApplications submitted that day · 7-day rolling (small-denominator stability)DISTINCT merchant_mid · creation_order (~5/day)
↳ disabled denomEnabled merchant stockCOUNT · t_merchant WHERE status='ENABLED' (~5710)

⚠ Bad rate is disabled while a compare-by dimension is active (rate-by-dimension needs per-dimension denominators — phase 2).

Dimensions: compare / filter / locate

DimensionUseSource columnValues
Bad familyCompare (split lines)computedrisk / high-reject / app-rejected / disabled
Acquisition sourceCompare + filtert_merchant[create_source]PORTAL / BASIS / AGENT / BOTIM
Legal typeCompare + filtert_merchant[biz_org_structure]LLC / SOLE_P / FZC / FZE / CIVIL_C…
Category (MCC)Compare + filtert_merchant[category]5411 / 4722 / 5812… (ISO MCC)
Current statusFiltert_merchant[status]ENABLED / CREATED / DISABLED
Risk case typeFilter (risk only)t_risk_case[case_type]Chargeback fraud/service · fraud report…
Merchant (identity)Search + drillmid (exact) / name·business_name (contains)

Drill-down table · columns

ColumnDefinitionSource
MerchantMerchant name (falls back to business_name)t_merchant[name → business_name]
Families hitBad families tripped in the period (colored pills)computed
Bad daysNumber of days the merchant tripped any active definition (repeat-offender sort)COUNT(DISTINCT date)
Last bad dateMost recent day trippedMAX(date)
Source·Legal·StatusMerchant attributes; “Unknown” when not joinablet_merchant.* (LEFT JOIN)

C · Open questions (take these to confirm)

⚠ Definitions that need owner sign-off

  1. High-reject “reject” definition: currently status ≠ 'SETTLED' (includes in-flight/processing orders, inflating recent days). Suggest an explicit failed/declined status set — please provide the full t_acquire_order.status enum.
  2. High-reject threshold: default reject rate ≥50% and ≥20 txns/day (≈7 merchants/day). Are the % and volume floor agreed?
  3. Risk definition: default status='Valid' (all valid cases incl. all fraud reports) vs chargeback-only. Which is the default?
  4. App-rejected: order final status REJECTED vs audit-step REJECT? The two overlap and some merchants have no t_merchant profile (→ Unknown).
  5. Default active definitions: risk_all · hireject_rate · app_rejected_status · disabled (one per family). Agreed?
  6. TAT averaging (Basic): per transaction row or per merchant?
  7. GMV: exclude settlement-type accounts (Remittance/PPC/Fuze…)? List Card brand N/A separately?

Join keys (linking the two sources): risk / app-rejected / disabled use merchant_id·merchant_mid; high-reject uses partner_id (= mid). Channel taxonomies align: TiDB create_source ≈ Fabric acquired_via.

Source boundary: the Fabric fact holds successful transactions only (no rejects/risk) → use Fabric for the operations side; the risk side (reject rate / risk / disabled) must come from TiDB.

Merchant Metrics Dictionary · for definition sign-off · figures live to 2026-08-24 · draft v1