Commerce

Compose server-authored products, one-time checkout, finite stock, immutable orders, and physical fulfillment without turning one provider into the domain model.

Supported approaches

Catalog and quotes

available

Resolve immutable server-authored offers against an explicit payment provider and configured merchant instance.

Packages

@playstack/catalog@playstack/nest-catalog

Frameworks and integrations

One-time checkout

available

Persist an order and optional stock reservation before creating hosted provider checkout with repeat-safe commands.

Refunds and reconciliation

available

Project verified payment, refund, and dispute events while keeping browser redirects outside payment authority.

Physical fulfillment

available

Create encrypted fulfillment requests and run manual or provider-backed delivery work independently of payment state.

Frameworks and integrations

framework

NestJS

Connect portable Playstack capabilities to dependency injection, guards, decorators, request context, workers, and lifecycle hooks.

integration

Prisma

Persist Playstack capabilities through explicit application-owned Prisma clients, transactions, and managed schema fragments.

integration

Stripe

Create hosted subscription and one-time checkout, then reconcile verified Stripe events into separate billing and payment projections.

Package reference

@playstack/catalog

Keep commercial responsibilities separate

Catalog owns the terms offered for sale. Payments owns provider projections. Inventory owns stock promises. Commerce owns immutable order snapshots and coordinates their transaction boundaries. Fulfillment owns what happens to paid physical lines next.

ts
const commerce = createCommerce({
  persistence,
  catalog,
  payments,
  inventory,
  entitlements,
  fulfillment,
  events,
  ids,
  orderNumbers,
  clock,
  allowedRedirectOrigins: ['https://shop.example.com'],
})

const result = await commerce.createCheckout({
  buyer: { accountId, userId, email },
  items: [{ offerId: 'controller-stand-black', quantity: 1 }],
  paymentProvider: { provider: 'stripe', instance: 'store' },
  successUrl,
  cancelUrl,
  idempotencyKey,
})

The browser submits offer identities and quantities, never authoritative prices. Order creation and stock reservation can share one application transaction. Hosted checkout starts only after that commit.

Confirm only verified provider facts

Success redirects improve the buyer experience but never confirm an order. Verified, queued webhook projections flow through @playstack/payments before @playstack/commerce advances payment state. Amount drift quarantines the order for reconciliation.

ts
await payments.handleWebhook(verifiedPaymentEvent)
await commerce.applyPaymentProjection(paymentProjection)

Provider and configured instance are both persisted identities, so one application can safely use multiple Stripe accounts or mix future providers.

Fulfill through application-owned edges

@playstack/fulfillment encrypts address material behind an application codec. Its manual driver supports real staff workflows, while the Nest worker boundary can run through BullMQ, Inngest, or another queue. Subscriptions remain a separate Billing and entitlements path and can coexist with one-time purchases.

Go

Playstack Pro tag
OriginsPricingBlogNewsletterChangelogStatusRoadmap
ContributorsCommunityIn Use ShowcaseCase StudiesPartnersSponsors
FAQsSupportContact

© 2026 Playstack. All rights reserved.

With OSS
Terms of ServicePrivacy PolicyCookie PolicyImprint

By

Commune Software