@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
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Users
|
|
3
|
+
description: Customers and admin users — authentication, accounts, and permissions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Spree has two separate user types:
|
|
9
|
+
|
|
10
|
+
- **Customers** — users who browse your store, manage their account, and purchase products via the Store API
|
|
11
|
+
- **Admins** — users who manage the store via the Admin Panel
|
|
12
|
+
|
|
13
|
+
| User type | Class | Default |
|
|
14
|
+
|-----------|-------|---------|
|
|
15
|
+
| Customers | `Spree.user_class` | `Spree::User` |
|
|
16
|
+
| Admins | `Spree.admin_user_class` | `Spree::AdminUser` |
|
|
17
|
+
|
|
18
|
+
> **INFO:** You can use your own user classes. See the [Customize Authentication guide](/developer/customization/authentication) for details.
|
|
19
|
+
|
|
20
|
+
## Customers
|
|
21
|
+
|
|
22
|
+
Customers interact with your store through the Store API. They can register, log in, manage their profile, and view order history.
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
erDiagram
|
|
26
|
+
Customer ||--o{ Order : "places"
|
|
27
|
+
Customer ||--o{ Address : "has many"
|
|
28
|
+
Customer ||--o{ Wishlist : "has many"
|
|
29
|
+
Customer ||--o{ StoreCredit : "has many"
|
|
30
|
+
Customer ||--o{ PaymentSource : "has many"
|
|
31
|
+
|
|
32
|
+
Customer {
|
|
33
|
+
string id
|
|
34
|
+
string email
|
|
35
|
+
string first_name
|
|
36
|
+
string last_name
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Order {
|
|
40
|
+
string number
|
|
41
|
+
string state
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Address {
|
|
45
|
+
string firstname
|
|
46
|
+
string lastname
|
|
47
|
+
string address1
|
|
48
|
+
string city
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Wishlist {
|
|
52
|
+
string name
|
|
53
|
+
boolean is_default
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Registration
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
```typescript SDK
|
|
61
|
+
const { token, user } = await client.customers.create({
|
|
62
|
+
email: 'john@example.com',
|
|
63
|
+
password: 'password123',
|
|
64
|
+
password_confirmation: 'password123',
|
|
65
|
+
first_name: 'John',
|
|
66
|
+
last_name: 'Doe',
|
|
67
|
+
})
|
|
68
|
+
// token => JWT token for subsequent authenticated requests
|
|
69
|
+
// user => { id: "usr_xxx", email: "john@example.com", first_name: "John", ... }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```bash cURL
|
|
73
|
+
curl -X POST 'https://api.mystore.com/api/v3/store/customers' \
|
|
74
|
+
-H 'X-Spree-Api-Key: spree_pk_xxx' \
|
|
75
|
+
-H 'Content-Type: application/json' \
|
|
76
|
+
-d '{
|
|
77
|
+
"email": "john@example.com",
|
|
78
|
+
"password": "password123",
|
|
79
|
+
"password_confirmation": "password123",
|
|
80
|
+
"first_name": "John",
|
|
81
|
+
"last_name": "Doe"
|
|
82
|
+
}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Login
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
```typescript SDK
|
|
90
|
+
const { token, user } = await client.auth.login({
|
|
91
|
+
email: 'john@example.com',
|
|
92
|
+
password: 'password123',
|
|
93
|
+
})
|
|
94
|
+
// Use the token for authenticated requests
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```bash cURL
|
|
98
|
+
curl -X POST 'https://api.mystore.com/api/v3/store/auth/login' \
|
|
99
|
+
-H 'Authorization: Bearer spree_pk_xxx' \
|
|
100
|
+
-H 'Content-Type: application/json' \
|
|
101
|
+
-d '{
|
|
102
|
+
"email": "john@example.com",
|
|
103
|
+
"password": "password123"
|
|
104
|
+
}'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
The response includes a JWT `token` and a `user` object. Pass the token in subsequent requests via the `Authorization: Bearer <token>` header.
|
|
109
|
+
|
|
110
|
+
### Token Refresh
|
|
111
|
+
|
|
112
|
+
Refresh an expiring token to keep the session alive:
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
```typescript SDK
|
|
116
|
+
const { token } = await client.auth.refresh({
|
|
117
|
+
token: existingToken,
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```bash cURL
|
|
122
|
+
curl -X POST 'https://api.mystore.com/api/v3/store/auth/refresh' \
|
|
123
|
+
-H 'Authorization: Bearer <jwt_token>'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
### Customer Profile
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
```typescript SDK
|
|
131
|
+
// Get current customer
|
|
132
|
+
const customer = await client.customer.get()
|
|
133
|
+
// {
|
|
134
|
+
// id: "usr_xxx",
|
|
135
|
+
// email: "john@example.com",
|
|
136
|
+
// first_name: "John",
|
|
137
|
+
// last_name: "Doe",
|
|
138
|
+
// default_shipping_address: { ... },
|
|
139
|
+
// default_billing_address: { ... },
|
|
140
|
+
// addresses: [{ ... }, { ... }],
|
|
141
|
+
// }
|
|
142
|
+
|
|
143
|
+
// Update profile
|
|
144
|
+
const updated = await client.customer.update({
|
|
145
|
+
first_name: 'Jonathan',
|
|
146
|
+
accepts_email_marketing: true,
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```bash cURL
|
|
151
|
+
# Get current customer
|
|
152
|
+
curl 'https://api.mystore.com/api/v3/store/customer' \
|
|
153
|
+
-H 'Authorization: Bearer <jwt_token>'
|
|
154
|
+
|
|
155
|
+
# Update profile
|
|
156
|
+
curl -X PATCH 'https://api.mystore.com/api/v3/store/customer' \
|
|
157
|
+
-H 'Authorization: Bearer <jwt_token>' \
|
|
158
|
+
-H 'Content-Type: application/json' \
|
|
159
|
+
-d '{ "first_name": "Jonathan", "accepts_email_marketing": true }'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
### Customer Resources
|
|
164
|
+
|
|
165
|
+
Authenticated customers have access to these resources:
|
|
166
|
+
|
|
167
|
+
| Resource | Description |
|
|
168
|
+
|----------|-------------|
|
|
169
|
+
| [**Addresses**](/developer/core-concepts/addresses#customer-address-book) | Billing and shipping addresses with default selection |
|
|
170
|
+
| [**Orders**](/developer/core-concepts/orders#order-history) | Past order history |
|
|
171
|
+
| **Credit Cards** | Saved credit cards for checkout |
|
|
172
|
+
| **Payment Sources** | Other saved payment methods (PayPal, Klarna, etc.) |
|
|
173
|
+
| **Store Credits** | Balance assigned by the store, usable at checkout |
|
|
174
|
+
| **Gift Cards** | Gift cards owned by or assigned to the customer |
|
|
175
|
+
| **Wishlists** | Saved product lists |
|
|
176
|
+
|
|
177
|
+
### Guest Checkout
|
|
178
|
+
|
|
179
|
+
Customers don't need to register to purchase. Guest checkout uses an order token (`X-Spree-Token`) to identify the cart. See [Orders — Cart](/developer/core-concepts/orders#cart) for details.
|
|
180
|
+
|
|
181
|
+
## Admin Users
|
|
182
|
+
|
|
183
|
+
Admin users manage the store via the Admin Panel. They have roles that control what they can access.
|
|
184
|
+
|
|
185
|
+
```mermaid
|
|
186
|
+
erDiagram
|
|
187
|
+
AdminUser ||--o{ RoleUser : "has many"
|
|
188
|
+
RoleUser }o--|| Role : "belongs to"
|
|
189
|
+
RoleUser }o--|| Store : "scoped to"
|
|
190
|
+
AdminUser ||--o{ Invitation : "invites"
|
|
191
|
+
|
|
192
|
+
AdminUser {
|
|
193
|
+
string id
|
|
194
|
+
string email
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
RoleUser {
|
|
198
|
+
string role_id
|
|
199
|
+
string resource_type
|
|
200
|
+
string resource_id
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
Role {
|
|
204
|
+
string name
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
Invitation {
|
|
208
|
+
string email
|
|
209
|
+
string status
|
|
210
|
+
string token
|
|
211
|
+
datetime expires_at
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Roles
|
|
216
|
+
|
|
217
|
+
Admin users can have different roles that control their permissions:
|
|
218
|
+
|
|
219
|
+
| Role | Description |
|
|
220
|
+
|------|-------------|
|
|
221
|
+
| `admin` | Full access to all Admin Panel features |
|
|
222
|
+
|
|
223
|
+
> **INFO:** You can create custom roles with specific permissions. See the [Customize Permissions guide](/developer/customization/permissions) for details.
|
|
224
|
+
|
|
225
|
+
### Creating Admin Users
|
|
226
|
+
|
|
227
|
+
Use the Spree CLI to create admin users:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
spree user create
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The CLI will prompt you for the email and password. You can also pass them directly:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
spree user create --email admin@example.com --password secret123
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The created user gets the `admin` role on the default store.
|
|
240
|
+
|
|
241
|
+
### Inviting Admin Users
|
|
242
|
+
|
|
243
|
+
You can invite new admins through the Admin Panel or programmatically.
|
|
244
|
+
|
|
245
|
+
**Via Admin Panel:**
|
|
246
|
+
|
|
247
|
+
1. Navigate to **Settings → Users**
|
|
248
|
+
2. Click **Invite User**
|
|
249
|
+
3. Enter the email address and select a role
|
|
250
|
+
4. Click **Send Invitation**
|
|
251
|
+
|
|
252
|
+
The invitee receives an email with an invitation link. If they already have an account, they log in to accept. Otherwise, they create an account first.
|
|
253
|
+
|
|
254
|
+
```mermaid
|
|
255
|
+
flowchart TB
|
|
256
|
+
A[Admin creates invitation] --> B[Invitation email sent]
|
|
257
|
+
B --> C[Invitee clicks link]
|
|
258
|
+
C --> D{Has account?}
|
|
259
|
+
D -->|Yes| E[Log in]
|
|
260
|
+
D -->|No| F[Create account]
|
|
261
|
+
E --> G[Accept invitation]
|
|
262
|
+
F --> G
|
|
263
|
+
G --> H[Role assigned to store]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Invitation Details
|
|
267
|
+
|
|
268
|
+
| Attribute | Description |
|
|
269
|
+
|-----------|-------------|
|
|
270
|
+
| `email` | Invitee's email address |
|
|
271
|
+
| `token` | Secure token for the invitation link |
|
|
272
|
+
| `status` | `pending` or `accepted` |
|
|
273
|
+
| `expires_at` | Expiration date (default: 2 weeks) |
|
|
274
|
+
| `resource` | The store being granted access to |
|
|
275
|
+
| `role` | The role to assign upon acceptance |
|
|
276
|
+
|
|
277
|
+
#### Invitation Events
|
|
278
|
+
|
|
279
|
+
The invitation system publishes [events](/developer/core-concepts/events) you can subscribe to:
|
|
280
|
+
|
|
281
|
+
| Event | Description |
|
|
282
|
+
|-------|-------------|
|
|
283
|
+
| `invitation.created` | Invitation was created (triggers email) |
|
|
284
|
+
| `invitation.accepted` | Invitation was accepted and role assigned |
|
|
285
|
+
| `invitation.resent` | Invitation was resent to the invitee |
|
|
286
|
+
|
|
287
|
+
## Permissions
|
|
288
|
+
|
|
289
|
+
Spree uses [CanCanCan](https://github.com/CanCanCommunity/cancancan) for authorization. Permissions apply to both customers (Store API access) and admins (Admin Panel access).
|
|
290
|
+
|
|
291
|
+
See the [Customize Permissions guide](/developer/customization/permissions) for details on creating custom roles and permission sets.
|
|
292
|
+
|
|
293
|
+
## Related Documentation
|
|
294
|
+
|
|
295
|
+
- [Addresses](/developer/core-concepts/addresses) — Customer address management
|
|
296
|
+
- [Orders](/developer/core-concepts/orders) — Order history and checkout
|
|
297
|
+
- [Authentication](/developer/customization/authentication) — Custom authentication setup
|
|
298
|
+
- [Permissions](/developer/customization/permissions) — Roles and authorization
|
|
299
|
+
- [Events](/developer/core-concepts/events) — Subscribe to user and invitation events
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Webhooks
|
|
3
|
+
description: Send real-time HTTP notifications to external services when events occur in your store.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Webhooks allow your Spree store to send real-time HTTP POST notifications to external services when events occur. When an order is completed, a product is updated, or inventory changes, Spree can automatically notify your CRM, fulfillment service, analytics platform, or any other system.
|
|
9
|
+
|
|
10
|
+
Webhooks are built on top of Spree's [event system](/developer/core-concepts/events), providing:
|
|
11
|
+
|
|
12
|
+
- **Multi-store support** - Each store has its own webhook endpoints
|
|
13
|
+
- **Event filtering** - Subscribe to specific events or patterns with wildcards
|
|
14
|
+
- **Secure delivery** - HMAC-SHA256 signatures for payload verification
|
|
15
|
+
- **Automatic retries** - Failed deliveries retry with exponential backoff
|
|
16
|
+
- **Full audit trail** - Track every delivery attempt with response codes and timing
|
|
17
|
+
|
|
18
|
+
## How Webhooks Work
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
flowchart LR
|
|
22
|
+
subgraph Spree Store
|
|
23
|
+
A[Event Published] --> B[WebhookEventSubscriber]
|
|
24
|
+
B --> C{Find Matching<br/>Endpoints}
|
|
25
|
+
C --> D[Create WebhookDelivery]
|
|
26
|
+
D --> E[Queue DeliveryJob]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
subgraph Delivery
|
|
30
|
+
E --> F[Build JSON Payload]
|
|
31
|
+
F --> G[Sign with HMAC-SHA256]
|
|
32
|
+
G --> H[HTTP POST]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
subgraph External Service
|
|
36
|
+
H --> I{Response}
|
|
37
|
+
I -->|2xx| J[Success]
|
|
38
|
+
I -->|Error| K[Retry with Backoff]
|
|
39
|
+
K -->|Max Retries| L[Mark Failed]
|
|
40
|
+
K -->|Retry| H
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
1. An event is published (e.g., `order.completed`)
|
|
45
|
+
2. The `WebhookEventSubscriber` receives all events
|
|
46
|
+
3. It finds active webhook endpoints subscribed to that event
|
|
47
|
+
4. For each endpoint, it creates a `WebhookDelivery` record and queues a job
|
|
48
|
+
5. The job sends an HTTP POST request with the event payload and HMAC signature
|
|
49
|
+
|
|
50
|
+
## Creating Webhook Endpoints
|
|
51
|
+
|
|
52
|
+
### Via Admin Panel
|
|
53
|
+
|
|
54
|
+
Navigate to **Settings → Developers → Webhooks** in the admin panel to create and manage webhook endpoints.
|
|
55
|
+
|
|
56
|
+
### Via Code
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
endpoint = Spree::WebhookEndpoint.create!(
|
|
60
|
+
store: Spree::Store.default,
|
|
61
|
+
url: 'https://example.com/webhooks/spree',
|
|
62
|
+
subscriptions: ['order.*', 'product.created'],
|
|
63
|
+
active: true
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# The secret_key is auto-generated
|
|
67
|
+
endpoint.secret_key # => "a1b2c3d4e5f6..." (64-character hex string)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Endpoint Attributes
|
|
71
|
+
|
|
72
|
+
| Attribute | Type | Description |
|
|
73
|
+
|-----------|------|-------------|
|
|
74
|
+
| `url` | String | The HTTPS endpoint URL to receive webhooks |
|
|
75
|
+
| `active` | Boolean | Enable/disable delivery to this endpoint |
|
|
76
|
+
| `subscriptions` | Array | Event patterns to subscribe to |
|
|
77
|
+
| `secret_key` | String | Auto-generated key for HMAC signature verification |
|
|
78
|
+
| `store_id` | Integer | The store this endpoint belongs to |
|
|
79
|
+
|
|
80
|
+
## Event Subscriptions
|
|
81
|
+
|
|
82
|
+
The `subscriptions` attribute controls which events trigger webhooks to this endpoint.
|
|
83
|
+
|
|
84
|
+
### Subscribe to Specific Events
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
endpoint.subscriptions = ['order.completed', 'order.canceled']
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Subscribe to Event Patterns
|
|
91
|
+
|
|
92
|
+
Use wildcards to subscribe to multiple related events:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
# All order events
|
|
96
|
+
endpoint.subscriptions = ['order.*']
|
|
97
|
+
|
|
98
|
+
# All creation events
|
|
99
|
+
endpoint.subscriptions = ['*.created']
|
|
100
|
+
|
|
101
|
+
# Multiple patterns
|
|
102
|
+
endpoint.subscriptions = ['order.*', 'payment.*', 'shipment.shipped']
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Subscribe to All Events
|
|
106
|
+
|
|
107
|
+
Leave subscriptions empty or use `*` to receive all events:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
endpoint.subscriptions = [] # All events
|
|
111
|
+
endpoint.subscriptions = ['*'] # All events (explicit)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Webhook Payload
|
|
115
|
+
|
|
116
|
+
Each webhook delivery sends a JSON payload with the following structure. The `data` object uses the same [Store API V3 serializers](/api-reference/introduction) as the REST API, so webhook payloads and API responses share the same schema:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
121
|
+
"name": "order.completed",
|
|
122
|
+
"created_at": "2025-01-15T10:30:00Z",
|
|
123
|
+
"data": {
|
|
124
|
+
"id": "or_m3Rp9wXz",
|
|
125
|
+
"number": "R123456789",
|
|
126
|
+
"state": "complete",
|
|
127
|
+
"total": "99.99",
|
|
128
|
+
"display_total": "$99.99",
|
|
129
|
+
"item_count": 3,
|
|
130
|
+
"currency": "USD",
|
|
131
|
+
"items": [ ... ],
|
|
132
|
+
"shipments": [ ... ],
|
|
133
|
+
"payments": [ ... ]
|
|
134
|
+
},
|
|
135
|
+
"metadata": {
|
|
136
|
+
"spree_version": "5.1.0"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| Field | Description |
|
|
142
|
+
|-------|-------------|
|
|
143
|
+
| `id` | Unique UUID for this event |
|
|
144
|
+
| `name` | Event name (e.g., `order.completed`) |
|
|
145
|
+
| `created_at` | ISO8601 timestamp when event occurred |
|
|
146
|
+
| `data` | Serialized resource data (V3 API format with [prefixed IDs](/api-reference/introduction)) |
|
|
147
|
+
| `metadata` | Additional context including Spree version |
|
|
148
|
+
|
|
149
|
+
For complete payload schemas for each event type, see [Webhook Events & Payloads](/api-reference/webhooks-events).
|
|
150
|
+
|
|
151
|
+
## HTTP Request Details
|
|
152
|
+
|
|
153
|
+
### Headers
|
|
154
|
+
|
|
155
|
+
Each webhook request includes these headers:
|
|
156
|
+
|
|
157
|
+
| Header | Description |
|
|
158
|
+
|--------|-------------|
|
|
159
|
+
| `Content-Type` | `application/json` |
|
|
160
|
+
| `User-Agent` | `Spree-Webhooks/1.0` |
|
|
161
|
+
| `X-Spree-Webhook-Event` | Event name (e.g., `order.completed`) |
|
|
162
|
+
| `X-Spree-Webhook-Signature` | HMAC-SHA256 signature for verification |
|
|
163
|
+
|
|
164
|
+
### Verifying Webhook Signatures
|
|
165
|
+
|
|
166
|
+
To ensure webhooks are genuinely from your Spree store, verify the signature:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
# In your webhook receiver
|
|
170
|
+
def verify_webhook(request)
|
|
171
|
+
payload = request.body.read
|
|
172
|
+
signature = request.headers['X-Spree-Webhook-Signature']
|
|
173
|
+
secret_key = ENV['SPREE_WEBHOOK_SECRET'] # Your endpoint's secret_key
|
|
174
|
+
|
|
175
|
+
expected = OpenSSL::HMAC.hexdigest('SHA256', secret_key, payload)
|
|
176
|
+
|
|
177
|
+
ActiveSupport::SecurityUtils.secure_compare(signature, expected)
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Example in a Rails controller:
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
class WebhooksController < ApplicationController
|
|
185
|
+
skip_before_action :verify_authenticity_token
|
|
186
|
+
|
|
187
|
+
def receive
|
|
188
|
+
unless verify_signature
|
|
189
|
+
head :unauthorized
|
|
190
|
+
return
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
event = JSON.parse(request.body.read)
|
|
194
|
+
|
|
195
|
+
case event['name']
|
|
196
|
+
when 'order.completed'
|
|
197
|
+
handle_order_completed(event['data'])
|
|
198
|
+
when 'product.updated'
|
|
199
|
+
handle_product_updated(event['data'])
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
head :ok
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
private
|
|
206
|
+
|
|
207
|
+
def verify_signature
|
|
208
|
+
payload = request.body.read
|
|
209
|
+
request.body.rewind
|
|
210
|
+
|
|
211
|
+
signature = request.headers['X-Spree-Webhook-Signature']
|
|
212
|
+
expected = OpenSSL::HMAC.hexdigest('SHA256', ENV['SPREE_WEBHOOK_SECRET'], payload)
|
|
213
|
+
|
|
214
|
+
ActiveSupport::SecurityUtils.secure_compare(signature.to_s, expected)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Delivery Status & Retries
|
|
220
|
+
|
|
221
|
+
### Automatic Retries
|
|
222
|
+
|
|
223
|
+
Failed webhook deliveries automatically retry up to 5 times with exponential backoff. This handles temporary network issues and endpoint downtime.
|
|
224
|
+
|
|
225
|
+
### Checking Delivery Status
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
endpoint = Spree::WebhookEndpoint.find(id)
|
|
229
|
+
|
|
230
|
+
# Recent deliveries
|
|
231
|
+
endpoint.webhook_deliveries.recent
|
|
232
|
+
|
|
233
|
+
# Filter by status
|
|
234
|
+
endpoint.webhook_deliveries.successful
|
|
235
|
+
endpoint.webhook_deliveries.failed
|
|
236
|
+
endpoint.webhook_deliveries.pending
|
|
237
|
+
|
|
238
|
+
# Filter by event
|
|
239
|
+
endpoint.webhook_deliveries.for_event('order.completed')
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Delivery Attributes
|
|
243
|
+
|
|
244
|
+
| Attribute | Description |
|
|
245
|
+
|-----------|-------------|
|
|
246
|
+
| `event_name` | Name of the event delivered |
|
|
247
|
+
| `payload` | Complete webhook payload sent |
|
|
248
|
+
| `response_code` | HTTP status code (nil if pending) |
|
|
249
|
+
| `success` | Boolean indicating 2xx response |
|
|
250
|
+
| `execution_time` | Delivery time in milliseconds |
|
|
251
|
+
| `error_type` | `'timeout'`, `'connection_error'`, or nil |
|
|
252
|
+
| `request_errors` | Error message details |
|
|
253
|
+
| `response_body` | Response from endpoint (truncated) |
|
|
254
|
+
| `delivered_at` | Timestamp of delivery attempt |
|
|
255
|
+
|
|
256
|
+
## Configuration
|
|
257
|
+
|
|
258
|
+
### Enabling/Disabling Webhooks
|
|
259
|
+
|
|
260
|
+
Webhooks are enabled by default. To disable globally:
|
|
261
|
+
|
|
262
|
+
```ruby
|
|
263
|
+
# config/initializers/spree.rb
|
|
264
|
+
Spree::Api::Config.webhooks_enabled = false
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### SSL Verification
|
|
268
|
+
|
|
269
|
+
SSL verification is enabled by default in production. In development, it's disabled to allow testing with self-signed certificates:
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
# config/initializers/spree.rb
|
|
273
|
+
Spree::Api::Config.webhooks_verify_ssl = true # Force SSL verification
|
|
274
|
+
Spree::Api::Config.webhooks_verify_ssl = false # Disable (not recommended for production)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Available Events
|
|
278
|
+
|
|
279
|
+
Webhooks can subscribe to any event in Spree's event system. See [Events](/developer/core-concepts/events#available-events) for a complete list.
|
|
280
|
+
|
|
281
|
+
Common webhook events include:
|
|
282
|
+
|
|
283
|
+
| Event | Description |
|
|
284
|
+
|-------|-------------|
|
|
285
|
+
| `order.completed` | Order checkout finished |
|
|
286
|
+
| `order.canceled` | Order was canceled |
|
|
287
|
+
| `order.paid` | Order is fully paid |
|
|
288
|
+
| `shipment.shipped` | Shipment was shipped |
|
|
289
|
+
| `payment.paid` | Payment was completed |
|
|
290
|
+
| `product.created` | New product created |
|
|
291
|
+
| `product.updated` | Product was modified |
|
|
292
|
+
| `customer.created` | New customer registered |
|
|
293
|
+
|
|
294
|
+
## Testing Webhooks
|
|
295
|
+
|
|
296
|
+
### In Development
|
|
297
|
+
|
|
298
|
+
Use tools like [ngrok](https://ngrok.com) or [webhook.site](https://webhook.site) to test webhooks locally:
|
|
299
|
+
|
|
300
|
+
```ruby
|
|
301
|
+
# Create a test endpoint
|
|
302
|
+
endpoint = Spree::WebhookEndpoint.create!(
|
|
303
|
+
store: Spree::Store.default,
|
|
304
|
+
url: 'https://your-ngrok-url.ngrok.io/webhooks',
|
|
305
|
+
subscriptions: ['order.*'],
|
|
306
|
+
active: true
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# Trigger an event
|
|
310
|
+
order = Spree::Order.complete.last
|
|
311
|
+
order.publish_event('order.completed')
|
|
312
|
+
|
|
313
|
+
# Check delivery
|
|
314
|
+
endpoint.webhook_deliveries.last.success?
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### In Tests
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
RSpec.describe 'Webhook delivery' do
|
|
321
|
+
let(:store) { create(:store) }
|
|
322
|
+
let(:endpoint) { create(:webhook_endpoint, store: store, subscriptions: ['order.completed']) }
|
|
323
|
+
let(:order) { create(:completed_order_with_totals, store: store) }
|
|
324
|
+
|
|
325
|
+
it 'delivers webhook when order completes' do
|
|
326
|
+
stub_request(:post, endpoint.url).to_return(status: 200)
|
|
327
|
+
|
|
328
|
+
expect {
|
|
329
|
+
order.publish_event('order.completed')
|
|
330
|
+
}.to have_enqueued_job(Spree::WebhookDeliveryJob)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Best Practices
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
- **Respond quickly** — Return a 2xx response as fast as possible. Process webhook data asynchronously in a background job.
|
|
339
|
+
|
|
340
|
+
- **Verify signatures** — Always verify the `X-Spree-Webhook-Signature` header to ensure the webhook is authentic.
|
|
341
|
+
|
|
342
|
+
- **Handle duplicates** — Use the event `id` to detect and handle duplicate deliveries. Webhooks may be retried.
|
|
343
|
+
|
|
344
|
+
- **Subscribe selectively** — Only subscribe to events you need. Use specific patterns rather than `*` when possible.
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
## Troubleshooting
|
|
348
|
+
|
|
349
|
+
### Webhooks Not Delivering
|
|
350
|
+
|
|
351
|
+
1. Check that webhooks are enabled: `Spree::Api::Config.webhooks_enabled`
|
|
352
|
+
2. Verify the endpoint is active: `endpoint.active?`
|
|
353
|
+
3. Confirm the endpoint subscribes to the event: `endpoint.subscribed_to?('order.completed')`
|
|
354
|
+
4. Check the event has a `store_id` matching the endpoint's store
|
|
355
|
+
|
|
356
|
+
### Signature Verification Failing
|
|
357
|
+
|
|
358
|
+
1. Ensure you're using the raw request body (not parsed JSON)
|
|
359
|
+
2. Verify you're using the correct `secret_key` for this endpoint
|
|
360
|
+
3. Check that no middleware is modifying the request body
|
|
361
|
+
|
|
362
|
+
### Deliveries Failing
|
|
363
|
+
|
|
364
|
+
Check the delivery record for details:
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
delivery = endpoint.webhook_deliveries.failed.last
|
|
368
|
+
delivery.error_type # => 'timeout' or 'connection_error'
|
|
369
|
+
delivery.request_errors # => Error message
|
|
370
|
+
delivery.response_code # => HTTP status code
|
|
371
|
+
delivery.response_body # => Response from your endpoint
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Related Documentation
|
|
375
|
+
|
|
376
|
+
- [Events](/developer/core-concepts/events) - Understanding Spree's event system
|
|
377
|
+
- [Customization Quickstart](/developer/customization/quickstart) - Overview of all customization options
|
|
378
|
+
- [Dependencies](/developer/customization/dependencies) - Customizing Spree services
|