AI Prompts for Commerce Engine
Copy these prompts into your AI coding assistant (Claude, Cursor, Copilot, etc.) to generate production-quality Commerce Engine code. Each prompt includes the right context for accurate results.For best results, install the Commerce Engine skills package in your project, or paste the LLM docs URL so your assistant can fetch live API details.
Type import rule: All prompts assume types are imported directly from
@commercengine/storefront (e.g., import type { Cart, Product, CreateCartBody } from "@commercengine/storefront"), never hand-written. If the AI generates custom interfaces for API types, ask it to use the SDK’s named exports instead. See Importing Types for details.Foundation Context
Prepend this block to any prompt for best results. It gives the AI the essential Commerce Engine knowledge that every task depends on.You are working with the Commerce Engine TypeScript SDK (@commercengine/storefront).
This is the preferred package — it contains the core SDK plus all framework bindings (Next.js, etc.) in a single install. The older @commercengine/storefront-sdk package still works but is not the recommended path.
Essential rules:
1. SDK Response Pattern: All SDK methods return { data, error, response }. Always check error before using data.
The SDK automatically unwraps the API's "content" envelope — access fields directly on data (e.g., data.products, data.cart, data.user), NOT data.content.
2. SDK Architecture: createStorefront() returns a storefront instance with two accessors:
- storefront.public() → public reads (catalog, store config) — API-key-backed, no session needed
- storefront.session() → session flows (auth, cart, orders) — requires an active session
3. Token Lifecycle: Every user (even anonymous) needs tokens. Call sdk.ensureAccessToken() on the session accessor to bootstrap an anonymous session. After login, the SDK receives new privileged tokens. On logout, the API returns NEW anonymous tokens (not just clears them).
4. Type Imports: Always import types directly from "@commercengine/storefront". Never define custom interfaces for API schemas. All schema types and operation types are available as named exports.
5. variant_id Rule: variant_id is ALWAYS required in cart operations. Pass null for products without variants.
6. Cart Creation: POST /carts REQUIRES at least one item. You cannot create an empty cart. First add uses createCart(), subsequent adds use addDeleteCartItem().
7. Cart Merge: When an anonymous user logs in, their cart automatically merges into the logged-in user's account. Do not re-create or re-fetch carts manually after login.
8. Error Shape: Errors have { message: string, success: boolean, code: string }. Common HTTP status codes: 400 (bad request), 401 (unauthorized), 403 (forbidden), 404 (not found), 500 (server error), 502 (bad gateway). Always check error before using data.
Public accessor clients: publicSdk.catalog.*, publicSdk.store.*
Session accessor clients: sdk.auth.*, sdk.catalog.*, sdk.cart.*, sdk.customer.*, sdk.order.*, sdk.payments.*, sdk.helpers.*
Type lookup (fetch for exact TypeScript definitions):
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/{SchemaName}
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/{operation-name}.md
Type Lookup
Look Up a Schema Definition
I need the exact TypeScript definition for the Commerce Engine Cart type.
Fetch it from: curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/Cart
Then show me how to import and use this type in my code. Remember: always import directly from the SDK package as a named export, never define custom interfaces:
import type { Cart } from "@commercengine/storefront";
Look Up an SDK Method Signature
I need the exact TypeScript signature and usage example for the createCart SDK method.
Fetch it from: curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/create-cart.md
Show me the full method call with proper typing. Import operation types directly from the SDK:
import type { CreateCartBody, CreateCartContent } from "@commercengine/storefront";
SDK Setup
Initialize SDK (React / Vue / SPA)
Set up the Commerce Engine TypeScript SDK for a client-side React app.
Requirements:
- Use @commercengine/storefront (the unified package — NOT the older @commercengine/storefront-sdk)
- Import createStorefront, Environment, and BrowserTokenStorage from "@commercengine/storefront"
- Use Environment enum (Environment.Production or Environment.Staging) — do NOT hardcode strings
- Use BrowserTokenStorage for automatic token persistence in the session config
- Use environment variables for storeId and apiKey (VITE_ prefix for Vite, REACT_APP_ prefix for CRA)
- Export two SDK accessors from lib/storefront.ts:
- publicSdk = storefront.public() — for catalog reads (no auth needed)
- sdk = storefront.session() — for auth, cart, orders (session-scoped)
- Include onTokensUpdated callback (to sync auth state) and onTokensCleared callback (to redirect on session loss)
- On app init, call sdk.ensureAccessToken() on the session accessor to bootstrap an anonymous session — this is REQUIRED before session-scoped API calls will work
- Public reads (storefront.public().catalog.*) do NOT require an anonymous session
Example setup:
import { createStorefront, Environment, BrowserTokenStorage } from "@commercengine/storefront";
const storefront = createStorefront({
storeId: import.meta.env.VITE_STORE_ID,
environment: import.meta.env.PROD ? Environment.Production : Environment.Staging,
apiKey: import.meta.env.VITE_API_KEY,
session: {
tokenStorage: new BrowserTokenStorage("myapp_"),
},
});
export const publicSdk = storefront.public();
export const sdk = storefront.session();
Anti-patterns to avoid:
- Do NOT make session-scoped API calls before calling sdk.ensureAccessToken() — they will return 401
- Do NOT hardcode "production" or "staging" as strings — use the Environment enum
- Do NOT use storefront.public() for cart, auth, or order operations — those require storefront.session()
Reference:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/get-anonymous-token.md
Initialize SDK (Next.js App Router)
Set up the Commerce Engine Next.js SDK for an App Router project.
Requirements:
- Use @commercengine/storefront (the unified package — NOT the deprecated @commercengine/storefront-sdk-nextjs)
- Import createNextjsStorefront from "@commercengine/storefront/nextjs" and Environment from "@commercengine/storefront"
- Create lib/storefront.ts that calls createNextjsStorefront() and exports the storefront instance
- Create a StorefrontBootstrap client component that calls storefront.bootstrap() in a useEffect — this establishes the anonymous session on first visit (it's deduped and idempotent)
- Mount <StorefrontBootstrap /> in the root layout
Three accessors — use the right one for each context:
- storefront.publicStorefront() — Root layout, SSG, generateMetadata, build time, public reads
- await storefront.serverStorefront() — Session-aware Server Components, Server Actions, Route Handlers (async — auto-reads cookies)
- storefront.clientStorefront() — Client Components (browser-side session)
Environment variables: NEXT_PUBLIC_STORE_ID, NEXT_PUBLIC_API_KEY
Example lib/storefront.ts:
import { Environment } from "@commercengine/storefront";
import { createNextjsStorefront } from "@commercengine/storefront/nextjs";
export const storefront = createNextjsStorefront({
storeId: process.env.NEXT_PUBLIC_STORE_ID!,
apiKey: process.env.NEXT_PUBLIC_API_KEY!,
environment: Environment.Staging,
tokenStorageOptions: { prefix: "myapp_" },
});
Example StorefrontBootstrap component:
"use client";
import { useEffect } from "react";
import { storefront } from "@/lib/storefront";
export function StorefrontBootstrap() {
useEffect(() => { storefront.bootstrap().catch(console.error); }, []);
return null;
}
Anti-patterns to avoid:
- Do NOT call auth endpoints from Server Components — they MUST be in Server Actions or API Routes
- Do NOT use serverStorefront() in Client Components — it throws; use clientStorefront()
- Do NOT use clientStorefront() on the server — it throws; use await serverStorefront()
- Do NOT use session accessors in the root layout or SSG — use publicStorefront()
Reference: https://llm-docs.commercengine.io/sdk/
Initialize SDK (Node.js Backend)
Set up the Commerce Engine SDK for a Node.js Express backend.
Requirements:
- Use @commercengine/storefront with MemoryTokenStorage (NOT the older @commercengine/storefront-sdk)
- Import createStorefront, Environment, and MemoryTokenStorage from "@commercengine/storefront"
- Configure for server-side usage with proper timeout
- Show middleware that creates per-request SDK instances — this is critical for token isolation between concurrent users
- The middleware should extract the Bearer token from the request Authorization header and pass it via accessToken for manual token management
- For public reads (catalog, store config), use storefront.public() — no auth needed
- For session-scoped operations (cart, orders), create per-request instances with the user's token
- Include health check endpoint using sdk.helpers.retrieveAllCountries()
Reference: https://llm-docs.commercengine.io/sdk/
Authentication
Email OTP Login Flow
Implement a complete email OTP login flow using the Commerce Engine SDK.
IMPORTANT PREREQUISITE: The user MUST already have an anonymous session before calling loginWithEmail. For SPAs, call sdk.ensureAccessToken() on the session accessor at app init. For Next.js, mount a StorefrontBootstrap component that calls storefront.bootstrap().
The auth methods live on the session accessor: storefront.session().auth.*
Steps:
1. Call sdk.auth.loginWithEmail({ email, register_if_not_exists: true })
- Response: { data, error } where data contains otp_token and otp_action
- Access: data.otp_token, data.otp_action (NOT data.content.otp_token)
2. Show OTP input UI
3. Call sdk.auth.verifyOtp({ otp, otp_token: data.otp_token, otp_action: data.otp_action })
- On success: data contains user, access_token, refresh_token
- The SDK automatically stores the new tokens if tokenStorage is configured
4. After verification, the user object has is_anonymous: false, is_logged_in: true
Requirements:
- Handle both login and registration (register_if_not_exists: true)
- Show loading states during API calls
- Handle errors for each step (invalid email, wrong OTP, expired OTP)
- Use the { data, error } pattern, not try/catch
- Include a "Resend OTP" button that calls loginWithEmail again
- After successful login, the user's anonymous cart automatically merges into their account
- Import types from "@commercengine/storefront" (NOT the older storefront-sdk)
Anti-patterns to avoid:
- Do NOT try to log in without an anonymous session first — it will 401
- Do NOT access data.content.otp_token — the SDK unwraps content, use data.otp_token directly
Reference: fetch these for exact signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/login-with-email.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/verify-otp.md
Phone OTP Login Flow
Implement a phone number OTP login flow using the Commerce Engine SDK.
IMPORTANT PREREQUISITE: The user MUST already have an anonymous session (call sdk.ensureAccessToken() for SPAs, or mount StorefrontBootstrap for Next.js).
The auth methods live on the session accessor: storefront.session().auth.*
Steps:
1. Call sdk.auth.loginWithPhone({ phone, country_code, register_if_not_exists: true })
- country_code format: string with "+" prefix, e.g., "+91", "+1", "+44"
- Response: data.otp_token, data.otp_action
2. Show OTP input UI
3. Call sdk.auth.verifyOtp({ otp, otp_token: data.otp_token, otp_action: data.otp_action })
Requirements:
- Include country code selector dropdown (use sdk.helpers.retrieveAllCountries() for the list)
- Country code must include the "+" prefix (e.g., "+91" for India, "+1" for US)
- Handle errors for each step
- Use { data, error } pattern
- Include "Resend OTP" button
- After successful login, anonymous cart merges automatically
- Import types from "@commercengine/storefront"
Reference: fetch these for exact signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/login-with-phone.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/verify-otp.md
Next.js Server Action Auth
Implement Commerce Engine authentication as Next.js Server Actions.
Requirements:
- Add "use server" directive at the top of the server action file
- Import the storefront instance from your lib/storefront.ts (created with createNextjsStorefront)
- Use await storefront.serverStorefront() in every server action — it auto-reads cookies for session persistence
- Create server actions for: sendOTP (email), verifyOTP, logout
- Use redirect() after successful auth
- IMPORTANT: Auth endpoints that return tokens MUST be in Server Actions or API Routes, NOT Server Components
- Server actions should return { success: boolean, error?: string } to the client
- On error, return the error message to the client — do NOT throw
Example server action structure:
"use server"
import { storefront } from "@/lib/storefront";
export async function sendOTP(email: string) {
const sdk = await storefront.serverStorefront();
const { data, error } = await sdk.auth.loginWithEmail({ email, register_if_not_exists: true });
if (error) return { success: false, error: error.message };
return { success: true, otp_token: data.otp_token, otp_action: data.otp_action };
}
Reference: https://llm-docs.commercengine.io/sdk/
Product Catalog
Product Listing Page
Build a product listing page using the Commerce Engine SDK.
Requirements:
- Use the public accessor for catalog reads: storefront.public().catalog.listProducts() — no session needed
- For Next.js: use storefront.publicStorefront().catalog.listProducts()
- Response shape: data.products (array of Product) and data.pagination
- Support pagination (page, limit query params)
- Support filtering by category_id or category_slug
- Display: product name, images[0].url (for the primary image), selling_price, slug
- Link each product to /products/[slug]
- Handle loading and error states
- Use { data, error } pattern
- Import types directly from SDK: import type { Product, ListProductsContent } from "@commercengine/storefront"
Variant handling on PLP:
- Check the has_variant flag on each product
- For products with has_variant: true, show variant indicators (e.g., color swatches from variant_options)
- Consider using the default variant's price/image for the listing card
- Alternative approach: use sdk.catalog.listSkus() which returns pre-flattened Items (product_id + variant_id) — simpler for PLPs where you want each variant as its own card
Anti-patterns to avoid:
- Do NOT render all products identically — check has_variant and handle variant display
- Do NOT access data.content.products — use data.products directly
- Do NOT use session accessor for public catalog reads — use storefront.public()
Reference: fetch for exact response shape and TypeScript definitions:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/list-products.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/Product
Product Detail Page (Next.js SSG)
Build a statically generated product detail page in Next.js App Router using Commerce Engine.
Requirements:
- Use storefront.publicStorefront() for all build-time reads — no session is available at build time
- Use generateStaticParams() to pre-render product pages from publicStorefront().catalog.listProducts()
- Fetch product detail with publicStorefront().catalog.getProductDetail({ product_id_or_slug: slug })
- Response shape: data.product (a ProductDetail object)
- Display: name, description, images (loop over images array, show images[n].url), price, variants, availability
- Set revalidation for ISR: export const revalidate = 3600 (or your preferred interval)
Variant selection UI:
- If product.has_variant is true, fetch variants with sdk.catalog.listProductVariants({ product_id })
- Display variant_options as selectors (e.g., color swatches, size buttons)
- When user selects options, find the matching variant from the associated_options
- Update the displayed price, image, and stock based on the selected variant
- The selected variant_id is needed for add-to-cart
AddToCart button (client component):
- Use storefront.clientStorefront() for browser-side cart interactions
- Must pass both product_id AND variant_id (null if no variants) to cart operations
- First add creates the cart (sdk.cart.createCart), subsequent adds use sdk.cart.addDeleteCartItem
Anti-patterns to avoid:
- Do NOT use serverStorefront() or clientStorefront() in generateStaticParams or generateMetadata — use publicStorefront()
Reference: fetch for exact response shape:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/get-product-detail.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/list-product-variants.md
Product Search
Implement product search using the Commerce Engine SDK.
Requirements:
- Use the public accessor for search: storefront.public().catalog.searchProducts({ query: { q: searchTerm } })
- IMPORTANT: Search returns Items (SKUs), not Products — each result has product_id and variant_id
- Response includes facet_distribution for building filter UI (category, brand, price range, etc.)
- Debounce search input (300ms)
- Show search results with product name, image, price
- Display facet filters alongside results for refinement
- Handle empty results and errors
- Support keyboard navigation of results
Reference: fetch for exact signature:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/search-products.md
Cart & Checkout
Shopping Cart
Build a complete shopping cart using the Commerce Engine SDK.
Cart operations use the session accessor: storefront.session().cart.*
For Next.js: use await storefront.serverStorefront() in Server Actions, or storefront.clientStorefront() in Client Components.
CRITICAL RULES:
- POST /carts (createCart) REQUIRES at least one item — you CANNOT create an empty cart
- First item add: use sdk.cart.createCart({ items: [{ product_id, variant_id, quantity }] })
- Subsequent item adds: use sdk.cart.addDeleteCartItem({ id: cartId }, { product_id, variant_id, quantity }) — NOTE: two arguments (path params object + body object)
- variant_id is ALWAYS required — pass null for products without variants
- When a user logs in, their anonymous cart automatically merges into their account — do NOT manually re-create carts
Requirements:
- Fetch existing cart with sdk.cart.getUserCart() — the session accessor infers the user from the token; returns 404 if no active cart exists, handle gracefully
- Implement two-phase cart logic: check if cart exists (getUserCart), if not, use createCart on first add; if yes, use addDeleteCartItem
- Update quantity by calling addDeleteCartItem with the new total quantity
- Remove items by setting quantity to 0
- Display: cart_items, quantities, selling_price, subtotal, items_tax_amount, shipping_amount, grand_total, to_be_paid
- Delete entire cart with sdk.cart.deleteCart(cartId)
- Import types directly from SDK: import type { Cart, CartItem, UpdateCartItem } from "@commercengine/storefront"
Coupon considerations:
- Some coupons require the user to be logged in — applying a login-required coupon with an anonymous token will fail
- Prompt users to log in before applying coupons if they are anonymous
Anti-patterns to avoid:
- Do NOT try to create an empty cart — POST /carts requires items
- Do NOT re-create carts after login — carts merge automatically
- Do NOT access data.content.grand_total — use data.cart.grand_total
- Do NOT use storefront.public() for cart operations — use storefront.session()
Reference: fetch for exact TypeScript definitions and signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/create-cart.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/update-cart.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/Cart
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/UpdateCartItem
Apply Coupon / Promotions
Implement coupon and promotion handling for the Commerce Engine cart.
Coupon/promotion operations use the session accessor: storefront.session().cart.*
Requirements:
- Apply coupon: sdk.cart.applyCoupon({ id: cartId }, { coupon_code: "CODE" }) — NOTE: two arguments (path params object + body object)
- Remove coupon: sdk.cart.removeCoupon({ id: cartId }) — one argument (path params object)
- List available coupons: sdk.cart.listCoupons()
- List available promotions: sdk.cart.listPromotions()
- Show discount breakdown in cart summary (coupon_discount_amount, promotion_discount_amount)
- Handle invalid/expired coupon errors
- IMPORTANT: Some coupons require the user to be logged in. If the user is anonymous and a coupon requires login, the API returns a 400 error. Show a "Please log in to use this coupon" message.
Reference: fetch for exact signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/apply-coupon.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/list-coupons.md
Checkout Flow
Implement checkout for a Commerce Engine storefront.
RECOMMENDED APPROACH: Use the Commerce Engine Hosted Checkout — a pre-built, embeddable checkout that handles cart, authentication, address collection, payments, and order confirmation inside an iframe. This is the fastest and most reliable way to add checkout.
Hosted Checkout setup:
- Install: npm install @commercengine/checkout (React/Vue/Svelte/Solid) or @commercengine/js (vanilla)
- Initialize once: const { addToCart, openCart, openCheckout, destroyCheckout } = initCheckout({ storeId, apiKey, environment, onComplete, onCartUpdate })
- Open cart: openCart() — shows cart drawer
- Open checkout directly: openCheckout() — no arguments, skips cart, goes to checkout
- Add to cart: addToCart(productId, variantId, quantity) — positional args, variantId can be null
- Cleanup: destroyCheckout() — call when unmounting the component
- Auth sync (if your app handles auth): use authMode: "provided" and call updateTokens(accessToken, refreshToken) when tokens change
- Callbacks: onComplete({ id, orderNumber }), onCartUpdate({ count, total, currency }), onLogin(), onLogout() — passed in initCheckout config, NOT .on() event listeners
For React:
import { initCheckout, useCheckout } from "@commercengine/checkout/react";
// Call initCheckout() once at app entry
// Use useCheckout() hook in components for openCart, openCheckout, addToCart, etc.
For details on all framework integrations, configuration options, and events, see:
https://commercengine.io/docs/hosted-checkout/overview
IMPORTANT: The user MUST be logged in before creating an order. Anonymous users cannot check out. Use OTP auth with register_if_not_exists: true for a seamless login-before-checkout experience.
ALTERNATIVE: Custom Checkout (only if you need full UI control)
If you must build a custom checkout, all operations use the session accessor (storefront.session().*):
1. Authenticate user (required): sdk.auth.loginWithEmail({ email, register_if_not_exists: true }) → sdk.auth.verifyOtp(...)
2. Update cart address: sdk.cart.createCartAddress({ id: cartId }, { shipping_address, billing_address })
- For logged-in users: can use billing_address_id / shipping_address_id for saved addresses
- This returns updated cart with recalculated shipping and totals — re-render cart summary
3. Validate pincode: sdk.cart.checkPincodeDeliverability({ cart_id: cartId, delivery_pincode: pincode })
4. Create order: sdk.order.createOrder({ cart_id, payment_method: { payment_provider_slug: "JUSPAY", integration_type: "hyper-checkout", action: "paymentPage", return_url: "https://yourstore.com/checkout/return", gateway_reference_id: "optional_pg_id" } })
- NOTE: uses payment_method (single object), NOT payment_gateway + payment_gateway_params
- Response: data.order, data.payment_required, data.payment_info
5. Redirect user to: data.payment_info.payment_links.web (Juspay payment page)
6. On return to your return_url, POLL payment status:
- Call sdk.order.getPaymentStatus(orderNumber) immediately — takes a STRING, not an object
- If status is "pending" or "partially_paid", wait 3 seconds and poll again
- Continue polling until "success" or "failed" (timeout after 1-2 minutes)
- NEVER trust payment gateway callback URL parameters alone
7. If status is "failed" and is_retry_available is true:
- Show "Retry Payment" button
- Call sdk.order.retryOrderPayment({ order_number }, { payment_method: { payment_provider_slug: "JUSPAY", integration_type: "hyper-checkout", action: "paymentPage", return_url: "..." } })
- NOTE: two arguments — path params object + body object
- Redirect to new payment URL and repeat polling
Anti-patterns to avoid:
- Do NOT trust payment gateway callbacks as the final status — always poll the API
- Do NOT skip pincode serviceability check — orders to unserviceable areas will fail
- Do NOT forget to re-render cart summary after address update (shipping costs change)
Reference: fetch for exact signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/create-order.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/create-cart-address.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/get-payment-status.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/retry-payment.md
Hosted Checkout Integration
Integrate the Commerce Engine Hosted Checkout into my app.
The Hosted Checkout is a pre-built, iframe-based checkout that handles the entire purchase flow — cart, auth, address, payments, and order confirmation.
Requirements:
- Install: npm install @commercengine/checkout (for React/Vue/Svelte/Solid)
- Initialize once at app entry: const { addToCart, openCart, openCheckout, destroyCheckout } = initCheckout({ storeId, apiKey, environment, onComplete, onCartUpdate })
- Add an "Add to Cart" button that calls addToCart(productId, variantId, quantity) — positional args
- variantId can be null for products without variants
- Add a "View Cart" button that calls openCart()
- Add a "Buy Now" button that calls openCheckout() — no arguments
- Show a cart badge with item count using onCartUpdate callback ({ count, total, currency })
- Handle order completion with onComplete callback ({ id, orderNumber })
- Clean up: call destroyCheckout() when the component unmounts
Auth mode (passed in initCheckout config):
- Default (authMode: "managed"): Checkout handles its own login/registration via OTP
- If your app already handles CE auth, use authMode: "provided":
- Pass initial tokens: initCheckout({ ..., authMode: "provided", accessToken, refreshToken })
- Sync token changes: call updateTokens(accessToken, refreshToken) whenever your app refreshes tokens
- Listen for onTokensUpdated callback in initCheckout to sync tokens from checkout back to your SDK
- Listen for onLogin and onLogout callbacks to sync auth state back to your app
- IMPORTANT: If your app uses Commerce Engine auth (loginWithEmail, verifyOtp, etc.), you MUST use authMode: "provided". Otherwise both your app and checkout will manage separate sessions.
Next.js integration pattern (with @commercengine/storefront):
- In lib/storefront.ts, add onTokensUpdated to createNextjsStorefront() config that calls getCheckout().updateTokens()
- In your StorefrontBootstrap component, call storefront.bootstrap() THEN initCheckout() with authMode: "provided"
- Pass initial tokens from storefront.clientStorefront() to initCheckout
- In initCheckout's onTokensUpdated, call sdk.setTokens() to sync tokens back to the SDK
- Use useCheckout() hook in any Client Component — no provider wrapper needed
Quick Buy (direct purchase):
- Use quickBuy config: initCheckout({ ..., quickBuy: { productId, variantId, quantity } })
- sessionMode: "continue-existing" (default, adds to existing cart) or "force-new" (fresh cart)
Framework-specific setup:
- React: import { initCheckout, useCheckout } from "@commercengine/checkout/react" — useCheckout() returns { openCart, openCheckout, addToCart, destroyCheckout, isReady, cart }
- Vue: import { useCheckout } from "@commercengine/checkout/vue" — composable with reactive refs
- Svelte: import from "@commercengine/checkout/svelte" — readable stores
- Solid: import { useCheckout } from "@commercengine/checkout/solid" — fine-grained signals
- Vanilla JS: import from "@commercengine/js" — initCheckout() returns methods directly
Reference:
https://commercengine.io/docs/hosted-checkout/overview
https://commercengine.io/docs/hosted-checkout/configuration
Customer Account
Customer Profile & Order Management
Build a customer account area using the Commerce Engine SDK. This includes profile, addresses, order history, cancellations, and returns.
All account operations use the session accessor: storefront.session().*
For Next.js: use await storefront.serverStorefront() in Server Components/Actions, or storefront.clientStorefront() in Client Components.
Import types from "@commercengine/storefront".
Requirements:
Profile:
- Fetch user details: sdk.auth.retrieveUser()
- Response: data.user with email, phone, is_logged_in, login_methods, etc.
- The session accessor infers the user from the token — no need to pass user_id
- Update user: sdk.auth.updateUser({ id: userId }, { first_name, last_name })
- Fetch customer detail: sdk.customer.getCustomer({ id: userId })
Address Book:
- List addresses: sdk.customer.listAddresses({ user_id: userId })
- Each address has is_default_billing and is_default_shipping flags
- Create address: sdk.customer.createAddress({ user_id: userId }, addressData)
- Update address: sdk.customer.updateAddress({ user_id: userId, address_id: addressId }, updates)
- Delete address: sdk.customer.deleteAddress({ user_id: userId, address_id: addressId })
Order History:
- List orders: sdk.order.listOrders() — returns paginated order list
- Order detail: sdk.order.getOrderDetail({ order_number }) — returns full OrderDetail
- Shipments: sdk.order.listShipments({ order_number })
- Payments: sdk.order.listPayments({ order_number })
Order Cancellation:
- IMPORTANT: Check is_cancellation_allowed flag on OrderDetail before showing cancel button
- Cancel: sdk.order.cancelOrder({ order_number }, { cancellation_reason, refund_mode })
- refund_mode: "original_payment_mode" or "bank_transfer"
- If bank_transfer, also pass bank_account_id
Order Returns:
- Returns are currently managed by store administrators through the Admin Portal
- There is no storefront SDK method for customers to initiate returns
- Customers can cancel orders (if is_cancellation_allowed is true) but not request returns from the storefront
- Return APIs for the storefront are under development
Loyalty Points:
- Fetch loyalty: sdk.customer.getLoyaltyDetails({ user_id: userId })
Reference: fetch for exact signatures:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/get-user-detail.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/list-addresses.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/list-orders.md
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/operations/cancel-order.md
Webhooks
Webhook Handler
Set up webhook handlers for Commerce Engine events.
Requirements:
- Create an Express/Next.js API route that receives POST requests from Commerce Engine
- Handle these webhook events: order.created, order.confirmed, order.cancelled, payment.successful, payment.failed, shipment.created, shipment.delivered
- Verify webhook signatures using HMAC-SHA256:
- Extract the signature from the request header
- Compute HMAC-SHA256 of the raw request body using your webhook secret
- Compare the computed hash with the received signature
- Reject requests with invalid signatures
- Process events asynchronously (push to a queue for background processing)
- Return 200 immediately to acknowledge receipt — do not do heavy processing synchronously
- Log webhook payloads for debugging
- Handle duplicate events idempotently (store processed event IDs)
Reference: fetch for webhook payload schemas:
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/webhooks/
curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/webhooks/order.created
Full Application
Complete Next.js Storefront
Scaffold a complete Next.js App Router storefront using Commerce Engine.
Requirements:
- Use @commercengine/storefront (the unified package — NOT the deprecated @commercengine/storefront-sdk-nextjs)
- Import createNextjsStorefront from "@commercengine/storefront/nextjs"
- Use @commercengine/checkout for the checkout experience (Hosted Checkout)
Project structure (App Router):
app/
layout.tsx — Root layout with StorefrontBootstrap component, public reads via publicStorefront()
page.tsx — Homepage with featured products and categories
products/
page.tsx — Product listing with filters and pagination (publicStorefront())
[slug]/page.tsx — Product detail with variant selection (SSG with generateStaticParams using publicStorefront())
account/
page.tsx — Customer profile (await serverStorefront(), redirect if not logged in)
orders/page.tsx — Order history
orders/[id]/page.tsx — Order detail with cancel/return actions
addresses/page.tsx — Address book management
auth/
actions.ts — Server actions: sendOTP, verifyOTP, logout (with "use server", await serverStorefront())
components/
StorefrontBootstrap.tsx — Client component calling storefront.bootstrap() + initCheckout()
AddToCartButton.tsx — Client component using clientStorefront(), handles createCart vs addDeleteCartItem
CartButton.tsx — Opens hosted checkout cart with openCart()
AuthForm.tsx — Email/phone OTP login form
ProductCard.tsx — Product card for listings
VariantSelector.tsx — Variant option selector (color, size, etc.)
lib/
storefront.ts — createNextjsStorefront() config, export storefront instance
Key patterns:
- Accessors: publicStorefront() for catalog/SSG, await serverStorefront() for Server Actions/Components, clientStorefront() for Client Components
- Auth: Email OTP login via Server Actions in app/auth/actions.ts using await serverStorefront()
- SSG: Pre-render product pages with generateStaticParams using publicStorefront() + revalidate for ISR
- Cart: Use Hosted Checkout — initCheckout() in StorefrontBootstrap, openCart()/openCheckout() from buttons
- Error handling: Use { data, error } pattern everywhere
- Middleware: Add middleware.ts to protect /account routes (check for logged-in tokens)
Full SDK reference: https://llm-docs.commercengine.io/
API operations: https://llm-docs.commercengine.io/operations/
Hosted Checkout: https://commercengine.io/docs/hosted-checkout/overview
React Context + Hooks Setup
Create a complete React context and hooks setup for Commerce Engine.
SDK setup (lib/storefront.ts):
- Use createStorefront from "@commercengine/storefront"
- Export publicSdk = storefront.public() for catalog reads
- Export sdk = storefront.session() for auth, cart, orders
- Use BrowserTokenStorage in session config for automatic token persistence
Requirements:
- CommerceProvider: Shares the session SDK instance (type: SessionStorefrontSDK) via context, calls sdk.ensureAccessToken() on mount to bootstrap the anonymous session
- AuthProvider: Manages auth state (user, isLoggedIn, login, logout, loading)
- Use sdk.auth.retrieveUser() to check current user state
- Use sdk.auth.logoutUser() + sdk.clearTokens() for logout
- useCart hook:
- State: cart, itemCount, loading
- Methods: addItem, updateItem, removeItem, clearCart
- IMPORTANT: addItem must handle two-phase cart logic:
- If no cart exists yet, call sdk.cart.createCart({ items: [...] }) — cart creation requires at least one item
- If cart already exists, call sdk.cart.addDeleteCartItem({ id: cartId }, { product_id, variant_id, quantity })
- Fetch cart with sdk.cart.getUserCart() — session accessor infers user from token
- After login, re-fetch cart (it merged automatically)
- For good UX, update state optimistically then reconcile with the server response
- useProducts hook: fetch products with publicSdk.catalog.listProducts() — public reads don't need a session
- All hooks use { data, error } pattern from SDK
- Import ALL types directly from the SDK — never define custom interfaces:
import type { Cart, Product, CartItem, UpdateCartItem, SessionStorefrontSDK, UserInfo } from "@commercengine/storefront";
import type { CreateCartBody, ListProductsContent } from "@commercengine/storefront";
Reference: https://llm-docs.commercengine.io/sdk/
Fetch type definitions: curl -H "Accept: text/markdown" https://llm-docs.commercengine.io/storefront/schemas/Cart
Pro tip: When using these prompts, paste the relevant
curl commands so your AI assistant can fetch the latest API schemas directly. This ensures the generated code matches the current API exactly.