Checkout
Create a hosted pay-first checkout session for a cart of catalog products. ibakepro reprices the cart server-side, returns a hosted checkout URL, and creates the order only on payment success. An abandoned session never becomes an order.
This is the headless equivalent of the ibakepro storefront checkout. It reuses the same hosted page and the same mint path.
Checkout accepts both secret (ibp_sk_) and publishable (ibp_pk_)
keys, answers OPTIONS preflights, and returns CORS headers
(Access-Control-Allow-Origin: *) on every response including errors, so you
can create a session straight from the browser with a publishable key.
How it works
- Build a cart of
product_id+variant_id+choicesfrom the Products catalog. POST /api/v2/checkoutwith those items. ibakepro reprices server-side (you do not send prices here - this is the server-authoritative path, unlike Orders).- Redirect the shopper to the returned
checkout_url. On that page they enter their contact details, pick a fulfilment method, choose a date and time slot, optionally apply a discount code, and pay (Stripe, PayPal including Venmo, or Square, depending on what the merchant has enabled). - On payment success ibakepro mints the order, records the payment, and marks the session
completed. The shopper stays on the hosted page and sees its confirmation state.
The session is the only artifact created at step 2. No order, no customer, and no payment record exist until the shopper pays.
Create a checkout session
Reprice a cart and create a hosted session. Returns the session id, the hosted checkout_url, an expiry, and the server-computed pricing.
Required scope: checkout:write (in the publishable allowlist)
Send an Idempotency-Key header so a retried network call reuses the same session. The same key with a different body returns 422 idempotency_key_reused; a retry while the first call is still running returns 409 request_in_flight. Keys are retained for 24 hours.
Request body
- Name
items- Type
- array
- Description
Required, at least one. Each item:
product_id, optionalvariant_id(the product's size/variant id, defaults to none),quantity(defaults to1), optionalcustom_field_values(an object keyed by custom-field definition id), and optionalchoices: [{ choice_id, selected_option_id }]. Every product is checked before pricing: an unknown id, a product whosestatusis notactive, or one withstorefrontEnabled: falsereturns400. Repricing failures (invalid variant, unknown choice option) are collected and also returned as400.
- Name
success_url- Type
- string
- Description
Optional. Must be an absolute http or https URL. See Return URLs - this is a link on the hosted page, not an automatic redirect.
- Name
cancel_url- Type
- string
- Description
Optional. Must be an absolute http or https URL.
Delivery details, time slots and discount codes are not accepted here. The session is priced as pickup with no discount, and the shopper resolves all three on the hosted page.
Response fields
- Name
session_id- Type
- string
- Description
The checkout session id. Always prefixed
cs_followed by 32 random bytes, base64url encoded.
- Name
checkout_url- Type
- string
- Description
The hosted page to redirect the shopper to, on the regional app host for the key's region (
{app_host}/checkout/{session_id}).
- Name
expires_at- Type
- string
- Description
ISO 8601. Exactly one hour after creation.
- Name
pricing- Type
- object
- Description
Server-computed
subtotal,tax,delivery_fee,total,currency(the merchant's configured currency).delivery_feeis always0at this point because the session is priced as pickup. Treat this as a quote for the cart contents, not the final amount charged: delivery can add to it and a discount code can reduce it on the hosted page.
Request
curl -X POST https://au.api.ibakepro.com/api/v2/checkout \
-H "Authorization: Bearer ibp_pk_live_au_ABC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: cart-9f3a" \
-d '{
"items": [
{ "product_id": "prod_ze9HI0w0LpVbemUI",
"variant_id": "base", "quantity": 1,
"choices": [
{ "choice_id": "cho_hoFEGdk3rJ2waVe3",
"selected_option_id": "opt_JiK6AYdC3lARutKE" }
] }
],
"success_url": "https://shop.example.com/thanks",
"cancel_url": "https://shop.example.com/cart"
}'
Response (201)
{
"session_id": "cs_6JXKKFTPvP0ZyOT-YTeBgVcqfy5taB2CxA_wZGd7CEQ",
"checkout_url": "https://au.app.ibakepro.com/checkout/cs_6JXKKFTPvP0ZyOT-YTeBgVcqfy5taB2CxA_wZGd7CEQ",
"expires_at": "2026-06-09T05:25:29.969Z",
"pricing": {
"subtotal": 97.00,
"tax": 9.70,
"delivery_fee": 0,
"total": 106.70,
"currency": "AUD"
}
}
Session lifetime and expiry
A session expires one hour after creation, and that expiry is enforced:
- An unpaid session past
expires_atcannot be loaded. The hosted page returns404withInvalid or expired portal link, the same response as an unknown token. - Every payment route resolves the session through the same gate and refuses an expired one, so no charge can be created against it.
- A session that was already paid is exempt. It still mints its order and still renders its confirmation long after
expires_athas passed.
An expired session cannot be revived or extended. A new session is the only way to price and pay for that cart again.
Return URLs
success_url and cancel_url are optional, and neither is an automatic redirect. The hosted page owns the full return flow: after a gateway redirect the shopper lands back on {checkout_url}?status=success or ?status=cancelled, and the page shows its own confirmation or a "payment cancelled" notice.
- With a URL for the relevant outcome, the page additionally renders a single onward link in the merchant's button colours: "Return to store" on success, "Back to store" on cancel. The shopper chooses when to follow it.
- Without one, no link is rendered and the shopper stays on the hosted confirmation. Nothing else changes.
Only absolute http and https URLs are stored and rendered; anything else is rejected at create.
Session states
A session doc moves open to minting to completed. minting is a short-lived claim held while the order is committed, so concurrent gateway callbacks cannot mint twice. Only open (and unexpired) sessions are payable; only completed sessions carry an orderId.
Subscribe to the order.created and payment.completed webhook
events to know when a session converts to an order. There is no
endpoint to read a session back.
Notes
- This endpoint is server-authoritative: you send items, ibakepro computes the price. The trusted-pricing model, where the caller supplies
unit_priceandpricing.total, is Orders-only and secret-key only. - No order, customer or payment is created until the shopper pays. Abandoned sessions expire silently.
- Which gateways appear on the hosted page depends on what the merchant has enabled in their dashboard.
- The hosted page is served
noindex, nofollow.