@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.
Files changed (183) hide show
  1. package/README.md +54 -0
  2. package/dist/api-reference/platform/authentication.md +38 -0
  3. package/dist/api-reference/store-api/authentication.md +188 -0
  4. package/dist/api-reference/store-api/errors.md +277 -0
  5. package/dist/api-reference/store-api/idempotency.md +129 -0
  6. package/dist/api-reference/store-api/introduction.md +34 -0
  7. package/dist/api-reference/store-api/localization.md +279 -0
  8. package/dist/api-reference/store-api/metadata.md +160 -0
  9. package/dist/api-reference/store-api/monetary-amounts.md +65 -0
  10. package/dist/api-reference/store-api/querying.md +399 -0
  11. package/dist/api-reference/store-api/rate-limitting.md +103 -0
  12. package/dist/api-reference/store-api/relations.md +185 -0
  13. package/dist/api-reference/storefront/authentication.md +88 -0
  14. package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
  15. package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
  16. package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
  17. package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
  18. package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
  19. package/dist/api-reference/v2/introduction.md +22 -0
  20. package/dist/api-reference/v2/pagination.md +37 -0
  21. package/dist/api-reference/webhooks-events.md +883 -0
  22. package/dist/developer/admin/admin.md +205 -0
  23. package/dist/developer/admin/authentication.md +59 -0
  24. package/dist/developer/admin/components.md +711 -0
  25. package/dist/developer/admin/custom-css.md +243 -0
  26. package/dist/developer/admin/custom-javascript.md +116 -0
  27. package/dist/developer/admin/extending-ui.md +1964 -0
  28. package/dist/developer/admin/form-builder.md +444 -0
  29. package/dist/developer/admin/helper-methods.md +531 -0
  30. package/dist/developer/admin/navigation.md +805 -0
  31. package/dist/developer/admin/tables.md +491 -0
  32. package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
  33. package/dist/developer/cli/quickstart.md +137 -0
  34. package/dist/developer/contributing/creating-an-extension.md +258 -0
  35. package/dist/developer/contributing/developing-spree.md +339 -0
  36. package/dist/developer/contributing/quickstart.md +32 -0
  37. package/dist/developer/contributing/updating-extensions.md +67 -0
  38. package/dist/developer/core-concepts/addresses.md +265 -0
  39. package/dist/developer/core-concepts/adjustments.md +107 -0
  40. package/dist/developer/core-concepts/architecture.md +177 -0
  41. package/dist/developer/core-concepts/calculators.md +323 -0
  42. package/dist/developer/core-concepts/customers.md +230 -0
  43. package/dist/developer/core-concepts/events.md +624 -0
  44. package/dist/developer/core-concepts/imports-exports.md +698 -0
  45. package/dist/developer/core-concepts/inventory.md +191 -0
  46. package/dist/developer/core-concepts/markets.md +250 -0
  47. package/dist/developer/core-concepts/media.md +167 -0
  48. package/dist/developer/core-concepts/metafields.md +187 -0
  49. package/dist/developer/core-concepts/orders.md +328 -0
  50. package/dist/developer/core-concepts/payments.md +710 -0
  51. package/dist/developer/core-concepts/pricing.md +163 -0
  52. package/dist/developer/core-concepts/products.md +360 -0
  53. package/dist/developer/core-concepts/promotions.md +322 -0
  54. package/dist/developer/core-concepts/reports.md +206 -0
  55. package/dist/developer/core-concepts/search-filtering.md +237 -0
  56. package/dist/developer/core-concepts/shipments.md +212 -0
  57. package/dist/developer/core-concepts/slugs.md +111 -0
  58. package/dist/developer/core-concepts/staff-roles.md +123 -0
  59. package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
  60. package/dist/developer/core-concepts/stores.md +117 -0
  61. package/dist/developer/core-concepts/taxes.md +135 -0
  62. package/dist/developer/core-concepts/translations.md +120 -0
  63. package/dist/developer/core-concepts/users.md +299 -0
  64. package/dist/developer/core-concepts/webhooks.md +378 -0
  65. package/dist/developer/create-spree-app/quickstart.md +158 -0
  66. package/dist/developer/customization/api.md +93 -0
  67. package/dist/developer/customization/authentication.md +88 -0
  68. package/dist/developer/customization/checkout.md +204 -0
  69. package/dist/developer/customization/configuration.md +55 -0
  70. package/dist/developer/customization/decorators.md +523 -0
  71. package/dist/developer/customization/dependencies.md +232 -0
  72. package/dist/developer/customization/emails.md +21 -0
  73. package/dist/developer/customization/extensions.md +92 -0
  74. package/dist/developer/customization/metadata.md +236 -0
  75. package/dist/developer/customization/model-preferences.md +130 -0
  76. package/dist/developer/customization/permissions.md +265 -0
  77. package/dist/developer/customization/quickstart.md +229 -0
  78. package/dist/developer/customization/routes.md +24 -0
  79. package/dist/developer/customization/v4/admin-panel.md +78 -0
  80. package/dist/developer/customization/v4/authentication.md +210 -0
  81. package/dist/developer/customization/v4/checkout.md +212 -0
  82. package/dist/developer/customization/v4/deface.md +251 -0
  83. package/dist/developer/customization/v4/images.md +86 -0
  84. package/dist/developer/customization/v4/storefront.md +450 -0
  85. package/dist/developer/deployment/assets.md +87 -0
  86. package/dist/developer/deployment/aws.md +335 -0
  87. package/dist/developer/deployment/caching.md +27 -0
  88. package/dist/developer/deployment/cdn.md +39 -0
  89. package/dist/developer/deployment/database.md +155 -0
  90. package/dist/developer/deployment/docker.md +128 -0
  91. package/dist/developer/deployment/emails.md +77 -0
  92. package/dist/developer/deployment/environment_variables.md +111 -0
  93. package/dist/developer/deployment/heroku.md +51 -0
  94. package/dist/developer/deployment/render.md +95 -0
  95. package/dist/developer/getting-started/quickstart.md +82 -0
  96. package/dist/developer/how-to/custom-payment-method.md +374 -0
  97. package/dist/developer/how-to/custom-promotion.md +373 -0
  98. package/dist/developer/how-to/custom-report.md +387 -0
  99. package/dist/developer/how-to/custom-search-provider.md +230 -0
  100. package/dist/developer/multi-store/quickstart.md +71 -0
  101. package/dist/developer/multi-store/setup.md +38 -0
  102. package/dist/developer/multi-tenant/configuration.md +41 -0
  103. package/dist/developer/multi-tenant/core-concepts.md +75 -0
  104. package/dist/developer/multi-tenant/installation.md +96 -0
  105. package/dist/developer/multi-tenant/quickstart.md +20 -0
  106. package/dist/developer/multi-vendor/installation.md +45 -0
  107. package/dist/developer/multi-vendor/quickstart.md +17 -0
  108. package/dist/developer/sdk/admin/quickstart.md +22 -0
  109. package/dist/developer/sdk/authentication.md +89 -0
  110. package/dist/developer/sdk/configuration.md +225 -0
  111. package/dist/developer/sdk/quickstart.md +82 -0
  112. package/dist/developer/sdk/store/account.md +67 -0
  113. package/dist/developer/sdk/store/cart-checkout.md +140 -0
  114. package/dist/developer/sdk/store/markets.md +151 -0
  115. package/dist/developer/sdk/store/payments.md +96 -0
  116. package/dist/developer/sdk/store/products.md +149 -0
  117. package/dist/developer/sdk/store/wishlists.md +52 -0
  118. package/dist/developer/security/pci_compliance.md +15 -0
  119. package/dist/developer/security/security_policy.md +68 -0
  120. package/dist/developer/storefront/blocks.md +285 -0
  121. package/dist/developer/storefront/custom-css.md +260 -0
  122. package/dist/developer/storefront/custom-javascript.md +166 -0
  123. package/dist/developer/storefront/helper-methods.md +1288 -0
  124. package/dist/developer/storefront/links.md +298 -0
  125. package/dist/developer/storefront/nextjs/architecture.md +150 -0
  126. package/dist/developer/storefront/nextjs/customization.md +141 -0
  127. package/dist/developer/storefront/nextjs/deployment.md +180 -0
  128. package/dist/developer/storefront/nextjs/quickstart.md +92 -0
  129. package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
  130. package/dist/developer/storefront/pages.md +163 -0
  131. package/dist/developer/storefront/sections.md +569 -0
  132. package/dist/developer/storefront/storefront.md +56 -0
  133. package/dist/developer/storefront/themes.md +161 -0
  134. package/dist/developer/tutorial/admin.md +134 -0
  135. package/dist/developer/tutorial/extending-models.md +380 -0
  136. package/dist/developer/tutorial/file-uploads.md +121 -0
  137. package/dist/developer/tutorial/introduction.md +33 -0
  138. package/dist/developer/tutorial/model.md +41 -0
  139. package/dist/developer/tutorial/page-builder.md +487 -0
  140. package/dist/developer/tutorial/rich-text.md +73 -0
  141. package/dist/developer/tutorial/seo.md +332 -0
  142. package/dist/developer/tutorial/storefront.md +352 -0
  143. package/dist/developer/tutorial/testing.md +558 -0
  144. package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
  145. package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
  146. package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
  147. package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
  148. package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
  149. package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
  150. package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
  151. package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
  152. package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
  153. package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
  154. package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
  155. package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
  156. package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
  157. package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
  158. package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
  159. package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
  160. package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
  161. package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
  162. package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
  163. package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
  164. package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
  165. package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
  166. package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
  167. package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
  168. package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
  169. package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
  170. package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
  171. package/dist/developer/upgrades/quickstart.md +36 -0
  172. package/dist/integrations/analytics/google-analytics.md +64 -0
  173. package/dist/integrations/analytics/google-tag-manager.md +78 -0
  174. package/dist/integrations/integrations.md +39 -0
  175. package/dist/integrations/marketing/klaviyo.md +99 -0
  176. package/dist/integrations/payments/adyen.md +90 -0
  177. package/dist/integrations/payments/paypal.md +41 -0
  178. package/dist/integrations/payments/razorpay.md +45 -0
  179. package/dist/integrations/payments/stripe.md +109 -0
  180. package/dist/integrations/search/meilisearch.md +236 -0
  181. package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
  182. package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
  183. package/package.json +27 -0
