@spree/docs 0.1.93 → 0.1.95
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.
- package/dist/api-reference/admin-api/authentication.md +8 -7
- package/dist/api-reference/admin-api/endpoints.md +348 -0
- package/dist/api-reference/admin-api/errors.md +2 -0
- package/dist/api-reference/admin-api/introduction.md +11 -0
- package/dist/api-reference/store.yaml +243 -232
- package/dist/developer/agentic/overview.md +1 -1
- package/dist/developer/cli/admin-api.md +146 -0
- package/dist/developer/cli/quickstart.md +40 -5
- package/dist/developer/core-concepts/addresses.md +32 -16
- package/dist/developer/core-concepts/adjustments.md +11 -5
- package/dist/developer/core-concepts/architecture.md +8 -8
- package/dist/developer/core-concepts/calculators.md +31 -51
- package/dist/developer/core-concepts/channels.md +13 -6
- package/dist/developer/core-concepts/customers.md +47 -23
- package/dist/developer/core-concepts/events.md +22 -17
- package/dist/developer/core-concepts/imports-exports.md +69 -14
- package/dist/developer/core-concepts/inventory.md +79 -1
- package/dist/developer/core-concepts/markets.md +64 -20
- package/dist/developer/core-concepts/media.md +43 -6
- package/dist/developer/core-concepts/metafields.md +76 -13
- package/dist/developer/core-concepts/orders.md +95 -17
- package/dist/developer/core-concepts/payments.md +14 -13
- package/dist/developer/core-concepts/pricing.md +95 -9
- package/dist/developer/core-concepts/products.md +192 -26
- package/dist/developer/core-concepts/promotions.md +61 -4
- package/dist/developer/core-concepts/reports.md +4 -2
- package/dist/developer/core-concepts/search-filtering.md +82 -32
- package/dist/developer/core-concepts/shipments.md +16 -13
- package/dist/developer/core-concepts/slugs.md +20 -11
- package/dist/developer/core-concepts/staff-roles.md +51 -1
- package/dist/developer/core-concepts/store-credits-gift-cards.md +90 -9
- package/dist/developer/core-concepts/stores.md +16 -14
- package/dist/developer/core-concepts/taxes.md +28 -0
- package/dist/developer/core-concepts/translations.md +16 -7
- package/dist/developer/core-concepts/users.md +13 -9
- package/dist/developer/core-concepts/webhooks.md +95 -64
- package/dist/developer/getting-started/quickstart.md +20 -0
- package/dist/developer/how-to/custom-api-authentication.md +103 -23
- package/dist/developer/multi-store/quickstart.md +1 -1
- package/dist/developer/sdk/admin/authentication.md +1 -1
- package/dist/developer/sdk/admin/resources.md +2 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +1 -1
- package/dist/developer/upgrades/5.4-to-5.5.md +1 -1
- package/dist/integrations/integrations.md +0 -7
- package/package.json +1 -1
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +0 -57
- package/dist/integrations/sso-mfa-social-login/storefront.md +0 -56
|
@@ -74,7 +74,7 @@ If no market matches the customer's country, the store's **default market** is u
|
|
|
74
74
|
Fetch all markets for the current store, including their countries:
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
```typescript SDK
|
|
77
|
+
```typescript Store SDK
|
|
78
78
|
const { data: markets } = await client.markets.list()
|
|
79
79
|
// [
|
|
80
80
|
// {
|
|
@@ -94,6 +94,10 @@ const { data: markets } = await client.markets.list()
|
|
|
94
94
|
// ]
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
```typescript Admin SDK
|
|
98
|
+
const { data: markets } = await adminClient.markets.list()
|
|
99
|
+
```
|
|
100
|
+
|
|
97
101
|
```bash cURL
|
|
98
102
|
curl 'https://api.mystore.com/api/v3/store/markets' \
|
|
99
103
|
-H 'X-Spree-API-Key: pk_xxx'
|
|
@@ -105,7 +109,7 @@ curl 'https://api.mystore.com/api/v3/store/markets' \
|
|
|
105
109
|
When you know a customer's country (e.g., from geolocation or a country picker), resolve which market applies:
|
|
106
110
|
|
|
107
111
|
|
|
108
|
-
```typescript SDK
|
|
112
|
+
```typescript Store SDK
|
|
109
113
|
const market = await client.markets.resolve('DE')
|
|
110
114
|
// { id: "mkt_gbHJdmfr", name: "Europe", currency: "EUR", tax_inclusive: true, ... }
|
|
111
115
|
```
|
|
@@ -125,7 +129,7 @@ This is useful for building a country switcher — resolve the market to show th
|
|
|
125
129
|
List countries belonging to a specific market. Useful for populating address form dropdowns during checkout:
|
|
126
130
|
|
|
127
131
|
|
|
128
|
-
```typescript SDK
|
|
132
|
+
```typescript Store SDK
|
|
129
133
|
const { data: countries } = await client.markets.countries.list('mkt_k5nR8xLq')
|
|
130
134
|
// [
|
|
131
135
|
// { iso: "CA", name: "Canada", states_required: true, zipcode_required: true },
|
|
@@ -134,7 +138,7 @@ const { data: countries } = await client.markets.countries.list('mkt_k5nR8xLq')
|
|
|
134
138
|
|
|
135
139
|
// Get a country with its states (for address form dropdowns)
|
|
136
140
|
const usa = await client.markets.countries.get('mkt_k5nR8xLq', 'US', {
|
|
137
|
-
|
|
141
|
+
expand: ['states'],
|
|
138
142
|
})
|
|
139
143
|
```
|
|
140
144
|
|
|
@@ -152,15 +156,21 @@ curl 'https://api.mystore.com/api/v3/store/markets/mkt_k5nR8xLq/countries/US?exp
|
|
|
152
156
|
You can also fetch countries flat (across all markets) or include the market on a country:
|
|
153
157
|
|
|
154
158
|
|
|
155
|
-
```typescript SDK
|
|
159
|
+
```typescript Store SDK
|
|
156
160
|
// All countries across all markets
|
|
157
161
|
const { data: countries } = await client.countries.list()
|
|
158
162
|
|
|
159
163
|
// Get a country with its market details
|
|
160
|
-
const germany = await client.countries.get('DE', {
|
|
164
|
+
const germany = await client.countries.get('DE', { expand: ['market'] })
|
|
161
165
|
// { iso: "DE", name: "Germany", market: { currency: "EUR", default_locale: "de", tax_inclusive: true } }
|
|
162
166
|
```
|
|
163
167
|
|
|
168
|
+
```typescript Admin SDK
|
|
169
|
+
const { data: countries } = await adminClient.countries.list()
|
|
170
|
+
|
|
171
|
+
const germany = await adminClient.countries.get('DE')
|
|
172
|
+
```
|
|
173
|
+
|
|
164
174
|
```bash cURL
|
|
165
175
|
# All countries across all markets
|
|
166
176
|
curl 'https://api.mystore.com/api/v3/store/countries' \
|
|
@@ -174,12 +184,12 @@ curl 'https://api.mystore.com/api/v3/store/countries/DE?expand=market' \
|
|
|
174
184
|
|
|
175
185
|
## Currency and Locale
|
|
176
186
|
|
|
177
|
-
Each market defines a currency and set of supported locales. When a market is resolved, its currency and locale become the defaults for the session.
|
|
187
|
+
Each market defines a [currency and set of supported locales](../../api-reference/store-api/monetary-amounts.md). When a market is resolved, its currency and locale become the defaults for the session.
|
|
178
188
|
|
|
179
189
|
You can discover all available currencies and locales (aggregated from all markets) via dedicated endpoints:
|
|
180
190
|
|
|
181
191
|
|
|
182
|
-
```typescript SDK
|
|
192
|
+
```typescript Store SDK
|
|
183
193
|
const { data: currencies } = await client.currencies.list()
|
|
184
194
|
// [{ iso_code: "USD", name: "US Dollar", symbol: "$" }, { iso_code: "EUR", name: "Euro", symbol: "€" }]
|
|
185
195
|
|
|
@@ -221,31 +231,65 @@ See [Pricing — Price Rules](pricing.md#price-rules) for details on configuring
|
|
|
221
231
|
|
|
222
232
|
Markets are managed in the admin dashboard under **Settings → Markets**. When you run `rails db:seed`, Spree automatically creates a default market for each store.
|
|
223
233
|
|
|
224
|
-
To create markets programmatically:
|
|
234
|
+
To create markets programmatically, use the [Admin API](../../api-reference/admin-api/introduction.md). See the [Admin API endpoints](../../api-reference/admin-api/endpoints.md) for the full list of `/markets` routes and required scopes:
|
|
235
|
+
|
|
225
236
|
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
|
|
237
|
+
```typescript Admin SDK
|
|
238
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
239
|
+
|
|
240
|
+
const client = createAdminClient({
|
|
241
|
+
baseUrl: 'https://store.example.com',
|
|
242
|
+
secretKey: 'sk_xxx',
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// North America market (countries by ISO code)
|
|
246
|
+
const northAmerica = await client.markets.create({
|
|
229
247
|
name: 'North America',
|
|
230
248
|
currency: 'USD',
|
|
231
249
|
default_locale: 'en',
|
|
232
|
-
|
|
233
|
-
default: true
|
|
234
|
-
)
|
|
250
|
+
country_isos: ['US', 'CA'],
|
|
251
|
+
default: true,
|
|
252
|
+
})
|
|
235
253
|
|
|
236
|
-
|
|
237
|
-
|
|
254
|
+
// Europe market with tax-inclusive pricing
|
|
255
|
+
const europe = await client.markets.create({
|
|
238
256
|
name: 'Europe',
|
|
239
257
|
currency: 'EUR',
|
|
240
258
|
default_locale: 'de',
|
|
241
|
-
supported_locales: 'de,en,fr',
|
|
259
|
+
supported_locales: ['de', 'en', 'fr'],
|
|
242
260
|
tax_inclusive: true,
|
|
243
|
-
|
|
244
|
-
)
|
|
261
|
+
country_isos: ['DE', 'FR', 'AT', 'NL'],
|
|
262
|
+
})
|
|
245
263
|
```
|
|
246
264
|
|
|
265
|
+
```bash CLI
|
|
266
|
+
spree api post /markets -d '{
|
|
267
|
+
"name": "North America",
|
|
268
|
+
"currency": "USD",
|
|
269
|
+
"default_locale": "en",
|
|
270
|
+
"country_isos": ["US", "CA"],
|
|
271
|
+
"default": true
|
|
272
|
+
}'
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
Update or remove a market the same way:
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
```typescript Admin SDK
|
|
280
|
+
await client.markets.update('market_xxx', { tax_inclusive: true })
|
|
281
|
+
await client.markets.delete('market_xxx')
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
```bash CLI
|
|
285
|
+
spree api patch /markets/market_xxx -d '{"tax_inclusive": true}'
|
|
286
|
+
spree api delete /markets/market_xxx
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
|
|
247
290
|
## Related Documentation
|
|
248
291
|
|
|
292
|
+
- [Markets (Store SDK)](../sdk/store/markets.md) — Listing, resolving, and reading markets from the Store SDK
|
|
249
293
|
- [Stores](stores.md) — Multi-store setup and configuration
|
|
250
294
|
- [Pricing](pricing.md) — Price Lists, Price Rules, and the Pricing Context
|
|
251
295
|
- [Addresses](addresses.md) — Countries, States, and Zones
|
|
@@ -54,6 +54,31 @@ curl -X POST 'https://api.mystore.com/api/v3/admin/products/prod_86Rf07xd4z/medi
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
#### Creating media from a remote URL
|
|
58
|
+
|
|
59
|
+
When the image already lives at a public URL, pass `url` instead of a `signed_id` — Spree fetches the remote file and stores it as product media, so you skip the direct-upload step entirely.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
```typescript Admin SDK
|
|
63
|
+
await client.products.media.create('prod_86Rf07xd4z', {
|
|
64
|
+
url: 'https://cdn.example.com/images/tote-front.jpg',
|
|
65
|
+
position: 1,
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```bash cURL
|
|
70
|
+
curl -X POST 'https://api.mystore.com/api/v3/admin/products/prod_86Rf07xd4z/media' \
|
|
71
|
+
-H 'X-Spree-API-Key: sk_xxx' \
|
|
72
|
+
-H 'Content-Type: application/json' \
|
|
73
|
+
-d '{
|
|
74
|
+
"url": "https://cdn.example.com/images/tote-front.jpg",
|
|
75
|
+
"position": 1
|
|
76
|
+
}'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
> **NOTE:** The fetch runs in the background, so this request returns `202 Accepted` with no body — the media appears in the gallery once the download and processing finish. Re-fetch the product's media to know when it's ready.
|
|
81
|
+
|
|
57
82
|
#### Sharing a single image across variants
|
|
58
83
|
|
|
59
84
|
Pass a `variant_ids` array on the same media endpoint to link/unlink variants. The server replaces the asset's link set on every call — empty array clears all links, omitting the field leaves them untouched.
|
|
@@ -99,10 +124,10 @@ All variants are cropped to fill the exact dimensions and converted to WebP form
|
|
|
99
124
|
|
|
100
125
|
### Thumbnails (Always Available)
|
|
101
126
|
|
|
102
|
-
Every product response includes a `thumbnail_url` field — ready to use without any expands. Similarly, each variant includes a `
|
|
127
|
+
Every product response includes a `thumbnail_url` field — ready to use without any expands. Similarly, each variant includes a `thumbnail_url` and a `media_count` counter.
|
|
103
128
|
|
|
104
129
|
|
|
105
|
-
```typescript SDK
|
|
130
|
+
```typescript Store SDK
|
|
106
131
|
// List products — thumbnail_url is always included
|
|
107
132
|
const { data: products } = await client.products.list({ limit: 12 })
|
|
108
133
|
|
|
@@ -111,6 +136,10 @@ products.forEach(product => {
|
|
|
111
136
|
})
|
|
112
137
|
```
|
|
113
138
|
|
|
139
|
+
```typescript Admin SDK
|
|
140
|
+
const { data: products } = await adminClient.products.list({ limit: 12 })
|
|
141
|
+
```
|
|
142
|
+
|
|
114
143
|
```bash cURL
|
|
115
144
|
# thumbnail_url is always in the response — no ?expand needed
|
|
116
145
|
curl 'https://api.mystore.com/api/v3/store/products?limit=12' \
|
|
@@ -122,10 +151,10 @@ curl 'https://api.mystore.com/api/v3/store/products?limit=12' \
|
|
|
122
151
|
|
|
123
152
|
### Full Media (On Demand)
|
|
124
153
|
|
|
125
|
-
On the product detail page, expand
|
|
154
|
+
On the product detail page, [expand media and variants](../../api-reference/store-api/relations.md) to get the full set of media with all named variant URLs:
|
|
126
155
|
|
|
127
156
|
|
|
128
|
-
```typescript SDK
|
|
157
|
+
```typescript Store SDK
|
|
129
158
|
const product = await client.products.get('spree-tote', {
|
|
130
159
|
expand: ['media', 'variants'],
|
|
131
160
|
})
|
|
@@ -135,12 +164,18 @@ product.media // [{ id, media_type, product_id, variant_ids, original_url, mini_
|
|
|
135
164
|
|
|
136
165
|
// Each variant has its own thumbnail and media_count
|
|
137
166
|
product.variants?.forEach(variant => {
|
|
138
|
-
variant.
|
|
167
|
+
variant.thumbnail_url // "https://cdn.../tote-red.webp" — present in the response, null when the variant has no media
|
|
139
168
|
variant.media_count // 3 — quick check without loading media
|
|
140
169
|
variant.media // full media array (only with ?expand=media)
|
|
141
170
|
})
|
|
142
171
|
```
|
|
143
172
|
|
|
173
|
+
```typescript Admin SDK
|
|
174
|
+
const product = await adminClient.products.get('prod_86Rf07xd4z', {
|
|
175
|
+
expand: ['media', 'variants'],
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
144
179
|
```bash cURL
|
|
145
180
|
curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=media,variants' \
|
|
146
181
|
-H 'X-Spree-API-Key: pk_xxx'
|
|
@@ -174,7 +209,7 @@ curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=media,vari
|
|
|
174
209
|
| Field | Available on | Always Returned | Description |
|
|
175
210
|
|-------|-------------|:---:|-------------|
|
|
176
211
|
| `thumbnail_url` | Product | Yes | URL to the product's first media |
|
|
177
|
-
| `
|
|
212
|
+
| `thumbnail_url` | Variant | Yes | URL to the variant's first media |
|
|
178
213
|
| `media_count` | Variant | Yes | Number of media items (counter cache) |
|
|
179
214
|
| `media` | Product, Variant | No | Full media array (requires `?expand=media`) |
|
|
180
215
|
|
|
@@ -224,4 +259,6 @@ Spree supports two storage service types:
|
|
|
224
259
|
## Related Documentation
|
|
225
260
|
|
|
226
261
|
- [Products](products.md) — Product catalog and media
|
|
262
|
+
- [Products & Categories](../sdk/store/products.md) — Store SDK guide for fetching products, `thumbnail_url`, and expanded media
|
|
263
|
+
- [Admin SDK](../sdk/admin/resources.md) — Admin SDK resource methods, including the nested `products.media` create/update calls
|
|
227
264
|
- [Deployment — Assets](../deployment/assets.md) — Storage and CDN configuration
|
|
@@ -3,9 +3,12 @@ title: Metafields
|
|
|
3
3
|
description: Add custom structured data to products, orders, and other resources with type-safe metafields
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
import { Since } from '/snippets/since.mdx';
|
|
7
|
+
|
|
8
|
+
|
|
6
9
|
## Overview
|
|
7
10
|
|
|
8
|
-
Metafields provide a flexible, type-safe system for adding custom structured
|
|
11
|
+
Metafields provide a flexible, type-safe system for adding custom structured attributes to Spree models. Unlike [metadata](../customization/metadata.md) which is simple JSON storage, metafields are schema-defined with strong typing, validation, and visibility controls.
|
|
9
12
|
|
|
10
13
|
Use metafields for:
|
|
11
14
|
|
|
@@ -14,8 +17,6 @@ Use metafields for:
|
|
|
14
17
|
- Integration data from external systems
|
|
15
18
|
- Order-specific custom attributes
|
|
16
19
|
|
|
17
|
-
> **NOTE:** Metafields are available from Spree 5.2 onwards.
|
|
18
|
-
|
|
19
20
|
## Architecture
|
|
20
21
|
|
|
21
22
|
```mermaid
|
|
@@ -75,12 +76,11 @@ flowchart LR
|
|
|
75
76
|
|
|
76
77
|
## Visibility Control
|
|
77
78
|
|
|
78
|
-
Metafields support
|
|
79
|
+
Metafields support two visibility levels via the `display_on` attribute:
|
|
79
80
|
|
|
80
81
|
| Visibility | Store API | Admin API | Use Case |
|
|
81
82
|
|------------|:---------:|:---------:|----------|
|
|
82
83
|
| `both` | Yes | Yes | Public product specifications |
|
|
83
|
-
| `front_end` | Yes | No | Customer-facing data |
|
|
84
84
|
| `back_end` | No | Yes | Internal notes, integration IDs |
|
|
85
85
|
|
|
86
86
|
## Supported Resources
|
|
@@ -104,10 +104,12 @@ Namespaces organize metafields into logical groups and prevent key conflicts:
|
|
|
104
104
|
|
|
105
105
|
## Store API
|
|
106
106
|
|
|
107
|
-
Metafields with `display_on` set to `both`
|
|
107
|
+
Metafields with `display_on` set to `both` are included in Store API responses when you [request the `custom_fields` expand](../../api-reference/store-api/relations.md):
|
|
108
|
+
|
|
109
|
+
> **INFO:** Metafields in API are called Custom Fields as we plan to rename Metafields to Custom Fields completely in Spree 6.0.
|
|
108
110
|
|
|
109
111
|
|
|
110
|
-
```typescript SDK
|
|
112
|
+
```typescript Store SDK
|
|
111
113
|
const product = await client.products.get('spree-tote', {
|
|
112
114
|
expand: ['custom_fields'],
|
|
113
115
|
})
|
|
@@ -115,8 +117,14 @@ const product = await client.products.get('spree-tote', {
|
|
|
115
117
|
product.custom_fields?.forEach(field => {
|
|
116
118
|
console.log(field.key) // "properties.manufacturer"
|
|
117
119
|
console.log(field.label) // "Manufacturer"
|
|
118
|
-
console.log(field.value)
|
|
119
|
-
console.log(field.
|
|
120
|
+
console.log(field.value) // "Wilson"
|
|
121
|
+
console.log(field.field_type) // "short_text"
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```typescript Admin SDK
|
|
126
|
+
const product = await adminClient.products.get('prod_86Rf07xd4z', {
|
|
127
|
+
expand: ['custom_fields'],
|
|
120
128
|
})
|
|
121
129
|
```
|
|
122
130
|
|
|
@@ -137,14 +145,14 @@ curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=custom_fie
|
|
|
137
145
|
"id": "cf_k5nR8xLq",
|
|
138
146
|
"label": "Manufacturer",
|
|
139
147
|
"key": "properties.manufacturer",
|
|
140
|
-
"
|
|
148
|
+
"field_type": "short_text",
|
|
141
149
|
"value": "Wilson"
|
|
142
150
|
},
|
|
143
151
|
{
|
|
144
152
|
"id": "cf_m3Rp9wXz",
|
|
145
153
|
"label": "Material",
|
|
146
154
|
"key": "properties.material",
|
|
147
|
-
"
|
|
155
|
+
"field_type": "short_text",
|
|
148
156
|
"value": "100% Cotton"
|
|
149
157
|
}
|
|
150
158
|
]
|
|
@@ -153,16 +161,70 @@ curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=custom_fie
|
|
|
153
161
|
|
|
154
162
|
> **NOTE:** The `display_on` attribute is intentionally excluded from Store API responses for security.
|
|
155
163
|
|
|
156
|
-
## Admin
|
|
164
|
+
## Admin Management
|
|
157
165
|
|
|
158
166
|
### Managing Definitions
|
|
159
167
|
|
|
160
168
|
Navigate to **Settings → Metafield Definitions** in the Admin Panel to create and manage metafield definitions. Select the resource type, enter namespace and key, choose the data type, and set visibility.
|
|
161
169
|
|
|
170
|
+
Definitions are also [managed via the Admin API](../../api-reference/admin-api/endpoints.md). `storefront_visible: true` is equivalent to `display_on: both` — it exposes the field to the Store API:
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
```typescript Admin SDK
|
|
174
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
175
|
+
|
|
176
|
+
const client = createAdminClient({
|
|
177
|
+
baseUrl: 'https://store.example.com',
|
|
178
|
+
secretKey: 'sk_xxx',
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
const definition = await client.customFieldDefinitions.create({
|
|
182
|
+
resource_type: 'Spree::Product',
|
|
183
|
+
namespace: 'properties',
|
|
184
|
+
key: 'manufacturer',
|
|
185
|
+
label: 'Manufacturer',
|
|
186
|
+
field_type: 'short_text',
|
|
187
|
+
storefront_visible: true,
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
await client.customFieldDefinitions.update(definition.id, { storefront_visible: false })
|
|
191
|
+
await client.customFieldDefinitions.delete(definition.id)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```bash CLI
|
|
195
|
+
spree api post /custom_field_definitions -d '{
|
|
196
|
+
"resource_type": "Spree::Product",
|
|
197
|
+
"namespace": "properties",
|
|
198
|
+
"key": "manufacturer",
|
|
199
|
+
"label": "Manufacturer",
|
|
200
|
+
"field_type": "short_text",
|
|
201
|
+
"storefront_visible": true
|
|
202
|
+
}'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
|
|
162
206
|
### Managing Values
|
|
163
207
|
|
|
164
208
|
When editing a resource (e.g., a product), metafields appear in a dedicated section. The admin panel automatically builds forms for all defined metafields.
|
|
165
209
|
|
|
210
|
+
To set a value programmatically, use the resource's nested `customFields` accessor (parent ID first):
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
```typescript Admin SDK
|
|
214
|
+
await client.products.customFields.create('prod_xxx', {
|
|
215
|
+
custom_field_definition_id: 'cfdef_xxx',
|
|
216
|
+
value: 'Wilson',
|
|
217
|
+
})
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
```bash CLI
|
|
221
|
+
spree api post /products/prod_xxx/custom_fields -d '{
|
|
222
|
+
"custom_field_definition_id": "cfdef_xxx",
|
|
223
|
+
"value": "Wilson"
|
|
224
|
+
}'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
|
|
166
228
|
## Metafields vs Metadata
|
|
167
229
|
|
|
168
230
|
Spree has two permanent, complementary systems for custom data — **metadata for machines, metafields for humans**. They serve different purposes and are not interchangeable. Neither is going away.
|
|
@@ -182,10 +244,11 @@ Spree has two permanent, complementary systems for custom data — **metadata fo
|
|
|
182
244
|
|
|
183
245
|
**Use [Metadata](../customization/metadata.md)** for external system IDs, tracking attribution, syncing with integrations, or simple write-and-forget data that only backend systems need to read.
|
|
184
246
|
|
|
185
|
-
> **WARNING:** Product Properties are deprecated and will be removed in Spree 6.0. For new projects, always use Metafields. For existing projects, plan to migrate using the [migration guide](../upgrades/5.1-to-5.2.md#
|
|
247
|
+
> **WARNING:** Product Properties are deprecated and will be removed in Spree 6.0. For new projects, always use Metafields. For existing projects, plan to migrate using the [migration guide](../upgrades/5.1-to-5.2.md#migrate-to-metafields-or-keep-using-product-properties).
|
|
186
248
|
|
|
187
249
|
## Related Documentation
|
|
188
250
|
|
|
189
251
|
- [Metadata](../customization/metadata.md) — Simple key-value metadata
|
|
190
252
|
- [Products](products.md) — Product catalog
|
|
191
253
|
- [Events](events.md) — Subscribe to metafield events
|
|
254
|
+
- [Admin SDK](../sdk/admin/resources.md) — Manage definitions and values from TypeScript
|
|
@@ -62,28 +62,27 @@ The API returns these key fields on every order:
|
|
|
62
62
|
| Attribute | Description |
|
|
63
63
|
|-----------|-------------|
|
|
64
64
|
| `number` | Unique order number (e.g., `R123456789`), shown to customers |
|
|
65
|
-
| `state` | Current checkout state (`cart`, `address`, `delivery`, `payment`, `confirm`, `complete`) |
|
|
66
65
|
| `email` | Customer's email address |
|
|
67
66
|
| `currency` | Order currency (e.g., `USD`) |
|
|
68
|
-
| `
|
|
67
|
+
| `total_quantity` | Total number of items |
|
|
69
68
|
| `item_total` / `display_item_total` | Sum of line item prices |
|
|
70
69
|
| `delivery_total` / `display_delivery_total` | Delivery cost |
|
|
71
70
|
| `tax_total` / `display_tax_total` | Total tax |
|
|
72
|
-
| `
|
|
71
|
+
| `discount_total` / `display_discount_total` | Total discount from promotions |
|
|
73
72
|
| `adjustment_total` / `display_adjustment_total` | Sum of all adjustments (tax + delivery + promos) |
|
|
74
73
|
| `total` / `display_total` | Final order total |
|
|
75
|
-
| `
|
|
74
|
+
| `payment_status` | Payment status (`balance_due`, `paid`, `credit_owed`, `failed`, `void`) |
|
|
76
75
|
| `fulfillment_status` | Fulfillment status (`pending`, `ready`, `partial`, `shipped`, `backorder`) |
|
|
77
76
|
| `completed_at` | Timestamp when the order was placed |
|
|
78
77
|
|
|
79
|
-
The `display_*` fields return formatted strings with currency symbols (e.g., `"$15.99"`).
|
|
78
|
+
The [`display_*` fields return formatted strings with currency symbols](../../api-reference/store-api/monetary-amounts.md) (e.g., `"$15.99"`).
|
|
80
79
|
|
|
81
80
|
## Cart
|
|
82
81
|
|
|
83
|
-
A cart is simply an order in the `cart` state. Guest carts are identified by a cart token; authenticated users' carts are linked to their account.
|
|
82
|
+
A cart is simply an order in the `cart` state. Guest carts are [identified by a cart token; authenticated users' carts are linked to their account](../../api-reference/store-api/authentication.md).
|
|
84
83
|
|
|
85
84
|
|
|
86
|
-
```typescript SDK
|
|
85
|
+
```typescript Store SDK
|
|
87
86
|
// Create a cart
|
|
88
87
|
const cart = await client.carts.create()
|
|
89
88
|
// cart.token => "abc123" (save this for guest checkout)
|
|
@@ -171,21 +170,21 @@ Order is placed. `completed_at` is set and fulfillment begins.
|
|
|
171
170
|
If the order doesn't meet the requirements for the next state (e.g., missing address), the API returns an error.
|
|
172
171
|
|
|
173
172
|
|
|
174
|
-
```typescript SDK
|
|
173
|
+
```typescript Store SDK
|
|
175
174
|
// Set addresses
|
|
176
175
|
await client.carts.update(cartId, {
|
|
177
176
|
email: 'john@example.com',
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
shipping_address: {
|
|
178
|
+
first_name: 'John', last_name: 'Doe',
|
|
180
179
|
address1: '123 Main St', city: 'Los Angeles',
|
|
181
|
-
country_iso: 'US', state_abbr: 'CA',
|
|
180
|
+
country_iso: 'US', state_abbr: 'CA', postal_code: '90001',
|
|
182
181
|
phone: '555-0100',
|
|
183
182
|
},
|
|
184
183
|
})
|
|
185
184
|
|
|
186
185
|
// Get fulfillments and select a delivery rate
|
|
187
186
|
// (the Store API/SDK exposes shipments as `fulfillments`)
|
|
188
|
-
const cart = await client.carts.get(cartId
|
|
187
|
+
const cart = await client.carts.get(cartId)
|
|
189
188
|
await client.carts.fulfillments.update(cartId, cart.fulfillments[0].id, {
|
|
190
189
|
selected_delivery_rate_id: 'rate_xxx',
|
|
191
190
|
})
|
|
@@ -211,10 +210,10 @@ curl -X PATCH 'https://api.mystore.com/api/v3/store/carts/cart_xxx' \
|
|
|
211
210
|
-H 'Content-Type: application/json' \
|
|
212
211
|
-d '{
|
|
213
212
|
"email": "john@example.com",
|
|
214
|
-
"
|
|
215
|
-
"
|
|
213
|
+
"shipping_address": {
|
|
214
|
+
"first_name": "John", "last_name": "Doe",
|
|
216
215
|
"address1": "123 Main St", "city": "Los Angeles",
|
|
217
|
-
"country_iso": "US", "state_abbr": "CA", "
|
|
216
|
+
"country_iso": "US", "state_abbr": "CA", "postal_code": "90001",
|
|
218
217
|
"phone": "555-0100"
|
|
219
218
|
}
|
|
220
219
|
}'
|
|
@@ -238,7 +237,7 @@ curl -X POST 'https://api.mystore.com/api/v3/store/carts/cart_xxx/complete' \
|
|
|
238
237
|
Apply or remove promotional coupon codes during checkout:
|
|
239
238
|
|
|
240
239
|
|
|
241
|
-
```typescript SDK
|
|
240
|
+
```typescript Store SDK
|
|
242
241
|
// Apply a discount code
|
|
243
242
|
await client.carts.discountCodes.apply(cartId, 'SAVE20')
|
|
244
243
|
|
|
@@ -266,7 +265,7 @@ curl -X DELETE 'https://api.mystore.com/api/v3/store/carts/cart_xxx/discount_cod
|
|
|
266
265
|
Authenticated customers can view their past orders:
|
|
267
266
|
|
|
268
267
|
|
|
269
|
-
```typescript SDK
|
|
268
|
+
```typescript Store SDK
|
|
270
269
|
// List past orders
|
|
271
270
|
const { data: orders } = await client.customer.orders.list()
|
|
272
271
|
|
|
@@ -276,6 +275,10 @@ const order = await client.orders.get('or_xxx', {
|
|
|
276
275
|
})
|
|
277
276
|
```
|
|
278
277
|
|
|
278
|
+
```typescript Admin SDK
|
|
279
|
+
const order = await adminClient.orders.get('or_xxx')
|
|
280
|
+
```
|
|
281
|
+
|
|
279
282
|
```bash cURL
|
|
280
283
|
# List past orders
|
|
281
284
|
curl 'https://api.mystore.com/api/v3/store/customer/orders' \
|
|
@@ -287,6 +290,80 @@ curl 'https://api.mystore.com/api/v3/store/orders/or_xxx?expand=items,fulfillmen
|
|
|
287
290
|
```
|
|
288
291
|
|
|
289
292
|
|
|
293
|
+
## Managing Orders
|
|
294
|
+
|
|
295
|
+
Everything above is the **Store API** — the customer's own cart and orders. Back-office order management (listing every order, creating phone/manual orders, capturing payments, cancelling) uses the [Admin API](../../api-reference/admin-api/introduction.md).
|
|
296
|
+
|
|
297
|
+
### Listing and creating orders
|
|
298
|
+
|
|
299
|
+
List orders with [Ransack filters and pagination](../../api-reference/admin-api/querying.md) (`state_eq`, `limit`, sorting). A draft order is created in one call; pass line items as `items` (each `{ variant_id, quantity }`):
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
```typescript Admin SDK
|
|
303
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
304
|
+
|
|
305
|
+
const client = createAdminClient({
|
|
306
|
+
baseUrl: 'https://store.example.com',
|
|
307
|
+
secretKey: 'sk_xxx',
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
// List orders (Ransack filters)
|
|
311
|
+
const { data: orders } = await client.orders.list({ state_eq: 'complete', limit: 25 })
|
|
312
|
+
|
|
313
|
+
// Create a draft order on a customer's behalf
|
|
314
|
+
const order = await client.orders.create({
|
|
315
|
+
email: 'buyer@example.com',
|
|
316
|
+
items: [{ variant_id: 'variant_xxx', quantity: 2 }],
|
|
317
|
+
currency: 'USD',
|
|
318
|
+
})
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
```bash CLI
|
|
322
|
+
spree api get /orders -q state_eq=complete --limit 25
|
|
323
|
+
spree api post /orders -d '{
|
|
324
|
+
"email": "buyer@example.com",
|
|
325
|
+
"items": [{ "variant_id": "variant_xxx", "quantity": 2 }]
|
|
326
|
+
}'
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
### Order state actions
|
|
331
|
+
|
|
332
|
+
Orders move through their [state machine](#checkout-flow) via dedicated actions rather than raw `state` writes:
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
```typescript Admin SDK
|
|
336
|
+
await client.orders.complete('or_xxx') // finalize a draft
|
|
337
|
+
await client.orders.cancel('or_xxx', { reason: 'customer' })
|
|
338
|
+
await client.orders.approve('or_xxx')
|
|
339
|
+
await client.orders.resume('or_xxx')
|
|
340
|
+
await client.orders.resendConfirmation('or_xxx')
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
```bash CLI
|
|
344
|
+
spree api patch /orders/or_xxx/complete
|
|
345
|
+
spree api patch /orders/or_xxx/cancel -d '{"reason": "customer"}'
|
|
346
|
+
spree api patch /orders/or_xxx/approve
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
### Payments and refunds
|
|
351
|
+
|
|
352
|
+
Capture or void an authorized payment, and issue refunds, through the nested order resources:
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
```typescript Admin SDK
|
|
356
|
+
await client.orders.payments.capture('or_xxx', 'pay_xxx')
|
|
357
|
+
await client.orders.payments.void('or_xxx', 'pay_xxx')
|
|
358
|
+
await client.orders.refunds.create('or_xxx', { payment_id: 'pay_xxx', amount: 19.99 })
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
```bash CLI
|
|
362
|
+
spree api patch /orders/or_xxx/payments/pay_xxx/capture
|
|
363
|
+
spree api post /orders/or_xxx/refunds -d '{"payment_id": "pay_xxx", "amount": 19.99}'
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
|
|
290
367
|
## Line Items
|
|
291
368
|
|
|
292
369
|
Line items represent individual products in an order. Each line item links to a [Variant](products.md#variants) and tracks the quantity and price at the time of purchase.
|
|
@@ -323,6 +400,7 @@ For more details, see [Shipments](shipments.md) and [Payments](payments.md).
|
|
|
323
400
|
|
|
324
401
|
## Related Documentation
|
|
325
402
|
|
|
403
|
+
- [Cart, Checkout & Orders](../sdk/store/cart-checkout.md) — Store SDK guide for carts, checkout, coupon codes, and order history
|
|
326
404
|
- [Payments](payments.md) — Payment processing and payment sessions
|
|
327
405
|
- [Shipments](shipments.md) — Fulfillment and shipping rates
|
|
328
406
|
- [Addresses](addresses.md) — Billing and shipping addresses
|