@spree/docs 0.1.182 → 0.1.183

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/developer/core-concepts/addresses.md +106 -198
  2. package/dist/developer/core-concepts/architecture.md +97 -126
  3. package/dist/developer/core-concepts/calculators.md +75 -252
  4. package/dist/developer/core-concepts/carts.md +1 -1
  5. package/dist/developer/core-concepts/channels.md +0 -4
  6. package/dist/developer/core-concepts/companies-and-catalogs.md +1 -1
  7. package/dist/developer/core-concepts/customers.md +0 -3
  8. package/dist/developer/core-concepts/discounts.md +133 -0
  9. package/dist/developer/core-concepts/events.md +83 -576
  10. package/dist/developer/core-concepts/fees.md +144 -0
  11. package/dist/developer/core-concepts/imports-exports.md +105 -679
  12. package/dist/developer/core-concepts/inventory.md +114 -248
  13. package/dist/developer/core-concepts/markets.md +9 -12
  14. package/dist/developer/core-concepts/media.md +9 -11
  15. package/dist/developer/core-concepts/metafields.md +123 -200
  16. package/dist/developer/core-concepts/order-totals.md +110 -0
  17. package/dist/developer/core-concepts/orders.md +1 -1
  18. package/dist/developer/core-concepts/payments.md +11 -14
  19. package/dist/developer/core-concepts/pricing.md +11 -13
  20. package/dist/developer/core-concepts/products.md +35 -19
  21. package/dist/developer/core-concepts/promotions.md +12 -11
  22. package/dist/developer/core-concepts/search-filtering.md +2 -4
  23. package/dist/developer/core-concepts/store-credits-gift-cards.md +0 -3
  24. package/dist/developer/core-concepts/taxes.md +125 -113
  25. package/dist/developer/core-concepts/translations.md +61 -68
  26. package/dist/developer/core-concepts/webhooks.md +25 -59
  27. package/dist/developer/how-to/custom-promotion.md +3 -3
  28. package/package.json +1 -1
  29. package/dist/developer/core-concepts/taxes-discounts-fees.md +0 -199
@@ -1,281 +1,189 @@
1
1
  ---
2
2
  title: Addresses
3
- description: How Spree models addresses, countries, states, and zones, and how geographic data drives checkout, tax calculation, and shipping rates.
3
+ description: How Spree handles addresses, country and state data, and building address forms that adapt to the country a customer picks.
4
4
  ---
5
5
 
6
6
  ## Overview
7
7
 
