Skip to main content
POST
Create a checkout session

Authorizations

Authorization
string
header
required

Bearer token authentication. Pass your API key as Authorization: Bearer sk_.... See Authentication for keys, scopes, and sandbox vs production.

Body

application/json

Checkout with a cart of catalog products (each item may override its price via pricing).

product_cart
object[]
required

Catalog products to include in this checkout session. Mutually exclusive with pricing.

Required array length: 1 - 20 elements
billing_currency
string | null

Optional checkout billing currency. If omitted, defaults to product pricing currency.

Example:

"USD"

payment_method_types
string[] | null

Restricts the checkout to specific payment methods. Values are exact payment-method corridors, not payment types: USD_CARD and NGN_CARD are separate corridors, as is each of the nine mobile money corridors. Valid values: USD_CARD (US card, USD), NGN_CARD (Nigerian card, NGN), NGN_BANK_TRANSFER (Nigerian bank transfer, NGN), MOMO_GHS (Ghana mobile money), MOMO_KES (Kenya mobile money), MOMO_TZS (Tanzania mobile money), MOMO_UGX (Uganda mobile money), MOMO_XAF (Central Africa CFA mobile money), MOMO_XOF (West Africa CFA mobile money), MOMO_RWF (Rwanda mobile money), MOMO_MWK (Malawi mobile money), MOMO_ZMW (Zambia mobile money), and CRYPTO (all supported crypto assets). A corridor you leave out is not offered. Restricting only narrows what the customer sees: it never adds a corridor your account is not already enabled for. If the restriction leaves no payable method, the request is rejected.

Example:
cancel_url
string<uri> | null

Where to send the customer if they cancel or abandon the checkout. Returned on the checkout so the hosted page can route back to it.

Example:

"https://shop.example.com/cart"

return_url
string<uri> | null

Deprecated alias for success_url, kept for backward compatibility. If both are set, success_url wins.

Example:

"https://shop.example.com/thanks"

success_url
string

Where to redirect the customer after a successful payment. Bachs appends ?checkout_id=<id>. This is the primary success-redirect field.

Example:

"https://shop.example.com/success"

customer
object

Customer for the checkout session, optional. Omit it and the hosted checkout page collects the buyer's email and name instead, recording them on customer_details. Send customer_creation: always to also create a customer record from what they give. Required for a subscription checkout, which has no later opportunity to collect it.

metadata
object | null

Optional metadata (max 20 keys, max 10KB total).

pricing
object | null

Raw pricing for a product-less (pure) checkout. Mutually exclusive with product_cart.

platform_fee
string | null

The platform's cut of this sale, in the base currency of the sale, taken from the merchant's proceeds rather than from Bachs's processing fee. On a destination charge, this is one of two ways to state the split: the account receives the gross minus this amount. Mutually exclusive with transfer_data.amount. A destination charge needs one of the two; a direct charge can set this alone to move part of its own charge up to the platform. See Platform fees.

Example:

"20000.00"

transfer_data
object | null

Names the account this checkout pays out to. Its presence, on its own, is what makes this a destination charge belonging to your platform rather than the account. A destination charge needs a split term: either platform_fee on the request root, or transfer_data.amount here. Omit transfer_data entirely, and act as the account with X-Account-Id instead, for a direct charge. See Destination charges.

reference
string | null

Your own reference for this session, unique per account. Omit it and the session has none; use the session's id to track it.

Maximum string length: 128
Example:

"order_9876"

expires_in_minutes
integer
default:60

Minutes until the checkout session expires. Defaults to 60. After expiry the checkout URL is invalid.

Required range: 1 <= x <= 1440
Example:

60

customer_creation
enum<string>
default:if_required

Whether a buyer who identifies themselves on the hosted page also becomes a customer record. Applies only when you omit customer. if_required (default) keeps them out of your directory: customer stays null, no customer.created or customer.updated webhook fires, and their email and name reach you on customer_details instead. Their purchases still group together in your dashboard. always adds them to your directory, matched by email to a customer you already hold where one exists, and returns it on customer. That match is on the email alone, and an email typed on the checkout page is not verified, so a buyer who knows one of your customers' addresses has their purchase recorded against that customer. Ignored for a subscription or setup checkout, which always create a customer. See Whether a guest becomes a customer.

Available options:
always,
if_required
Example:

"if_required"

save_payment_method
boolean
default:false

Save the customer's card so you can charge it later without them present. Send it with a price and the customer pays now and the card is kept. Send it with no pricing and the checkout collects a card and charges nothing, which needs an existing customer (customer.customer_id) for the card to belong to. Only cards can be charged again, so a checkout that offers none is refused with CHECKOUT_CANNOT_SAVE_PAYMENT_METHOD. Saving cards is in beta and this might change.

Response

Success - Checkout session created successfully

Response containing checkout session details and hosted checkout URL.

checkout_id
string

Unique identifier for the underlying checkout.

Example:

"5d7ab015-5886-4a1e-89bb-abe499d0b8ee"

checkout_url
string<uri>

Hosted checkout URL where your customer can complete payment.

Example:

"https://checkout.bachs.io/c/Mz9wDp3sVn7QaTf"

status
enum<string>

Current checkout status. open: awaiting customer payment, where every new session starts. completed: payment succeeded, a terminal state. expired: the session window elapsed before payment, a terminal state. cancelled: cancelled before completion, a terminal state.

Available options:
open,
completed,
expired,
cancelled
Example:

"open"

expires_at
string<date-time>

ISO 8601 timestamp indicating when the checkout will expire. After this time, customers cannot complete payment through this checkout.

Example:

"2026-01-24T15:30:00.000Z"

created_at
string<date-time>

ISO 8601 timestamp indicating when the checkout was created.

Example:

"2026-01-24T14:30:00.000Z"

reference
string | null

Your own reference for this checkout, echoed back unchanged. null when you did not supply one.

Example:

"order_9876"

platform_fee
string | null

The platform's cut of this sale, echoed back from the request, in the base currency of the sale. The key is always present; it reads null, not "0.00", on a checkout that carries no fee, and on a checkout that split the sale with transfer_data.amount instead. See Platform fees.

Example:

"20000.00"

destination_amount
string | null

The seller's contracted share of this sale, echoed back from transfer_data.amount, in the base currency of the sale. Null on a checkout that carries no split, and on one that split the sale with platform_fee instead.

Example:

"80000.00"