@spree/docs 0.1.297 → 0.1.299

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.
@@ -25,6 +25,20 @@ curl -X POST https://api.mystore.com/api/v3/store/carts/cart_xxx/items \
25
25
 
26
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
27
 
28
+ ## Who A Cached Response Belongs To
29
+
30
+ A cached response is only ever returned to the caller that produced it, so the request has to say who that caller is. One of these identifies them:
31
+
32
+ - the **customer's access token** (`Authorization: Bearer ...`), for a signed-in shopper
33
+ - the **cart token** (`X-Spree-Token`), for a guest working on a cart they already hold
34
+ - a **secret key** (`sk_...`), for a server-to-server caller on the Admin API
35
+
36
+ Retry with the same credentials you sent the first time. A replay answers from the cache without running the request again, so it never re-checks your access — a retry that drops or swaps a credential is treated as a different caller and runs for real.
37
+
38
+ Your publishable key (`pk_...`) does not count. Every visitor to your storefront sends the same one, so a key value that two shoppers happen to share — `checkout-1`, an order number, a timestamp — would hand one shopper the other's response, cart token included.
39
+
40
+ A request that carries none of the credentials above still runs exactly as it always has — it is simply never cached, so the `Idempotency-Key` header has no effect on it. Guests are not second-class here: a guest holds a cart token from the moment their cart exists, which covers the whole of checkout, including the steps where a duplicate costs money.
41
+
28
42
  ## Supported Endpoints
29
43
 
30
44
  | Endpoint | Actions |
@@ -38,13 +52,15 @@ If the client retries this exact request with the same idempotency key, the API
38
52
  | `POST /carts/:id/coupon_codes` | Applying coupon codes |
39
53
  | `POST /carts/:id/store_credits` | Applying store credits |
40
54
 
55
+ Every one of these is replayable for a guest as well as for a signed-in shopper, because every one of them is reached with the cart's token. The exception is creating the cart itself: there is no cart yet, so a guest has no token to present and the key is ignored — a retry may leave behind a second, empty cart. Sign the shopper in, or accept the spare cart.
56
+
41
57
  Idempotency keys are ignored on `GET`, `DELETE`, and other non-supported actions.
42
58
 
43
59
  ## Key Requirements
44
60
 
45
61
  - Must be a string of **255 characters or less**
46
62
  - 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
63
+ - Keys are scoped to the caller and the store, so two callers can use the same key value without conflict
48
64
  - Cached responses expire after **24 hours**
49
65
 
50
66
  ## Response Headers
@@ -8461,7 +8461,7 @@ paths:
8461
8461
  client_secret: secret_123
8462
8462
  payment_method_id: pm_UkLWZg9DAJ
8463
8463
  payment_source_id: card_UkLWZg9DAJ
8464
- payment_source_type: Spree::CreditCard
8464
+ payment_source_type: credit_card
8465
8465
  customer_id: cust_UkLWZg9DAJ
8466
8466
  payment_method:
8467
8467
  id: pm_UkLWZg9DAJ
@@ -12746,9 +12746,6 @@ components:
12746
12746
  type: string
12747
12747
  label:
12748
12748
  type: string
12749
- type:
12750
- type: string
12751
- deprecated: true
12752
12749
  field_type:
12753
12750
  type: string
12754
12751
  enum:
@@ -12765,7 +12762,6 @@ components:
12765
12762
  required:
12766
12763
  - id
12767
12764
  - label
12768
- - type
12769
12765
  - field_type
12770
12766
  - key
12771
12767
  - value
@@ -38,7 +38,7 @@ erDiagram
38
38
  | `default` | Exactly one channel per store is the default. Used as a fallback when no channel header is present and as the auto-publish target for new products | `true` |
39
39
  | `storefront_access` | Controls what an anonymous visitor may see: `public`, `prices_hidden`, or `login_required`. Unset inherits the store's setting. See [Storefront Access Gating](#storefront-access-gating) | `login_required` |
40
40
  | `guest_checkout` | Whether an order may be placed without an account on this channel. Unset inherits the store's setting | `false` |
41
- | `preferred_order_routing_strategy` | Optional per-channel override of the store's [Order Routing](../how-to/custom-order-routing.md) strategy | `Spree::OrderRouting::Strategy::Rules` |
41
+ | `preferred_order_routing_strategy` | Optional per-channel override of the store's [Order Routing](../how-to/custom-order-routing.md) strategy | `rules` |
42
42
 
43
43
  `code` is normalized to a URL-safe slug on save — `POS` becomes `pos`, `Point of Sale!` becomes `point-of-sale`. Leaving `code` blank derives it from `name`.
44
44
 