@@ -0,0 +1,399 @@
1
+ ---
2
+ title: "Querying"
3
+ sidebarTitle: "Querying"
4
+ description: "How to filter, sort, and paginate Store API results using Ransack"
5
+ ---
6
+
7
+ The Store API uses [Ransack](https://activerecord-hackery.github.io/ransack/) for filtering and sorting collection endpoints. All query parameters are passed via the `q` parameter.
8
+
9
+ ## Filtering
10
+
11
+ Pass filter conditions using the `q` parameter with Ransack predicates:
12
+
13
+
14
+ ```typescript SDK
15
+ const products = await client.products.list({
16
+ name_cont: 'shirt',
17
+ price_gte: 20,
18
+ price_lte: 100,
19
+ })
20
+ ```
21
+
22
+ ```bash cURL
23
+ curl -G 'http://localhost:3000/api/v3/store/products' \
24
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
25
+ --data-urlencode 'q[name_cont]=shirt' \
26
+ --data-urlencode 'q[price_gte]=20' \
27
+ --data-urlencode 'q[price_lte]=100'
28
+ ```
29
+
30
+
31
+ ### Common Predicates
32
+
33
+ | Predicate | Description | SDK | cURL |
34
+ |-----------|-------------|-----|------|
35
+ | `eq` | Equals | `status_eq: 'active'` | `q[status_eq]=active` |
36
+ | `not_eq` | Not equals | `status_not_eq: 'draft'` | `q[status_not_eq]=draft` |
37
+ | `cont` | Contains (case-insensitive) | `name_cont: 'shirt'` | `q[name_cont]=shirt` |
38
+ | `start` | Starts with | `name_start: 'Spree'` | `q[name_start]=Spree` |
39
+ | `end` | Ends with | `slug_end: 'tote'` | `q[slug_end]=tote` |
40
+ | `lt` | Less than | `price_lt: 50` | `q[price_lt]=50` |
41
+ | `lteq` | Less than or equal | `price_lteq: 50` | `q[price_lteq]=50` |
42
+ | `gt` | Greater than | `price_gt: 10` | `q[price_gt]=10` |
43
+ | `gteq` | Greater than or equal | `price_gteq: 10` | `q[price_gteq]=10` |
44
+ | `in` | In a list | `status_in: ['active', 'draft']` | `q[status_in][]=active&q[status_in][]=draft` |
45
+ | `null` | Is null | `deleted_at_null: true` | `q[deleted_at_null]=true` |
46
+ | `not_null` | Is not null | `completed_at_not_null: true` | `q[completed_at_not_null]=true` |
47
+ | `present` | Is present (not empty) | `description_present: true` | `q[description_present]=true` |
48
+ | `blank` | Is blank (null or empty) | `description_blank: true` | `q[description_blank]=true` |
49
+ | `true` | Is true (boolean) | `purchasable_true: 1` | `q[purchasable_true]=1` |
50
+ | `false` | Is false (boolean) | `purchasable_false: 1` | `q[purchasable_false]=1` |
51
+
52
+ > **NOTE:** The SDK automatically wraps filter keys in `q[...]` and appends `[]` for array values — just pass flat params.
53
+
54
+ ### Combining Filters
55
+
56
+ Multiple filters are combined with AND logic:
57
+
58
+
59
+ ```typescript SDK
60
+ // Products that contain "shirt" AND cost between $20-$100
61
+ const products = await client.products.list({
62
+ name_cont: 'shirt',
63
+ price_gteq: 20,
64
+ price_lteq: 100,
65
+ })
66
+ ```
67
+
68
+ ```bash cURL
69
+ curl -G 'http://localhost:3000/api/v3/store/products' \
70
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
71
+ --data-urlencode 'q[name_cont]=shirt' \
72
+ --data-urlencode 'q[price_gteq]=20' \
73
+ --data-urlencode 'q[price_lteq]=100'
74
+ ```
75
+
76
+
77
+ ### Filtering by Association
78
+
79
+ You can filter by associated model attributes using underscore notation:
80
+
81
+
82
+ ```typescript SDK
83
+ // Products in a specific category
84
+ const products = await client.products.list({
85
+ categories_id_eq: 'ctg_abc123',
86
+ })
87
+
88
+ // Categories at a specific depth
89
+ const categories = await client.categories.list({
90
+ depth_eq: 1,
91
+ })
92
+ ```
93
+
94
+ ```bash cURL
95
+ # Products in a specific category
96
+ curl -G 'http://localhost:3000/api/v3/store/products' \
97
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
98
+ --data-urlencode 'q[categories_id_eq]=ctg_abc123'
99
+
100
+ # Top-level categories only
101
+ curl -G 'http://localhost:3000/api/v3/store/categories' \
102
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
103
+ --data-urlencode 'q[depth_eq]=1'
104
+ ```
105
+
106
+
107
+ ## Product Scopes
108
+
109
+ Products support additional filter scopes beyond standard Ransack predicates:
110
+
111
+
112
+ ```typescript SDK
113
+ const products = await client.products.list({
114
+ price_gte: 20, // Minimum price
115
+ price_lte: 100, // Maximum price
116
+ with_option_value_ids: ['optval_abc', 'optval_def'], // Filter by option values
117
+ in_stock: true, // Only in-stock products
118
+ })
119
+ ```
120
+
121
+ ```bash cURL
122
+ curl -G 'http://localhost:3000/api/v3/store/products' \
123
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
124
+ --data-urlencode 'q[price_gte]=20' \
125
+ --data-urlencode 'q[price_lte]=100' \
126
+ --data-urlencode 'q[with_option_value_ids][]=optval_abc' \
127
+ --data-urlencode 'q[with_option_value_ids][]=optval_def' \
128
+ --data-urlencode 'q[in_stock]=true'
129
+ ```
130
+
131
+
132
+ | Scope | Description | SDK | cURL |
133
+ |-------|-------------|-----|------|
134
+ | `price_gte` | Minimum price | `price_gte: 20` | `q[price_gte]=20` |
135
+ | `price_lte` | Maximum price | `price_lte: 100` | `q[price_lte]=100` |
136
+ | `with_option_value_ids` | Filter by option value IDs | `with_option_value_ids: ['optval_abc']` | `q[with_option_value_ids][]=optval_abc` |
137
+ | `in_stock` | Only in-stock products | `in_stock: true` | `q[in_stock]=true` |
138
+ | `out_of_stock` | Only out-of-stock products | `out_of_stock: true` | `q[out_of_stock]=true` |
139
+ | `search` | Full-text search | `search: 'shirt'` | `q[search]=shirt` |
140
+
141
+ ## Sorting
142
+
143
+ Use the `sort` parameter on any list endpoint. Prefix a field with `-` for descending order (ascending is the default). This follows the [JSON:API sorting convention](https://jsonapi.org/format/#fetching-sorting).
144
+
145
+
146
+ ```typescript SDK
147
+ // Sort by price (low to high)
148
+ const products = await client.products.list({
149
+ sort: 'price',
150
+ })
151
+
152
+ // Sort by price (high to low)
153
+ const products = await client.products.list({
154
+ sort: '-price',
155
+ })
156
+
157
+ // Sort by best selling
158
+ const products = await client.products.list({
159
+ sort: 'best_selling',
160
+ })
161
+ ```
162
+
163
+ ```bash cURL
164
+ # Sort by price low to high
165
+ curl -G 'http://localhost:3000/api/v3/store/products' \
166
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
167
+ -d 'sort=price'
168
+
169
+ # Sort by price high to low
170
+ curl -G 'http://localhost:3000/api/v3/store/products' \
171
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
172
+ -d 'sort=-price'
173
+ ```
174
+
175
+
176
+ ### Product Sort Options
177
+
178
+ | Value | Description |
179
+ |-------|-------------|
180
+ | `manual` | Manual sort order (default, uses taxon position) |
181
+ | `best_selling` | Best selling products first |
182
+ | `price` | Price low to high |
183
+ | `-price` | Price high to low |
184
+ | `name` | Name A-Z |
185
+ | `-name` | Name Z-A |
186
+ | `-available_on` | Newest first |
187
+ | `available_on` | Oldest first |
188
+
189
+ ### Sorting Other Resources
190
+
191
+ The `sort` parameter works on all list endpoints. Use any sortable column name:
192
+
193
+
194
+ ```typescript SDK
195
+ // Categories sorted by name
196
+ const categories = await client.categories.list({
197
+ sort: 'name',
198
+ })
199
+
200
+ // Customer orders sorted by most recent
201
+ const orders = await client.customer.orders.list({
202
+ sort: '-completed_at',
203
+ })
204
+ ```
205
+
206
+ ```bash cURL
207
+ # Categories sorted by name
208
+ curl -G 'http://localhost:3000/api/v3/store/categories' \
209
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
210
+ -d 'sort=name'
211
+
212
+ # Customer orders by most recent
213
+ curl -G 'http://localhost:3000/api/v3/store/customer/orders' \
214
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
215
+ -H 'Authorization: Bearer <token>' \
216
+ -d 'sort=-completed_at'
217
+ ```
218
+
219
+
220
+ ## Expanding Associations
221
+
222
+ Use the `expand` parameter to include associated resources in the response. Pass a comma-separated list of association names:
223
+
224
+
225
+ ```typescript SDK
226
+ const product = await client.products.get('spree-tote', {
227
+ expand: ['variants', 'images'],
228
+ })
229
+ ```
230
+
231
+ ```bash cURL
232
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
233
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
234
+ -d 'expand=variants,images'
235
+ ```
236
+
237
+
238
+ ### Nested Expand
239
+
240
+ Use dot notation to expand nested associations (up to 4 levels deep):
241
+
242
+
243
+ ```typescript SDK
244
+ // Expand variants and their images in one request
245
+ const product = await client.products.get('spree-tote', {
246
+ expand: ['variants.images'],
247
+ })
248
+
249
+ // Multiple nested expands
250
+ const product = await client.products.get('spree-tote', {
251
+ expand: ['variants.images', 'variants.metafields', 'option_types'],
252
+ })
253
+
254
+ // Category with nested children
255
+ const category = await client.categories.get('clothing/shirts', {
256
+ expand: ['children.children'], // Two levels of subcategories
257
+ })
258
+ ```
259
+
260
+ ```bash cURL
261
+ # Expand variants with their images
262
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
263
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
264
+ -d 'expand=variants.images'
265
+
266
+ # Multiple nested expands
267
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
268
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
269
+ -d 'expand=variants.images,variants.metafields,option_types'
270
+ ```
271
+
272
+
273
+ ### Rules
274
+
275
+ - Maximum depth is **4 levels** (e.g., `a.b.c.d`)
276
+ - A nested expand automatically includes its parent — `expand=variants.images` expands both `variants` and their `images`
277
+ - Nested expand only applies to conditional associations (those controlled by `expand`)
278
+
279
+ ## Field Selection
280
+
281
+ Use the `fields` parameter to request only specific fields in the response. This reduces payload size for bandwidth-sensitive clients like mobile apps or server-side rendering.
282
+
283
+
284
+ ```typescript SDK
285
+ // Only return name, slug, and price
286
+ const products = await client.products.list({
287
+ fields: ['name', 'slug', 'price', 'display_price'],
288
+ })
289
+
290
+ // Works on single resources too
291
+ const product = await client.products.get('spree-tote', {
292
+ fields: ['name', 'slug', 'price'],
293
+ })
294
+ ```
295
+
296
+ ```bash cURL
297
+ curl -G 'http://localhost:3000/api/v3/store/products' \
298
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
299
+ -d 'fields=name,slug,price,display_price'
300
+ ```
301
+
302
+
303
+ ```json
304
+ {
305
+ "data": [
306
+ {
307
+ "id": "prod_86Rf07xd4z",
308
+ "name": "Spree Tote",
309
+ "slug": "spree-tote",
310
+ "price": "15.99",
311
+ "display_price": "$15.99"
312
+ }
313
+ ],
314
+ "meta": { ... }
315
+ }
316
+ ```
317
+
318
+ ### Rules
319
+
320
+ - The `id` field is **always included**, even if not listed in `fields`
321
+ - Omitting `fields` returns all fields (default behavior)
322
+ - Field selection applies to the top-level resource only — expanded associations always return their full set of fields
323
+ - Expanded associations are **always included** in the response regardless of `fields` — `?fields=name&expand=variants` returns `id`, `name`, and `variants`
324
+
325
+ > **NOTE:** The SDK TypeScript types remain fully typed regardless of field selection. When using `fields`, be aware that only the requested fields will be present at runtime.
326
+
327
+ ## Pagination
328
+
329
+ All collection endpoints return paginated results. Control pagination with `page` and `limit` parameters:
330
+
331
+
332
+ ```typescript SDK
333
+ const { data: products, meta } = await client.products.list({
334
+ page: 2,
335
+ limit: 10,
336
+ })
337
+
338
+ // meta contains pagination info
339
+ console.log(meta)
340
+ // {
341
+ // page: 2,
342
+ // limit: 10,
343
+ // count: 85,
344
+ // pages: 9,
345
+ // from: 11,
346
+ // to: 20,
347
+ // in: 10,
348
+ // previous: 1,
349
+ // next: 3
350
+ // }
351
+ ```
352
+
353
+ ```bash cURL
354
+ curl -G 'http://localhost:3000/api/v3/store/products' \
355
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
356
+ -d 'page=2' \
357
+ -d 'limit=10'
358
+ ```
359
+
360
+
361
+ ### Pagination Parameters
362
+
363
+ | Parameter | Default | Max | Description |
364
+ |-----------|---------|-----|-------------|
365
+ | `page` | `1` | - | Page number |
366
+ | `limit` | `25` | `100` | Number of records per page |
367
+
368
+ ### Pagination Metadata
369
+
370
+ Collection responses include a `meta` object with pagination info:
371
+
372
+ ```json
373
+ {
374
+ "data": [...],
375
+ "meta": {
376
+ "page": 1,
377
+ "limit": 25,
378
+ "count": 85,
379
+ "pages": 4,
380
+ "from": 1,
381
+ "to": 25,
382
+ "in": 25,
383
+ "previous": null,
384
+ "next": 2
385
+ }
386
+ }
387
+ ```
388
+
389
+ | Field | Description |
390
+ |-------|-------------|
391
+ | `page` | Current page number |
392
+ | `limit` | Records per page |
393
+ | `count` | Total number of records |
394
+ | `pages` | Total number of pages |
395
+ | `from` | Starting record number on this page |
396
+ | `to` | Ending record number on this page |
397
+ | `in` | Number of records returned on this page |
398
+ | `previous` | Previous page number (null if first page) |
399
+ | `next` | Next page number (null if last page) |
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: "Rate Limiting"
3
+ sidebarTitle: "Rate Limiting"
4
+ description: "Rate limits and throttling for the Store API"
5
+ ---
6
+
7
+ The Store API enforces rate limits to protect against abuse and ensure fair usage. Rate limits are applied per API key or per IP address depending on the endpoint.
8
+
9
+ ## Default Limits
10
+
11
+ | Endpoint | Limit | Scope | Window |
12
+ |----------|-------|-------|--------|
13
+ | All endpoints | 300 requests | Per API key | 1 minute |
14
+ | `POST /auth/login` | 5 requests | Per IP | 1 minute |
15
+ | `POST /customers` | 3 requests | Per IP | 1 minute |
16
+ | `POST /auth/refresh` | 10 requests | Per IP | 1 minute |
17
+ | `POST /auth/oauth/callback` | 5 requests | Per IP | 1 minute |
18
+
19
+ The global rate limit is tracked by your publishable API key (`X-Spree-Api-Key`). If the key is not provided, the limit falls back to the client's IP address.
20
+
21
+ Authentication endpoints have stricter per-IP limits to prevent brute-force attacks.
22
+
23
+ ## Rate Limit Headers
24
+
25
+ Every Store API response includes headers that show your current rate limit usage:
26
+
27
+ | Header | Description |
28
+ |--------|-------------|
29
+ | `X-RateLimit-Limit` | Maximum number of requests allowed per window |
30
+ | `X-RateLimit-Remaining` | Number of requests remaining in the current window |
31
+ | `Retry-After` | Seconds to wait before retrying (only present when limit is reached) |
32
+
33
+ Example response headers:
34
+
35
+ ```
36
+ HTTP/1.1 200 OK
37
+ X-RateLimit-Limit: 300
38
+ X-RateLimit-Remaining: 295
39
+ ```
40
+
41
+ ## Rate Limit Response
42
+
43
+ When you exceed the rate limit, the API returns a `429 Too Many Requests` response:
44
+
45
+ ```json
46
+ {
47
+ "error": {
48
+ "code": "rate_limit_exceeded",
49
+ "message": "Too many requests. Please retry later."
50
+ }
51
+ }
52
+ ```
53
+
54
+ The response includes rate limit headers and a `Retry-After` header indicating how many seconds to wait before retrying:
55
+
56
+ ```
57
+ HTTP/1.1 429 Too Many Requests
58
+ Content-Type: application/json
59
+ X-RateLimit-Limit: 300
60
+ X-RateLimit-Remaining: 0
61
+ Retry-After: 60
62
+ ```
63
+
64
+ ## SDK Retry Handling
65
+
66
+ The Spree SDK automatically handles rate-limited responses with built-in retry logic and exponential backoff:
67
+
68
+ ```typescript
69
+ import { createClient } from '@spree/sdk'
70
+
71
+ const client = createClient({
72
+ baseUrl: 'http://localhost:3000',
73
+ publishableKey: 'spree_pk_xxx',
74
+ retry: {
75
+ maxRetries: 2, // Number of retry attempts (default: 2)
76
+ baseDelay: 300, // Initial delay in ms (default: 300)
77
+ maxDelay: 10000, // Maximum delay in ms (default: 10000)
78
+ },
79
+ })
80
+ ```
81
+
82
+ The SDK respects the `Retry-After` header and only retries on `429` status codes for non-GET requests. For GET/HEAD requests, it also retries on `500`, `502`, `503`, and `504` errors.
83
+
84
+ ## Configuring Rate Limits
85
+
86
+ If you're self-hosting Spree, you can adjust rate limits in your initializer:
87
+
88
+ ```ruby
89
+ # config/initializers/spree.rb
90
+ Spree::Api::Config[:rate_limit_per_key] = 300 # Global limit per API key
91
+ Spree::Api::Config[:rate_limit_window] = 60 # Window in seconds
92
+ Spree::Api::Config[:rate_limit_login] = 5 # Login attempts per IP
93
+ Spree::Api::Config[:rate_limit_register] = 3 # Registration attempts per IP
94
+ Spree::Api::Config[:rate_limit_refresh] = 10 # Token refresh per IP
95
+ Spree::Api::Config[:rate_limit_oauth] = 5 # OAuth callbacks per IP
96
+ ```
97
+
98
+ Rate limiting uses `Rails.cache` as the backing store. For production environments with multiple application servers, ensure you're using a shared cache store like Redis:
99
+
100
+ ```ruby
101
+ # config/environments/production.rb
102
+ config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }
103
+ ```
@@ -0,0 +1,185 @@
1
+ ---
2
+ title: "Relations"
3
+ sidebarTitle: "Relations"
4
+ description: "How to include related resources in API responses"
5
+ ---
6
+
7
+ By default, the Store API returns only the primary resource attributes to keep responses fast and lightweight. Use the `expand` parameter to expand related resources inline.
8
+
9
+ ## Including Relations
10
+
11
+ Pass a comma-separated list of relation names via the `expand` query parameter:
12
+
13
+
14
+ ```typescript SDK
15
+ // Product with variants and images
16
+ const product = await client.products.get('spree-tote', {
17
+ expand: ['variants', 'images'],
18
+ })
19
+
20
+ // Access included relations directly
21
+ console.log(product.variants) // Array of variant objects
22
+ console.log(product.images) // Array of image objects
23
+ ```
24
+
25
+ ```bash cURL
26
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
27
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
28
+ -d 'expand=variants,images'
29
+ ```
30
+
31
+
32
+ ## Response Format
33
+
34
+ Without `expand`, relation fields are omitted from the response:
35
+
36
+ ```json
37
+ {
38
+ "id": "prod_86Rf07xd4z",
39
+ "name": "Spree Tote",
40
+ "slug": "spree-tote",
41
+ "price": { "amount": "15.99", "currency": "USD" },
42
+ "created_at": "2025-01-15T10:30:00Z"
43
+ }
44
+ ```
45
+
46
+ With `?expand=variants,images`, the related resources are embedded:
47
+
48
+ ```json
49
+ {
50
+ "id": "prod_86Rf07xd4z",
51
+ "name": "Spree Tote",
52
+ "slug": "spree-tote",
53
+ "price": { "amount": "15.99", "currency": "USD" },
54
+ "created_at": "2025-01-15T10:30:00Z",
55
+ "variants": [
56
+ {
57
+ "id": "variant_k5nR8xLq",
58
+ "sku": "SPR-TOTE-RED",
59
+ "price": { "amount": "15.99", "currency": "USD" },
60
+ "in_stock": true,
61
+ "option_values": [{ "name": "Red", "option_type_name": "Color" }]
62
+ }
63
+ ],
64
+ "images": [
65
+ {
66
+ "id": "img_9xPq2wLm",
67
+ "url": "https://cdn.example.com/spree-tote.jpg",
68
+ "alt": "Spree Tote"
69
+ }
70
+ ]
71
+ }
72
+ ```
73
+
74
+ ## Available Relations by Resource
75
+
76
+ ### Products
77
+
78
+ | Relation | Description |
79
+ |----------|-------------|
80
+ | `variants` | All purchasable variants |
81
+ | `default_variant` | The default variant |
82
+ | `master_variant` | The master variant |
83
+ | `images` | All product images (across all variants) |
84
+ | `option_types` | Option types (e.g., Size, Color) |
85
+ | `categories` | Categories this product belongs to |
86
+ | `metafields` | Public metafields (custom structured data) |
87
+
88
+
89
+ ```typescript SDK
90
+ const product = await client.products.get('spree-tote', {
91
+ expand: ['variants', 'images', 'option_types', 'metafields'],
92
+ })
93
+ ```
94
+
95
+ ```bash cURL
96
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
97
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
98
+ -d 'expand=variants,images,option_types,metafields'
99
+ ```
100
+
101
+
102
+ ### Categories
103
+
104
+ | Relation | Description |
105
+ |----------|-------------|
106
+ | `ancestors` | Parent categories (for breadcrumbs) |
107
+ | `children` | Direct child categories |
108
+ | `products` | Products in this category |
109
+
110
+
111
+ ```typescript SDK
112
+ const category = await client.categories.get('clothing/shirts', {
113
+ expand: ['ancestors', 'children'],
114
+ })
115
+ ```
116
+
117
+ ```bash cURL
118
+ curl -G 'http://localhost:3000/api/v3/store/categories/clothing/shirts' \
119
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
120
+ -d 'expand=ancestors,children'
121
+ ```
122
+
123
+
124
+ ### Countries
125
+
126
+ | Relation | Description |
127
+ |----------|-------------|
128
+ | `states` | States/provinces within the country |
129
+
130
+
131
+ ```typescript SDK
132
+ const usa = await client.countries.get('US', {
133
+ expand: ['states'],
134
+ })
135
+ console.log(usa.states) // Array of state objects
136
+ ```
137
+
138
+ ```bash cURL
139
+ curl -G 'http://localhost:3000/api/v3/store/countries/US' \
140
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
141
+ -d 'expand=states'
142
+ ```
143
+
144
+
145
+ ## Collections with Includes
146
+
147
+ The `expand` parameter also works on collection endpoints:
148
+
149
+
150
+ ```typescript SDK
151
+ // List products with their images and default variant
152
+ const { data: products } = await client.products.list({
153
+ expand: ['images', 'default_variant'],
154
+ limit: 12,
155
+ })
156
+ ```
157
+
158
+ ```bash cURL
159
+ curl -G 'http://localhost:3000/api/v3/store/products' \
160
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
161
+ -d 'expand=images,default_variant' \
162
+ -d 'limit=12'
163
+ ```
164
+
165
+
166
+ ## Nested Includes
167
+
168
+ Use dot notation to include nested relations:
169
+
170
+
171
+ ```typescript SDK
172
+ // Include variants and their nested option values
173
+ const product = await client.products.get('spree-tote', {
174
+ expand: ['variants.option_values'],
175
+ })
176
+ ```
177
+
178
+ ```bash cURL
179
+ curl -G 'http://localhost:3000/api/v3/store/products/spree-tote' \
180
+ -H 'X-Spree-Api-Key: spree_pk_xxx' \
181
+ -d 'expand=variants.option_values'
182
+ ```
183
+
184
+
185
+ > **NOTE:** Only include relations you actually need. Each included relation requires additional database queries, so requesting unnecessary relations will slow down the response.