Skip to content

Quoting in the buyer's currency

Read time: 4 minutes. Who it's for: Merchants selling into multiple Shopify Markets and quoting in the buyer's local currency.

QuotWay locks the FX rate at quote-intake time. Once a quote is in flight, the buyer sees stable prices regardless of how the FX rate moves before they accept. Internal analytics stay comparable in your base currency.


The basic flow

  1. Buyer browses your storefront in their local market (e.g., France, EUR).
  2. Buyer requests a quote on a product. QuotWay queries Shopify's ProductVariant.contextualPricing(context: { country }) to get the EUR-priced variant.
  3. Quote intake records:
    • Quote.currency = "EUR" (the presentment currency).
    • Quote.exchangeRateSnapshot = 0.91 (the EUR-per-USD rate captured from Shopify at intake).
    • Shop.baseCurrency = "USD" (your store's base currency).
  4. Proposal editor in the admin shows EUR prices to you (the merchant). Analytics dashboards aggregate in USD using the captured snapshot.
  5. Buyer accepts. The accepted prices are EUR. Shopify draft order converts at the recorded rate.

What you (the merchant) see

Every quote in the inbox shows both currencies side by side:

EUR 1,000.00 (≈ USD 1,088.42)

The presentment amount is the source of truth. The USD equivalent is informational - it uses the snapshot stored at quote intake, so it doesn't drift with the live FX rate.

If the quote is in your base currency (USD here), the dual display collapses to just USD 1,000.00.

Where the rate comes from

QuotWay reads the rate from Shopify itself, not from a third-party FX provider. Specifically, the ProductVariant.contextualPricing GraphQL query in the Storefront API returns the presentment-currency price for a buyer in a given country. QuotWay derives the rate as (presentmentPrice / baseCurrencyPrice) for the same product.

Why this matters:

  • The rate you quote matches the rate Shopify checkout will use.
  • No drift between your quote price and the eventual draft order / Shopify order price.
  • You don't pay for a third-party FX feed.

If the contextualPricing query fails (network blip, Shopify outage, unsupported country), QuotWay sets exchangeRateSnapshot = null and treats the quote as base-currency - no false-confidence rate captured. The merchant sees a "Currency conversion unavailable - quoting in USD" banner.

Analytics in base currency

Dashboard KPIs (open pipeline, accepted this month, conversion rate) aggregate in base currency. The code path:

  • For each quote, prefer Quote.baseCurrencyTotal (computed at-intake or at-version-update using the snapshot).
  • Fall back to Quote.totalEstimate when the snapshot is null (same-currency quote).

This lets you sum quotes from EUR + GBP + CAD merchants in one USD-anchored number.

What buyers see

In the storefront drawer, all prices show in the buyer's presentment currency. On the proposal, in the portal, and on PDFs - same. The buyer never sees a USD equivalent unless the merchant explicitly types it into the message field.

For accepted quotes, the Shopify draft order is created in the presentment currency. Shopify Checkout collects payment in the same currency.

Limitations + Phase 2 items

  • Locked-at-intake. The rate doesn't update on negotiation rounds. If the rate moves significantly between rounds, the merchant may see a stale equivalent. The quote total (in presentment currency) is unaffected.
  • No FX hedging tools. QuotWay doesn't let you set a "lock this rate for 30 days" policy. The rate is whatever Shopify surfaced at intake time.
  • Same currency for the whole quote. Line items can't have different currencies. All-EUR or all-USD or all-GBP.

Phase 2 may add: per-round rate refresh, materialized aggregate views for cross-currency reporting, and merchant-configurable rate-staleness alerts.

Markets without a configured currency

If a buyer reaches your storefront in a market that doesn't have a defined presentment currency (e.g., your Shopify Markets configuration only has US + EU), the storefront defaults to your base currency. The quote intake records exchangeRateSnapshot = null and the dual-currency display collapses to single-currency.


Common gotchas

  • "Currency conversion unavailable" banner appears. Means the intake-time contextualPricing query returned an error. Re-check your Markets configuration; verify the variant has a presentment price in the buyer's currency.
  • Inbox totals look small. Currencies have different magnitudes. JPY at ¥150,000 ≈ USD $1,000. If you sort the inbox by totalEstimate, you'll see mixed magnitudes. Sort by baseCurrencyTotal instead for an apples-to-apples sort.
  • Buyer reports a different price than what the proposal said. Check whether the snapshot was captured (quote.exchangeRateSnapshot). If it's null, the proposal may have used the live rate at view time which differs from intake time. Recreate the quote.

Related articles

Still need a hand? The team is happy to help.