L1 loader pattern. Each L1 domain (eCommerce, Stores, Get-paid, Contacts, …) owns its own context loader. This file is the eCommerce L1 loader. Other L1s have their own (e.g. stores-load-context.md will detect Catalog V1/V3 for Stores categories). The boilerplate (Step 1 + 2) is small; the field list and runtime detections differ by L1.
When to run. Called from the dispatch block of any eCommerce category's default.md (Tax, Pricing & promotions, …) before tag-matching. Run once per session. If siteData.country is already in your conversation context, skip the API calls below and return immediately — every subsequent eCommerce category entry reuses the loaded data.
This is the canonical extract of Steps 1 + 3 from today's recommend-ecommerce-strategy.md, scoped to the fields eCommerce categories actually need.
If a siteId is not already known, call ListWixSites:
Do not proceed without a siteId.
Same call today's recommend-ecommerce-strategy.md Step 3 makes. The field list below is the eCommerce subset — orchestrator-needed metrics (visitors / orders / GPV → AOV) plus locale/currency/industry used for dispatch tags and recommendations.
Extract each field into conversation context as siteData:
| Field in response | Maps to | Notes |
|---|---|---|
fields.language.aSingleValue.aString | siteData.language | Locale code (e.g. en-US) |
fields.merchant_business_country.aSingleValue.aString | siteData.country | ISO-3166-1 alpha-2 |
fields.suggested_main_industry.aSingleValue.aString | siteData.industry | Used by Pricing orchestrator's goal classification |
fields.suggested_sub_industry.aSingleValue.aString | siteData.subIndustry | Optional |
fields.last_30_days_distinct_visitors.aSingleValue.aLong | siteData.visitors30d | Returned as JSON string — parseInt before arithmetic |
fields.last_30_days_orders_count.aSingleValue.aLong | siteData.orders30d | parseInt |
fields.online_gpv_last_30_days.aSingleValue.aLong | siteData.gpv30d | parseInt |
fields.payment_currency.aSingleValue.aString | siteData.currency | ISO-4217 |
Missing fields ⇒ no data for that field (don't fabricate). If merchant_business_country, suggested_main_industry, or online_gpv_last_30_days are missing or null, surface to the merchant: "Cannot resolve required site data:
Derived value: siteData.aov = parseInt(gpv30d) / parseInt(orders30d) — in siteData.currency units.
Call GetCatalogAnalytics once here so all downstream pricing/promotions flows can reference siteData.catalogAnalytics without re-fetching.
Save the full categoryGroups array as siteData.catalogAnalytics. From the "All Products" group extract:
siteData.catalogProductCount = count() value (0 if missing or call fails)siteData.hasCatalog = siteData.catalogProductCount > 0If the call fails, set siteData.hasCatalog = true (assume catalog exists; let downstream fail naturally).
This data is used by all pricing & promotions discount flows. Flows that require a product catalog (Bundle & Save, Upsell Boost, Stock Mover, Seasonal) MUST check siteData.hasCatalog before proceeding — if false, stop with: "This site has no products. Set up your product catalog first before running promotions."
From siteData.country, set siteData.region:
BR | AR | MX | CL | CO | PE → LATAMDE | FR | IT | ES | NL | BE | PL | SE | IE | AT | PT | FI | DK | CZ | HU | GR | RO | BG | HR | SK | SI | LT | LV | EE | CY | MT | LU) → EUJP | CN | KR | SG | AU | NZ | IN | TH | ID | MY | PH | VN | HK | TW → APACnull(UK is not in region:EU. AU/NZ are in region:APAC but Tax inclusive-pricing rules differ — handled inside Tax promotions.)
Return immediately. Subsequent eCommerce category dispatches read siteData.* from conversation context without re-fetching. If the agent crosses into a different L1 (e.g. Stores) within the same session, that L1's loader will see siteData.country already loaded, skip its Steps 1-3, and only fire its own general derivations.
This file must contain only general / cross-cutting site data — fields that every category in this L1 needs. It must not include L3-category-specific runtime detection (e.g. Tax calculator, Catalog V1/V3, payment-provider state, shipping-coverage state).
Reasoning:
exposure: INTERNAL); if the L1 loader depends on them, the entire L1 fails to load. Keeping the loader general-only contains the blast radius.Where category-specific runtime data is detected instead: inside the category's default.md (Step before dispatch) or inside the specific promotion that needs it. The L1 loader does not prime per-category fields; the category does its own detection lazily, only when its own intent dispatch fires.
Concretely for the categories we know about:
ecom-tax.md (the merged category-doc + dispatcher) or in each Tax promotion when it runs. Not here.getCatalogAnalytics (product count/margin/price) is already loaded here as a cross-cutting concern; V1/V3 detection is a separate, Stores-specific signal.finance-and-payments/get-paid-finance-default.md.getCatalogAnalytics (product count, margin, price distribution) IS loaded here as a cross-cutting concern; Catalog V1/V3 version detection is separate and belongs in the Stores category's own loader.default.md is what scores tags and picks a promotion — this file only fills general site context.When a new L1 domain is migrated to the routing tree, author a <l1>-load-context.md at its root:
references/stores/stores-load-context.md — Stores L1 loader. Steps 1-3 same boilerplate, Step 4 runtime-detects Catalog version (V1/V3) and any other Stores-specific fields.references/get-paid/get-paid-load-context.md — Get-paid L1 loader. Step 4 inspects payment provider state, enabled methods.references/contacts/contacts-load-context.md — Contacts L1 loader. Possibly minimal — most CRM ops don't need runtime detection.Each lives sibling to its L1's category-docs. Each is referenced from every category's default.md within its L1. Skip-if-loaded check across L1s makes cross-L1 sessions cost-free.
Last updated: 25 June 2026