Skip to content
New Webhooks added: Inventory and Order modifications. Check the changelog →
Cartly Developers

Markets: Country-Specific Storefronts

Run one shop, sell in many countries. Per-market currency, language, duty mode, and tax treatment. Primary Market guarantee enforced at three layers.

Overview

Markets group countries that share a currency and language. Cartly routes visitors to the matching market via GeoIP and serves market-specific prices and translated content. Every shop has exactly one Primary Market as a fallback.

Primary Market Guarantee

Enforced at three layers: DB partial unique index, Ent mutation hooks, and service-layer atomic PromoteToPrimary transaction. Cannot be deleted or deactivated. Its default_locale drives the platform translation source language.

Admin API

  • POST /admin/markets — create (name, countries[], base_currency, default_locale, available_locales[], tax_inclusive, duty_mode, active)
  • PUT /admin/markets/:id — update
  • DELETE /admin/markets/:id — non-primary only
  • POST /admin/markets/:id/promote — atomic promote-to-primary
  • PUT /admin/markets/:id/prices — bulk per-variant price overrides
  • POST /admin/markets/:id/exclusions — exclude product from market

Localization Liquid Context

localization.language, localization.market, localization.available_languages — populated by internal/storefront/storefront_context.go buildLocalizationContext. Endonym names (русский, Deutsch, ქართული) come from internal/markets/endonym.go.

Orphan Locale Handling

When cartly_locale cookie references an inactive locale, the storefront clears it via Set-Cookie: cartly_locale=; Max-Age=0 and falls back to default_locale.

Tax & Duty Modes

tax_inclusive: true = VAT-style (tax extracted from displayed price), false = sales-tax-style (tax added at checkout). duty_mode: DDP = merchant pays duties, DDU = buyer pays.

Full guide → | Cross-Border Markets API →