Documentation

Customer storefront

Customer-facing browse, cart, order history, saved carts, and subscription management on /storefront/*.

The storefront API at /storefront/* is a hybrid — the browse side is fully public (anyone can hit GET /storefront/products without auth), and the customer side is scoped to the authenticated customer. This page covers the customer-side surface; for the public catalogue, see Products and variants and Cart.

Order history

GET/storefront/orders/get/:authorNo auth
GET/storefront/order/get/:author/:orderNumberNo auth
GET/storefront/order/email/:email/:orderNumberNo auth

The :author segment is the customer's sk (when signed in) or guest ID (anonymous flow). The endpoints are technically public — there's no JWT requirement on the path — but the platform requires the author to match the authenticated principal's sk when a JWT is present, preventing customer A from reading customer B's orders by URL guessing.

The email/:email/:orderNumber variant lets a logged-out customer view a specific order via the order-confirmation email link, where the URL embeds both fields and the platform validates that the email matches the order's billing email.

const orders = await fetch(`/api/storefront/orders/get/${customer.sk}`, {
  headers: { orgid: ORG_ID, Authorization: `Bearer ${customerJwt}` },
}).then(r => r.json());

For a stricter customer-portal "my orders" view, use /client-data/orders (see Customer account) — same data, but JWT is required.

Order actions

A handful of customer-initiated actions on orders:

POST/storefront/order/cancel/:orderNumberNo auth
POST/storefront/order/refund/:orderNumberNo auth

Cancel works only while the order is still in pre-fulfillment states. The customer's identity is verified by the sk in the body or the JWT. Refund-from-customer-side is gated to the configured org policy — most orgs don't expose customer-driven refunds, instead routing through the Returns and RMA workflow.

Saved cart

GET/storefront/cart/get/:authorid/:cartid?No auth
POST/storefront/cart/update/:cartidNo auth
GET/storefront/cart/clear/:cartidNo auth

Same cart endpoints as for guest shoppers. After sign-in, the customer's saved cart attaches to their sk; multiple carts (saved-for-later patterns) can coexist. See Cart for the full flow.

Subscriptions

GET/storefront/subscriptions/get/:author/:subscriptionid?No auth
POST/storefront/update-subscriptionJWT

get returns one or all subscriptions for a customer. update-subscription accepts:

{
  "subscriptionId": "sub-abc",
  "action": "pause",
  "reason": "Travelling for two months"
}

Actions: pause, resume, skip-cycle, change-plan, change-quantity, cancel. The platform routes through Stripe (or PayPal) and the change reflects on the next bill cycle unless the body specifies effective: 'immediate'.

See Subscriptions and rentals for the full subscription lifecycle.

Send welcome / receipt

GET/storefront/order/send-welcome/:orderNumberNo auth

Re-sends the order-confirmation/welcome email. Useful when the original send bounced or the customer asks for a copy.

Payment verification

GET/storefront/verify-payment/:provider/:configId/:paymentIdNo auth

The order-success page calls this to confirm the order is paid before showing the receipt — used as a fallback when payment-provider webhooks are delayed. See Stripe and PayPal for vendor-specific notes.

Refund

POST/storefront/order/refund/:orderNumberNo auth

Customer-initiated refunds (where allowed). The platform checks the org's refund policy (time window, item eligibility) before processing. Most orgs disable this and route through Returns/RMA instead.

Public vs JWT-required

Many storefront customer endpoints accept both. The pattern:

  • No JWT — the endpoint expects the URL to carry enough identity (e.g. email + order number, or guest cart ID).
  • With JWT — the platform additionally verifies the principal owns the resource.

Carrying a JWT when one is available is always the safer pattern; it tightens authorisation on the same endpoint.

Don't rely on the public-endpoint URL pattern alone for security. The platform validates ownership server-side; a malicious customer can't read another's order even if they guess the order number, because the email or sk check fails. But your own client code should still default to authenticated calls.