@spree/docs 0.1.0
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/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @spree/docs
|
|
2
|
+
|
|
3
|
+
Spree Commerce developer documentation packaged for local access by AI agents and development tools.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @spree/docs
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @spree/docs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Documentation files are plain Markdown, accessible at:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
node_modules/@spree/docs/dist/
|
|
19
|
+
├── developer/
|
|
20
|
+
│ ├── core-concepts/ # Products, orders, payments, inventory, etc.
|
|
21
|
+
│ ├── customization/ # Decorators, extensions, configuration
|
|
22
|
+
│ ├── admin/ # Admin panel customization
|
|
23
|
+
│ ├── storefront/ # Storefront building guides
|
|
24
|
+
│ ├── sdk/ # TypeScript SDK documentation
|
|
25
|
+
│ ├── deployment/ # Deployment guides
|
|
26
|
+
│ └── tutorial/ # Step-by-step tutorials
|
|
27
|
+
├── api-reference/
|
|
28
|
+
│ └── store-api/ # Store API reference
|
|
29
|
+
└── integrations/ # Third-party integration guides
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### For AI Agents
|
|
33
|
+
|
|
34
|
+
Point your `CLAUDE.md` or agent configuration to the docs:
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
## Spree Documentation
|
|
38
|
+
Full developer docs: `node_modules/@spree/docs/dist/`
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Programmatic Access (Node.js)
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import { readFileSync } from 'fs'
|
|
45
|
+
import { createRequire } from 'module'
|
|
46
|
+
|
|
47
|
+
const require = createRequire(import.meta.url)
|
|
48
|
+
const docsPath = require.resolve('@spree/docs/dist/developer/core-concepts/products.md')
|
|
49
|
+
const content = readFileSync(docsPath, 'utf-8')
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
CC-BY-4.0 — same as the Spree Commerce documentation.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Platform API is meant to be used by external applications to perform operations within Spree. Because of that, it uses a different authentication schema than the Storefront API.
|
|
2
|
+
|
|
3
|
+
### Creating an application inside Spree
|
|
4
|
+
|
|
5
|
+
To generate a valid token for the Platform API, you'll first need to create an application inside Spree.
|
|
6
|
+
|
|
7
|
+
1. Go to Spree's admin panel and open `Apps` -> `oAuth Applications` in the menu
|
|
8
|
+
|
|
9
|
+
<img src="/images/Platform API 1.png"/>
|
|
10
|
+
|
|
11
|
+
2. Click on `New oAuth Application`
|
|
12
|
+
|
|
13
|
+
<img src="/images/Platform API 2.png"/>
|
|
14
|
+
|
|
15
|
+
3. Give your application a name and click `Create`
|
|
16
|
+
|
|
17
|
+
<img src="/images/Platform API 3.png"/>
|
|
18
|
+
|
|
19
|
+
4. Save your Client ID and Secret - you'll later use it to generate a OAuth token to access the platform API
|
|
20
|
+
|
|
21
|
+
<img src="/images/Platform API 4.png"/>
|
|
22
|
+
|
|
23
|
+
### Generating OAuth token
|
|
24
|
+
|
|
25
|
+
Once the application is configured inside Spree, you can use its credentials to generate an OAuth token that will give you access to the APIs.
|
|
26
|
+
|
|
27
|
+
To obtain the token, send the following `POST` request to `/spree_oauth/token`
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"grant_type": "client_credentials",
|
|
32
|
+
"client_id": "xxx",
|
|
33
|
+
"client_secret": "xxx",
|
|
34
|
+
"scope": "admin"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
In the response, you'll receive a token to pass in `Authorization: Bearer {token}` header when making requests to the Platform API.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Authentication"
|
|
3
|
+
sidebarTitle: "Authentication"
|
|
4
|
+
description: "How to authenticate requests to the Store API"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The Store API uses three authentication mechanisms depending on the use case: **API keys** for all requests, **JWT tokens** for authenticated customers, and **order tokens** for guest checkout.
|
|
8
|
+
|
|
9
|
+
## API Key (Required)
|
|
10
|
+
|
|
11
|
+
Every request to the Store API requires a **publishable API key**. This key identifies your storefront and is safe to use in client-side code.
|
|
12
|
+
|
|
13
|
+
Pass the key via the `X-Spree-Api-Key` header:
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
```typescript SDK
|
|
17
|
+
import { createClient } from '@spree/sdk'
|
|
18
|
+
|
|
19
|
+
const client = createClient({
|
|
20
|
+
baseUrl: 'http://localhost:3000',
|
|
21
|
+
publishableKey: 'spree_pk_xxx',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// The SDK automatically sends the publishable key with every request
|
|
25
|
+
const products = await client.products.list()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash cURL
|
|
29
|
+
curl -X GET 'http://localhost:3000/api/v3/store/products' \
|
|
30
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
Publishable API keys are prefixed with `spree_pk_`. You can create them in the Spree Admin under **Settings > API Keys** or via the Spree CLI:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
spree api-key create # Create a new API key
|
|
38
|
+
spree api-key list # List existing API keys
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> **WARNING:** If you omit the API key, the API returns a `401 Unauthorized` error:
|
|
42
|
+
>
|
|
43
|
+
> ```json
|
|
44
|
+
{
|
|
45
|
+
"error": {
|
|
46
|
+
"code": "invalid_token",
|
|
47
|
+
"message": "Valid API key required"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## JWT Token (Authenticated Customer)
|
|
53
|
+
|
|
54
|
+
For actions that require a logged-in customer (viewing orders, managing addresses, saved payment methods), use a **JWT bearer token** in addition to the API key.
|
|
55
|
+
|
|
56
|
+
### Login
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
```typescript SDK
|
|
60
|
+
// Login to get a JWT token
|
|
61
|
+
const { token, user } = await client.auth.login({
|
|
62
|
+
email: 'customer@example.com',
|
|
63
|
+
password: 'password123',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// Use the token for authenticated requests
|
|
67
|
+
const orders = await client.customer.orders.list({}, { token })
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```bash cURL
|
|
71
|
+
# Login
|
|
72
|
+
curl -X POST 'http://localhost:3000/api/v3/store/auth/login' \
|
|
73
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
74
|
+
-H 'Content-Type: application/json' \
|
|
75
|
+
-d '{"email": "customer@example.com", "password": "password123"}'
|
|
76
|
+
|
|
77
|
+
# Use the returned token for authenticated requests
|
|
78
|
+
curl -X GET 'http://localhost:3000/api/v3/store/orders' \
|
|
79
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
80
|
+
-H 'Authorization: Bearer <jwt_token>'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Register
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
```typescript SDK
|
|
88
|
+
const { token, user } = await client.customers.create({
|
|
89
|
+
email: 'new@example.com',
|
|
90
|
+
password: 'password123',
|
|
91
|
+
password_confirmation: 'password123',
|
|
92
|
+
first_name: 'John',
|
|
93
|
+
last_name: 'Doe',
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```bash cURL
|
|
98
|
+
curl -X POST 'http://localhost:3000/api/v3/store/customers' \
|
|
99
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
100
|
+
-H 'Content-Type: application/json' \
|
|
101
|
+
-d '{
|
|
102
|
+
"email": "new@example.com",
|
|
103
|
+
"password": "password123",
|
|
104
|
+
"password_confirmation": "password123",
|
|
105
|
+
"first_name": "John",
|
|
106
|
+
"last_name": "Doe"
|
|
107
|
+
}'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
### Token Refresh
|
|
112
|
+
|
|
113
|
+
JWT tokens expire after 1 hour by default. Use the refresh endpoint to get a new token:
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
```typescript SDK
|
|
117
|
+
const { token } = await client.auth.refresh({ token: currentToken })
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```bash cURL
|
|
121
|
+
curl -X POST 'http://localhost:3000/api/v3/store/auth/refresh' \
|
|
122
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
123
|
+
-H 'Authorization: Bearer <current_jwt_token>'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
## Order Token (Guest Checkout)
|
|
128
|
+
|
|
129
|
+
For guest checkout flows, use the **order token** returned when creating a cart. This allows unauthenticated users to manage their cart and complete checkout.
|
|
130
|
+
|
|
131
|
+
Pass the token via the `x-spree-token` header:
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
```typescript SDK
|
|
135
|
+
// Create a cart (guest)
|
|
136
|
+
const cart = await client.carts.create()
|
|
137
|
+
|
|
138
|
+
// Use spreeToken for all guest cart operations
|
|
139
|
+
const options = { spreeToken: cart.token }
|
|
140
|
+
|
|
141
|
+
// Add items
|
|
142
|
+
await client.carts.items.create(cart.id, {
|
|
143
|
+
variant_id: 'variant_abc123',
|
|
144
|
+
quantity: 1,
|
|
145
|
+
}, options)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```bash cURL
|
|
149
|
+
# Create a cart
|
|
150
|
+
curl -X POST 'http://localhost:3000/api/v3/store/carts' \
|
|
151
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx'
|
|
152
|
+
|
|
153
|
+
# Use the returned token for cart operations
|
|
154
|
+
curl -X POST 'http://localhost:3000/api/v3/store/carts/cart_xxx/items' \
|
|
155
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
156
|
+
-H 'X-Spree-Token: <order_token>' \
|
|
157
|
+
-H 'Content-Type: application/json' \
|
|
158
|
+
-d '{"variant_id": "variant_abc123", "quantity": 1}'
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### Associating a Guest Cart
|
|
163
|
+
|
|
164
|
+
After a guest user logs in, you can associate their guest cart with their account:
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
```typescript SDK
|
|
168
|
+
await client.carts.associate(cart.id, {
|
|
169
|
+
token: jwtToken,
|
|
170
|
+
spreeToken: cart.token,
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```bash cURL
|
|
175
|
+
curl -X PATCH 'http://localhost:3000/api/v3/store/carts/cart_xxx/associate' \
|
|
176
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
177
|
+
-H 'Authorization: Bearer <jwt_token>' \
|
|
178
|
+
-H 'X-Spree-Token: <order_token>'
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
## Authentication Summary
|
|
183
|
+
|
|
184
|
+
| Method | Header | Use Case |
|
|
185
|
+
|--------|--------|----------|
|
|
186
|
+
| API Key | `X-Spree-Api-Key: spree_pk_xxx` | All requests (required) |
|
|
187
|
+
| JWT Token | `Authorization: Bearer <token>` | Authenticated customer actions |
|
|
188
|
+
| Order Token | `X-Spree-Token: <token>` | Guest cart and checkout |
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Errors
|
|
3
|
+
description: Error response format, error codes, and handling strategies
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The Store API uses a consistent, Stripe-style error format across all endpoints. Every error response includes a machine-readable `code` and a human-readable `message`.
|
|
7
|
+
|
|
8
|
+
## Error Response Format
|
|
9
|
+
|
|
10
|
+
All errors return a JSON object with a single `error` key:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"error": {
|
|
15
|
+
"code": "record_not_found",
|
|
16
|
+
"message": "Product not found"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Validation errors include an additional `details` field with per-field error messages:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"error": {
|
|
26
|
+
"code": "validation_error",
|
|
27
|
+
"message": "Name can't be blank and Email is invalid",
|
|
28
|
+
"details": {
|
|
29
|
+
"name": ["can't be blank"],
|
|
30
|
+
"email": ["is invalid"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Schema
|
|
37
|
+
|
|
38
|
+
| Field | Type | Description |
|
|
39
|
+
|-------|------|-------------|
|
|
40
|
+
| `error.code` | `string` | Machine-readable error code (see table below) |
|
|
41
|
+
| `error.message` | `string` | Human-readable description of the error |
|
|
42
|
+
| `error.details` | `object` | Field-specific validation errors. Each key is a field name, each value is an array of error strings. Only present for validation errors. |
|
|
43
|
+
|
|
44
|
+
## HTTP Status Codes
|
|
45
|
+
|
|
46
|
+
| Status | Meaning | When |
|
|
47
|
+
|--------|---------|------|
|
|
48
|
+
| `400` | Bad Request | Missing required parameters, malformed JSON, invalid arguments |
|
|
49
|
+
| `401` | Unauthorized | Missing or invalid API key, expired JWT token |
|
|
50
|
+
| `403` | Forbidden | Authenticated but not authorized for this resource |
|
|
51
|
+
| `404` | Not Found | Resource doesn't exist or isn't accessible |
|
|
52
|
+
| `409` | Conflict | Resource was modified by another request (concurrent update) |
|
|
53
|
+
| `422` | Unprocessable Content | Validation failed, invalid state transition, payment error |
|
|
54
|
+
| `429` | Too Many Requests | Rate limit exceeded (see [Rate Limiting](/api-reference/store-api/rate-limitting)) |
|
|
55
|
+
|
|
56
|
+
## Error Codes
|
|
57
|
+
|
|
58
|
+
### Authentication & Authorization
|
|
59
|
+
|
|
60
|
+
| Code | Status | Description |
|
|
61
|
+
|------|--------|-------------|
|
|
62
|
+
| `authentication_required` | 401 | Request requires a valid JWT token |
|
|
63
|
+
| `authentication_failed` | 401 | Email or password is incorrect |
|
|
64
|
+
| `invalid_token` | 401 | API key or JWT token is invalid or expired |
|
|
65
|
+
| `invalid_provider` | 400 | OAuth provider not recognized |
|
|
66
|
+
| `access_denied` | 403 | User doesn't have permission for this action |
|
|
67
|
+
|
|
68
|
+
### Resource Errors
|
|
69
|
+
|
|
70
|
+
| Code | Status | Description |
|
|
71
|
+
|------|--------|-------------|
|
|
72
|
+
| `record_not_found` | 404 | Resource doesn't exist or isn't accessible in the current store |
|
|
73
|
+
| `resource_invalid` | 422 | Resource couldn't be saved |
|
|
74
|
+
|
|
75
|
+
### Validation Errors
|
|
76
|
+
|
|
77
|
+
| Code | Status | Description |
|
|
78
|
+
|------|--------|-------------|
|
|
79
|
+
| `validation_error` | 422 | Model validation failed. Check `details` for field-specific messages. |
|
|
80
|
+
| `parameter_missing` | 400 | A required parameter is missing |
|
|
81
|
+
| `parameter_invalid` | 400 | A parameter has an invalid value |
|
|
82
|
+
|
|
83
|
+
### Cart Errors
|
|
84
|
+
|
|
85
|
+
| Code | Status | Description |
|
|
86
|
+
|------|--------|-------------|
|
|
87
|
+
| `cart_not_found` | 404 | Cart doesn't exist or doesn't belong to the current user/guest |
|
|
88
|
+
| `cart_cannot_complete` | 422 | Cart cannot be completed (e.g., missing payment or address) |
|
|
89
|
+
| `cart_cannot_transition` | 422 | Internal state machine transition failed (e.g., completing a cart that isn't ready) |
|
|
90
|
+
| `cart_empty` | 422 | Cart has no line items |
|
|
91
|
+
| `cart_invalid_state` | 422 | Cart is in an invalid state for this operation |
|
|
92
|
+
| `cart_already_updated` | 409 | Cart was modified by another request (optimistic locking conflict) |
|
|
93
|
+
|
|
94
|
+
### Order Errors
|
|
95
|
+
|
|
96
|
+
| Code | Status | Description |
|
|
97
|
+
|------|--------|-------------|
|
|
98
|
+
| `order_not_found` | 404 | Completed order doesn't exist or doesn't belong to the current user/guest |
|
|
99
|
+
|
|
100
|
+
### Line Item & Stock Errors
|
|
101
|
+
|
|
102
|
+
| Code | Status | Description |
|
|
103
|
+
|------|--------|-------------|
|
|
104
|
+
| `line_item_not_found` | 404 | Line item doesn't exist in this order |
|
|
105
|
+
| `variant_not_found` | 404 | Variant doesn't exist or isn't available |
|
|
106
|
+
| `insufficient_stock` | 422 | Not enough stock to fulfill the requested quantity |
|
|
107
|
+
| `invalid_quantity` | 422 | Quantity must be a positive integer |
|
|
108
|
+
|
|
109
|
+
### Payment Errors
|
|
110
|
+
|
|
111
|
+
| Code | Status | Description |
|
|
112
|
+
|------|--------|-------------|
|
|
113
|
+
| `payment_failed` | 422 | Payment was declined or couldn't be processed |
|
|
114
|
+
| `payment_processing_error` | 422 | Error communicating with the payment gateway |
|
|
115
|
+
| `gateway_error` | 422 | Payment gateway returned an error |
|
|
116
|
+
|
|
117
|
+
### Digital Download Errors
|
|
118
|
+
|
|
119
|
+
| Code | Status | Description |
|
|
120
|
+
|------|--------|-------------|
|
|
121
|
+
| `attachment_missing` | 403 | File attachment not found for this digital product |
|
|
122
|
+
| `download_unauthorized` | 403 | User is not authorized to download this file |
|
|
123
|
+
| `digital_link_expired` | 403 | Download link has expired |
|
|
124
|
+
| `download_limit_exceeded` | 403 | Maximum number of downloads reached |
|
|
125
|
+
|
|
126
|
+
### Concurrency & Idempotency Errors
|
|
127
|
+
|
|
128
|
+
| Code | Status | Description |
|
|
129
|
+
|------|--------|-------------|
|
|
130
|
+
| `order_already_updated` | 409 | Order was modified by another concurrent request. Retry with fresh data. |
|
|
131
|
+
| `idempotency_key_reused` | 422 | Idempotency key was already used with different request parameters. See [Idempotency](/api-reference/store-api/idempotency). |
|
|
132
|
+
|
|
133
|
+
### Other Errors
|
|
134
|
+
|
|
135
|
+
| Code | Status | Description |
|
|
136
|
+
|------|--------|-------------|
|
|
137
|
+
| `rate_limit_exceeded` | 429 | Too many requests. Retry after the `Retry-After` header value. |
|
|
138
|
+
| `request_too_large` | 413 | Request body exceeds the size limit |
|
|
139
|
+
| `processing_error` | 422 | Generic server-side processing error |
|
|
140
|
+
| `invalid_request` | 400 | Request is malformed (e.g., invalid JSON body) |
|
|
141
|
+
|
|
142
|
+
## Examples
|
|
143
|
+
|
|
144
|
+
### Not Found
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
curl https://api.mystore.com/api/v3/store/products/prod_nonexistent \
|
|
148
|
+
-H "Authorization: Bearer spree_pk_xxx"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```json 404
|
|
152
|
+
{
|
|
153
|
+
"error": {
|
|
154
|
+
"code": "record_not_found",
|
|
155
|
+
"message": "Product not found"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Validation Error
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
curl -X POST https://api.mystore.com/api/v3/store/account/addresses \
|
|
164
|
+
-H "Authorization: Bearer <jwt_token>" \
|
|
165
|
+
-H "Content-Type: application/json" \
|
|
166
|
+
-d '{}'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```json 422
|
|
170
|
+
{
|
|
171
|
+
"error": {
|
|
172
|
+
"code": "validation_error",
|
|
173
|
+
"message": "First name can't be blank, Address can't be blank, City can't be blank, and Country can't be blank",
|
|
174
|
+
"details": {
|
|
175
|
+
"firstname": ["can't be blank"],
|
|
176
|
+
"address1": ["can't be blank"],
|
|
177
|
+
"city": ["can't be blank"],
|
|
178
|
+
"country": ["can't be blank"]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Insufficient Stock
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/items \
|
|
188
|
+
-H "Authorization: Bearer spree_pk_xxx" \
|
|
189
|
+
-H "X-Spree-Token: abc123" \
|
|
190
|
+
-H "Content-Type: application/json" \
|
|
191
|
+
-d '{"variant_id": "var_xxx", "quantity": 999}'
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```json 422
|
|
195
|
+
{
|
|
196
|
+
"error": {
|
|
197
|
+
"code": "insufficient_stock",
|
|
198
|
+
"message": "Quantity selected exceeds available stock"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Invalid State Transition
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/complete \
|
|
207
|
+
-H "Authorization: Bearer spree_pk_xxx"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```json 422
|
|
211
|
+
{
|
|
212
|
+
"error": {
|
|
213
|
+
"code": "cart_cannot_transition",
|
|
214
|
+
"message": "Cannot transition cart to complete — ensure address, shipping, and payment are set"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Handling Errors in the SDK
|
|
220
|
+
|
|
221
|
+
The `@spree/sdk` package throws a `SpreeError` for all non-2xx responses:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { SpreeError } from '@spree/sdk';
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const product = await client.products.get('nonexistent');
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (error instanceof SpreeError) {
|
|
230
|
+
console.log(error.code); // 'record_not_found'
|
|
231
|
+
console.log(error.message); // 'Product not found'
|
|
232
|
+
console.log(error.status); // 404
|
|
233
|
+
console.log(error.details); // undefined (or field errors for validation)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Common Patterns
|
|
239
|
+
|
|
240
|
+
Handle specific error codes:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
try {
|
|
244
|
+
await client.carts.items.create(cartId, {
|
|
245
|
+
variant_id: variantId,
|
|
246
|
+
quantity: 1,
|
|
247
|
+
});
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (error instanceof SpreeError) {
|
|
250
|
+
switch (error.code) {
|
|
251
|
+
case 'insufficient_stock':
|
|
252
|
+
showNotification('This item is out of stock');
|
|
253
|
+
break;
|
|
254
|
+
case 'variant_not_found':
|
|
255
|
+
showNotification('This product is no longer available');
|
|
256
|
+
break;
|
|
257
|
+
default:
|
|
258
|
+
showNotification(error.message);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Display validation errors per field:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
try {
|
|
268
|
+
await client.customer.addresses.create(addressData);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (error instanceof SpreeError && error.details) {
|
|
271
|
+
// error.details = { city: ["can't be blank"], zipcode: ["is invalid"] }
|
|
272
|
+
for (const [field, messages] of Object.entries(error.details)) {
|
|
273
|
+
setFieldError(field, messages.join(', '));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Idempotency"
|
|
3
|
+
sidebarTitle: "Idempotency"
|
|
4
|
+
description: "Prevent duplicate operations with idempotency keys"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The Store API supports idempotency keys on mutating endpoints. This lets you safely retry requests without risking duplicate side effects — for example, adding an item to cart twice or creating duplicate payments due to network timeouts.
|
|
8
|
+
|
|
9
|
+
## How It Works
|
|
10
|
+
|
|
11
|
+
Include an `Idempotency-Key` header with a unique value (e.g., a UUID) on any supported request. The API will:
|
|
12
|
+
|
|
13
|
+
1. **First request** — process normally and cache the response for 24 hours
|
|
14
|
+
2. **Duplicate request** (same key, same parameters) — return the cached response without re-executing the operation
|
|
15
|
+
3. **Key reuse with different parameters** — return a `422` error to prevent misuse
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/items \
|
|
19
|
+
-H "Authorization: Bearer spree_pk_xxx" \
|
|
20
|
+
-H "X-Spree-Token: abc123" \
|
|
21
|
+
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
|
|
22
|
+
-H "Content-Type: application/json" \
|
|
23
|
+
-d '{"variant_id": "variant_xxx", "quantity": 1}'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If the client retries this exact request with the same idempotency key, the API returns the original response with an `Idempotent-Replayed: true` header — without adding the item again.
|
|
27
|
+
|
|
28
|
+
## Supported Endpoints
|
|
29
|
+
|
|
30
|
+
| Endpoint | Actions |
|
|
31
|
+
|----------|---------|
|
|
32
|
+
| `POST /carts` | Cart creation |
|
|
33
|
+
| `PATCH /carts/:id` | Cart updates |
|
|
34
|
+
| `POST /carts/:id/complete` | Order completion |
|
|
35
|
+
| `POST /carts/:id/items` | Adding items to cart |
|
|
36
|
+
| `POST /carts/:id/payment_sessions` | Payment session creation |
|
|
37
|
+
| `PATCH /carts/:id/payment_sessions/:id/complete` | Payment completion |
|
|
38
|
+
| `POST /carts/:id/coupon_codes` | Applying coupon codes |
|
|
39
|
+
| `POST /carts/:id/store_credits` | Applying store credits |
|
|
40
|
+
|
|
41
|
+
Idempotency keys are ignored on `GET`, `DELETE`, and other non-supported actions.
|
|
42
|
+
|
|
43
|
+
## Key Requirements
|
|
44
|
+
|
|
45
|
+
- Must be a string of **255 characters or less**
|
|
46
|
+
- Should be unique per distinct operation (UUIDs are recommended)
|
|
47
|
+
- Keys are scoped per API key — different API keys can use the same idempotency key without conflict
|
|
48
|
+
- Cached responses expire after **24 hours**
|
|
49
|
+
|
|
50
|
+
## Response Headers
|
|
51
|
+
|
|
52
|
+
When a cached response is replayed, the API sets:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Idempotent-Replayed: true
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
You can use this header to detect replayed responses in your application or logging.
|
|
59
|
+
|
|
60
|
+
## Error Handling
|
|
61
|
+
|
|
62
|
+
### Key Reuse with Different Parameters
|
|
63
|
+
|
|
64
|
+
If you send a request with an idempotency key that was previously used with different request parameters (different body, different path), the API returns a `422` error:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"error": {
|
|
69
|
+
"code": "idempotency_key_reused",
|
|
70
|
+
"message": "This Idempotency-Key has already been used with different request parameters."
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Key Too Long
|
|
76
|
+
|
|
77
|
+
Keys longer than 255 characters return a `400` error:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"error": {
|
|
82
|
+
"code": "invalid_request",
|
|
83
|
+
"message": "Idempotency-Key must be 255 characters or less."
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Server Errors
|
|
89
|
+
|
|
90
|
+
`5xx` responses are **not cached**. If the server fails to process your request, you can safely retry with the same idempotency key and the request will be re-executed.
|
|
91
|
+
|
|
92
|
+
## SDK Usage
|
|
93
|
+
|
|
94
|
+
The Spree SDK supports idempotency keys via the `idempotencyKey` option:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { createClient } from '@spree/sdk'
|
|
98
|
+
|
|
99
|
+
const client = createClient({
|
|
100
|
+
baseUrl: 'http://localhost:3000',
|
|
101
|
+
publishableKey: 'spree_pk_xxx',
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Add item to cart with idempotency key
|
|
105
|
+
await client.carts.items.create(cartId, {
|
|
106
|
+
variant_id: 'variant_xxx',
|
|
107
|
+
quantity: 1,
|
|
108
|
+
}, {
|
|
109
|
+
idempotencyKey: '550e8400-e29b-41d4-a716-446655440000',
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Best Practices
|
|
114
|
+
|
|
115
|
+
- **Generate a new key for each distinct operation.** Use a UUID (v4) or another random identifier. Never reuse keys across different operations.
|
|
116
|
+
- **Store the key before sending the request.** If the request fails due to a network error, retry with the same key to ensure the operation is only performed once.
|
|
117
|
+
- **Don't use idempotency keys for GET requests.** GET requests are naturally idempotent and the API ignores the header on read-only endpoints.
|
|
118
|
+
- **Let keys expire naturally.** Cached responses expire after 24 hours. Don't rely on idempotency keys for longer-term deduplication.
|
|
119
|
+
|
|
120
|
+
## Relationship with Optimistic Locking
|
|
121
|
+
|
|
122
|
+
The Store API also uses [optimistic locking](/api-reference/store-api/introduction) via the `state_lock_version` field on orders. These mechanisms complement each other:
|
|
123
|
+
|
|
124
|
+
| Mechanism | Prevents | Scope |
|
|
125
|
+
|-----------|----------|-------|
|
|
126
|
+
| **Idempotency keys** | Duplicate operations from retries | Per-request deduplication |
|
|
127
|
+
| **Optimistic locking** (`state_lock_version`) | Concurrent modifications | Conflict detection between clients |
|
|
128
|
+
|
|
129
|
+
Use both together for robust checkout flows: idempotency keys protect against network retries, while `state_lock_version` detects when another client has modified the order.
|