2.2.0 (2026-08-06)
Catches the SDK up to Spwig 1.7.1 (sale-aware pricing, region availability,
AVIF <picture> sources, subscription card→token capture).
it is released as a minor deliberately, and the breaks below are cheaper to absorb in-house now than to
carry a 3.0.0 boundary for a handful of first-party sites. Read the Breaking and
Migration sections before upgrading.
⚠️ Breaking
CreatePaymentIntentInput.checkout_session_idis nownumber, notstring.
The backend keysCheckoutSessionby integer PK; the olduuidtyping/docs
were wrong. Pass the numeric session id (you rarely need to pass it at all —
it defaults to the active cart's session).Product.compare_at_price_amountchanged meaning. It is no longer a stored
MSRP; it is the struck-through regular price and isnullunless the product
is on sale. Render price from the neweffective_price_amount+is_on_sale
and only strike throughcompare_at_price_amountwhenis_on_sale. Same field
name and type, so this will not raise a compile error — audit price display
code by hand.Product.is_in_stocknow returnstruefor pre-order / backorder products,
not only in-stock ones. Gate "buyable" UI on this; useproducts.availability()
for the pre-order/backorder distinction.adminAttributeAssignInputreshaped to
{ assignments: [{ attribute_id, value_ids: number[], sort_order? }] }(was
{ attributes: [{ attribute_id, values: string[] }] }). The backend now
enforces the new shape; the old one was already incorrect.adminBrandingSettingsUpdateInputno longer acceptsprimary_color—
the backend never persisted it (silent no-op). It is still returned on the
read typeBrandingSettings(sourced from theme tokens).adminBulkPriceUpdateInput/BulkSaleUpdateInputvalidation tightened:
round_tomax is now the currency precision (2, was 4); pricevaluemust be
>= 0(absolute) />= -100(percentage); salesale_valuemust be> 0
(0 is rejected).adminAdminOrder.item_countnow excludes bundle child lines, so the
value can differ for orders containing bundles.
Added
store.setRegion(country)→POST /api/store/set-region/. Sets the
shopper's ship-to region from an ISO-3166 country the store ships to; drives
Product.ships_to_region/ regional stock and may switch the active currency.
NewSetRegionResulttype.subscriptions.beginTokenSetup(providerAccountId)→
POST /api/subscriptions/tokens/begin-setup/. Provider-agnostic setup for a
reusable subscription payment method; returns aSubscriptionSetupBundle.cart.attachSubscriptionToken(itemId, paymentTokenId)→
POST /api/cart/items/{id}/attach-subscription-token/. Binds a reusable
PaymentToken to a subscription line so the first cycle and renewals can be
charged (card capture is deferred to checkout).Product/ProductListsale + region fields:effective_price_amount,
is_on_sale,ships_to_region.- AVIF
<picture>support: newPictureSourcestype andimage_sources
onProductImage,ProductVariant,Category(+banner_image_sources),
plusprimary_image.image_sources. Emitted alongside the existing URL fields. CartItemsubscription + sale fields:is_on_sale,regular_total,
pricing_tier_details,subscription_billing_display,subscription_unit_price.AddToCartInputsubscription fields:is_subscription,
subscription_plan_id,pricing_tier_id, optionalpayment_token_id
(attach later viaattachSubscriptionToken(); subscription add-to-cart
requires an authenticated shopper).SearchResultregular_priceandis_on_sale;priceis now the
sale-aware display price.adminanalytics:SalesComparisongainscurrent_order_count,
previous_order_count,daily_breakdown;DashboardAnalyticsgains
custom_range.adminMessageReplyResponsetype;messages.reply()is now typed with
it (includesemail_errorwhen the reply saved but the email failed to send).- SVG store logos are now accepted by
adminsettings.uploadLogo()
(sanitised server-side); no request-shape change.
Fixed
- Regenerated
src/generated/schema.tsfrom the 1.7.1api-schema.yml
(3 new endpoints, 4 new component schemas, 14 changed). The committed types
were a release behind the contract.
Migration
Consumers are Spwig's own installations. Do the following, in order:
- Switch product price rendering to
effective_price_amount+is_on_sale;
treatcompare_at_price_amountas the strike-through value (null off-sale). - If you pass
checkout_session_idtopayments.createIntent(), pass a number. - Update any
adminattribute-assign call to theassignments/value_ids
shape and dropprimary_colorfrom branding updates. - Re-check
is_in_stockusage where pre-orders should be treated differently.