@spree/docs 0.1.93 → 0.1.94
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/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
|
@@ -83,10 +83,11 @@ Categories help organize store credits by their purpose:
|
|
|
83
83
|
|
|
84
84
|
| Category | Description |
|
|
85
85
|
|----------|-------------|
|
|
86
|
-
| Default | General purpose store credit |
|
|
87
|
-
|
|
|
86
|
+
| Default | General purpose store credit (also the default reimbursement category) |
|
|
87
|
+
| Expiring | Store credit that may expire |
|
|
88
|
+
| Non-expiring | Store credit that does not expire |
|
|
88
89
|
|
|
89
|
-
> **INFO:**
|
|
90
|
+
> **INFO:** "Gift Card" is not a seeded category but a special name recognized by the model: any category named "Gift Card" (or one listed in `Spree::Config[:non_expiring_credit_types]`) is treated as non-expiring via `StoreCreditCategory#non_expiring?`.
|
|
90
91
|
|
|
91
92
|
### Store Credit Types
|
|
92
93
|
|
|
@@ -120,7 +121,34 @@ Store credits are managed in the Admin Panel:
|
|
|
120
121
|
5. Enter the amount, category, and optional memo
|
|
121
122
|
6. Click **Create**
|
|
122
123
|
|
|
123
|
-
Store credits can also be created via the Admin API.
|
|
124
|
+
Store credits can also be created via the [Admin API](../../api-reference/admin-api/introduction.md), as a nested resource under the customer:
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
```typescript Admin SDK
|
|
128
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
129
|
+
|
|
130
|
+
const client = createAdminClient({
|
|
131
|
+
baseUrl: 'https://store.example.com',
|
|
132
|
+
secretKey: 'sk_xxx',
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const credit = await client.customers.storeCredits.create('cus_xxx', {
|
|
136
|
+
amount: 25.0,
|
|
137
|
+
currency: 'USD',
|
|
138
|
+
category_id: 'sccat_xxx',
|
|
139
|
+
memo: 'Goodwill credit for delayed shipment',
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```bash CLI
|
|
144
|
+
spree api post /customers/cus_xxx/store_credits -d '{
|
|
145
|
+
"amount": 25.0,
|
|
146
|
+
"currency": "USD",
|
|
147
|
+
"category_id": "sccat_xxx",
|
|
148
|
+
"memo": "Goodwill credit"
|
|
149
|
+
}'
|
|
150
|
+
```
|
|
151
|
+
|
|
124
152
|
|
|
125
153
|
### Store Credit Events
|
|
126
154
|
|
|
@@ -151,7 +179,7 @@ erDiagram
|
|
|
151
179
|
decimal amount_used
|
|
152
180
|
decimal amount_authorized
|
|
153
181
|
string currency
|
|
154
|
-
|
|
182
|
+
date expires_at
|
|
155
183
|
datetime redeemed_at
|
|
156
184
|
}
|
|
157
185
|
|
|
@@ -160,7 +188,7 @@ erDiagram
|
|
|
160
188
|
integer codes_count
|
|
161
189
|
decimal amount
|
|
162
190
|
string currency
|
|
163
|
-
|
|
191
|
+
date expires_at
|
|
164
192
|
}
|
|
165
193
|
```
|
|
166
194
|
|
|
@@ -218,7 +246,34 @@ flowchart TB
|
|
|
218
246
|
4. Click **Create**
|
|
219
247
|
5. Share the generated code with the recipient
|
|
220
248
|
|
|
221
|
-
Gift cards can also be created via the Admin API.
|
|
249
|
+
Gift cards can also be created via the [Admin API](../../api-reference/admin-api/introduction.md). The code is generated automatically if you don't supply one:
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
```typescript Admin SDK
|
|
253
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
254
|
+
|
|
255
|
+
const client = createAdminClient({
|
|
256
|
+
baseUrl: 'https://store.example.com',
|
|
257
|
+
secretKey: 'sk_xxx',
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
const giftCard = await client.giftCards.create({
|
|
261
|
+
amount: 50,
|
|
262
|
+
currency: 'USD',
|
|
263
|
+
expires_at: '2026-12-31',
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
console.log(giftCard.code) // share this with the recipient
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```bash CLI
|
|
270
|
+
spree api post /gift_cards -d '{
|
|
271
|
+
"amount": 50,
|
|
272
|
+
"currency": "USD",
|
|
273
|
+
"expires_at": "2026-12-31"
|
|
274
|
+
}'
|
|
275
|
+
```
|
|
276
|
+
|
|
222
277
|
|
|
223
278
|
#### Batch Gift Card Generation
|
|
224
279
|
|
|
@@ -233,6 +288,30 @@ For promotions or bulk distribution, you can create multiple gift cards at once
|
|
|
233
288
|
- **Expiration** - Optional expiration date
|
|
234
289
|
4. Click **Create**
|
|
235
290
|
|
|
291
|
+
Batches can also be created via the Admin API:
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
```typescript Admin SDK
|
|
295
|
+
const batch = await client.giftCardBatches.create({
|
|
296
|
+
prefix: 'HOLIDAY',
|
|
297
|
+
codes_count: 1000,
|
|
298
|
+
amount: 25,
|
|
299
|
+
currency: 'USD',
|
|
300
|
+
expires_at: '2026-12-31',
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
```bash CLI
|
|
305
|
+
spree api post /gift_card_batches -d '{
|
|
306
|
+
"prefix": "HOLIDAY",
|
|
307
|
+
"codes_count": 1000,
|
|
308
|
+
"amount": 25,
|
|
309
|
+
"currency": "USD",
|
|
310
|
+
"expires_at": "2026-12-31"
|
|
311
|
+
}'
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
|
|
236
315
|
> **INFO:** Large batches are processed in the background to avoid timeout issues.
|
|
237
316
|
|
|
238
317
|
### Redeeming Gift Cards
|
|
@@ -246,10 +325,10 @@ When a gift card is applied to an order:
|
|
|
246
325
|
- The gift card is marked as redeemed (or partially redeemed)
|
|
247
326
|
- No Store Credit is created for guest checkouts
|
|
248
327
|
|
|
249
|
-
Gift cards are applied
|
|
328
|
+
Gift cards are applied via a dedicated `POST /api/v3/store/carts/:cart_id/gift_cards` endpoint (separate from the `discount_codes` endpoint used for promotion codes); the discount-codes endpoint does not handle gift cards. See the [cart & checkout SDK guide](../sdk/store/cart-checkout.md) for the full cart flow these calls belong to.
|
|
250
329
|
|
|
251
330
|
|
|
252
|
-
```typescript SDK
|
|
331
|
+
```typescript Store SDK
|
|
253
332
|
// Apply gift card code to cart (works for guests and registered customers)
|
|
254
333
|
// Gift cards use a dedicated endpoint — they reduce amount_due, not total
|
|
255
334
|
const cart = await client.carts.giftCards.apply('cart_abc123', 'abc1234def', {
|
|
@@ -324,3 +403,5 @@ When a registered customer has multiple store credits, they are applied in order
|
|
|
324
403
|
- [Orders](orders.md) — Order management
|
|
325
404
|
- [Customers](customers.md) — Customer management
|
|
326
405
|
- [Events](events.md) — Event system and subscribers
|
|
406
|
+
- [Admin SDK Quickstart](../sdk/admin/quickstart.md) — Set up and authenticate the Admin SDK
|
|
407
|
+
- [Monetary Amounts](../../api-reference/store-api/monetary-amounts.md) — How the API represents `amount`, `amount_used`, and other money fields
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Stores
|
|
3
|
-
description: The Store is Spree's top-level multi-tenant boundary — learn how products, orders, channels,
|
|
3
|
+
description: The Store is Spree's top-level multi-tenant boundary — learn how products, orders, channels, and markets are scoped to a store.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
|
-
The Store is the top-level tenant in Spree. Every resource — products, orders, channels, markets, taxonomies
|
|
8
|
+
The Store is the top-level tenant in Spree. Every resource — products, orders, channels, markets, taxonomies — belongs to exactly one store. A store owns its branding (logo, custom domain, mail-from address), its [channels](channels.md) (online, POS, wholesale, …), its [markets](markets.md) (region/currency/locale), and its catalog.
|
|
9
9
|
|
|
10
10
|
## Store Attributes
|
|
11
11
|
|
|
@@ -19,33 +19,34 @@ The Store is the top-level tenant in Spree. Every resource — products, orders,
|
|
|
19
19
|
| `seo_title` | Custom SEO title |
|
|
20
20
|
| `customer_support_email` | Email for customer support inquiries |
|
|
21
21
|
| `mail_from_address` | Sender address for transactional emails |
|
|
22
|
-
| `
|
|
22
|
+
| `logo_url` | URL to the store's logo |
|
|
23
23
|
| `facebook`, `twitter`, `instagram` | Social media links |
|
|
24
|
-
| `payment_methods` | Payment methods available in this store |
|
|
25
24
|
|
|
26
25
|
## Fetching Store Information
|
|
27
26
|
|
|
28
|
-
Use the store endpoint to
|
|
27
|
+
Store configuration is exposed through the Admin API. Use the store endpoint to read the current store's settings — name, URL, branding, and email addresses:
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
```typescript SDK
|
|
32
|
-
const store = await
|
|
30
|
+
```typescript Admin SDK
|
|
31
|
+
const store = await adminClient.store.get()
|
|
33
32
|
// {
|
|
34
33
|
// name: "My Store",
|
|
35
34
|
// url: "https://mystore.com",
|
|
36
|
-
//
|
|
35
|
+
// logo_url: "https://cdn.mystore.com/logo.png",
|
|
36
|
+
// mailer_logo_url: "https://cdn.mystore.com/mailer-logo.png",
|
|
37
37
|
// customer_support_email: "support@mystore.com",
|
|
38
|
-
// payment_methods: [{ id: "pm_xxx", name: "Stripe", kind: "card" }],
|
|
39
38
|
// ...
|
|
40
39
|
// }
|
|
41
40
|
```
|
|
42
41
|
|
|
43
42
|
```bash cURL
|
|
44
|
-
curl 'https://api.mystore.com/api/v3/
|
|
45
|
-
-H 'X-Spree-API-Key:
|
|
43
|
+
curl 'https://api.mystore.com/api/v3/admin/store' \
|
|
44
|
+
-H 'X-Spree-API-Key: sk_xxx'
|
|
46
45
|
```
|
|
47
46
|
|
|
48
47
|
|
|
48
|
+
This is an admin endpoint, so it requires a secret API key (`sk_xxx`) or a Bearer JWT — a publishable key cannot reach it.
|
|
49
|
+
|
|
49
50
|
## Channels vs. Markets
|
|
50
51
|
|
|
51
52
|
Two different ways to split a store, often confused:
|
|
@@ -65,7 +66,7 @@ Each store owns its own resources. Products, orders, channels, markets, and taxo
|
|
|
65
66
|
| [**Markets**](markets.md) | A store has many markets, each defining a geographic region with its own currency and locale |
|
|
66
67
|
| [**Orders**](orders.md) | An order belongs to one store and one channel |
|
|
67
68
|
| [**Products**](products.md) | A product belongs to one store. Its visibility across channels is controlled by [publications](channels.md#publishing-products-on-channels). |
|
|
68
|
-
| [**Taxonomies**](products.md#
|
|
69
|
+
| [**Taxonomies**](products.md#categories) | A taxonomy belongs to one store |
|
|
69
70
|
| [**Payment Methods**](payments.md) | A payment method belongs to one store |
|
|
70
71
|
| [**Shipping Methods**](shipments.md) | A shipping method belongs to one store |
|
|
71
72
|
| [**Promotions**](promotions.md) | A promotion belongs to one store |
|
|
@@ -75,9 +76,9 @@ Each store owns its own resources. Products, orders, channels, markets, and taxo
|
|
|
75
76
|
If you need one Spree backend to serve **multiple distinct merchant brands** — different domains, different catalogs, different admin teams — there are two patterns:
|
|
76
77
|
|
|
77
78
|
- **Multiple channels under one store** (recommended for most cases) — model each storefront as a Sales Channel. Products are scoped per-channel via publications, orders carry the channel that originated them, and routing/pricing can differ per channel. This is the supported pattern in core Spree 5.5+.
|
|
78
|
-
- **Multiple stores in one app** — the legacy multi-store pattern, where each store is fully independent (catalog, admin, branding). In Spree 5.5+ this requires the
|
|
79
|
+
- **Multiple stores in one app** — the legacy multi-store pattern, where each store is fully independent (catalog, admin, branding). In Spree 5.5+ this requires the [spree_multi_store](../multi-store/quickstart.md) extension. Core Spree treats each product as belonging to a single store.
|
|
79
80
|
|
|
80
|
-
For most multi-brand operations, the channel pattern is simpler and more flexible. Reach for
|
|
81
|
+
For most multi-brand operations, the channel pattern is simpler and more flexible. Reach for [spree_multi_store](../multi-store/quickstart.md) only when stores need genuinely independent catalogs, branding, and admin teams.
|
|
81
82
|
|
|
82
83
|
## Related Documentation
|
|
83
84
|
|
|
@@ -85,3 +86,4 @@ For most multi-brand operations, the channel pattern is simpler and more flexibl
|
|
|
85
86
|
- [Markets](markets.md) — Multi-region commerce within a store
|
|
86
87
|
- [Products](products.md) — Product catalog
|
|
87
88
|
- [Orders](orders.md) — Order management and checkout
|
|
89
|
+
- [Admin SDK](../sdk/admin/quickstart.md) — TypeScript client for the Admin API used to read and update store configuration
|
|
@@ -55,6 +55,33 @@ Each product is assigned a tax category. One category can be set as the default
|
|
|
55
55
|
| `is_default` | Whether this is the default category | `true` |
|
|
56
56
|
| `tax_code` | Code from your tax provider (e.g., Stripe, Avalara) | `1257L` |
|
|
57
57
|
|
|
58
|
+
Manage tax categories via the [Admin API](../../api-reference/admin-api/introduction.md), using the [Admin SDK resource clients](../sdk/admin/resources.md):
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
```typescript Admin SDK
|
|
62
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
63
|
+
|
|
64
|
+
const client = createAdminClient({
|
|
65
|
+
baseUrl: 'https://store.example.com',
|
|
66
|
+
secretKey: 'sk_xxx',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const clothing = await client.taxCategories.create({
|
|
70
|
+
name: 'Clothing',
|
|
71
|
+
tax_code: '1257L',
|
|
72
|
+
is_default: true,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
await client.taxCategories.update('taxcat_xxx', { is_default: false })
|
|
76
|
+
await client.taxCategories.delete('taxcat_xxx')
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```bash CLI
|
|
80
|
+
spree api post /tax_categories -d '{"name": "Clothing", "tax_code": "1257L", "is_default": true}'
|
|
81
|
+
spree api get /tax_categories
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
|
|
58
85
|
## Tax Rates
|
|
59
86
|
|
|
60
87
|
Tax rates define the percentage charged for a specific tax category within a geographic zone.
|
|
@@ -133,3 +160,4 @@ Tax categories and rates are managed in the Admin Panel under **Settings → Tax
|
|
|
133
160
|
- [Addresses](addresses.md) — Zones and address-based taxation
|
|
134
161
|
- [Adjustments](adjustments.md) — Tax adjustments
|
|
135
162
|
- [Orders](orders.md) — How taxes affect order totals
|
|
163
|
+
- [Avalara integration](../../integrations/tax/avalara.md) — Automated tax calculation for complex jurisdictions
|
|
@@ -52,23 +52,23 @@ erDiagram
|
|
|
52
52
|
|
|
53
53
|
| Resource | Translatable Fields |
|
|
54
54
|
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
-
| Product | `name`, `description`, `slug`, `meta_description`, `
|
|
55
|
+
| Product | `name`, `description`, `slug`, `meta_description`, `meta_title` |
|
|
56
56
|
| Taxon | `name`, `description`, `permalink` |
|
|
57
57
|
| Taxonomy | `name` |
|
|
58
58
|
| Option Type | `presentation` |
|
|
59
59
|
| Option Value | `presentation` |
|
|
60
60
|
| Property | `presentation` |
|
|
61
61
|
| Product Property | `value` |
|
|
62
|
-
| Store | `name`, `meta_description`, `meta_keywords`, `seo_title`, `
|
|
62
|
+
| Store | `name`, `meta_description`, `meta_keywords`, `seo_title`, `customer_support_email`, `address`, `contact_phone` |
|
|
63
63
|
|
|
64
64
|
### Store API
|
|
65
65
|
|
|
66
|
-
To retrieve translated content, pass the locale via the `X-Spree-Locale` header or the SDK `locale` option:
|
|
66
|
+
To retrieve translated content, pass the locale via the [`X-Spree-Locale` header](../../api-reference/store-api/localization.md) or the SDK `locale` option:
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
```typescript SDK
|
|
69
|
+
```typescript Store SDK
|
|
70
70
|
// Fetch product in French
|
|
71
|
-
const product = await client.products.get('spree-tote', {
|
|
71
|
+
const product = await client.products.get('spree-tote', {}, {
|
|
72
72
|
locale: 'fr',
|
|
73
73
|
})
|
|
74
74
|
|
|
@@ -82,6 +82,14 @@ const { data: categories } = await client.categories.list({}, {
|
|
|
82
82
|
})
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
```typescript Admin SDK
|
|
86
|
+
// Pass the locale as a request option to get translated content.
|
|
87
|
+
// The Admin API resolves by prefixed ID only — slugs are not accepted.
|
|
88
|
+
const product = await adminClient.products.get('prod_86Rf07xd4z', {}, { locale: 'fr' })
|
|
89
|
+
|
|
90
|
+
const { data: categories } = await adminClient.categories.list({}, { locale: 'de' })
|
|
91
|
+
```
|
|
92
|
+
|
|
85
93
|
```bash cURL
|
|
86
94
|
# Fetch product in French
|
|
87
95
|
curl 'https://api.mystore.com/api/v3/store/products/spree-tote' \
|
|
@@ -96,11 +104,11 @@ Slugs are also localized — a product can have different slugs per locale. See
|
|
|
96
104
|
|
|
97
105
|
Translations are managed in the Admin Panel. When editing a product, taxon, or other translatable resource, switch the locale selector to enter content in each language.
|
|
98
106
|
|
|
99
|
-
Translations can also be managed via the Admin API.
|
|
107
|
+
Translations can also be [managed via the Admin API](../sdk/admin/quickstart.md).
|
|
100
108
|
|
|
101
109
|
## UI Translations
|
|
102
110
|
|
|
103
|
-
Spree stores UI translation strings in a separate project: [Spree I18n](https://github.com/spree/spree_i18n). This is a community-maintained project with locale files for 43+ languages.
|
|
111
|
+
Spree stores UI translation strings in a separate project: [Spree I18n](https://github.com/spree-contrib/spree_i18n). This is a community-maintained project with locale files for 43+ languages.
|
|
104
112
|
|
|
105
113
|
To install UI translations:
|
|
106
114
|
|
|
@@ -121,6 +129,7 @@ Once installed, all translation files are available automatically — no need to
|
|
|
121
129
|
## Related Documentation
|
|
122
130
|
|
|
123
131
|
- [Markets](markets.md) — Locale and currency configuration per geographic region
|
|
132
|
+
- [Localization](../../api-reference/store-api/localization.md) — Locale, currency, and country headers in API requests
|
|
124
133
|
- [Slugs](slugs.md) — Localized slugs and URL identifiers
|
|
125
134
|
- [Stores](stores.md) — Multi-store setup
|
|
126
135
|
- [Products](products.md) — Product translations
|
|
@@ -57,7 +57,7 @@ erDiagram
|
|
|
57
57
|
### Registration
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
```typescript SDK
|
|
60
|
+
```typescript Store SDK
|
|
61
61
|
const { token, user } = await client.customers.create({
|
|
62
62
|
email: 'john@example.com',
|
|
63
63
|
password: 'password123',
|
|
@@ -86,7 +86,7 @@ curl -X POST 'https://api.mystore.com/api/v3/store/customers' \
|
|
|
86
86
|
### Login
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
```typescript SDK
|
|
89
|
+
```typescript Store SDK
|
|
90
90
|
const { token, user } = await client.auth.login({
|
|
91
91
|
email: 'john@example.com',
|
|
92
92
|
password: 'password123',
|
|
@@ -105,29 +105,31 @@ curl -X POST 'https://api.mystore.com/api/v3/store/auth/login' \
|
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
The response includes a JWT
|
|
108
|
+
The response includes a [JWT token](../../api-reference/store-api/authentication.md) and a `user` object. Pass the token in subsequent requests via the `Authorization: Bearer <token>` header. See the [account SDK guide](../sdk/store/account.md) for the full `auth.login`, refresh, and profile flows.
|
|
109
109
|
|
|
110
110
|
### Token Refresh
|
|
111
111
|
|
|
112
112
|
Refresh an expiring token to keep the session alive:
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
```typescript SDK
|
|
115
|
+
```typescript Store SDK
|
|
116
116
|
const { token } = await client.auth.refresh({
|
|
117
|
-
|
|
117
|
+
refresh_token: existingRefreshToken,
|
|
118
118
|
})
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
```bash cURL
|
|
122
122
|
curl -X POST 'https://api.mystore.com/api/v3/store/auth/refresh' \
|
|
123
|
-
-H '
|
|
123
|
+
-H 'X-Spree-API-Key: pk_xxx' \
|
|
124
|
+
-H 'Content-Type: application/json' \
|
|
125
|
+
-d '{ "refresh_token": "rt_xxx" }'
|
|
124
126
|
```
|
|
125
127
|
|
|
126
128
|
|
|
127
129
|
### Customer Profile
|
|
128
130
|
|
|
129
131
|
|
|
130
|
-
```typescript SDK
|
|
132
|
+
```typescript Store SDK
|
|
131
133
|
// Get current customer
|
|
132
134
|
const customer = await client.customer.get()
|
|
133
135
|
// {
|
|
@@ -149,11 +151,11 @@ const updated = await client.customer.update({
|
|
|
149
151
|
|
|
150
152
|
```bash cURL
|
|
151
153
|
# Get current customer
|
|
152
|
-
curl 'https://api.mystore.com/api/v3/store/
|
|
154
|
+
curl 'https://api.mystore.com/api/v3/store/customers/me' \
|
|
153
155
|
-H 'Authorization: Bearer <jwt_token>'
|
|
154
156
|
|
|
155
157
|
# Update profile
|
|
156
|
-
curl -X PATCH 'https://api.mystore.com/api/v3/store/
|
|
158
|
+
curl -X PATCH 'https://api.mystore.com/api/v3/store/customers/me' \
|
|
157
159
|
-H 'Authorization: Bearer <jwt_token>' \
|
|
158
160
|
-H 'Content-Type: application/json' \
|
|
159
161
|
-d '{ "first_name": "Jonathan", "accepts_email_marketing": true }'
|
|
@@ -297,3 +299,5 @@ See the [Customize Permissions guide](../customization/permissions.md) for detai
|
|
|
297
299
|
- [Authentication](../customization/authentication.md) — Custom authentication setup
|
|
298
300
|
- [Permissions](../customization/permissions.md) — Roles and authorization
|
|
299
301
|
- [Events](events.md) — Subscribe to user and invitation events
|
|
302
|
+
- [Store API Authentication](../../api-reference/store-api/authentication.md) — Customer JWT auth flow
|
|
303
|
+
- [Admin API Authentication](../../api-reference/admin-api/authentication.md) — Staff JWT + scopes auth flow
|
|
@@ -56,20 +56,39 @@ flowchart LR
|
|
|
56
56
|
|
|
57
57
|
Navigate to **Settings → Developers → Webhooks** in the admin panel to create and manage webhook endpoints.
|
|
58
58
|
|
|
59
|
-
### Via
|
|
59
|
+
### Via the Admin API
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
|
|
62
|
+
```typescript Admin SDK
|
|
63
|
+
import { createAdminClient } from '@spree/admin-sdk'
|
|
64
|
+
|
|
65
|
+
const client = createAdminClient({
|
|
66
|
+
baseUrl: 'https://store.example.com',
|
|
67
|
+
secretKey: 'sk_xxx',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const endpoint = await client.webhookEndpoints.create({
|
|
64
71
|
url: 'https://example.com/webhooks/spree',
|
|
65
72
|
subscriptions: ['order.*', 'product.created'],
|
|
66
|
-
active: true
|
|
67
|
-
)
|
|
73
|
+
active: true,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// secret_key is auto-generated and returned ONLY on create —
|
|
77
|
+
// store it now for HMAC signature verification.
|
|
78
|
+
endpoint.secret_key // => "a1b2c3d4e5f6..." (64-character hex string)
|
|
79
|
+
```
|
|
68
80
|
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
```bash CLI
|
|
82
|
+
spree api post /webhook_endpoints -d '{
|
|
83
|
+
"url": "https://example.com/webhooks/spree",
|
|
84
|
+
"subscriptions": ["order.*", "product.created"],
|
|
85
|
+
"active": true
|
|
86
|
+
}'
|
|
71
87
|
```
|
|
72
88
|
|
|
89
|
+
|
|
90
|
+
> **WARNING:** The `secret_key` is returned **only once**, in the create response. Save it immediately — it can't be retrieved later and is required to verify webhook signatures.
|
|
91
|
+
|
|
73
92
|
### Endpoint Attributes
|
|
74
93
|
|
|
75
94
|
| Attribute | Type | Description |
|
|
@@ -78,41 +97,35 @@ endpoint.secret_key # => "a1b2c3d4e5f6..." (64-character hex string)
|
|
|
78
97
|
| `active` | Boolean | Enable/disable delivery to this endpoint |
|
|
79
98
|
| `subscriptions` | Array | Event patterns to subscribe to |
|
|
80
99
|
| `secret_key` | String | Auto-generated key for HMAC signature verification |
|
|
81
|
-
|
|
100
|
+
|
|
101
|
+
Endpoints always belong to the current store — the association is set automatically from the request scope, so you never pass it when creating or updating an endpoint.
|
|
82
102
|
|
|
83
103
|
## Event Subscriptions
|
|
84
104
|
|
|
85
|
-
The `subscriptions` attribute controls which events trigger webhooks to this endpoint.
|
|
105
|
+
The `subscriptions` attribute controls which events trigger webhooks to this endpoint. Set it when creating the endpoint, or change it later:
|
|
86
106
|
|
|
87
|
-
### Subscribe to Specific Events
|
|
88
107
|
|
|
89
|
-
```
|
|
90
|
-
|
|
108
|
+
```typescript Admin SDK
|
|
109
|
+
await client.webhookEndpoints.update('whe_xxx', {
|
|
110
|
+
subscriptions: ['order.completed', 'order.canceled'],
|
|
111
|
+
})
|
|
91
112
|
```
|
|
92
113
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```ruby
|
|
98
|
-
# All order events
|
|
99
|
-
endpoint.subscriptions = ['order.*']
|
|
100
|
-
|
|
101
|
-
# All creation events
|
|
102
|
-
endpoint.subscriptions = ['*.created']
|
|
103
|
-
|
|
104
|
-
# Multiple patterns
|
|
105
|
-
endpoint.subscriptions = ['order.*', 'payment.*', 'shipment.shipped']
|
|
114
|
+
```bash CLI
|
|
115
|
+
spree api patch /webhook_endpoints/whe_xxx \
|
|
116
|
+
-d '{"subscriptions": ["order.completed", "order.canceled"]}'
|
|
106
117
|
```
|
|
107
118
|
|
|
108
|
-
### Subscribe to All Events
|
|
109
119
|
|
|
110
|
-
|
|
120
|
+
The `subscriptions` array accepts exact event names and wildcard patterns:
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
| `subscriptions` value | Receives |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `['order.completed', 'order.canceled']` | Only those two events |
|
|
125
|
+
| `['order.*']` | All order events |
|
|
126
|
+
| `['*.created']` | All creation events |
|
|
127
|
+
| `['order.*', 'payment.*', 'shipment.shipped']` | Multiple patterns |
|
|
128
|
+
| `[]` or `['*']` | All events |
|
|
116
129
|
|
|
117
130
|
## Webhook Payload
|
|
118
131
|
|
|
@@ -126,10 +139,11 @@ Each webhook delivery sends a JSON payload with the following structure. The `da
|
|
|
126
139
|
"data": {
|
|
127
140
|
"id": "or_m3Rp9wXz",
|
|
128
141
|
"number": "R123456789",
|
|
129
|
-
"
|
|
142
|
+
"fulfillment_status": "shipped",
|
|
143
|
+
"payment_status": "paid",
|
|
130
144
|
"total": "99.99",
|
|
131
145
|
"display_total": "$99.99",
|
|
132
|
-
"
|
|
146
|
+
"total_quantity": 3,
|
|
133
147
|
"currency": "USD",
|
|
134
148
|
"items": [ ... ],
|
|
135
149
|
"fulfillments": [ ... ],
|
|
@@ -163,6 +177,7 @@ Each webhook request includes these headers:
|
|
|
163
177
|
| `User-Agent` | `Spree-Webhooks/1.0` |
|
|
164
178
|
| `X-Spree-Webhook-Event` | Event name (e.g., `order.completed`) |
|
|
165
179
|
| `X-Spree-Webhook-Signature` | HMAC-SHA256 signature for verification |
|
|
180
|
+
| `X-Spree-Webhook-Timestamp` | Unix timestamp (seconds) generated at send time; included in the HMAC-SHA256 signed string as `{timestamp}.{payload}` and required to verify `X-Spree-Webhook-Signature` |
|
|
166
181
|
|
|
167
182
|
### Verifying Webhook Signatures
|
|
168
183
|
|
|
@@ -244,21 +259,23 @@ Failed webhook deliveries automatically retry up to 5 times with exponential bac
|
|
|
244
259
|
|
|
245
260
|
### Checking Delivery Status
|
|
246
261
|
|
|
247
|
-
|
|
248
|
-
endpoint = Spree::WebhookEndpoint.find(id)
|
|
262
|
+
Inspect an endpoint's delivery log, and re-send a failed delivery, via the Admin API:
|
|
249
263
|
|
|
250
|
-
# Recent deliveries
|
|
251
|
-
endpoint.webhook_deliveries.recent
|
|
252
264
|
|
|
253
|
-
|
|
254
|
-
endpoint
|
|
255
|
-
|
|
256
|
-
|
|
265
|
+
```typescript Admin SDK
|
|
266
|
+
// Recent deliveries for an endpoint
|
|
267
|
+
const { data: deliveries } = await client.webhookEndpoints.deliveries.list('whe_xxx')
|
|
268
|
+
|
|
269
|
+
// Re-send a specific delivery
|
|
270
|
+
await client.webhookEndpoints.deliveries.redeliver('whe_xxx', 'whd_xxx')
|
|
271
|
+
```
|
|
257
272
|
|
|
258
|
-
|
|
259
|
-
|
|
273
|
+
```bash CLI
|
|
274
|
+
spree api get /webhook_endpoints/whe_xxx/deliveries -q event_name_eq=order.completed
|
|
275
|
+
spree api post /webhook_endpoints/whe_xxx/deliveries/whd_xxx/redeliver
|
|
260
276
|
```
|
|
261
277
|
|
|
278
|
+
|
|
262
279
|
### Delivery Attributes
|
|
263
280
|
|
|
264
281
|
| Attribute | Description |
|
|
@@ -309,31 +326,38 @@ Common webhook events include:
|
|
|
309
326
|
| `payment.paid` | Payment was completed |
|
|
310
327
|
| `product.created` | New product created |
|
|
311
328
|
| `product.updated` | Product was modified |
|
|
312
|
-
| `
|
|
329
|
+
| `user.created` | New customer/user registered (the admin user class emits `admin.created`) |
|
|
313
330
|
|
|
314
331
|
## Testing Webhooks
|
|
315
332
|
|
|
316
333
|
### In Development
|
|
317
334
|
|
|
318
|
-
Use tools like [ngrok](https://ngrok.com) or [webhook.site](https://webhook.site) to test webhooks locally:
|
|
335
|
+
Use tools like [ngrok](https://ngrok.com) or [webhook.site](https://webhook.site) to test webhooks locally. Create a test endpoint pointed at the tunnel:
|
|
319
336
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
endpoint =
|
|
323
|
-
store: Spree::Store.default,
|
|
337
|
+
|
|
338
|
+
```typescript Admin SDK
|
|
339
|
+
const endpoint = await client.webhookEndpoints.create({
|
|
324
340
|
url: 'https://your-ngrok-url.ngrok.io/webhooks',
|
|
325
341
|
subscriptions: ['order.*'],
|
|
326
|
-
active: true
|
|
327
|
-
)
|
|
342
|
+
active: true,
|
|
343
|
+
})
|
|
328
344
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
// Fire a synthetic delivery to confirm it's reachable
|
|
346
|
+
await client.webhookEndpoints.sendTest(endpoint.id)
|
|
347
|
+
```
|
|
332
348
|
|
|
333
|
-
|
|
334
|
-
|
|
349
|
+
```bash CLI
|
|
350
|
+
spree api post /webhook_endpoints -d '{
|
|
351
|
+
"url": "https://your-ngrok-url.ngrok.io/webhooks",
|
|
352
|
+
"subscriptions": ["order.*"],
|
|
353
|
+
"active": true
|
|
354
|
+
}'
|
|
355
|
+
spree api post /webhook_endpoints/whe_xxx/send_test
|
|
335
356
|
```
|
|
336
357
|
|
|
358
|
+
|
|
359
|
+
`send_test` delivers a synthetic `webhook.test` event so you can verify the endpoint is reachable and your signature-verification code works, without having to trigger a real order.
|
|
360
|
+
|
|
337
361
|
### In Tests
|
|
338
362
|
|
|
339
363
|
```ruby
|
|
@@ -381,18 +405,25 @@ end
|
|
|
381
405
|
|
|
382
406
|
### Deliveries Failing
|
|
383
407
|
|
|
384
|
-
Check the delivery
|
|
408
|
+
Check the delivery records for details — each carries `error_type`, `request_errors`, `response_code`, and `response_body`. Filter the log with [Ransack predicates](../../api-reference/admin-api/querying.md) such as `success_eq=false` or `event_name_eq`:
|
|
385
409
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
410
|
+
|
|
411
|
+
```typescript Admin SDK
|
|
412
|
+
const { data: deliveries } = await client.webhookEndpoints.deliveries.list('whe_xxx', {
|
|
413
|
+
success_eq: false,
|
|
414
|
+
})
|
|
415
|
+
const failed = deliveries[0]
|
|
416
|
+
// failed.error_type, failed.request_errors, failed.response_code, failed.response_body
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
```bash CLI
|
|
420
|
+
spree api get /webhook_endpoints/whe_xxx/deliveries -q success_eq=false
|
|
392
421
|
```
|
|
393
422
|
|
|
423
|
+
|
|
394
424
|
## Related Documentation
|
|
395
425
|
|
|
396
426
|
- [Events](events.md) - Understanding Spree's event system
|
|
427
|
+
- [Admin SDK](../sdk/admin/quickstart.md) - Setting up the `@spree/admin-sdk` client used in the management examples above
|
|
397
428
|
- [Customization Quickstart](../customization/quickstart.md) - Overview of all customization options
|
|
398
429
|
- [Dependencies](../customization/dependencies.md) - Customizing Spree services
|