Products & subscriptions
The catalog is the heart of a store. NanoSite supports two kinds of products — standard (one-time purchase) and subscription (recurring billing) — plus variants, options, multi-currency pricing, inventory, and collections.
Product types
A product's type is one of:
| Type | Value | Billing |
|---|---|---|
| Standard | standard |
One-time purchase (default). |
| Subscription | subscription |
Recurring billing on an interval. |
The type controls how pricing works and how checkout behaves.
Standard products
A normal one-time product. Prices carry no recurring interval. Checkout charges the shopper once.
Subscription products
A recurring product. Every price must declare a recurring interval:
recurringInterval— one ofday,week,month,year.recurringIntervalCount— how many intervals per billing cycle (1–52, default1). For examplemonth×3bills quarterly.
These map directly to Stripe's recurring price model. NanoSite enforces the invariant at create time: a subscription product must have a recurring interval on every price; a standard product must have none.
Subscription rules (current phase)
Subscriptions are backed by Stripe's hosted subscription checkout, which imposes some rules today:
- Stripe only. A subscription can only be paid with the Stripe provider.
- Standalone cart. A subscription must be purchased on its own — you can't mix a subscription and one-time items in the same cart.
- Hosted redirect. Subscription checkout returns a
redirectUrlto Stripe's hosted Checkout (mode=subscription); you must supplysuccessUrlandcancelUrl. - Webhook required. The store's Stripe webhook signing secret must be configured — renewals and status changes arrive by webhook.
- Discounts, shipping, and tax are skipped for subscription checkouts in this phase (Stripe bills the recurring price directly).
Subscription records track the lifecycle with a normalized status —
active, trialing, past_due, unpaid, incomplete, or canceled — kept current by Stripe
webhooks. Stripe remains the billing source of truth. Subscriptions are readable via the admin API
(useListAdminSubscriptions).
Prices & currency
Money is always stored as integer minor units — 1999 means $19.99 — and a product can carry
one price per currency for true multi-currency pricing. Amounts never use floats, so there's no
rounding drift.
Options & variants
- Options are the choosable axes of a product — e.g.
Sizewith valuesS/M/L,ColorwithBlack/White. They're defined per product. - Variants are the concrete purchasable combinations (e.g. Medium / Black), each with its own
sku, per-currencyprices, and inventory.
This is exactly what apparel and fashion stores need: a T-shirt with Size and Color generates a
variant per combination, each independently priced and stocked. High-value categories work the same
way — a ring can offer a Material and ring Size, or a made-to-order piece can carry custom
options. There's no practical limit that makes NanoSite "boutique-only".
Inventory model
Inventory follows a Shopify-style "track or don't" model:
- Omit
onHand→ the variant is untracked: effectively unlimited, always in stock, never counts down, and holds no reservation. - Provide
onHand→ the variant is tracked: stock is reserved at checkout and decremented on sale. An explicittrackInventoryflag always wins if you set it. allowBackorderlets a tracked variant sell past zero.
Reservations are evaluated under a row lock, so concurrent checkouts can't oversell a tracked variant.
Collections
Collections group products (e.g. New arrivals, Sale). A product joins collections via its
collectionIds, and the storefront can list a collection together with its published products.
Querying products from the storefront
Use useListStoreProducts with filters — q (search over title/description/options/collections),
collection, currency, minPrice/maxPrice, and sort (relevance, newest, title,
price_asc, price_desc, rating). Fetch a single product with useGetStoreProduct (by slug).
See the SDK overview for how these hooks are configured.