8
- Geography is central to how Spree handles checkout, pricing, taxes, and shipping. The system works through a chain of related concepts:
9
-
10
- ```
11
- Markets → Countries → Zones → Tax Rates & Shipping Methods
12
- ↘ States
13
- ↘ Addresses
8
+ An address is where something goes or who gets billed. Every cart collects a shipping and a billing address, and signed-in customers can keep an address book.
9
+
10
+ Addresses matter beyond the label on a parcel: the shipping address decides which delivery options a customer sees and how much tax they pay.
11
+
12
+ ```mermaid
13
+ erDiagram
14
+ Customer ||--o{ Address : "address book"
15
+ Cart }o--|| Address : "shipping"
16
+ Cart }o--|| Address : "billing"
17
+ Order }o--|| Address : "shipping (copied)"
18
+ Order }o--|| Address : "billing (copied)"
19
+
20
+ Address {
21
+ string first_name
22
+ string last_name
23
+ string address1
24
+ string city
25
+ string postal_code
26
+ string country_code
27
+ string state_code
28
+ }
14
29
  ```
15
30
 
16
- - [**Markets**](markets.md) group countries into selling regions with their own currency and locale
17
- - **Countries** and **States** provide the geographic data for addresses
18
- - **Zones** group countries or states together to define where tax rates and shipping methods apply
19
- - **Addresses** tie a customer to a specific location, determining which zones — and therefore which taxes and shipping options — apply to their order
20
-
21
- ## Addresses
22
-
23
- 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.
31
+ ## Address fields
24
32
 
25
33
  | Field | Description |
26
- |-------|-------------|
34
+ |---|---|
27
35
  | `first_name`, `last_name` | Contact name |
28
36
  | `address1`, `address2` | Street address |
29
37
  | `city` | City |
30
- | `postal_code` | Postal code (not required for all countries) |
38
+ | `postal_code` | Postal code not used by every country |
31
39
  | `phone` | Phone number |
32
- | `company` | Company name (optional) |
33
- | `country_iso` | Country (ISO alpha-2 code, e.g., `US`) |
34
- | `state_abbr` | State/province abbreviation (required for some countries, e.g., `CA`) |
40
+ | `company` | Company name, optional |
41
+ | `country_code` | Country, as an ISO code such as `US` |
42
+ | `state_code` | State or province code such as `CA`, where the country has them |
43
+ | `state_name` | Free text, for countries with no official list |
44
+ | `label` | What the customer filed it under — "Home", "Office" |
45
+ | `is_default_shipping`, `is_default_billing` | Whether it is the default in the address book |
46
+
47
+ > **NOTE:** Countries and states are named by their **ISO codes** — `country_code: "US"`, `state_code: "CA"` — never by an ID. A code means the same thing everywhere, so you can send one without looking anything up first.
48
+ >
49
+ > The older names `country_iso` and `state_abbr` still work but are going away. Use `country_code` and `state_code` in new code.
35
50
 
36
- 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.
51
+ ## Address forms that adapt
37
52
 
38
- ### Customer Address Book
53
+ Address formats are not universal. The United States wants a state and a ZIP code; Hong Kong wants neither. A form that demands both everywhere will block real customers from checking out.
39
54
 
40
- 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.
55
+ Every country tells you what it needs:
56
+
57
+
58
+ ```typescript Store SDK
59
+ const { data: countries } = await client.countries.list()
60
+
61
+ // One country, with its states for a picker
62
+ const usa = await client.countries.get('US', { expand: ['states'] })
63
+
64
+ usa.states_required // true → show a state picker
65
+ usa.zipcode_required // true → require a postal code
66
+ usa.states // [{ abbr: "CA", name: "California" }, ...]
67
+ ```
68
+
69
+ ```bash cURL
70
+ curl 'https://api.mystore.com/api/v3/store/countries' \
71
+ -H 'X-Spree-API-Key: pk_xxx'
72
+
73
+ curl 'https://api.mystore.com/api/v3/store/countries/US?expand=states' \
74
+ -H 'X-Spree-API-Key: pk_xxx'
75
+ ```
76
+
77
+
78
+ Drive the form from those two flags rather than hardcoding a list of countries. When `states_required` is `false`, let the customer type a `state_name` instead of picking a `state_code`.
79
+
80
+ Only countries you actually sell to are listed — that's decided by your [Markets](markets.md).
81
+
82
+ ## The customer address book
83
+
84
+ A signed-in customer can save addresses and mark defaults, so checkout is one tap next time.
41
85
 
42
86
 
43
87
  ```typescript Store SDK
44
- // List addresses
45
88
  const { data: addresses } = await client.customer.addresses.list()
46
89
 
47
- // Create an address
48
90
  const address = await client.customer.addresses.create({
91
+ label: 'Home',
49
92
  first_name: 'John',
50
93
  last_name: 'Doe',
51
94
  address1: '123 Main St',
52
95
  city: 'Los Angeles',
53
- country_iso: 'US',
54
- state_abbr: 'CA',
96
+ country_code: 'US',
97
+ state_code: 'CA',
55
98
  postal_code: '90001',
56
99
  phone: '555-0100',
100
+ is_default_shipping: true,
57
101
  })
58
102
 
