Changelog
Notable changes to the public developer surface — the API, the
@dscodotco/sdk client, and the storefront contract. Internal-only changes
(console panels, infra scaffolding) are omitted. Dates are grouped by month;
where a change alters a contract you consume, the migration note says so.
September 2026
Public catalog now returns a resolvable image_url
The public catalog previously emitted only the opaque asset:<store>/<sha>
ref and pushed all resolution to the client. Commerce now resolves the ref and
includes image_url (and a per-image url) on products list, product-by-slug,
search, and collection detail. Resolution is a pure string transform against an
ASSET_BASE_URL; when the base is unset the field is null (honest absence,
never a broken guess). The OpenAPI spec and SDK types carry the new field.
Migration: none required — the field is additive. Headless consumers that were
resolving asset refs themselves can now read image_url directly.
Replay-safe webhook signatures
Outbound webhooks are now signed with a versioned, replay-safe scheme:
x-webhook-timestamp plus x-webhook-signature-v1, where the signature is
t=<ts>,v1=<HMAC(secret, ts.body)>. The delivery envelope also gains a
created_at. The legacy signature header is still sent but is deprecated.
See the webhooks reference for the verification recipe.
Migration: move verification to x-webhook-signature-v1 (timestamp + HMAC
over timestamp.body); stop trusting the legacy header.
Public authored-site endpoint — GET /v1/tenants/{tenant}/site
The merchant’s authored site (sections, nav, theme tokens) is now part of the
public contract. GET /v1/tenants/{tenant}/site returns the active manifest
for a live store — the same ETag contract as store resolve. A non-live or
unknown tenant is the same 404 (no existence oracle), and a repo failure is a
503, never a silent empty manifest. The SDK exposes it as store.site.get().
See Manifest & sections and
Build your own frontend.
Idempotency-Key on money-path routes
The money-moving routes now take a required, deterministic idempotency key so a
retried write replays instead of double-posting. Checkout requires an
Idempotency-Key header (a submit without it is a 400); the returns
receive (restock + settle refund) route requires it too; the storefront
cancel/edit/refund calls take the same key. Make the key deterministic — derive
it from the business event, never a fresh random value. See
Money invariants.
Store credit and gift cards as checkout tenders
Two money tenders are now first-class at checkout. Store credit (an authed
shopper’s cash balance) applies as a partial tender behind the
storeCredit.enabled manifest gate, reducing the card charge by
min(balance, orderTotal). Gift cards are
purchasable/redeemable bearer codes behind the giftCards.enabled gate — the
plaintext code is shown once at issue, and redemption applies as a partial
decrement. A multi-tender order stays zero-sum
across store credit + gift card + card. Recipes:
store credit, gift cards.
Public, unauthenticated catalog route
Commerce gained the one public, tenant-scoped catalog route the storefront
shop pages (and unauthenticated headless callers) need:
GET /commerce/v1/tenants/:tenant/catalog/products and .../products/:slug.
Read-only, and gated three independent ways — only active products, only a
live store, and a failed read is a 503 — so a draft or
suspended tenant 404s identically to an unknown tenant slug (no slug
enumeration).
Collections & faceted search
Two discovery surfaces on the public catalog:
GET /v1/tenants/:tenant/catalog/search (full-text search with price and
collection facets) and .../catalog/collections[/:slug]. Both share the
live-store gate and the honest-absence contract; a blank query is a valid “no
query” (empty 200), a DB failure is a 503. See the
collections & search reference.
Typed SDK — @dscodotco/sdk 0.0.3
@dscodotco/sdk is a typed fetch client generated from the API’s OpenAPI
document. createFlightdeckClient({ baseUrl, fdkToken?, storefrontToken? })
gives compile-time-checked paths, path/query/body shapes, and response types,
with the fdk_ Bearer / x-storefront-token credentials injected automatically;
createStorefrontClient(...) wraps it as a tenant-pinned storefront client. The
package is MIT-licensed, has zero workspace dependencies, and is publishable and
consumable standalone.
Merchant site builder — drafts, preview, publish, rollback
The manifest is now edited as immutable versioned drafts with an active
pointer. New merchant routes (GET /v1/my/site, PUT /v1/my/site/draft,
POST /v1/my/site/publish, POST /v1/my/site/preview-token) let a merchant
build against the live storefront without touching the published site;
publishing an older version is the rollback. A signed, short-lived preview token
renders a draft behind a non-dismissible banner and forced noindex. See
Manifest & sections.