@shoppexio/storefront/customer when your storefront runs on your own domain and you want to build the customer portal yourself. Shoppex handles email OTP login, tenant isolation, customer data, and buyer actions. Your frontend owns the UI.
Headless customer accounts are available on every plan as part of the Storefront SDK. They reuse the same publishable key and allowed origins as Headless Checkout, while creating Headless Checkout sessions still requires Business.
Setup
Open Dashboard -> Settings -> Developer -> Headless. Generate a publishable key and add the exact origin that hosts the customer page, for examplehttps://yourstore.com.
shx_ Developer API key in this client.
What you can build
The client covers the buyer-safe parts of the Shoppex customer portal:dashboard() is the starting payload for an account home page. It includes recent orders and tickets, licenses, subscriptions, deliverables, wallet state, rewards, affiliate state, and summary counts. Use the focused methods when the buyer opens or changes one area.
OTP login
sessionStorage and is valid for up to 12 hours. rememberMe: true stores it in localStorage and keeps the customer signed in for up to 30 days. Both are capped by the underlying Shoppex buyer session. A logout or an unauthorized response removes the saved session.
Use rememberMe only after the buyer explicitly selects a Keep me signed in option on a private device.
OTP requests use a success-like response for known and unknown email addresses. Do not use the response to decide if a customer account exists.
Check the saved session when your customer page starts:
Customer and orders
me, order-list, and order-detail response contracts before returning them. Prices remain decimal strings so your UI does not introduce floating-point rounding.
Order reviews
Load review state when the buyer opens a completed order. Shoppex decides if that signed-in customer may review the purchase, so render the action fromcan_review instead of deriving eligibility from the order status yourself.
orderReview() also returns an existing review. already_submitted, score,
message, and submitted_at let the customer dashboard show what was already
sent. Reviews are Shoppex shop reviews tied to a verified order, not separate
reviews for every line item. A foreign order ID returns 404.
Shoppex stores review sentiment in three levels. Send 1 for negative, 3
for neutral, or 5 for positive. Review messages may contain up to 256 visible
Unicode characters; joined emoji count as one character.
Account home and settings
Usedashboard() for the first account screen. The returned IDs are the inputs for the focused actions below.
invoice_uniqid and downloadIndex. Pass both values to
download() instead of following a hosted customer-portal URL:
updateAvatar().
Support tickets
The dashboard response contains the buyer’s recent ticket list. Use the ticket ID to open the full conversation and send replies.invoiceId is optional. When you include it, Shoppex verifies that the order belongs to the signed-in buyer.
Licenses and subscriptions
Use the license and subscription IDs returned bydashboard().
actions.can_* field is true. Ask for buyer confirmation immediately before a destructive action such as cancellation or hardware reset.
Wallet and license renewal methods create a normal Shoppex checkout. They do not charge the buyer inside the SDK:
Replacements, loyalty, warranties, and favorites
Affiliate and reseller views
affiliate() returns the existing affiliate links, balances, commissions, and payout state. createAffiliateLink() creates or requests a custom link. It does not move funds.
orders() returns summary rows for an order list. Each summary contains at most three line items. Do not use the summary as a full order.
Call order() when the buyer opens one order. The detail response contains pricing, payment, line-item, and delivery data.
Use pagination.has_more to decide if your UI must show a Load more button. The API returns at most 50 orders per page.
Order detail data
Use decimal strings from the response. Do not convert money to JavaScript floating-point values before calculations.displayName before apmMethod. The cryptoGateway field contains the exact coin when both labels are null. Format that coin with your buyer-facing labels. Do not show the raw gateway value because it can identify an internal payment rail.
The order detail contains these main groups:
Use
currentPayment for the active payment method. payments contains the same public payment snapshot in array form for existing consumers.
Delivery and service instructions
Callorder() before you build the delivery section. The order-list response does not contain delivery data.
Each item in order.lineItems contains these delivery fields:
Shoppex returns
deliveryText and product.serviceText only after the item is delivered. This rule prevents delivery content from appearing before payment and fulfillment.
Use the order-specific deliveryText first. Use the product serviceText when the order has no specific instructions.
deliveryText and serviceText can contain rich-text HTML. Sanitize this HTML before you use dangerouslySetInnerHTML or a similar API.
Open an external delivery link only when href is not null. Use rel="noopener noreferrer" when the link opens a new browser tab.
Each serial has these fields:
The Shoppex editor does not edit a self-hosted customer panel. Your site must render these fields in its own order-detail component.
Delivery status behavior
This delivery status belongs to one line item. It is separate from the payment status of the complete order.
Downloads
downloadIndex returned by order() or dashboard(). The SDK removes hosted-portal-only download URLs so a self-hosted site never follows a broken /api/customer/* link or receives an unsafe aggregate HTML launcher.
Logout and session state
logout() revokes only this external customer session. It does not sign the buyer out of a separate Shoppex-hosted customer portal tab. If the network request fails, the SDK keeps the local token so your UI can retry the revocation; a successful logout or an already-unauthorized response clears it.
Use clearSession() only when you must remove local state without a server request. For normal logout, call logout() by itself.
Error handling
UseHeadlessCustomerError to handle expected API errors. A 401 response clears an expired or rejected session.
Implementation checklist
- Build the OTP request and OTP verification forms.
- Add a buyer-controlled Keep me signed in option.
- Use
me()for the signed-in buyer and shop branding, thendashboard()for the account home. - Use
orders()for the order list and pagination. - Use
order()for pricing, payment, and delivery details. - Render delivery state for every line item.
- Use
download()only with a returneddownloadIndex. - Add account settings, support, license, subscription, and benefits screens from the focused methods above.
- Confirm destructive buyer actions in your UI immediately before calling the SDK.
- Handle
401by returning the buyer to the login form. - Add a logout action that calls
logout().
Security boundary
Every customer request must pass all of these checks:- valid
pk_live_orpk_test_publishable key - exact browser
Originin the shop’s allowed-origin list - active Shoppex shop
- valid
hcs_customer session bound to the same origin and shop - invoice ownership for order detail and downloads
For example, send the buyer to
https://your-shop.myshoppex.io/dashboard?tab=subscriptions for a protected subscription payment-method change. The hosted portal may ask the buyer to sign in again because the headless session is intentionally not transferred to another origin.
Wallet top-ups and license renewals are available because they return a plain Shoppex checkout URL. Your UI redirects there and the buyer still chooses whether and how to pay.
An unsupported headless route returns 404. Do not work around this by calling /v1/customer/* with a secret Developer API key or by proxying the buyer’s hcs_ token through your own backend.