Merchant Page Editing
Open a merchant from Merchants. The H1 is Merchant Details.
Header: Edit Merchant and Delete Merchant. Tablist
Merchant sections: Overview, Enquiries, Analytics,
Admin. All editing is inline. Do not start from
/admin/merchants/ or local-server.js.
Stay on Overview for the App card (Environment, Sandbox preview, Header snippet, Features). Click ⓘ for a short answer and Read full guide →. Admin help & docs.
Live URL:
https://admin.finmatch.io/merchants/?id=M000101. Path IDs like
/merchants/M000101 404. See Admin URLs.
Accessing the Merchant Page
From Merchants Table
- Click Company Name: Click on any merchant's company name in the merchants table
- Actions Menu: Click the "⋯" (three dots) button → "✏️ Edit"
From Other Pages
- Stripe Page: Click on linked merchant name to navigate to merchant page
- Direct URL:
https://admin.finmatch.io/merchants/?id=M000101(path IDs like/merchants/M000101404 on production)
Merchant Page Structure
The merchant page H1 is Merchant Details. Header actions are Edit Merchant and Delete Merchant. The tablist aria-label is Merchant sections. The tabs are Overview, Enquiries, Analytics, and Admin.
James-only Settings hub (signed in as james@finmatch.io; not
general operator chrome). Page title Settings. Menu aria-label
Merchant settings. Profile row avatar F plus Merchant name
(checker reads F Merchant name), aria-label FinMatch Account.
Menu row Performance. Subpages: FinMatch Account (back
Back to Settings), Websites (Back to FinMatch Account).
FinMatch Account → Stripe is a linker, not a read-only copy.
First row is Link / Unlink (same words as the Stripe Billing
card). Link opens Link Stripe Customer. Do not treat this menu
as the live path for other operators.
The merchant page has four tabs. Cards below are on Overview.
| Tab | What it is |
|---|---|
| Overview | Merchant, Finance Offer Summary, Stripe Billing, Merchant Status, Contact, Lender, and App cards. |
| Enquiries | Finance Assistant enquiry rows. Columns and expanded tiles: Enquiries. Credit Product is not “what Propensio received”. |
| Analytics | Storefront analytics capture for this merchant, plus a Looker embed when configured. Global capture toggles live on Analytics. |
| Admin | Toolbar Admin actions: JSON, History, and Quote. These live on this tab, not in the page header. JSON opens View JSON with Merchant profile, Merchant configuration, and Partner API view. Legend JSON field shading key: Profile only, Settings only, Duplicate (in both), Conflict (different shape), Partner API metadata. About this view and Field reference. Provenance counters: Duplicates, Conflicts. Badges: admin + system, admin (credentials), system meta, external api. Section headings: CONFLICTS — SAME KEY, DIFFERENT DATA, DUPLICATES — SAME KEY, SAME MEANING. Field reference tables Merchant profile fields, Merchant configuration fields, Partner API view fields with columns Parameter, Type / Format, Description, Example, Source of truth, Maps to. Copy Copy profile JSON, Copy settings JSON, Copy Partner API JSON. Idle JSON panels show Loading.... The tab shell shows Loading history…. The history card then shows |
| Loading history... while it fetches, No history events yet. when | |
| the feed is empty, or **History service endpoint is not deployed yet for | |
| this environment.** Toolbar Expand all, Collapse all, **Copy all | |
| for AI**, and per-event Copy for AI. Event cards open **Technical | |
| details** and Raw event JSON. Quote is the same three-source table as | |
| Quote comparison. |
View JSON → Field reference Parameters include fcaStatus on
both Merchant profile fields and Merchant configuration fields
(profile is canonical; runtime is the stamped copy so the storefront
can skip rate cards without reading merchants.json). Duplicate note:
Canonical on the profile; stamped onto runtime so the SDK can skip
rate-card downloads for Not authorised merchants. Merchant
configuration also lists merchantMinimumDeposit (Merchant-wide
minimum customer deposit (floor over per-product rules). Empty/absent
= no global floor.) and merchantDepositRules (legacy). There is no
Credit Products control for merchantMinimumDeposit yet — author
per-product Min Deposit % as today. See Merchant FCA
status and Calculator deposit
dropdown.
There is no Lender setup card (removed Sep 2026). Overview cards:
- Merchant — Merchant ID, Finance Assistant API Key (Copy; idle Loading…, empty Not provisioned — click Copy to create), Company Name, Company Number, Domain, Testing domain, Ecommerce platform, FCA status, CreditSafe (opens CreditSafe from Company Number, or N/A)
- Finance Offer Summary — Template and Preview. Mode buttons: Price template, No-price template, Non-regulated template, Badge template (Quick-Start). Editors: Finance Offer Summary Editor (Tokenised) - Price, Finance Offer Summary Editor (Tokenised) - No Price, Finance Offer Summary Editor (Tokenised) - Non-regulated, Finance Offer Summary Editor (Tokenised) - Badge (Quick-Start). Preview title Current draft. Reset current template restores the active editor. Storefront Template mode (Auto / always) is a different control: Finance offer summary template mode. Partner API quotes need these profile template strings even when Finance offer summary enabled is off. Partner API quotes.
- Stripe Billing — Customer ID, Name, Email, Phone, Address, Billing Status, Next Billing, Created (Link/Unlink)
- Merchant Status — FinMatch / lender approval / live / termination (separate from the SDK kill-switch). See Merchant Status.
- Contact — two cards, both titled Contact. Tell them apart by Type: Primary Contact and Technical. Fields: First Name, Last Name, Email, Phone. Empty values show N/A. Save/commit: Contact cards.
- Lender — Lender Name and Credit Products (profile mirror). Add
lender, Remove lender, and Save credit products. Empty
select: Select lender to add.... When none are assigned: No
lenders assigned yet. Add a lender to configure products. Idle
status: Edit checkboxes, apply URLs, and min deposit % rules.
Empty products table: No products for this lender.
Loading: Loading credit products.... Load failure: Unable to
load credit products. Missing product id shows Unknown ID.
Per-lender table columns Product ID, Credit Product, Min
Deposit %, plus Direct apply URL. Placeholder:
https://hummuk.app.link/… or https://example.com/apply. ⓘ About direct apply URLs. Attaches a link to the Apply for finance button (for example a Humm app link). If Finance Assistant is off for this lender, the button opens this link. If Finance Assistant is on, this link is only a backup if the Finance Assistant start fails. Not a setup wizard. Assignments: Calculator deposit dropdown. Per-product Min Deposit % is still the admin authoring path. Partner API also applies a merchant-wide floor when runtimemerchantMinimumDepositis set (View JSON Field reference); that object has no Credit Products control yet. - App — Environment and Environment integrity, Sandbox preview, Header snippet (and Detected snippet when the scan disagrees), Snippet status and Snippet details, Finance Assistant Proxy URL, Features, Pages with embed snippets
Overview ⓘ titles: About Finance Assistant API keys, About the ecommerce platform, About the merchant FCA status, How merchant status is computed, How App environment works, How environment integrity is checked, How Sandbox preview works, About the Header snippet, When Detected snippet appears, How snippet status works, Possible snippet detail messages, About the Finance Assistant Proxy URL, How Features and Save features work, About pages with embed snippets.
Overview toolbar titles: Validate merchant environment against router and snippet detection, Share header snippet by email, Re-check this merchant now and update the shared snapshot, Show snippet details.
Finance Assistant Settings is not a fifth tab. Open it from the Finance Assistant row in the Features matrix (cog). Snap / Zopa / Humm / Propensio credentials live there. See Bon Voyage and Zopa Start and Lender Apply start.
Enquiries
Open the Enquiries tab on the merchant page. The table columns are Timestamp, Customer, Lender, Credit Product, Purchase, Loan Amount, and Status. Load row: Loading enquiries.... Empty table: No enquiries found.
Click a row to expand tiles:
| Tile | Fields |
|---|---|
| Customer Details | Name, Email, Mobile, Address. Headless Propensio rows show Customer -. |
| Finance Details (at application start) | Purchase Amount, Deposit, Loan Amount, Upfront Payment, Monthly Payment, Cost for Credit, Total Payable. Snapshot at Apply, not the later agreed figure. |
| Credit Product (at application start) | Lender, Product, Product ID, Term, APR. This is our calculator snapshot. It is not what Propensio received (the start request has no FinMatch product; the webhook has no product). Live today a hidden dropdown can still fill this name. Agreed, not shipped: - when the dropdown was hidden. See Admin Enquiries: Credit Product column. |
| Propensio application status | Current status, Agreed loan (from webhook loan_amount after decision), Originate application ID, Application number, Initial decision recorded, Status history. |
| Zopa application status | Current status, Zopa application ID, Zopa reference, Lender reference, Referred reason, Status updated, E-sign, Satisfaction note, Application. |
| Reference Info | Reference #, Source Page, Email Status, Email Sent, Email To, Actions (Resend email). Snap rows dim the M…-P… prefix (Not sent to Snap) and highlight the R segment (Sent to Snap as invoiceNumber). |
Older enquiry rows may still name the retired DivideBuy brand; those join the Zopa session store. DivideBuy is not a live lender.
Analytics
Open the Analytics tab on the merchant page. The banner title is Storefront analytics capture. The lead is Whether this merchant posts events to the Analytics API (BigQuery).
The pill is On or Off (or Unknown if the capture policy cannot load). Change status here opens Admin → Analytics → Event capture by merchant. Capture is not toggled on this tab.
Below the banner, a Looker embed mounts when configured. The iframe title is Merchant analytics. If no embed URL is set, the placeholder subtitle is Connect a Looker Studio report to show charts for this merchant. Do not copy invoice or SKU pound figures from cost tools into this public docs site. Do not copy Looker setup steps that name internal BigQuery tables onto this menu page.
Recent activity
Below the Overview cards, Recent activity is collapsed by default.
It shows the last 20 history events from
GET /admin/merchant-history/:id — the same feed as Admin → History.
Expand it for a compact audit. While it loads it shows Loading recent
activity…. If the history endpoint is not on this environment it shows
Recent activity unavailable: history endpoint not deployed in this
environment. If the renderer cannot load it shows History renderer
unavailable. Request failures use the same Recent activity
unavailable prefix with the status or error. None of those states
block editing.
Presence banner
If another admin edited this merchant in the last five minutes, an amber banner names them and says Refresh recommended before editing. Refresh reloads the merchant and shows Refreshing… while it loads. The banner is not a lock: you can still save. It stays hidden when you are the only recent editor, or if history cannot load.
Save conflict
If you click Save Changes after someone else wrote the same merchant, Changed while you were editing opens. It is not the presence banner (that one is a warning before you edit).
The table columns are Field, On server (theirs), and Your draft (yours). If there is no field-level diff it says No field-level diff available; the underlying record changed since you opened the editor.
Choose:
- Keep mine and overwrite — your draft wins
- Discard mine, use server — reload their version
- Cancel — stay in the editor
When the other admin is known, the description names them (Another admin (… ) saved changes while you were editing. Compare and decide:).
Merchant Status
The Status column and the Merchant Status card are the same computed
badge: merchantStatus. There is no writable profiles[merchantId].status
field.
Precedence (first match wins):
| Order | Input | Badge |
|---|---|---|
| 1 | termination.status === 'terminated' | Terminated |
| 2 | finmatchApproval.status === 'suspended' | Suspended |
| 3 | billing.status is not active | Suspended |
| 4 | FinMatch approval is not approved | Pending |
| 5 | No lender with lenderApprovals[*].status === 'approved' | Pending |
| 6 | liveToggle.enabled === true | Live |
| 7 | otherwise | Approved |
A new merchant created from Add Merchant with no Stripe customer has
inactive billing, so the table shows Suspended. After Link,
merchant-api copies billing from the live Stripe subscription
(active / trialing → billing active) so status is not stuck
Suspended waiting for a webhook. The badge then becomes Pending
until FinMatch and at least one lender are approved. Unlink still
marks billing inactive. Approved is eligible to go live; Live is
the live toggle.
Merchant status is separate from the SDK Features kill-switch.
The card subtitle is Controls commit immediately. Merchant status is
separate from the SDK Features kill-switch — changing status here does
not change sdkEnabled or take the merchant's integration offline.
ENFORCE_STATUS_SDK_GATING is off, so changing status does not set
sdkEnabled or take the integration offline. Use the App card
Features toggle for that.
The card’s Status inputs checklist is Billing active, FinMatch approved, Approved lenders, and Live toggle. The computed badge row is computed from inputs above. Status-input flags: SUSPENDED — overrides all other inputs when FinMatch is suspended, and Account terminated — overrides everything when the account is terminated. Controls are FinMatch approval, Lender approvals (or No lenders assigned to this merchant.; lender-row placeholder Suspend reason (optional)), Live (Merchant is eligible to go live. when it is), and Danger zone (Terminate account; placeholder Reason for termination (recommended); Terminating blocks this company from re-registering with the same details and overrides every other status.). A terminated merchant hides those controls and shows Termination plus Reinstate account. Terminated muted copy: This account is terminated, which overrides every other status. Re-signup with the same company details is blocked, and the FinMatch / lender / live controls are hidden until the account is reinstated.
Click-to-commit
These controls commit immediately. They do not use Edit
Merchant / Save Changes. They do not flip sdkEnabled.
While a write runs, the card shows Saving… and disables the
controls. Success: Saved. plus a toast. Failure: Update failed.
plus Failed to update merchant status: and the reason; the card
reloads from the server.
| Control | Confirm first? | What the write does | Success toast |
|---|---|---|---|
| FinMatch Approve | No | PUT …/finmatch-approval with action approve | FinMatch approval granted. |
| FinMatch Suspend | Are you sure you want to suspend FinMatch approval for this merchant? | action suspend | FinMatch approval suspended — merchant is now suspended. |
| FinMatch Clear | Are you sure you want to clear FinMatch approval for this merchant? | action clear | FinMatch approval cleared. |
| Lender Approve | No | PUT …/lender-approval | Lender display name, then approved for this merchant. |
| Lender Suspend | No. Optional Suspend reason (optional) is sent only on suspend. | action suspend | Lender display name, then suspended for this merchant. |
| Lender Clear | Clear plus the lender display name, then approval for this merchant? | action clear | Lender display name, then approval cleared. |
| Live on | Set this merchant LIVE? This makes the merchant status "live". Cancel unticks the box. | PUT …/live enabled true | Merchant is now live. |
| Live off | No | enabled false | Live mode disabled — merchant returned to approved. |
| Terminate account | Prompt: type the company name exactly (or the merchant id if the card has no name). Mismatch toast: Company name did not match — termination cancelled. This is not Delete Merchant’s Type delete to confirm. | PUT …/termination action terminate plus optional reason | Merchant account terminated. The same company details are now blocked from re-registering. |
| Reinstate account | Reinstate this terminated merchant? Re-signup with the same company details will be allowed again. | action reinstate | Merchant account reinstated. |
Live stays disabled when the merchant is not eligible. Hover: Not eligible: plus blockers (Billing inactive, FinMatch not approved, FinMatch suspended, No approved lender, Account terminated). Enabling then failing the server check toasts Merchant is not eligible to go live yet. Resolve the blockers listed below and try again.
Terminate hides FinMatch / lender / live controls until reinstate. Delete Merchant (header) removes the profile, router row, and CORS hosts. Terminate keeps the merchant and blocks re-signup with the same company details. See Deleting a Merchant.
Environment and integrity
Top of the App card. The Environment badge is Production (p),
Staging (s), or Test (t) from the merchant profile / router. Changing
it in Edit Merchant regenerates the Header snippet
for that path. Do not switch a live merchant to Test to try a config
change — use Sandbox preview.
Check env reloads the router, runs Check snippet, then refreshes Environment integrity. Check env title: Validate merchant environment against router and snippet detection.
| Badge | Meaning |
|---|---|
| PASS | Profile env, router env, and detected snippet env agree. |
| WARN | Notes only (for example snippet env unavailable, or a router-managed /s SDK whose env comes from the router not the snippet path). |
| FAIL | Missing router row, or profile / router / detected snippet env disagree. |
Sandbox preview
On the App card, under Environment. Forks this merchant’s config onto
Test for preview links while live shoppers stay on Production. App
environment must stay p. Turn on sandbox, Open preview,
View changes, Promote to production, Discard changes, and
Turn off sandbox live on this row. Idle Loading…. Other row
states: Off, On, On (paused), Status unavailable. The
grid is Your admin edits save to, Preview link loads
(Production build / Test build), and Sandbox contents
(Matches production when the draft has not drifted). The bottom
dock has Merchant configuration, FinMatch app, and Open
preview. Click confirms, paused Open preview, and promote vs
discard: Sandbox preview.
Do not switch Environment to Test to try a config change. Full runbook: Sandbox preview.
Header snippet
The copy-paste <script> tag for this merchant’s current App
environment. Paste it in the site <head>. The envelope button on the
row opens Send Header Snippet Email (Template, To, Subject, Message).
Envelope title: Share header snippet by email. The code row copy
button is Copy code.
Changing Environment in Edit Merchant regenerates it.
Format, env paths, and the email modal: Merchant Snippet Integration.
Detected snippet
Detected snippet appears on the App card only when Snippet status is Snippet found and the scanned script path is for a different environment than the App badge. It shows the script tag the scan found. If it matches Header snippet, the row stays hidden.
Use this with Environment integrity when a merchant still has a Test or Staging snippet on a Production-routed shop.
Finance Assistant Proxy URL
The App card shows the Cloudflare Worker URL the storefront uses to reach Finance Assistant. Grey text is the platform default. Orange text is a custom override.
- Override (or Edit Override) reveals an input. Type the URL,
then click Save features on the same card. That PATCH also writes
financeAssistantProxyUrl. - Reset immediately restores the default (does not wait for Save features).
This is not Finance Assistant Settings (the Features cog). Credentials stay on that settings view.
Features
On the App card, Features is the per-merchant storefront control. Save features commits this block. It does not use Edit Merchant / Save Changes.
SDK kill-switch
The toggle next to the Features label is sdkEnabled. It defaults on
unless the profile stored false.
When off:
- The five feature tiles hide.
- The storefront SDK is disabled for this merchant.
- Disabled, Learn more. expands optional reasons (team notes, not a lock). Lead copy: Record why features are off (optional — for your team's reference). Reasons: No active Stripe billing, No snippet active on merchant site, Merchant appears to have switched to a non-supported lender.
- A Suggested tag appears on a reason when billing is not active or snippet status is not Snippet found. Tick the box if you want it stored.
Turning the toggle back on shows the tiles again. Click Save features either way. Merchant Status does not flip this switch.
Feature tiles
When the kill-switch is on, five tiles appear. If the Lender card has no lenders, the matrix says No lenders configured. Advisory: Assign lenders and add credit products from the Lender card before enabling features.
Each tile has a master toggle. When a tile is on: a lender matrix, + Add lender, a remove ×, and a Settings cog (hover title Settings). The cog is visible only while that tile is on. When every assigned merchant lender is already on that tile, the picker shows All lenders assigned.
| Tile | Lender columns | Settings cog | Tile description |
|---|---|---|---|
| Pay monthly message | On | Pay monthly settings (styling tiers) | Add a finance quote with "Learn more" link next to your prices. |
| Finance offer summary | Embed, Badge | Finance offer summary settings (template mode, Quick-Start badge) | Embed a finance summary with "Learn more" link, or float a Quick-Start badge on every page. |
| E-Commerce modal | Popup, Embed | Ecommerce modal settings | Pop up or embeddable finance information designed to drive customers to a checkout. |
| Calculator | Popup, Embed | Calculator editor | Pop up or embeddable finance calculator. |
| Finance Assistant | On | Finance Assistant settings (credentials). Envelope icon opens the Enquiries tab. | Enables customers to initiate a credit application. |
Inline advisories on the tiles:
- Finance Assistant: Requires Calculator in popup or embed mode with at least one lender assigned.
- Calculator popup: Popup mode is launched from Pay monthly message "Learn more" links.
- E-Commerce modal popup: Popup mode is launched from Pay monthly message or Finance offer summary "Learn more" links.
- E-Commerce modal embed: Embed mode requires a snippet on the merchant site wherever the modal should appear.
- Calculator embed: Embed mode requires a snippet on the merchant site wherever the calculator should appear.
- Finance offer summary embed: Requires a <div id="finance_offer_summary"> mount point on the merchant site.
- E-Commerce modal mount: Requires mount divs on the merchant site — one per embedded lender with that lender's …-modal-container id and embed-…-modal class (copy from E-commerce Modal settings).
- Calculator mount: Requires mount divs on the merchant site — one per embedded lender with that lender's …-calc-container id and embed-…-calculator class (copy from Calculator settings).
Embed columns also show copyable mount snippets for the merchant site.
Price mark (Pay monthly tile). Lead copy: Add a price mark so FinMatch knows which prices should show finance marketing. Ask your website manager to add it in the theme — ideally on product prices and cart totals. Mark the price the customer pays (the sale price when discounted), not a “was” / compare-at price.
Copy actions: Copy static price mark demo, Copy Shopify price mark example. Labels: Static price (demo), Example in a theme template. Shopify Dawn example — open the price snippet and add the teal line to the sellable price element. Steps (Where to edit in Shopify): Online Store, Themes → Edit code, Snippets, price.liquid. Legend: FinMatch addition. Other platforms: same idea — put data-finmatch-price on the sellable / sale price in your product and cart templates.
Embed mount table: Embed code, Copy embed code, Copy finance
offer summary embed code, Copy all embed codes. FOS helper: Add
one mount div on the merchant site for the finance offer summary, with
class="finance-message".
Saving Features
Save features stays disabled until something changes. It writes
runtime financeFeaturesVisibility (PUT /admin/merchant-config/:id)
and the profile sdkEnabled / sdkDisabledReasons /
financeAssistantProxyUrl (PATCH /api/merchants/:id). Status text:
Saved to runtime config + merchant profile.
Pages with embed snippets
Read-only table on the App card. It reports pages the snippet
snapshot found with calculator or modal embed codes
(snippetStatus.pagesWithEmbedSnippets). It is not a Features
control.
Empty copy: None detected. Run "Check snippet" to scan for embed codes. After a scan, columns are Page (URL) then one column per detected lender (hover title Calculator / Modal) with Calc ✓ and/or Modal ✓.
Refresh with Check snippet. Check snippet title: Re-check this merchant now and update the shared snapshot. Toast Checking snippet..., then Snippet check updated. or Failed to check snippet. The write updates today’s shared snapshot plus this merchant’s badge, details, and Pages with embed snippets. The App card shows Snippet checked at next to that control. The plus toggle title is Show snippet details. Expanded title: Hide snippet details. Badge meanings: Snippet status. How the snapshot is built: Snippet snapshot.
Contact cards
Overview has two cards titled Contact. Type is read-only: Primary Contact on the first card, Technical on the second. Neither Type row becomes an input.
Empty First Name, Last Name, Email, and Phone show N/A. Admin → Contacts is a stub; these cards are the live edit path. See Contacts.
Save / commit
- Click Edit Merchant in the page header. Toast: Edit mode enabled. Click "Save Changes" when done. The header button becomes Save Changes and Cancel appears.
- Both Contact cards swap First Name, Last Name, Email, and Phone into inputs. Display N/A becomes an empty input. Email uses an email input; Phone uses a tel input. There are no placeholders on these fields.
- Click Save Changes. The header button shows Saving... and is disabled until the request finishes. A second click while Saving... is ignored.
- Save writes the Contacts API first (create, update, or delete per
card), then
PUTs the merchant profile withcontactIdsonly. The profilecontactsobject is cleared on that write. PII is not stored inmerchants.json. - Success toast: Merchant updated successfully! Edit mode exits. The cards reload from the Contacts API. Still-empty fields show N/A again.
Cancel discards the draft and restores the last loaded values (including N/A).
What Save does per card
Trimmed values. If any of First Name, Last Name,
Email, or Phone is non-empty, that card’s record is created
(no contactIds yet) or updated (primary / technical). If all
four are empty and a contact id existed, that record is deleted and
the matching contactIds slot is cleared.
No admin toast requires email or phone. Contacts-api create only requires the merchant id. The save-conflict popup does not list contact fields.
Contact write failures surface as the API message, or Failed to
update merchant. Please try again. Cross-merchant guards still
apply: Save blocked: you started editing … but are now viewing …
and Save blocked: edit started on … but detail view now shows ….
Missing draft: Required form fields not found. Please refresh and
try again.
Inline Editing
Enabling Edit Mode
- Navigate to the merchant page
- Click "Edit Merchant" in the page header (next to Delete Merchant)
- Fields on the Merchant card and both Contact cards become editable
- Button changes to "Save Changes"
- A "Cancel" button appears
- Toast: Edit mode enabled. Click "Save Changes" when done.
Editing Fields
When in edit mode, the following fields become editable:
- Company Name - Text input
- Domain - URL input (automatically adds
https://if missing) - Company Number - Text input (optional)
- Contact First Name, Last Name, Email, Phone on both Contact cards (see Contact cards)
Note: Merchant ID can be edited. Changes are validated and processed via the merchant ID change flow.
Saving Changes
- Make your edits
- Click "Save Changes" (the button shows Saving... while the request runs)
- Contact cards sync through the Contacts API, then the merchant profile is saved
- Page refreshes with updated data
- Edit mode exits automatically
- Success toast: Merchant updated successfully!
Canceling Edits
- Click "Cancel" button
- All changes are discarded
- Page reverts to read-only view
- Original data is restored
Stripe Billing Management
Link/Unlink Button
The Stripe Billing card has a Link/Unlink button in the header:
- "Link" - Shows when no Stripe customer is linked
- "Unlink" - Shows when a Stripe customer is already linked (green background)
Linking a Stripe Customer
- Click "Link" on the Stripe Billing card header (or, on the James-only Settings preview, FinMatch Account → Stripe first row Link)
- Link Stripe Customer opens showing the live Stripe customer list
- Search by Customer ID, Name, or Email (also Subscription ID; the
placeholder is still Search by Customer ID, Name, or Email...).
Ltd and LIMITED are the same legal name, so
ACCESS TRAINING (WALES) LIMITEDprefills and matchesAccess Training (Wales) Ltd. A unique match sorts to the top. Confirm in the picker. Do not auto-link. - View customer details:
- Customer ID
- Name
- Subscription Plan
- Current FinMatch Merchant (if linked)
- Click "Link" button next to desired customer
- Connection is saved. Billing hydrates from the live Stripe
subscription (
active/trialing→ billing active) - Page refreshes showing linked customer
Unlinking a Stripe Customer
- Click "Unlink" on the Stripe Billing card header (or James-only FinMatch Account → Stripe first row Unlink)
- Confirm the action
- Connection is removed. Billing is marked inactive.
- Page refreshes showing "Not linked" status
Universal Card Editing Layer
The merchant page uses a universal editing layer that can be extended to other cards:
Current Support
- ✅ Merchant card - Full inline editing
- ✅ Stripe Billing card - Link/Unlink functionality
- ✅ Contact cards - Inline editing (saved through Contacts API sync)
- ✅ Lender card - Names and credit products (derived profile mirror; not a setup wizard)
- ✅ App card - Environment integrity (Check env), snippet checks, sandbox preview, Finance Assistant Proxy URL, Features (Save features, not Edit Merchant), Pages with embed snippets (read-only)
- There is no Lender setup card. Do not document one.
Other Overview cards use the same inline editor when they have editable fields.
Navigation
Left nav on merchant detail is the same shell as the rest of admin
(admin/js/nav-builder.js). Live paths sit at the root of
admin.finmatch.io (for example /merchants/?id=…, not
/admin/merchants/). See
Admin URLs and
Live admin navigation.
Breadcrumb
The breadcrumb shows:
- Merchants →
{Merchant Name}
Clicking "Merchants" returns to the merchants table.
Calculator preview layout bands
On merchant calculator / modal preview, the width notice summary titles are Too narrow, Compact layout, Standard layout, and Maximum width. Hints: Below the Compact floor (feature under 304px)., Includes a breakpoint at 349px feature (381px merchant column and below)., Normal spacing and typography., The end of the standard range. Stops include Too narrow and Standard. Details table: Preview width details. Compact is one layout with two columns, not two named breakpoints. Below floor copy: Feature is Npx — Compact starts at 304px.
| Breakpoint | Merchant column | Finance feature width | Feature content padding | Default field font size |
|---|---|---|---|---|
| Comfortable | 382–451px | 350–419px | 15px | 14px |
| Tight | 336–381px | 304–349px | 10px | 12px |
The width notice table highlights the active column. Changing App → Environment is not how you preview a layout — use Sandbox preview for config forks.
API Integration
Update Merchant
Endpoint: PUT /api/merchants/{merchantId}
Request Body:
{
"merchantName": "Updated Company Name",
"companyName": "Updated Company Name",
"domain": "https://updated-domain.com",
"companyNo": "12345678"
}
Response: Updated merchant object
Link Stripe Customer
Endpoint: PUT /api/merchants/{merchantId}/stripe-connection
Request Body:
{
"stripeCustomerId": "cus_xxxxx"
}
Response: Updated merchant object with Stripe connection
Unlink Stripe Customer
Endpoint: DELETE /api/merchants/{merchantId}/stripe-connection
Response: Updated merchant object without Stripe connection
Best Practices
- Always Save: Click "Save Changes" after editing, or "Cancel" to discard
- Validate Domain: Domain is automatically normalized (adds
https://if missing) - Check Stripe Status: Verify Stripe customer is correctly linked before saving
- Use Search: Use search in Stripe linking modal to find customers quickly
- Review Changes: Page refreshes after save - verify changes are correct
Troubleshooting
If the URL shows one FinMatch ID (e.g. ?id=M524059) and the title matches that merchant, but contacts, lenders, header snippet, features matrix, or Admin tab actions (History, JSON, Quote) appear to belong to another merchant, treat this as a client-side state bug, not corrupt merchants.json.
Why it happened (historical): showMerchantDetails performs async work (contacts API, lender config). Overlapping calls could leave window.currentMerchantDetails, window.currentMerchantSourceConfig, or parts of the DOM out of sync with the visible URL. Saves could then hit the wrong merchant ID (e.g. spurious “Merchant with ID … already exists”). Navigation without re-showing the previous merchant and sequence guards on detail render reduce this.
Admin tab / sub-pages: Actions that open History, JSON, Quote, or Finance Assistant settings now resolve the merchant from ?id= first, then fall back to window.currentMerchantDetails, so they stay aligned with the address bar even if the global lags briefly.
If it still looks wrong after a hard refresh: Verify data (e.g. GET /api/merchants/{id} and contact IDs) — wrong contactIds can legitimately point another merchant’s contact row.
Operational workaround: Hard refresh the page (Cmd+Shift+R / Ctrl+Shift+R) or navigate away and open the merchant again from the table.
Edit Mode Not Working
Check:
- Merchant page is loaded (
window.currentMerchantDetailsexists) - JavaScript console for errors
- Network tab for API call failures
Stripe Link Not Working
Check:
- Stripe customers are loaded (
stripeCustomersarray exists) - API endpoint is accessible
- Merchant ID is correct
Navigation Links Broken
Check:
- URL is the query form (
/merchants/?id=M000101on production) nav-builder.jsis loaded- Navigation uses
getAdminBasePath()/getMerchantsAppBase(), not a hardcoded/admin/prefix
Related Documentation
- Editing Merchants - Field validation and what Save Changes writes
- Merchant Snippet Integration - Snippet code details
- Snippet status - Badge meanings and Check snippet
- Calculator editor - Calculator Settings from the Features cog
- Developer Field Mapping - Backend field mapping