59
- // Update an address
60
- await client.customer.addresses.update('addr_xxx', { city: 'Brooklyn' })
61
-
62
- // Delete an address
63
- await client.customer.addresses.delete('addr_xxx')
64
-
65
- // Set as default shipping or billing address — pass the boolean flags to create or update
66
- await client.customer.addresses.update('addr_xxx', { is_default_shipping: true })
67
- await client.customer.addresses.update('addr_xxx', { is_default_billing: true })
103
+ await client.customer.addresses.update(address.id, { city: 'Brooklyn' })
104
+ await client.customer.addresses.delete(address.id)
68
105
  ```
69
106
 
70
107
  ```bash cURL
71
- # List addresses
72
- curl 'https://api.mystore.com/api/v3/store/customers/me/addresses' \
73
- -H 'X-Spree-API-Key: pk_xxx' \
74
- -H 'Authorization: Bearer <jwt_token>'
75
-
76
- # Create an address
77
108
  curl -X POST 'https://api.mystore.com/api/v3/store/customers/me/addresses' \
78
109
  -H 'X-Spree-API-Key: pk_xxx' \
79
- -H 'Authorization: Bearer <jwt_token>' \
110
+ -H 'Authorization: Bearer <customer_token>' \
80
111
  -H 'Content-Type: application/json' \
81
112
  -d '{
113
+ "label": "Home",
82
114
  "first_name": "John",
83
115
  "last_name": "Doe",
84
116
  "address1": "123 Main St",
85
117
  "city": "Los Angeles",
86
- "country_iso": "US",
87
- "state_abbr": "CA",
88
- "postal_code": "90001",
89
- "phone": "555-0100"
118
+ "country_code": "US",
119
+ "state_code": "CA",
120
+ "postal_code": "90001"
90
121
  }'
91
-
92
- # Update an address
93
- curl -X PATCH 'https://api.mystore.com/api/v3/store/customers/me/addresses/addr_xxx' \
94
- -H 'X-Spree-API-Key: pk_xxx' \
95
- -H 'Authorization: Bearer <jwt_token>' \
96
- -H 'Content-Type: application/json' \
97
- -d '{ "city": "Brooklyn" }'
98
-
99
- # Delete an address
100
- curl -X DELETE 'https://api.mystore.com/api/v3/store/customers/me/addresses/addr_xxx' \
101
- -H 'X-Spree-API-Key: pk_xxx' \
102
- -H 'Authorization: Bearer <jwt_token>'
103
122
  ```
104
123
 
105
124
 
106
- ### Checkout Addresses
107
-
108
- During checkout, you can either reference a saved address by ID or pass a new address inline. See the [cart and checkout SDK guide](../sdk/store/cart-checkout.md) for the full flow of passing addresses during checkout:
125
+ ## Addresses at checkout
109
126
 
127
+ On a cart you can point at a saved address or send a new one inline:
110
128
 
111
129
  ```typescript Store SDK
112
- // Use saved addresses
130
+ // Reuse something from the address book
113
131
  await client.carts.update(cartId, {
114
132
  shipping_address_id: 'addr_xxx',
115
133
  billing_address_id: 'addr_yyy',
116
134
  })
117
135
 
118
- // Or pass new addresses inline
136
+ // Or send one directly — nothing needs saving first
119
137
  await client.carts.update(cartId, {
138
+ email: 'john@example.com',
120
139
  shipping_address: {
121
140
  first_name: 'John',
122
141
  last_name: 'Doe',
123
142
  address1: '123 Main St',
124
143
  city: 'Los Angeles',
125
- country_iso: 'US',
126
- state_abbr: 'CA',
144
+ country_code: 'US',
145
+ state_code: 'CA',
127
146
  postal_code: '90001',
128
- phone: '555-0100',
129
147
  },
130
148
  })