@@ -243,7 +243,7 @@ split.
243
243
  ```typescript Admin SDK
244
244
  await adminClient.deliveryMethods.create({
245
245
  name: 'Pallet freight',
246
- rate_provider: 'Spree::DeliveryRateProvider::Freight',
246
+ rate_provider: 'freight',
247
247
  rules: [
248
248
  { type: 'volume_rule', preferences: { minimum_volume: 1, maximum_volume: 15 } },
249
249
  { type: 'company_rule', preferences: { company_orders_only: true } },
@@ -257,7 +257,7 @@ curl -X POST 'https://api.mystore.com/api/v3/admin/delivery_methods' \
257
257
  -H 'Content-Type: application/json' \
258
258
  -d '{
259
259
  "name": "Pallet freight",
260
- "rate_provider": "Spree::DeliveryRateProvider::Freight",
260
+ "rate_provider": "freight",
261
261
  "rules": [
262
262
  { "type": "volume_rule", "preferences": { "minimum_volume": 1, "maximum_volume": 15 } },
263
263
  { "type": "company_rule", "preferences": { "company_orders_only": true } }
@@ -257,6 +257,16 @@ curl 'https://api.mystore.com/api/v3/store/delivery_methods/dm_xxx/pickup_locati
257
257
  ```
258
258
 
259
259
 
260
+ Third-party pickup points come from a pickup point provider — a locker network or partner-shop integration. Spree ships none; an extension registers its provider so a delivery method can select it by its short name (for example `inpost` for `SpreeInpost::PickupPointProvider`):
261
+
262
+ ```ruby server/config/initializers/spree.rb
263
+ Rails.application.config.after_initialize do
264
+ Spree.pickup_point_providers << SpreeInpost::PickupPointProvider
265
+ end
266
+ ```
267
+
268
+ A delivery method can only use a registered provider.
269
+
260
270
  ## Managing fulfillments
261
271
 
262
272
 
@@ -71,7 +71,7 @@ Because the definition carries the type and the label, the dashboard can build a
71
71
 
72
72
  ```typescript Admin SDK
73
73
  const definition = await adminClient.customFieldDefinitions.create({
74
- resource_type: 'Spree::Product',
74
+ resource_type: 'product',
75
75
  namespace: 'properties',
76
76
  key: 'material',
77
77
  label: 'Material',
@@ -83,7 +83,7 @@ const definition = await adminClient.customFieldDefinitions.create({
83
83
 
84
84
  ```bash CLI
85
85
  spree api post /custom_field_definitions -d '{
86
- "resource_type": "Spree::Product",
86
+ "resource_type": "product",
87
87
  "namespace": "properties",
88
88
  "key": "material",
89
89
  "label": "Material",
@@ -686,7 +686,7 @@ sequenceDiagram
686
686
  | `external_client_secret` | Client secret for the frontend SDK | `seti_ABC123_secret_xyz` |
687
687
  | `external_data` | Provider-specific data | `{}` |
688
688
  | `payment_source_id` | The saved payment source created after completion | `card_xyz789` |
689
- | `payment_source_type` | The type of saved payment source | `Spree::CreditCard` |
689
+ | `payment_source_type` | The type of saved payment source | `credit_card` |
690
690
 
691
691
  ### Payment Setup Session API
692
692
 
