@spree/docs 0.1.31 → 0.1.33

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.
@@ -0,0 +1,296 @@
1
+ ---
2
+ title: "Querying"
3
+ sidebarTitle: "Querying"
4
+ description: "Filter, sort, paginate, and expand Admin API list responses"
5
+ ---
6
+
7
+ The Admin API uses [Ransack](https://activerecord-hackery.github.io/ransack/) for filtering and sorting on collection endpoints. All filter conditions go through the `q` parameter; sorting and pagination are top-level params.
8
+
9
+ ## Filtering
10
+
11
+ Pass filter conditions via `q`:
12
+
13
+
14
+ ```typescript SDK
15
+ const orders = await client.orders.list({
16
+ status_eq: 'complete',
17
+ total_gteq: 100,
18
+ email_cont: '@example.com',
19
+ })
20
+ ```
21
+
22
+ ```bash cURL
23
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
24
+ -H 'X-Spree-Api-Key: sk_xxx' \
25
+ --data-urlencode 'q[status_eq]=complete' \
26
+ --data-urlencode 'q[total_gteq]=100' \
27
+ --data-urlencode 'q[email_cont]=@example.com'
28
+ ```
29
+
30
+
31
+ > **NOTE:** The SDK automatically wraps filter keys in `q[...]` and appends `[]` for array values — pass flat params.
32
+
33
+ ### Common predicates
34
+
35
+ | Predicate | Description | SDK | cURL |
36
+ |---|---|---|---|
37
+ | `eq` | Equals | `status_eq: 'complete'` | `q[status_eq]=complete` |
38
+ | `not_eq` | Not equals | `status_not_eq: 'canceled'` | `q[status_not_eq]=canceled` |
39
+ | `cont` | Contains (case-insensitive) | `email_cont: '@acme'` | `q[email_cont]=@acme` |
40
+ | `start` | Starts with | `number_start: 'R10'` | `q[number_start]=R10` |
41
+ | `end` | Ends with | `slug_end: 'sale'` | `q[slug_end]=sale` |
42
+ | `lt` / `lteq` | Less than / less than or equal | `total_lteq: 50` | `q[total_lteq]=50` |
43
+ | `gt` / `gteq` | Greater than / greater than or equal | `total_gteq: 100` | `q[total_gteq]=100` |
44
+ | `in` | In a list | `status_in: ['complete', 'canceled']` | `q[status_in][]=complete&q[status_in][]=canceled` |
45
+ | `null` / `not_null` | Is null / not null | `completed_at_not_null: true` | `q[completed_at_not_null]=true` |
46
+ | `true` / `false` | Boolean | `accepts_email_marketing_true: 1` | `q[accepts_email_marketing_true]=1` |
47
+
48
+ ### Prefixed IDs in filters
49
+
50
+ Resource ID filters accept Stripe-style prefixed IDs directly. The server decodes them before querying:
51
+
52
+
53
+ ```typescript SDK
54
+ // All orders for a specific customer
55
+ const orders = await client.orders.list({
56
+ user_id_eq: 'cus_UkLWZg9DAJ',
57
+ })
58
+ ```
59
+
60
+ ```bash cURL
61
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
62
+ -H 'X-Spree-Api-Key: sk_xxx' \
63
+ --data-urlencode 'q[user_id_eq]=cus_UkLWZg9DAJ'
64
+ ```
65
+
66
+
67
+ The same applies to `_id_in`, `_id_not_eq`, and other ID predicates.
68
+
69
+ ### Combining filters
70
+
71
+ Multiple filters combine with AND:
72
+
73
+
74
+ ```typescript SDK
75
+ // Completed orders over $100 from the last 7 days
76
+ const orders = await client.orders.list({
77
+ status_eq: 'complete',
78
+ total_gteq: 100,
79
+ completed_at_gteq: new Date(Date.now() - 7 * 86_400_000).toISOString(),
80
+ })
81
+ ```
82
+
83
+ ```bash cURL
84
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
85
+ -H 'X-Spree-Api-Key: sk_xxx' \
86
+ --data-urlencode 'q[status_eq]=complete' \
87
+ --data-urlencode 'q[total_gteq]=100' \
88
+ --data-urlencode 'q[completed_at_gteq]=2026-04-22T00:00:00Z'
89
+ ```
90
+
91
+
92
+ ### Filtering by association
93
+
94
+ Use underscore notation to filter on associated model attributes:
95
+
96
+
97
+ ```typescript SDK
98
+ // Customers tagged as "wholesale"
99
+ const customers = await client.customers.list({
100
+ tags_name_eq: 'wholesale',
101
+ })
102
+
103
+ // Products in a specific category
104
+ const products = await client.products.list({
105
+ taxons_id_eq: 'ctg_xxx',
106
+ })
107
+ ```
108
+
109
+ ```bash cURL
110
+ curl -G 'https://store.example.com/api/v3/admin/customers' \
111
+ -H 'X-Spree-Api-Key: sk_xxx' \
112
+ --data-urlencode 'q[tags_name_eq]=wholesale'
113
+ ```
114
+
115
+
116
+ ### Custom search scopes
117
+
118
+ Some resources expose convenience search scopes:
119
+
120
+ | Resource | Scope | Example |
121
+ |---|---|---|
122
+ | Customers | `search` | Full-text over email + first/last name |
123
+ | Customers | `with_min_total_spent` | Filter by lifetime spend |
124
+ | Orders | `multi_search` | Number + email full-text |
125
+
126
+
127
+ ```typescript SDK
128
+ const customers = await client.customers.list({
129
+ search: 'jane',
130
+ })
131
+
132
+ const vipCustomers = await client.customers.list({
133
+ with_min_total_spent: 1000,
134
+ })
135
+ ```
136
+
137
+ ```bash cURL
138
+ curl -G 'https://store.example.com/api/v3/admin/customers' \
139
+ -H 'X-Spree-Api-Key: sk_xxx' \
140
+ --data-urlencode 'q[search]=jane'
141
+ ```
142
+
143
+
144
+ ## Sorting
145
+
146
+ Use the top-level `sort` parameter on any list endpoint. Prefix with `-` for descending. Follows the [JSON:API sorting convention](https://jsonapi.org/format/#fetching-sorting).
147
+
148
+
149
+ ```typescript SDK
150
+ // Most recent orders first
151
+ const orders = await client.orders.list({
152
+ sort: '-completed_at',
153
+ })
154
+
155
+ // Multiple sort keys (priority left to right)
156
+ const customers = await client.customers.list({
157
+ sort: '-total_spent,email',
158
+ })
159
+ ```
160
+
161
+ ```bash cURL
162
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
163
+ -H 'X-Spree-Api-Key: sk_xxx' \
164
+ -d 'sort=-completed_at'
165
+ ```
166
+
167
+
168
+ Sortable columns are limited to those whitelisted on the model (Ransack's `whitelisted_ransackable_attributes`). Sorting on a virtual column (e.g., a serializer-computed field like `display_total_spent`) is not supported.
169
+
170
+ ## Pagination
171
+
172
+ All collection endpoints return paginated results. Control with `page` and `limit`:
173
+
174
+
175
+ ```typescript SDK
176
+ const { data: orders, meta } = await client.orders.list({
177
+ page: 2,
178
+ limit: 50,
179
+ })
180
+
181
+ // meta.count, meta.pages, meta.previous, meta.next ...
182
+ ```
183
+
184
+ ```bash cURL
185
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
186
+ -H 'X-Spree-Api-Key: sk_xxx' \
187
+ -d 'page=2' \
188
+ -d 'limit=50'
189
+ ```
190
+
191
+
192
+ | Parameter | Default | Max | Description |
193
+ |---|---|---|---|
194
+ | `page` | `1` | — | Page number (1-indexed) |
195
+ | `limit` | `25` | `100` | Records per page |
196
+
197
+ ### Pagination metadata
198
+
199
+ Responses include a `meta` object:
200
+
201
+ ```json
202
+ {
203
+ "data": [...],
204
+ "meta": {
205
+ "page": 2,
206
+ "limit": 50,
207
+ "count": 327,
208
+ "pages": 7,
209
+ "from": 51,
210
+ "to": 100,
211
+ "in": 50,
212
+ "previous": 1,
213
+ "next": 3
214
+ }
215
+ }
216
+ ```
217
+
218
+ | Field | Description |
219
+ |---|---|
220
+ | `page` | Current page number |
221
+ | `limit` | Records per page |
222
+ | `count` | Total number of matching records |
223
+ | `pages` | Total number of pages |
224
+ | `from` / `to` / `in` | Position range / count of this page |
225
+ | `previous` / `next` | Previous/next page number, or `null` |
226
+
227
+ ## Expanding associations
228
+
229
+ Most admin endpoints return slim payloads by default — associations are returned as IDs. Use the `expand` parameter to include related resources inline:
230
+
231
+
232
+ ```typescript SDK
233
+ const order = await client.orders.get('or_xxx', {
234
+ expand: ['items', 'fulfillments', 'payments', 'customer'],
235
+ })
236
+
237
+ // Nested expand
238
+ const customer = await client.customers.get('cus_xxx', {
239
+ expand: ['addresses', 'store_credits'],
240
+ })
241
+ ```
242
+
243
+ ```bash cURL
244
+ curl -G 'https://store.example.com/api/v3/admin/orders/or_xxx' \
245
+ -H 'X-Spree-Api-Key: sk_xxx' \
246
+ -d 'expand=items,fulfillments,payments,customer'
247
+ ```
248
+
249
+
250
+ ### Nested expand
251
+
252
+ Use dot notation up to 4 levels deep:
253
+
254
+ ```typescript
255
+ const order = await client.orders.get('or_xxx', {
256
+ expand: ['items.variant.product', 'fulfillments.tracking'],
257
+ })
258
+ ```
259
+
260
+ A nested expand implicitly includes its parent — `expand: ['items.variant']` returns both `items` and their `variant` data.
261
+
262
+ ### What can I expand?
263
+
264
+ Each endpoint documents its supported expand keys in the OpenAPI reference. Common admin expansions:
265
+
266
+ | Resource | Common expands |
267
+ |---|---|
268
+ | Orders | `items`, `fulfillments`, `payments`, `customer`, `discounts`, `adjustments`, `billing_address`, `shipping_address` |
269
+ | Customers | `addresses`, `store_credits`, `orders` |
270
+ | Products | `variants`, `media`, `option_types`, `categories` |
271
+
272
+ ## Field selection
273
+
274
+ Use the `fields` parameter to request only specific fields on a resource. Reduces payload size for bandwidth-sensitive integrations:
275
+
276
+
277
+ ```typescript SDK
278
+ const orders = await client.orders.list({
279
+ fields: ['number', 'total', 'status', 'completed_at'],
280
+ })
281
+ ```
282
+
283
+ ```bash cURL
284
+ curl -G 'https://store.example.com/api/v3/admin/orders' \
285
+ -H 'X-Spree-Api-Key: sk_xxx' \
286
+ -d 'fields=number,total,status,completed_at'
287
+ ```
288
+
289
+
290
+ Rules:
291
+
292
+ - `id` is always included
293
+ - Expanded associations return their full payload regardless of `fields`
294
+ - Field selection applies to the top-level resource only
295
+
296
+ > **NOTE:** TypeScript types in `@spree/admin-sdk` remain fully typed regardless of `fields`. At runtime, only the requested fields are present — the rest are `undefined`.