Skip to main content
Three shapes cover almost every headless build. Pick the one that matches your stack and skim the others when you need to make a trade-off.

Setup A β€” Pure SPA (React / Vue / Svelte / Astro Islands)

Best when your frontend is static or client-rendered and your only backend is your webhook receiver. Typical flow:
  1. The browser reads public storefront data with @shoppexio/storefront.
  2. Checkout happens through hosted checkout or the Embed SDK.
  3. Shoppex sends signed webhooks to your worker.
  4. Your worker fulfills the order or updates your own systems.
Responsibilities:
PieceResponsibility
Browser SPAUI, product grid, cart UI, buy button with @shoppexio/storefront or Embed SDK
Webhook workerVerify X-Shoppex-Signature, run fulfillment, persist order state
ShoppexCatalog, PSP orchestration, invoice, license delivery, webhook emission
When to pick this: landing pages, marketing sites, brochure sites with buy buttons, lightweight storefronts, and any place where you do not want to run a full origin server. Pitfalls:
  • Do not ship shx_* API keys in the SPA bundle. Server-side reads need a tiny backend (worker or Route Handler).
  • If you need to transform data before it hits the browser, go to Setup B.

Setup B β€” Next.js SSR (or Nuxt / SvelteKit / Remix)

Best when you want SEO, per-request personalization, and a single deployable unit. Typical flow:
  1. The browser requests HTML from your app.
  2. Server Components or Route Handlers call the Dev API with your server-held API key.
  3. A Server Action creates the payment and redirects the buyer to hosted checkout.
  4. Shoppex posts signed webhooks back to your app.
Responsibilities:
PieceResponsibility
Server ComponentsCatalog reads, personalization, pricing overrides, session lookup
Server ActionsCreate payment session, return redirect URL
Route HandlersVerify and handle signed webhooks
ShoppexEverything payment, invoice, license, subscription
When to pick this: any storefront where SEO matters, where you have a login, or where you want to serve per-customer content. This is the shape the Next.js Quickstart builds. Pitfalls:
  • Server Actions and Route Handlers must be the only place you touch SHOPPEX_API_KEY. Wrap your SDK client in import 'server-only'.
  • Next.js 16 request APIs are async β€” await cookies(), await headers(), await params, await searchParams.
  • Do not forget constant-time signature comparison (timingSafeEqual) in your webhook route.

Setup C β€” Mobile + Backend-for-Frontend

Best for native iOS / Android / React Native apps, Electron apps, or any client that must not hold long-lived API keys. Typical flow:
  1. The app sends its own session token to your BFF.
  2. The BFF creates the payment with the Dev API.
  3. The app opens the hosted checkout URL in the system browser.
  4. Shoppex redirects the buyer back to your app or fallback return page.
  5. Shoppex also sends the signed webhook to your BFF so your backend has the final source of truth.
Responsibilities:
PieceResponsibility
Native appYour UI, your auth, deep-link handler for the return URL
BFFExchange user session for scoped Shoppex calls, create payment sessions, run fulfillment
ShoppexEverything commerce
When to pick this: any mobile or desktop app, or any setup where your users log in with a system other than Shoppex customer OTP. Pitfalls:
  • Use a universal link / app link as return_url so the OS hands control back to your app cleanly.
  • Never bundle the shx_* key in the app binary. Always route through your BFF.
  • For Apple App Store apps selling digital goods consumed in-app, App Store review rules may require In-App Purchase instead of a web checkout β€” check before shipping.

Auth Surface by Setup

SetupWho holds the API keyCustomer login
A β€” Pure SPAWorker / tiny backend onlyNone, or your own magic-link/OAuth
B β€” Next.js SSRServer Components + Route HandlersNext-Auth / your own / Shoppex customer OTP
C β€” Mobile + BFFBFF onlyYour app’s existing auth
Customer OTP (/v1/customer/auth/otp/request, /verify) is available as a drop-in auth for Setup A. Setup B and C typically keep their own auth and use Shoppex for commerce only. For headless frontends, pass an optional redirect_url on /v1/customer/auth/otp/request. The URL is validated against the shop’s allowed callback hosts (<slug>.myshoppex.io or any enabled custom domain) and is returned on the successful /verify response so your frontend can redirect after setting the session. Invalid or disallowed hosts are rejected with 400.

Idempotency and Retries

All three setups share the same rules:
  • Send Idempotency-Key on every mutating Dev API call (UUID v4 is fine). Shoppex stores the response for 24 hours and replays it on retry.
  • Webhook handlers must be idempotent. Shoppex retries on non-2xx. Use the event’s data.uniqid + event tuple as your dedupe key.
  • Ack webhooks fast. Queue heavy fulfillment work and return 2xx within a few seconds.

Data Flow Per Checkout Stage

StageWho actsEvent
BrowseYour frontend reads from Shoppex (Storefront SDK or Dev API proxy)β€”
Add to cartYour frontend (local state)β€”
Checkout startYour server calls POST /dev/v1/paymentsβ€”
Payment UIShoppex hosted checkout / Embed SDKβ€”
Payment successShoppex sends order:paid webhookorder:paid
FulfillmentYour webhook handler grants access, sends license, provisions subscriptionβ€”
ReturnCustomer hits your return_urlβ€”
Server-side cart state is not required for any of these setups today β€” carts live in your frontend (local state, cookie, or your DB) until you create the payment session. If you need a hosted cart API, follow the changelog; it is on the roadmap for the /dev/v1/carts surface.

Next Steps

Next.js Quickstart

Hands-on version of Setup B.

Use Cases

Discord bots, SaaS paywalls, mobile apps, gaming-key resellers.

Webhook Security

HMAC-SHA512, constant-time comparison, retry behavior.

Authentication

API keys, scopes, OAuth2 for installable apps.