> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shoppex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture Reference

> Three reference setups for using Shoppex as a headless commerce engine — pure SPA, Next.js SSR, and mobile with backend-for-frontend.

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:**

| Piece          | Responsibility                                                                  |
| -------------- | ------------------------------------------------------------------------------- |
| Browser SPA    | UI, product grid, cart UI, buy button with `@shoppexio/storefront` or Embed SDK |
| Webhook worker | Verify `X-Shoppex-Signature-V2`, run fulfillment, persist order state           |
| Shoppex        | Catalog, 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:**

| Piece             | Responsibility                                                    |
| ----------------- | ----------------------------------------------------------------- |
| Server Components | Catalog reads, personalization, pricing overrides, session lookup |
| Server Actions    | Create payment session, return redirect URL                       |
| Route Handlers    | Verify and handle signed webhooks                                 |
| Shoppex           | Everything 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](/headless/quickstart-nextjs) 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:**

| Piece      | Responsibility                                                                           |
| ---------- | ---------------------------------------------------------------------------------------- |
| Native app | Your UI, your auth, deep-link handler for the return URL                                 |
| BFF        | Exchange user session for scoped Shoppex calls, create payment sessions, run fulfillment |
| Shoppex    | Everything 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

| Setup            | Who holds the API key              | Customer login                              |
| ---------------- | ---------------------------------- | ------------------------------------------- |
| A — Pure SPA     | Worker / tiny backend only         | None, or your own magic-link/OAuth          |
| B — Next.js SSR  | Server Components + Route Handlers | Next-Auth / your own / Shoppex customer OTP |
| C — Mobile + BFF | BFF only                           | Your 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

| Stage                            | Who acts                                                                   | Event                                                                                            |
| -------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| Browse                           | Your frontend reads from Shoppex (Storefront SDK or Dev API proxy)         | —                                                                                                |
| Add to cart                      | Your frontend (local state)                                                | —                                                                                                |
| Checkout start (ad-hoc amount)   | Your server calls `POST /dev/v1/payments`                                  | —                                                                                                |
| Checkout start (catalog product) | Your server calls `POST /dev/v1/orders` with `items[].product_id`          | —                                                                                                |
| Payment UI                       | Shoppex hosted checkout / Embed SDK                                        | —                                                                                                |
| Payment success                  | Shoppex sends webhooks                                                     | `order:paid`; `subscription:created` / `subscription:renewed` when the product is a subscription |
| Fulfillment                      | Your webhook handler grants access, sends license, provisions subscription | —                                                                                                |
| Return                           | Customer hits your `return_url`                                            | —                                                                                                |

<Info>
  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.
</Info>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Next.js Quickstart" icon="bolt" href="/headless/quickstart-nextjs">
    Hands-on version of Setup B.
  </Card>

  <Card title="Use Cases" icon="shapes" href="/headless/use-cases/discord-bot-shop">
    Discord bots, SaaS paywalls, mobile apps, gaming-key resellers.
  </Card>

  <Card title="Webhook Security" icon="shield" href="/api-reference/webhooks/overview">
    HMAC-SHA256 timestamped signatures, constant-time comparison, retry behavior.
  </Card>

  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    API keys, scopes, OAuth2 for installable apps.
  </Card>
</CardGroup>
