Skip to main content
Build a custom storefront on Next.js 16 (App Router) that:
  1. Lists products from your Shoppex catalog on the server.
  2. Starts a checkout session from a Server Action.
  3. Redirects the customer to Shoppex hosted checkout.
  4. Receives a signed webhook when the order is paid and runs your own fulfillment.
Time budget: 15 minutes. You need a Shoppex shop and an API key (shx_*).
If you do not have an API key yet, open Dashboard → Settings → Developer API. Click Generate New API Key, then pick scopes products.read payments.write webhooks.read. Copy the key — it is shown once.

1. Set up the project

Add your API key to .env.local:
SHOPPEX_API_KEY must only exist on the server. Never prefix it with NEXT_PUBLIC_.
Create a tiny server-only client wrapper at lib/shoppex.ts:

2. List products on the server

app/products/page.tsx reads the catalog on every request. Because this is a Server Component, your API key never leaves the server.

3. Start checkout from a Server Action

A product page with a Server Action that creates a payment and redirects to hosted checkout. The API key stays on the server. The browser only ever sees the resulting checkout_url. app/products/[id]/page.tsx:
return_url is where Shoppex sends the customer after a successful payment. cancel_url is where they go if they abandon checkout.If you prefer the Stripe-style alias, POST /dev/v1/checkout/sessions is available too. The published JS SDK does not wrap that route yet, so the quickstart uses POST /dev/v1/payments, which already has first-class SDK support.
This quickstart uses POST /dev/v1/payments because it is the smallest ad-hoc checkout example (title + amount). That path does not link checkout to the catalog product you fetched above.If the product is a subscription, or you need serial/file/DYNAMIC delivery, use POST /dev/v1/orders with items: [{ product_id: product.uniqid, quantity: 1 }] instead. See Subscriptions and SaaS Paywall.

4. Verify the signed webhook

Create a webhook endpoint in the Shoppex dashboard (Settings → Webhooks → Add Endpoint). Point it at https://your-site.com/api/webhooks/shoppex and subscribe to order:paid. Copy the signing secret into SHOPPEX_WEBHOOK_SECRET. app/api/webhooks/shoppex/route.ts:
Always verify the signature with constant-time comparison. The timingSafeEqual call above is what prevents timing-side-channel attacks. Never compare signatures with ===.
Return 2xx within a few seconds. Shoppex retries failed deliveries with backoff. If fulfillment takes longer than a couple of seconds, queue the real work in a background job and ack the webhook immediately.

5. Local testing

Run the app and point a tunnel at it so the webhook is reachable:
Set the webhook URL in the Shoppex dashboard to the ngrok URL + /api/webhooks/shoppex. In the dashboard, click Send Test Event on your webhook to verify the signature check passes.

What you built

Your frontend, your routing, your brand. Shoppex handled the PSP selection, 3DS, the hosted checkout page, the payment confirmation, and the event delivery. It will also handle refunds, disputes, and subscriptions when you add them.

Next steps

Webhook Event Catalog

Every event Shoppex sends, with sample payloads.

Headless commerce

Three reference setups including mobile and backend-for-frontend.

Checkout Embed SDK

Prefer a modal over a redirect? Swap the Server Action for a buy button.

Dev API Reference

Subscriptions, licenses, coupons, customers, and more.