131
149
  ```
132
150
 
133
- ```bash cURL
134
- # Use a saved address
135
- curl -X PATCH 'https://api.mystore.com/api/v3/store/carts/cart_xxx' \
136
- -H 'X-Spree-API-Key: pk_xxx' \
137
- -H 'X-Spree-Token: order_token' \
138
- -H 'Content-Type: application/json' \
139
- -d '{ "shipping_address_id": "addr_xxx", "billing_address_id": "addr_yyy" }'
140
-
141
- # Or pass a new address inline
142
- curl -X PATCH 'https://api.mystore.com/api/v3/store/carts/cart_xxx' \
143
- -H 'X-Spree-API-Key: pk_xxx' \
144
- -H 'X-Spree-Token: order_token' \
145
- -H 'Content-Type: application/json' \
146
- -d '{
147
- "shipping_address": {
148
- "first_name": "John",
149
- "last_name": "Doe",
150
- "address1": "123 Main St",
151
- "city": "Los Angeles",
152
- "country_iso": "US",
153
- "state_abbr": "CA",
154
- "postal_code": "90001",
155
- "phone": "555-0100"
156
- }
157
- }'
158
- ```
159
-
160
-
161
- ## Countries
162
-
163
- Countries are the foundation of Spree's geographic system. They connect to [Markets](markets.md), contain states, and belong to zones.
164
-
165
- Each country includes metadata that drives address form behavior:
151
+ Setting the shipping address is what makes delivery options and tax appear, so do it before asking the customer to choose delivery. The updated cart comes back with new totals — you don't need a second request.
166
152
 
167
- | Field | Description | Example |
168
- |-------|-------------|---------|
169
- | `iso` | ISO 3166-1 alpha-2 code | `US` |
170
- | `iso3` | ISO 3166-1 alpha-3 code | `USA` |
171
- | `name` | Country name | `United States` |
172
- | `states_required` | Whether the address form should show a state/province picker | `true` |
173
- | `zipcode_required` | Whether the address form should require a postal code | `true` |
153
+ > **WARNING:** An address is **copied onto the order** when the cart completes, not linked to. Editing a saved address next year does not rewrite last year's invoice — which is exactly what you want when a customer moves house.
174
154
 
175
- ### Which Countries Are Available?
155
+ ## Validating addresses
176
156
 
177
- Only countries assigned to a [Market](markets.md) are available during checkout. This lets you control exactly where you sell.
178
-
179
-
180
- ```typescript Store SDK
181
- // List all countries available in this store
182
- const { data: countries } = await client.countries.list()
183
-
184
- // Get a country with its states (for address form dropdowns)
185
- const usa = await client.countries.get('US', { expand: ['states'] })
186
- // usa.states => [{ name: "Alabama", abbr: "AL" }, { name: "Alaska", abbr: "AK" }, ...]
157
+ Spree checks that required fields are present and that the state and postal code make sense for the country. Anything it rejects comes back as a `422` naming the field, so you can put the message next to the input.
187
158
 