@@ -15,7 +15,7 @@ Create a definition for products (Settings → Custom fields, the in-place "Set
15
15
 
16
16
  ```bash
17
17
  npx spree api post custom_field_definitions --data '{
18
- "resource_type": "Spree::Product",
18
+ "resource_type": "product",
19
19
  "namespace": "specs",
20
20
  "key": "tech_specs",
21
21
  "label": "Technical specifications",
@@ -808,7 +808,7 @@ A method priced by the **Freight** rate provider returns an unpriced rate. It re
808
808
  ```typescript Admin SDK
809
809
  await adminClient.deliveryMethods.create({
810
810
  name: 'Pallet freight',
811
- rate_provider: 'Spree::DeliveryRateProvider::Freight',
811
+ rate_provider: 'freight',
812
812
  rules: [
813
813
  { type: 'volume_rule', preferences: { minimum_volume: 1, maximum_volume: 15 } },
814
814
  { type: 'company_rule', preferences: { company_orders_only: true } },
@@ -822,7 +822,7 @@ curl -X POST 'https://api.mystore.com/api/v3/admin/delivery_methods' \
822
822
  -H 'Content-Type: application/json' \
823
823
  -d '{
824
824
  "name": "Pallet freight",
825
- "rate_provider": "Spree::DeliveryRateProvider::Freight",
825
+ "rate_provider": "freight",
826
826
  "rules": [
827
827
  { "type": "volume_rule", "preferences": { "minimum_volume": 1, "maximum_volume": 15 } },
828
828
  { "type": "company_rule", "preferences": { "company_orders_only": true } }
@@ -94,7 +94,7 @@ end
94
94
 
95
95
  Once registered, the provider appears as a source on the product's **Digital files** card: the **Add** button becomes a menu offering **Upload a file** alongside each registered provider. Picking your provider creates an asset with its `provider_type` set and no file attached.
96
96
 
97
- > **NOTE:** Registration is what makes a `provider_type` valid. An asset validates that its `provider_type` names a registered provider, so an unregistered or misspelled class name is rejected with a 422 rather than failing at download time. A blank `provider_type` is always the built-in `File` provider.
97
+ > **NOTE:** Registration is what makes a `provider_type` valid. The Admin API names a provider by its shorthand — the class name's last segment, underscored, so `license_key` for the provider above and `file` for the built-in one — and an asset validates that its `provider_type` names a registered provider, so an unregistered or misspelled value is rejected with a 422 rather than failing at download time. A blank `provider_type` is always the built-in `File` provider.
98
98
 
99
99
  ## The download contract
100
100
 
@@ -236,7 +236,11 @@ First register the class so it's selectable (this is the allowlist the model val
236
236
  Spree.order_routing.strategies << 'Acme::Oms::Strategy'.constantize
237
237
  ```
238
238
 
239
- Then select it by class name string — set on `Spree::Store` (default) or `Spree::Channel` (override). Setting an unregistered class fails validation.
239
+ Then select it — set on `Spree::Store` (default) or `Spree::Channel` (override). Setting an unregistered strategy fails validation. Ruby code may name the class; the Admin API and the dashboard name a strategy by its shorthand, `api_type` (the class name's last segment, underscored — `rules` for the built-in one). Override `self.api_type` on your strategy to give it a distinct, stable shorthand:
240
+
241
+ ```ruby
242
+ def self.api_type = 'acme_oms'
243
+ ```
240
244
 
241
245
  Activate on the whole store:
242
246
 
@@ -122,7 +122,7 @@ await client.products.customFields.create('prod_xxx', {
122
122
  The generic escape hatch covers any owner type:
123
123
 
124
124
  ```typescript
125
- await client.customFields('Spree::Product', 'prod_xxx').list()
125
+ await client.customFields('product', 'prod_xxx').list()
126
126
  ```
127
127
 
128
128
  ## Adding your own resources
@@ -495,6 +495,19 @@ now returns `nil` for an ID with another model's prefix, the same as
495
495
  `find_by_prefix_id`. Call `Spree::PrefixedId.decode_prefixed_id` if you
496
496
  really need to decode any prefix.
497
497
 
498
+ ## Type values are short names, not class names
499
+
500
+ The API no longer sends or accepts Ruby class names. Every value that used to name a class is now a short name (`Spree::CreditCard` becomes `credit_card`), so the API keeps the same shape whatever the server is built with. Records in the database are not touched.
501
+
502
+ If your storefront or webhook receiver reads any of these fields, compare against the short name instead:
503
+
504
+ | Field | Where | Before | After |
505
+ |---|---|---|---|
506
+ | `payment_source_type` | Store API payment setup sessions, `payment_setup_session.*` webhooks | `Spree::CreditCard` | `credit_card` |
507
+ | `type` | Custom fields on products, variants, categories and collections | `Spree::CustomFields::ShortText` | removed — read `field_type` (`short_text`) |
508
+
509
+ The Admin API follows the same rule everywhere: providers and strategies (`fulfillment_provider: 'manual'`, `preferred_order_routing_strategy: 'rules'`), custom field definition `resource_type` (`product`, `category`), tag `taggable_type`, the owner and originator types on records, and filters such as `q[type_eq]=orders`. An integration written against the Admin API preview sends and expects these short names; the [Admin SDK](../sdk/admin/resources.md) types list them.
510
+
498
511
  ## Every event is declared
499
512
 
500
513
  Events are now declared on the model that publishes them (`publishes_event`, `publishes_events`), and `publish_event` raises in development and test for a name nobody declared. Extensions that publish their own events need one line each — see [Publishing your own events](../core-concepts/events.md#publishing-your-own-events). In production an undeclared event is logged and still delivered.
@@ -21,10 +21,10 @@ The same setting through the Admin API:
21
21
 
22
22
  ```typescript Admin SDK
23
23
  const { data: providers } = await adminClient.payoutProviders.list()
24
- // find the row with id 'SpreeStripe::PayoutProvider' — `available` says whether this store can use it
24
+ // find the row with id 'stripe' — `available` says whether this store can use it
25
25
 
26
26
  await adminClient.store.update({
27
- preferred_payout_provider: 'SpreeStripe::PayoutProvider',
27
+ preferred_payout_provider: 'stripe',
28
28
  preferred_default_payouts_schedule_interval: 'weekly',
29
29
  preferred_default_minimum_payout_amount: 50,
30
30
  })
@@ -34,7 +34,7 @@ await adminClient.store.update({
34
34
  curl -X PATCH https://your-store.com/api/v3/admin/store \
35
35
  -H "X-Spree-API-Key: sk_xxx" \
36
36
  -H "Content-Type: application/json" \
37
- -d '{"preferred_payout_provider": "SpreeStripe::PayoutProvider", "preferred_default_payouts_schedule_interval": "weekly", "preferred_default_minimum_payout_amount": 50}'
37
+ -d '{"preferred_payout_provider": "stripe", "preferred_default_payouts_schedule_interval": "weekly", "preferred_default_minimum_payout_amount": 50}'
38
38
  ```
39
39
 
40
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.297",
3
+ "version": "0.1.299",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",