Commerce Quickstart

  1. What you're building
  2. What the starter already gives you
  3. Install the packages
  4. Wire the catalog layer
  5. Wire the economy layer
  6. Register the Commerce blocks
  7. Seed or create products
  8. Render the storefront
  9. Checkout & the managed tier

This quickstart stands up a product catalog and a storefront: the Commerce block pack (product cards, grids, pricing tables) on the front, the @wabbit/tome-catalog layer holding products underneath, and the @wabbit/tome-economy layer for orders and checkout. It assumes you have the block loop from Get Started working.

The Commerce block pack ships as @wabbit/tome-blocks-catalog-pack (its buyer-facing name is "Commerce Blocks"). It's a gated pack, so installing it needs an install token whose scope includes it.

What the starter already gives you

If you forked tome-starter, Commerce is already wired — the fork ships with all three pieces in package.json and composed in src/payload.config.ts:

  • @wabbit/tome-catalog — the five product collections and the product-type registry.
  • @wabbit/tome-economy — orders, payments, prices, and the checkout adapters.
  • @wabbit/tome-blocks-catalog-pack — the storefront blocks, bridged in src/blocks/catalog-pack-bridge.*.

So on a starter fork you can skip to seeding products. The wiring sections below are the reference for how it's assembled — read them if you're adding Commerce to a bare Payload app, or to understand what your fork already did.

Install the packages

Make sure your .npmrc has the registry line and an install token (see Get Started) — the catalog pack is gated, so it needs the token. Then:

npm install @wabbit/tome-blocks-core @wabbit/tome-blocks-catalog-pack @wabbit/tome-catalog @wabbit/tome-economy

@wabbit/tome-catalog is an optional peer of the block pack — the blocks render with static props even without it. Install it anyway: it's what lets the blocks read live product data, and it's the collection home for everything you sell. @wabbit/tome-economy adds the order and checkout machinery.

Wire the catalog layer

The catalog layer is a set of collection factories plus a product-type registry. Register the product types you sell before building the product collection (the type select reads them), then add the collections:

import {
  createProductCollection,
  createProductAttributeCollection,
  createProductAttributeValueCollection,
  createCategoryCollection,
  createProductMediaCollection,
  createEntitlementsCollection,
  productTypeRegistry,
} from '@wabbit/tome-catalog'

// Register the product types your store uses (runs before createProductCollection):
productTypeRegistry.register({ value: 'physical', label: 'Physical', source: 'my-store' })

// ...then add these to your config's `collections` array:
createCategoryCollection({ maxDepth: 3, mediaCollection: 'media' }),
createProductAttributeCollection(),
createProductAttributeValueCollection(),
createProductCollection({ mediaCollection: 'media' }),
createProductMediaCollection({ mediaCollection: 'media' }),
createEntitlementsCollection({ usersSlug: 'members', membersSlug: 'members' }),

This gives you the catalog-products, catalog-categories,catalog-attributes, catalog-attribute-values, and catalog-media collections. createEntitlementsCollection is what a completed order writes to — it's how a purchase grants access.

Wire the economy layer

Call initEconomy() once at module load (it registers the admin sidebar grouping), wire your order-complete handler, and add the collection factories:

import {
  initEconomy,
  createOrdersCollection,
  createPaymentsCollection,
  createPricesCollection,
  createVendorEarningsCollection,
} from '@wabbit/tome-economy'

initEconomy()

// ...add to your config's `collections` array:
createOrdersCollection(),
createPaymentsCollection(),
createPricesCollection(),
createVendorEarningsCollection(),

The economy layer ships two payment adapters: FreeAdapter (a zero-cost checkout that completes orders immediately — the default the starter demos with) and StripeAdapter (lazy-loads the Stripe SDK; only used when you add Stripe keys). The order-complete event is where you grant the entitlement — the starter wires this in src/lib/economy/orderHandlers.ts via registerStarterOrderHandlers(), which turns a completed order into a catalog entitlement (and an LMS enrollment for course products).

Register the Commerce blocks

The pack exposes six blocks: product-card, product-grid,category-strip, price-table, inventory-badge, and featured-product. Register them the same way as any pack — the one-call form:

import { blockRegistry, bundleRegistry } from '@wabbit/tome-blocks-core'
import { register } from '@wabbit/tome-blocks-catalog-pack'

register(blockRegistry, bundleRegistry)
// blockRegistry.resolveAll() now includes the six catalog blocks

The starter uses its bridge form instead: the config half (src/blocks/catalog-pack-bridge.config.ts) imports the block descriptors and spreads CatalogPackBlocks into the Pages layout field; the render half (src/blocks/catalog-pack-bridge.tsx) imports the components from @wabbit/tome-blocks-catalog-pack/render and folds catalogPackComponents into the master render map. When the @wabbit/tome-catalog layer is present, the blocks detect it and light up their rich data path; when it's absent they fall back to static props.

Seed or create products

The starter has a real seed. Running the demo seeds populate the catalog-products collection with live rows:

npm run demo:dev

That runs with DEMO_SEED=1 SANDBOX_SEED=1 and creates a set of demo products (physical goods, course products, and block-bundle products), categories, and attributes — all idempotent, so re-running is safe. Prefer to start clean? Create a product by hand in /admin under the catalog-products collection — pick a type you registered, set it active, and it's live.

Render the storefront

With the pack registered, drop a product-grid or featured-product block onto a page's layout in /admin and publish. RenderBlocks paints it through the component map you wired in the previous step. The starter's auto-gallery route /blocks/catalog-pack shows every catalog block and variant.

Heads up — blocks vs. live data. In the starter, the seeded storefront blocks are fed hand-written demo product props, and the auto-gallery uses fabricated demo props — neither is bound to the seeded catalog-products rows out of the box. The starter demonstrates live product data on a separate /products route that queries catalog-products directly with @wabbit/tome-ui card primitives, not the pack's ProductGrid. Wiring the pack blocks to live rows (via the block's @wabbit/tome-catalog integration) is the step you own — budget for it, and treat "blocks render" and "blocks show my real products" as two separate checkpoints.

Checkout & the managed tier

The economy layer's FreeAdapter gives you an end-to-end checkout with no payment processor — good for course sign-ups, comps, and proving the order → entitlement flow. Add Stripe by installing the stripe SDK and configuring the StripeAdapter; the lazy import means you carry no Stripe dependency until you opt in.

The fully-managed Commerce capability tier — where we run the payment-flow and its liability with you — is set up through a request-access conversation, not a checkout button. If that's where you're headed, reach out. For what a subscription keeps buying you after install, see Versioning & updates.