188
- // Get a country with its market (for currency/locale resolution)
189
- const germany = await client.countries.get('DE', { expand: ['market'] })
190
- // germany.market => { currency: "EUR", default_locale: "de", tax_inclusive: true }
191
- ```
192
-
193
- ```typescript Admin SDK
194
- const { data: countries } = await adminClient.countries.list()
195
-
196
- const usa = await adminClient.countries.get('US')
197
- ```
198
-
199
- ```bash cURL
200
- # List all countries
201
- curl 'https://api.mystore.com/api/v3/store/countries' \
202
- -H 'X-Spree-API-Key: pk_xxx'
203
-
204
- # Get a country with states
205
- curl 'https://api.mystore.com/api/v3/store/countries/US?expand=states' \
206
- -H 'X-Spree-API-Key: pk_xxx'
207
-
208
- # Get a country with its market
209
- curl 'https://api.mystore.com/api/v3/store/countries/DE?expand=market' \
210
- -H 'X-Spree-API-Key: pk_xxx'
211
- ```
212
-
213
-
214
- 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.
215
-
216
- ## States
217
-
218
- 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.
219
-
220
- States are fetched via the country endpoint using [`?expand=states`](../../api-reference/store-api/relations.md):
221
-
222
-
223
- ```typescript Store SDK
224
- const usa = await client.countries.get('US', { expand: ['states'] })
225
-
226
- // Build a state picker from the response
227
- usa.states.forEach(state => {
228
- console.log(state.abbr, state.name) // "AL", "Alabama"
229
- })
230
- ```
231
-
232
- ```typescript Admin SDK
233
- const usa = await adminClient.countries.get('US', { expand: ['states'] })
234
- ```
235
-
236
- ```bash cURL
237
- curl 'https://api.mystore.com/api/v3/store/countries/US?expand=states' \
238
- -H 'X-Spree-API-Key: pk_xxx'
239
- ```
159
+ For real-world verification — that a street exists, that a unit number is missing — connect an address validation service. See [Providers](../providers/overview.md).
240
160
 
161
+ ## How geography flows through a purchase
241
162
 
242
- For countries without predefined states, addresses accept a free-text `state_name` field instead of `state_abbr`.
163
+ **Step 1: A customer arrives**
243
164
 
244
- ## Zones
165
+ Their country resolves to a [Market](markets.md), which sets the currency and locale, and whether prices are shown with tax included.
245
166
 
246
- Zones group countries or states together for [tax](taxes.md) and [shipping](fulfillments.md) rules. A zone is either **country-based** or **state-based**.
167
+ **Step 2: They fill in an address**
247
168
 
248
- **Examples:**
249
- - **EU VAT** (country zone) — Germany, France, Italy, Spain, ... → applies EU VAT rates
250
- - **California** (state zone) — CA → applies California sales tax
251
- - **Domestic Shipping** (country zone) — US, CA → enables domestic shipping methods
169
+ The form adapts to the country using `states_required` and `zipcode_required`.
252
170
 
253
- When a customer enters their address at checkout, Spree matches it against zones to determine:
254
- 1. Which **tax rates** apply (see [Taxes](taxes.md))
255
- 2. Which **shipping methods** are available (see [Shipments](fulfillments.md))
171
+ **Step 3: Delivery options appear**
256
172
 
257
- Zones are configured in the admin dashboard storefront developers don't interact with them directly via the API.
173
+ The shipping address decides which [delivery methods](fulfillments.md) can reach them, and what each costs.
258
174
 
259
- ### Tax Zones and Markets
175
+ **Step 4: Tax is worked out**
260
176
 
261
- Each [Market](markets.md) 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.
177
+ The same address decides the [tax](taxes.md) charged.
262
178
 
263
- ## How It All Fits Together
179
+ **Step 5: The order is placed**
264
180
 
265
- Here's how geography flows through a typical checkout:
181
+ Both addresses are copied onto the order as a permanent record.
266
182
 
267
- 1. **Customer visits the store** — their country is detected (from URL, geolocation, or selection)
268
- 2. **Market resolved** — the country maps to a market, which sets the currency and locale
269
- 3. **Products displayed** — prices use the market's currency and tax zone for correct formatting
270
- 4. **Customer enters address** — the address form adapts based on `states_required` and `zipcode_required`
271
- 5. **Zones matched** — the shipping address determines which tax rates and shipping methods apply
272
- 6. **Order completed** — the address is cloned onto the order for permanent record
273
183
 
274
- ## Related Documentation
184
+ ## Related
275
185
 
276
- - [Markets](markets.md) — Multi-region commerce with currency, locale, and country grouping
277
- - [Taxes](taxes.md) — How zones and addresses affect taxation
278
- - [Shipments](fulfillments.md) — How zones and addresses affect shipping availability
279
- - [Orders](orders.md) — Order billing and shipping addresses
280
- - [Account SDK guide](../sdk/store/account.md) — Managing the logged-in customer's address book with `client.customer.addresses`
281
- - [Store API authentication](../../api-reference/store-api/authentication.md) — How to obtain and send the customer JWT (`Authorization: Bearer` header)
186
+ - [Markets](markets.md) — where you sell, in which currency
187
+ - [Fulfillments](fulfillments.md) — how the address shapes delivery options
188
+ - [Taxes](taxes.md) — how the address shapes tax
189
+ - [Carts](carts.md) — the checkout flow end to end