Skip to main content

Overview

Geography is central to how Spree handles checkout, pricing, taxes, and shipping. The system works through a chain of related concepts:
Markets → Countries → Zones → Tax Rates & Shipping Methods
                  ↘ States
                  ↘ Addresses
  • Markets group countries into selling regions with their own currency and locale
  • Countries and States provide the geographic data for addresses
  • Zones group countries or states together to define where tax rates and shipping methods apply
  • Addresses tie a customer to a specific location, determining which zones — and therefore which taxes and shipping options — apply to their order

Addresses

An address represents a shipping or billing location. Every order has a shipping address and a billing address, and customers can save multiple addresses in their address book.
FieldDescription
firstname, lastnameContact name
address1, address2Street address
cityCity
zipcodePostal code (not required for all countries)
phonePhone number
companyCompany name (optional)
labelUser-facing label like “Home” or “Office” (optional, unique per customer)
country_isoCountry (ISO alpha-2 code, e.g., US)
state_abbrState/province abbreviation (required for some countries, e.g., CA)
Whether a state or zipcode is required depends on the country. For example, the US requires both, while Hong Kong requires neither. The API returns states_required and zipcode_required on each country so your frontend can adapt the form dynamically.

Customer Address Book

Customers can save multiple addresses and set a default for shipping and billing. When a customer completes checkout, the selected addresses are cloned onto the order — so editing an address later doesn’t change past orders.
// List addresses
const { data: addresses } = await client.customer.addresses.list()

// Create an address
const address = await client.customer.addresses.create({
  firstname: 'John',
  lastname: 'Doe',
  address1: '123 Main St',
  city: 'Los Angeles',
  country_iso: 'US',
  state_abbr: 'CA',
  zipcode: '90001',
  phone: '555-0100',
})

// Update an address
await client.customer.addresses.update('addr_xxx', { city: 'Brooklyn' })

// Delete an address
await client.customer.addresses.delete('addr_xxx')

// Set as default shipping or billing address
await client.customer.addresses.markAsDefault('addr_xxx', 'shipping')

Checkout Addresses

During checkout, you can either reference a saved address by ID or pass a new address inline:
// Use saved addresses
await client.orders.update(orderId, {
  ship_address_id: 'addr_xxx',
  bill_address_id: 'addr_yyy',
})

// Or pass new addresses inline
await client.orders.update(orderId, {
  ship_address: {
    firstname: 'John',
    lastname: 'Doe',
    address1: '123 Main St',
    city: 'Los Angeles',
    country_iso: 'US',
    state_abbr: 'CA',
    zipcode: '90001',
    phone: '555-0100',
  },
})

Countries

Countries are the foundation of Spree’s geographic system. They connect to Markets, contain states, and belong to zones. Each country includes metadata that drives address form behavior:
FieldDescriptionExample
isoISO 3166-1 alpha-2 codeUS
iso3ISO 3166-1 alpha-3 codeUSA
nameCountry nameUnited States
states_requiredWhether the address form should show a state/province pickertrue
zipcode_requiredWhether the address form should require a postal codetrue

Which Countries Are Available?

Only countries assigned to a Market are available during checkout. This lets you control exactly where you sell.
// List all countries available in this store
const { data: countries } = await client.countries.list()

// Get a country with its states (for address form dropdowns)
const usa = await client.countries.get('US', { include: 'states' })
// usa.states => [{ name: "Alabama", abbr: "AL" }, { name: "Alaska", abbr: "AK" }, ...]

// Get a country with its market (for currency/locale resolution)
const germany = await client.countries.get('DE', { include: 'market' })
// germany.market => { currency: "EUR", default_locale: "de", tax_inclusive: true }
Use the states_required and zipcode_required fields to build adaptive address forms — show a state picker only when needed, and skip the zipcode field for countries that don’t use them.

States

States (provinces, regions) belong to a country and are used for address validation and zone matching. Countries like the US, Canada, Australia, and India have predefined states — for these countries, customers must select a state from the list rather than typing a name. States are fetched via the country endpoint using ?include=states:
const usa = await client.countries.get('US', { include: 'states' })

// Build a state picker from the response
usa.states.forEach(state => {
  console.log(state.abbr, state.name) // "AL", "Alabama"
})
For countries without predefined states, addresses accept a free-text state_name field instead of state_abbr.

Zones

Zones group countries or states together for tax and shipping rules. A zone is either country-based or state-based. Examples:
  • EU VAT (country zone) — Germany, France, Italy, Spain, … → applies EU VAT rates
  • California (state zone) — CA → applies California sales tax
  • Domestic Shipping (country zone) — US, CA → enables domestic shipping methods
When a customer enters their address at checkout, Spree matches it against zones to determine:
  1. Which tax rates apply (see Taxes)
  2. Which shipping methods are available (see Shipments)
Zones are configured in the admin dashboard — storefront developers don’t interact with them directly via the API.

Tax Zones and Markets

Each Market resolves a tax zone from its default country. This means product prices display the correct tax treatment (inclusive or exclusive) before the customer enters an address — just from knowing their market.

How It All Fits Together

Here’s how geography flows through a typical checkout:
  1. Customer visits the store — their country is detected (from URL, geolocation, or selection)
  2. Market resolved — the country maps to a market, which sets the currency and locale
  3. Products displayed — prices use the market’s currency and tax zone for correct formatting
  4. Customer enters address — the address form adapts based on states_required and zipcode_required
  5. Zones matched — the shipping address determines which tax rates and shipping methods apply
  6. Order completed — the address is cloned onto the order for permanent record
  • Markets — Multi-region commerce with currency, locale, and country grouping
  • Taxes — How zones and addresses affect taxation
  • Shipments — How zones and addresses affect shipping availability
  • Orders — Order billing and shipping addresses