docs
/
Client Integration

Endpoints

The endpoints a client application actually calls — auth, catalog, cart, checkout, orders, and the customer-scoped client/* surface.

The endpoints a client application uses, grouped by what you are doing. Paths are relative to the host; every one needs orgid.

Auth column: public — no customer needed · customer — needs x-client-authorization.

Authentication

MethodPathAuthPurpose
POSTprofile/customer/signinpublicEmail + password → token
POSTprofile/customer/signuppublicCreate a customer
POSTprofile/customer/refreshpublicExchange a refresh token
GETprofile/logoutcustomerEnd the session
GETprofile/customer/profilecustomerThe signed-in customer
POSTprofile/customer/updatecustomerUpdate profile
GETprofile/customer/existpublicIs this email registered?
GETprofile/magic-linkpublicSend a passwordless link
POSTprofile/magic-link/redirectpublicRedeem one
POSTprofile/customer/social-loginpublicGoogle / Facebook identity
GETprofile/customer/password/forgotpublicStart a reset
POSTprofile/customer/password/resetpublicComplete a reset
POSTprofile/customer/password/validate-tokenpublicCheck a reset token
POSTprofile/security/challenge/sendcustomerSend an MFA challenge
POSTprofile/security/challenge/verifycustomerVerify it

Catalog

MethodPathAuthPurpose
GETstorefront/productspublicPaged list. p, ps, categories, tags, brand, price, minPrice, maxPrice, sort
GETstorefront/product/:slugOrSkupublicOne product
GETstorefront/product/categorypublicProducts in a category
POSTstorefront/searchpublicKeyword search
POSTstorefront/findpublicStructured query
GETstorefront/categoriespublicCategory list
GETstorefront/brandspublicBrand list
GETstorefront/collectionspublicCollections

Responses carry minMaxPrice alongside the paging fields, so a price filter can be rendered without a second call.

Pricing, shipping and discounts

MethodPathAuthPurpose
POSTstorefront/pricing/calculate-carteitherThe money call. Items + address + coupon → full summary
POSTstorefront/discounts/applyeitherValidate a coupon on its own
POSTshipping/optionseitherEvery way this cart can ship, cheapest first
POSTshipping/calculateeitherOne shipping figure for a cart
POSTshipping/rateseitherLive carrier rates for a parcel
GETshipping/methodseitherConfigured methods (GET, not POST)
POSTshipping/product-costeitherShipping for a single product
POSTshipping/verify-addresseitherAddress validation

calculate-cart returns subtotal, discount, tax, total, deposit, productSubtotal, productDiscount, productTax, productShipping, productTotal, rentalSubtotal, rentalTotal, shippingMethod, shippingOptions, freeShipping, freeDelivery, depositWaived, discounts, valid, reason, message, cartId.

shipping/options returns { served, options[], currency, problems? }. served: false means no configuration covers that destination — it is an honest refusal, not a zero rate. served: true with an empty options means somewhere is covered but could not be priced right now; problems[] says why (carrier unreachable, no origin set, missing parcel dimensions, over a weight limit).

Checkout and orders

MethodPathAuthPurpose
POSTstorefront/checkout-carteitherPlace an order
POSTstorefront/take-paymenteitherCharge against an order
GETstorefront/payment-gatewayspublicEnabled gateways
POSTstorefront/stripe/intenteitherStripe PaymentIntent
POSTstorefront/stripe/checkout-sessioneitherStripe Checkout
POSTstorefront/stripe/subscription-sessioneitherSubscription checkout
GETstorefront/verify-paymenteitherConfirm a payment
GETstorefront/order/getcustomerOne order
GETstorefront/orders/getcustomerThe customer's orders
GETstorefront/order/emailpublicLook an order up by email
POSTstorefront/order/refundcustomerRequest a refund
GETstorefront/subscriptions/getcustomerSubscriptions
POSTstorefront/update-subscriptioncustomerChange one

The client/* surface

Customer-scoped. Routes resolve "me" from x-client-authorization — you never pass a customer id. Every route that writes needs it; a few reads (the Content Player's) also answer without one.

MethodPathPurpose
GETclient/affiliate/programsPrograms open to join
POSTclient/affiliate/joinEnrol
GETclient/affiliate/meEnrolments with stats and referral code
GETclient/affiliate/me/link?program=…Referral link (let the server build it)
GETclient/affiliate/me/referrals?program=…Referrals
GETclient/affiliate/me/earnings?program=…Earnings
GETclient/finance/walletWallet balance
GETclient/finance/payoutsPayout history
POSTclient/finance/payouts/requestRequest a payout
GET/POST/PUT/DELETEclient/finance/payout-methodsManage payout methods
GETclient/eventsEvents
POSTclient/events/tickets/purchaseBuy tickets
POSTclient/events/tickets/confirm-orderConfirm
GETclient/events/tickets/mineThe customer's tickets
GETclient/events/participation/mineTheir participation

Content Player — client/content-studio

Plays Content Studio posts (courses, applications, trainings, blog posts). Only published posts are served. Reading an unlocked page needs no customer token; saving needs one, and the first save enrolls the customer. An optional ?code= (access code or invitation) is passed through.

MethodPathBody / purpose
GETclient/content-studio/mineEverything the customer has started — status, %, next page, due date
GETclient/content-studio/:postThe post, its outline (each item's status, lock reason, type, duration, step; chapters' done / total), my progress, and next
POSTclient/content-studio/:post/enrollStart
GETclient/content-studio/:post/items/:itemIdOne page — content, prev / next, my progress and saved answer
POSTclient/content-studio/:post/items/:itemId/progress{ done, percent, score }
POSTclient/content-studio/:post/items/:itemId/answer{ values, done } — the page's answer; quizzes are marked 0–100

The staff side, content-studio/* (review queue, enrollments, review decisions, preview), is for signed-in business users only. It refuses the site's app token — never route it through a public proxy.

me/referrals, me/earnings and me/link require program as a query parameter. Omit it and you get 400 Program name is required.

Notes that save a debugging session

  • shipping/methods is a GET. Everything around it is a POST; posting to it 404s.
  • Referral codes are an array. An affiliate holds codes[] — live, retired and disabled. The client responses resolve the live one onto data.code for you; do not walk the array yourself.
  • forbidNonWhitelisted is on. Round-tripping a record — GET, change one field, POST back — fails with a 400 because the read shape carries fields the write DTO does not accept. Send only what the write accepts.
  • Bodies are capped at 4 MB. Use the upload endpoints for files.
  • Content Player answers upload their files first, to client-data/files/upload (category content-player), then send the answer with the file references. A proxy must allow that prefix.

Anything not listed here

This page covers the client-facing surface. AppEngine is much larger — see AppEngine API → Modules. From the browser runtime, any endpoint is reachable without a hand-written wrapper:

await appmint.api.post('shipping/options', { items, toAddress });