# Checkout **Category:** Store **Base URL:** `/store/carts` **Authentication:** Mixed **Routes:** 8 routes documented ## Overview This section documents 8 API routes for checkout. ## Quick Reference | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/store/carts/:id/batch-update` | No description | | POST | `/store/carts/:id/line-item-bundles` | No description | | DELETE | `/store/carts/:id/line-item-bundles/:bundle_id` | No description | | POST | `/store/carts/:id/subscribe` | No description | | POST | `/store/carts/:id/subscription-customer` | Link a guest customer to a cart so it can check out as a sub... | | POST | `/store/carts/:id/subscription-payment-session` | Create a payment session for a subscription cart, bound to t... | | POST | `/store/carts/:id/sync-subscription-pricing` | No description | | GET | `/store/checkout-config` | GET /store/checkout-config?sales_channel_id=sc_… Tells the c... | --- ## POST Store Carts :id Batch-update **Endpoint:** `POST /store/carts/:id/batch-update` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body | Field | Type | Required | |-------|------|----------| | `first_name` | string | No | | `last_name` | string | No | | `address_1` | string | No | | `address_2` | string | No | | `city` | string | No | | `country_code` | string | No | | `province` | string | No | | `postal_code` | string | No | | `phone` | string | No | ### Response **Success:** ```typescript { success, ...result } ``` **Error (400):** ```typescript { error, details, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/batch-update' \ -H 'Content-Type: application/json' ``` --- ## POST Store Carts :id Line-item-bundles **Endpoint:** `POST /store/carts/:id/line-item-bundles` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body | Field | Type | Required | |-------|------|----------| | `item_id` | string | Yes | | `variant_id` | string | Yes | ### Response **Success:** ```typescript { cart, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/line-item-bundles' \ -H 'Content-Type: application/json' ``` --- ## DELETE Store Carts :id Line-item-bundles :bundle_id **Endpoint:** `DELETE /store/carts/:id/line-item-bundles/:bundle_id` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | | `bundle_id` | string | Yes | Bundle_id identifier | ### Response **Success:** ```typescript { cart, } ``` ### Example Request ```bash curl -X DELETE 'https://your-store.omnicart.cc/store/carts/:id/line-item-bundles/:bundle_id' \ -H 'Content-Type: application/json' ``` --- ## POST Store Carts :id Subscribe **Endpoint:** `POST /store/carts/:id/subscribe` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response The handler does not return an object literal, so the response shape is not derivable from the source. ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/subscribe' \ -H 'Content-Type: application/json' ``` --- ## POST Store Carts :id Subscription-customer **Endpoint:** `POST /store/carts/:id/subscription-customer` **Authentication:** Customer (Optional) ### Description Link a guest customer to a cart so it can check out as a subscription. validate-subscription-cart requires cart.customer_id, and creating the payment session for a cart that has one is also what makes OmniCart create the Stripe account holder -- which that same validation requires. A guest cart satisfies neither, which is why subscribing produced an order and no subscription. Deliberately a guest customer: no account, no credentials, no authentication. A subscription needs a customer record to hang a reusable payment method on, not a login. The email is unverified, which decides the two rules below: - Only customers with has_account = false are ever matched. Attaching a checkout to a REGISTERED customer on an unverified email would let anyone transact as that account and inherit its saved cards. - The response is identical whether or not a registered account exists on that address, so this cannot be used to test which emails have accounts. ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success (200):** ```typescript { customer_id, } ``` **Also returns (200):** ```typescript { customer_id, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/subscription-customer' \ -H 'Content-Type: application/json' ``` --- ## POST Store Carts :id Subscription-payment-session **Endpoint:** `POST /store/carts/:id/subscription-payment-session` **Authentication:** Customer (Optional) ### Description Create a payment session for a subscription cart, bound to the cart's customer. The stock store route takes the customer from the request's auth context: customer_id: req.auth_context?.actor_id A guest checkout has no auth context, so it creates the session with no customer -- and createPaymentSessionWorkflow only creates the Stripe account holder `when("customer-id-exists")`. No account holder means validate-subscription-cart rejects the checkout, which is why attaching a customer to the cart was necessary but not sufficient. This reads the customer from the CART instead, which is the same customer the order will be placed for. It grants no access the caller did not already have: the cart is the caller's, and the customer on it is the guest record created for this checkout. Serves both purchase modes, because both need the cart's customer on the session -- a subscription to be chargeable at renewal, a one-time purchase so the card can be reused for a post-purchase upsell. setup_future_usage is the caller's, and the two values are not interchangeable: off_session charged later with nobody present -- a renewal. Requires the shopper to have agreed to it, which the subscribe copy does. on_session reused only while the shopper is still here, which is what an upsell moments after checkout is. Defaults to off_session so an omitted value cannot silently downgrade a subscription into a card that renewals cannot charge. ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success (200):** ```typescript { payment_collection, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/subscription-payment-session' \ -H 'Content-Type: application/json' ``` --- ## POST Store Carts :id Sync-subscription-pricing **Endpoint:** `POST /store/carts/:id/sync-subscription-pricing` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response The handler does not return an object literal, so the response shape is not derivable from the source. ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/carts/:id/sync-subscription-pricing' \ -H 'Content-Type: application/json' ``` --- ## GET Store Checkout-config **Endpoint:** `GET /store/checkout-config` **Authentication:** Customer (Optional) ### Description GET /store/checkout-config?sales_channel_id=sc_… Tells the checkout page which Stripe provider to initiate and which publishable key to load Stripe.js with, for one sales channel. Both answers have to come from the same place. Stripe rejects a live secret paired with a test publishable key, and the rejection surfaces at payment time — the buyer sees a card form that simply refuses. Deriving the provider on the client and the key from a build-time environment variable is exactly how those two drift apart, so the server returns them together or not at all. On a deploy with no sandbox configured this returns the live provider id and a null key, which is the state every deploy is in today: the page keeps using its build-time VITE_STRIPE_PUBLISHABLE_KEY and nothing changes. ### Response **Success:** ```typescript { payment_provider_id, stripe_publishable_key, sandbox, } ``` **Also returns:** ```typescript { payment_provider_id, stripe_publishable_key, sandbox, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/checkout-config' \ -H 'Content-Type: application/json' ``` ---