Business logic with side effects: carts, placing and updating orders, subscriptions, and the payment session flow (Stripe). These routes write real data and trigger hooks and e-mails.
Upsert a shopping cart (store/{sid}/carts/{cart}). Carts are deliberately inert: no triggers, no hooks, no stock interaction - one document write per call. Omit cart to create (a new id is returned - keep it client-side, e.g. localStorage). Provided fields overwrite (the items map wholesale - send the full desired map); absent fields survive. Every set restamps expires (now + setup/order.cart_ttl_days, default 30 d) - Firestore TTL garbage-collects stale carts. Callers on an identity-token are forced to their own customer id as the cart id (and uid). Check out with order/make {cart}.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
cart | string | optional | Cart id. Omit to create a new cart. Ignored (forced to the identity's customer) when an identity-token is presented. |
items | object | optional | Map of SKUs to quantities - positive integers, max 100 SKUs. Replaces the stored map wholesale. SKUs reference BASE product documents (group parents are denied at checkout). |
uid | string | optional | Customer id, when known (logged-in flows). Forced to the identity customer when an identity-token is presented. |
email | string | optional | Contact e-mail for cart recovery. |
promo | object | optional | Promotions object (credits, coupons array, referral) carried into checkout. |
locale | string | optional | Interface language / price currency (xx_XX), carried into checkout. |
origin | string | optional | Country code (currency override), carried into checkout. |
note | string | optional | Customer note (max 2000 chars). |
Response
object — Returns the stored cart including its id and the computed expires stamp.
Sample request
{
"items": {
"tshirt-blue": 2,
"mug-white": 1
},
"locale": "en_US",
"email": "customer@example.com"
}Omit cart to create a new cart (its id is returned - keep it client-side). items replaces the stored map wholesale, so always send the full map.
Read a cart by id. Identity-token callers read their own cart (the id is forced to the identity's customer).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
cart | string | optional | Cart id. Required unless an identity-token is presented. |
Response
object — Returns the cart document. 404 when it does not exist (expired carts are TTL-deleted).
Sample request
{
"cart": "cart_123"
}Delete a cart by id (e.g. after an anon-to-login merge). Identity-token callers delete their own cart. Deleting a missing cart succeeds (idempotent).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
cart | string | optional | Cart id. Required unless an identity-token is presented. |
Response
object — Returns {id, deleted}.
Sample request
{
"cart": "cart_123"
}Operations that needs to process input request. Should be exclusively used on backend.
When dealing with async mode it's recommended to implement custom pipeline with create/update endpoints. Buyers vs staff - staff is a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders; every identity-token caller and every other role (service tokens, tenant serving tokens, module tokens) is a buyer. A buyer may not send payment personal (400 payment_method_unavailable), a status other than cart/open, finalize or number (403 order_field_forbidden); a buyer's order must already exist (404 order_not_found), be cart/open/none and be its own (403 order_not_editable). An identity token (or a token carrying a customer) always acts as its own customer - user is overwritten. Refusals happen before anything is written.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
order | string | optional | Internal order ID. When an order with this ID already exists the given params are merged (depends on current status). Omit to create a new order. Buyers may name only an existing order of their own that is still none/cart/open (else 403 order_not_editable; an unknown id is 404 order_not_found); a token that is not an identity token never edits an existing order. Staff may create with an explicit new id - it is a create, a taken id answers 409 order_exists. |
cart | string | optional | Cart id to check out (see cart/set). The cart's items/promo/locale/origin/note/uid become the request base - explicit request fields win - and the cart doc is deleted after the order is created successfully. A denied order (out-of-stock lines) keeps the cart so the shopper can fix it and retry. Missing or expired cart returns 404. Identity-token callers are forced to their own cart. |
status | string | optional | Initial order status. Defaults to cart (runs the stock preview, which may flip to confirmed/denied). Use open for an editable draft. One of [none, cart, open, preview, confirmed, denied, active, ready, shipping, delivery, returned, completed, closed]. Buyers (non-staff) may send only cart or open - anything else is 403 order_field_forbidden. |
user | string | optional | Customer ID. Used to back-fill the shipping/invoicing address and to resolve the payment-service customer when a payment is requested. If omitted when creating a new order, a customer ID (UUID) is generated and returned as uid on the order. Forced to the identity's customer for identity-token callers, and to the token's customer when the access token carries one. |
number | string | optional | Overrides the generated order number (use when an internal order number is required). Check setup/order to modify the order number pattern. Staff only - a buyer gets 403 order_field_forbidden. |
items | object | required | Map of SKUs to quantities, e.g. one entry per ordered product. |
payment | string | optional | Preferred payment method. Forces sync mode. One of [stripe_intent, stripe_checkout, stripe_subscription, on_delivery, cash, personal]. personal (paid without a payment) is staff only - a buyer gets 400 payment_method_unavailable. |
payment_method | string | optional | The id of a row of the store's payment catalog (public/payments/options) - with a catalog (setup/payments.methods) the checkout must resolve to one of its enabled rows, else 400 payment_method_unavailable {reason: unknown | disabled | country | currency | amount | plan}. Wins over payment. Forces sync mode. |
payment_setup | object | optional | Payment options object with fields method (payment method / card id), confirm, reserve. |
promo | object | optional | Promotions object with fields credits, coupons (array of coupon codes), referral. Coupons are validated and redeemed at payment initialization - invalid or inapplicable codes are dropped silently (pre-validate with promo/coupons/verify). Combine rule - product coupons discount their matched cart line 100% (up to the coupon quantity), only the highest percentage coupon applies, amount coupons stack. The applied discount lands in invoice.discount (negative), the redeemed codes in invoice.coupons; credits then cover the remainder. |
origin | string | optional | Country code. Overrides currency to a different locale. Falls back to the store origin/locale. |
locale | string | optional | Interface language, also selects the price currency. xx_XX format. Falls back to the store locale. |
domain | string | optional | Base domain prefixed onto RELATIVE checkout/callback URLs. No store default - send absolute callbacks or a domain. Recommended when the store runs on multiple domains. |
callbacks | object | optional | Checkout redirect URLs object with fields success_url, error_url, cancel_url. Falls back to the store's setup/payments.callbacks (the Payments tab); a block sent here replaces it whole. |
address | object | optional | Shipping address - an address object or a string reference to a saved customer address (requires user). Falls back to the customer default address. |
address_tax | object | optional | Invoicing address when it differs from shipping - an address object or a reference. Falls back to the shipping address / customer tax data. |
note | string | optional | Customer note. |
finalize | boolean | optional | Commit the order - captures any pending payment and marks the order completed (or the provided status). Staff only - a buyer gets 403 order_field_forbidden. |
Response
object — Returns payment intent or state of the order - based on input params.\nWhen any item is out of stock, then whole order is denied.
Sample request
{
"items": {
"tshirt-blue": 2
},
"user": "user_123",
"payment": "stripe_checkout",
"locale": "en_US"
}Pass cart instead of items to check out a cart created with cart/set. With a Stripe payment method the returned order carries the payment intent or checkout session to continue with.
Create a subscription order. Same contract as order/make, but the payment defaults to stripe_subscription and the order starts as cart (stock preview). Items must reference products with a subscription interval; the Stripe Checkout Session URL surfaces as payment.service_intent.session on the returned order - redirect the customer there.
Same buyer/staff rules as order/make - staff is a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders. A buyer (identity tokens and every other role) gets 400 payment_method_unavailable for payment personal, 403 order_field_forbidden for finalize, number or a status other than cart/open, 404 order_not_found / 403 order_not_editable for an order id that is unknown or not its own open order. user is forced to the identity's (or the token's) customer.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
items | object | required | Map of SKUs to quantities. The products' subscription config drives the Stripe recurring price. |
user | string | optional | Customer ID - see order/make (forced to the caller's own customer for identity tokens and tokens carrying a customer). |
promo | object | optional | coupons - array of coupon codes. Subscriptions take at most ONE coupon (the best submitted code wins, only it is claimed) and it is attached to the subscription in Stripe, so a batch duration of repeating/forever discounts renewals too. product coupons, and any coupon on a sku billed through a fixed Stripe Price, are dropped. The discount is capped so the first invoice stays above the currency's minimum charge. Invalid or inapplicable codes are dropped silently - check invoice.discount on the returned order. |
payment_setup | object | optional | Payment options. replace - id of the customer's previous subscription this purchase supersedes (plan change); its unused period remainder is credited on the new subscription's first invoice (as a one-off discount, or as a negative invoice item when a customer coupon already occupies the discount). Ownership is validated; invalid references are dropped silently. |
callbacks | object | optional | Checkout redirect URLs object with fields success_url, error_url, cancel_url. Falls back to the store's setup/payments.callbacks (the Payments tab); a block sent here replaces it whole. |
Response
object — Returns the order with payment.service_intent.session (the Stripe Checkout URL).
Sample request
{
"items": {
"plan-pro": 1
},
"user": "user_123"
}Replace an existing order's item map. The supplied items object overwrites the order's current one wholesale - send the full desired map, not a delta. The order's status is NOT checked and totals/stock are NOT recomputed by this call, so re-run order/make against the same order afterwards to re-price and re-reserve.
Staff only - a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders; every other caller (identity tokens, service / serving / module tokens) gets 403 staff_only (a buyer edits its own cart-state order through order/make with order). An unknown order is 404 order_not_found - nothing is created.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
order | string | required | Internal order ID. |
items | object | required | Map of SKUs to quantities. Replaces the order's whole item map. |
Response
object — Returns result of write operation (confirmation).
Sample request
{
"order": "ord_123",
"items": {
"tshirt-blue": 3,
"mug-white": 1
}
}Close an order (status closed). When order is closed, any pending payment is canceled - but not refunded.
Staff (a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders) close any existing order. An identity-token caller may close only its own order (else 403 order_not_editable) while it is unpaid and at most confirmed (else 409 order_not_cancellable with reason paid or status). Every other caller (service / serving / module tokens) gets 403 staff_only - abandoned unpaid orders are closed by the hourly sweeper. An unknown order is 404 order_not_found - nothing is created.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
order | string | required | Internal order ID. |
reason | string | optional | Free-text reason stored on the order. |
Response
object — Returns {id, status closed}.
Sample request
{
"order": "ord_123"
}Cancel a Stripe subscription - by its id or by the order it belongs to. The subscription must belong to the store (checked against the provider's subscription record). Already-canceled subscriptions are a no-op.
Staff (a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders) cancel any of the store's subscriptions. An identity-token caller may cancel only its own - the subscription's order must be the identity customer's (else 403 order_not_editable). Every other caller (service / serving / module tokens) gets 403 staff_only.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
sub | string | optional | Stripe subscription id. Either sub or order is required. |
order | string | optional | Internal order ID - resolves the subscription created by this order. |
at_period_end | boolean | optional | When true the subscription stays active until the current period ends and is then canceled by Stripe. Defaults to false (immediate cancellation). |
Response
object — Returns {sub, status, cancel_at_period_end}.
Sample request
{
"order": "ord_123",
"at_period_end": true
}Staff only - a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders; every other caller (identity tokens included) gets 403 staff_only before anything is read.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | required | Store id. |
sub | string | optional | Stripe subscription id. Either this or [order] is required. |
order | string | optional | Order id - the subscription is resolved from it. |
batch | string | optional | Coupon batch id to take the discount from (value, value_type and duration). Preferred over passing amounts directly. |
amount | number | optional | Discount in major units, when no [batch] is given. Mutually exclusive with [percent]. |
percent | number | optional | Percentage discount, when no [batch] is given. Mutually exclusive with [amount]. |
duration | string | optional | once, repeating or forever. Defaults to the batch duration, else once. |
duration_months | integer | optional | Repeating only - months the discount recurs. |
Response
object — Returns the subscription id and its resulting discount.
Sample request
{
"store": "my-store",
"order": "xrmgetVCMCbDOSWPpgqX",
"batch": "SUMMER25"
}Grants a discount on an EXISTING subscription - the checkout only attaches one at creation. The discount comes from the store's own coupon batch; it replaces any existing discount rather than stacking, so re-running is idempotent.
Buyers vs staff (see order/make) - staff is a master token, or an owner/editor token whose scope is absent or writes store/{sid}/orders. For a buyer the effective service (service, else the store's default payment method) may not be personal (400 payment_method_unavailable); the order must be open or confirmed and not already paid (409 order_not_payable); an identity-token caller may pay only its own order (403 order_not_editable). user is forced to the caller's own customer (and customer is ignored) for identity tokens and tokens carrying a customer.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
order | string | required | Internal order ID. |
service | string | optional | Preferred payment method - [stripe_intent, stripe_checkout, stripe_subscription]. personal is staff only. Omitted = the store's default payment method. |
payment_method | string | optional | The id of a row of the store's payment catalog (public/payments/options). With a catalog the payment must resolve to one of its enabled rows, else 400 payment_method_unavailable. Wins over service. |
user | string | optional | Customer ID |
customer | string | optional | Customer ID of payment service. When not provided, system tries to retrieve customer id for given service. |
locale | string | optional | Interface language. Also uses price in locale currency. xx_XX format. When not provided, default locale is used. |
origin | string | optional | Country code. Overrides currency to different locale. When not provided, default origin/locale is used. |
domain | object | optional | Base domain prefixed onto RELATIVE callback URLs (no store default). Recommended when store is provided on multiple domains and checkout version of payment is used. |
callbacks | object | optional | Recommended when checkout version of payment is used. Falls back to the store's setup/payments.callbacks (the Payments tab). |
Response
object — Returns payment intent.
Sample request
{
"order": "ord_123",
"service": "stripe_checkout",
"callbacks": {
"success_url": "https://shop.example.com/thank-you",
"cancel_url": "https://shop.example.com/cart"
}
}Returns payment methods for given user and Intent to initialize new method.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
user | string | optional | Customer ID whose saved cards / SetupIntent to return. Forced to the caller's own customer for identity tokens and tokens carrying a customer. |
type | string | optional | Filters response - cards | intent | all |
Response
object — Returns available payment methods.
Sample request
{
"user": "user_123",
"type": "cards"
}Create a Stripe CustomerSession for the Payment Element so it can show the user's saved payment methods plus a save/remove UI (saved cards are charged off_session later). Returns the session client secret for stripe.elements({customerSessionClientSecret}).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
user | string | required | Customer id whose saved methods the Payment Element should manage. Forced to the caller's own customer for identity tokens and tokens carrying a customer. |
Response
object — Returns { customer, secret } - the Stripe customer id and the CustomerSession client secret.
Sample request
{
"user": "user_123"
}Read a payment back - the return leg of a checkout. By event (a Stripe payment id) or by order. For an order paid through a module gateway (payment.service = module:{id}, .dev/plans/invoice-providers.md G4) the gateway is asked once (payment.status) and its answer is applied through the one state writer before it is returned as {provider, state}; a gateway that cannot answer is 502 module_failed and nothing is applied. A bank-transfer order (.dev/plans/proforma-invoices.md) answers {status, transfer} - transfer is {pending: true} while its proforma is being issued, then {number, status, url?, account?, iban?, iban_print?, vs, amount, currency, due, spayd} (the QR Platba payload).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
event | string | optional | External event ID. |
order | string | optional | Internal order ID. |
Response
object — The stored payment object (Stripe), or {provider: 'module:{id}', state: {status, amount, currency, ...}} for a module gateway's payment.
Sample request
{
"order": "ord_123"
}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
user | string | required | Customer ID. |
method | string | required | Payment Method ID. |
Response
object — Returns result of the operation.
Sample request
{
"user": "user_123",
"method": "pm_1AbCdEfGhIjKlMnO"
}Parameters
| Name | Type | Required | Description |
|---|---|---|---|
store | string | optional | Only when store is not included in header. |
Response
object — Returns link to onboarding or already connected account.