Create Checkout Session
Opens a checkout session. No credentials required. Pass exactly one of items, checkout_configuration, or link. The response includes client_secret once; later calls authenticate with it.
Headers
A unique key that makes this request safe to retry. See Idempotent requests.
Request body
The affiliate this checkout is attributed to. Write-once — set it here or never.
String-to-string acquisition context. Recognized keys: utm_source, utm_medium, utm_campaign, utm_term, utm_content, tracking_link_id, funnel_id, source, country; anything else is dropped.
A seller's checkout configuration (ch_…) to open this checkout from. Its plan, mode, affiliate code, metadata, redirect URL, 3DS level and payment method configuration seed the session; anything you also send explicitly wins.
Any checkout link the seller has shared, resolved for you: a plan ID, a checkout configuration ID, a vanity short link (send page_route with it), a membership transfer code, or a checkout link the seller handed out earlier. A link that is not a checkout link is refused with a coded message rather than a bare not-found.
Free-form string-to-string map, at most 40 keys. Whop never interprets it.
Defaults to the checkout configuration's mode, then payment. setup sessions are not yet available and are refused.
Where this checkout is being opened from — the scheme and host of your page, with no path (https://shop.example.com). Ignored when the request carries a browser Origin header, which is used instead. Recorded against the session as acquisition context.
The product route a vanity link belongs to — the pageRoute in the seller's shared URL.
The password for a password-protected plan. Right, and the gate is cleared for the session's whole life; wrong or omitted, and the session still opens — it publishes a custom_password requirement, the answer arrives through update, and confirm refuses until it is right.
A promo code to apply to the quote.
Where the buyer lands after an off-site payment step. Absolute https URL without credentials.
An existing membership (mem_…) this checkout pays against instead of creating a new one — the buyer pays the plan's price again onto something they already own. Ownership is checked at confirm, against the buyer who confirms: a membership they do not own is refused as not found. Cannot accompany a membership transfer link.
First-party tracking-link candidates keyed by account ID. Ignored outside Whop's hosted checkout; an explicit attribution.tracking_link_id wins.
Example request
{
"affiliate_code": "aff_from_caller",
"checkout_configuration": "ch_xxxxxxxxxxxxxx",
"items": [
{
"plan": "plan_xxxxxxxxxxxxxx",
"quantity": 2
}
],
"link": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"metadata": {
"campaign": "summer"
},
"mode": "payment",
"page_route": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"password": "rotated-away",
"top_up_membership": "mem_xxxxxxxxxxxxxx"
}Response
a free plan, which needs no payment method
The affiliate this checkout is attributed to, or null. Set at create only.
The buyer's email, once one has been resolved for this checkout — null until then. Read-only, and read it together with buyer_identity: an address alone does not mean the person holds it.
The buyer's user account (user_…), once one has been resolved for this checkout — null until then. Read-only, and read it together with buyer_identity: attributed names the account the purchase is for and proves nothing about who is at the keyboard.
How well this checkout knows its buyer, or null before one is resolved. attributed means an account was matched from what the buyer typed — it says who the purchase is for and nothing about who is at the keyboard. authenticated means the person proved they hold that account during this checkout. Only authenticated may be handed anything that acts as the buyer, and the value only strengthens.
When the buyer's identity was last established or strengthened, as an ISO 8601 timestamp. null before a buyer is resolved.
How the buyer's identity was established — the mechanism behind buyer_identity, so a checkout stays explicable long after it completed. null before a buyer is resolved. New mechanisms are added over time.
The seller's checkout configuration this session was mounted from (ch_…), or null when it was opened directly from a plan. Its presets seeded this session at create.
The session's one credential — returned by create, and echoed on a session read authenticated with it (or with the checkout's own resume cookie, which holds the same value). Every other call authenticates with it; treat it like a password for this checkout.
Whether this seller offers tax ID entry on checkout (their VAT ID setting). When false, hide the input — a stored tax_id still applies either way.
When the session was created, as an ISO 8601 timestamp.
The verb for the button that confirms this checkout, so every surface names the act the same way: pay, subscribe, start_trial, join_waitlist, or continue when nothing is charged today (a free checkout, setup mode saving a payment method, or a transfer that charges nothing). Render your own wording for each value — this is a key, never display text — and fall back to a generic label on a value you do not recognize.
The currency this checkout is priced AND charged in, lowercase. Seeded at create from where the buyer is; update it to one of available_currencies to price and charge in that currency instead.
When the session expires, as an ISO 8601 timestamp. An expired session cannot be updated or confirmed — start a new one.
Checkout session ID, prefixed chs_.
When this checkout's invoice is due, as an ISO 8601 timestamp — null for everything that is not an invoice checkout, and for an invoice without a due date. Present when the plan collects a seller-issued invoice; a surface should state the date, and a date in the past reads as overdue.
Free-form string-to-string map set at create. Whop never interprets it.
payment charges the items at confirm; setup saves a payment method for later use.
Always checkout_session.
Whether confirm needs a confirmation_token. false when no charge will ever take money — a free plan, a transfer of a non-renewing plan, or an applied promo code that makes every charge free, now and forever: collect no payment method there and confirm without a token. Live like every session fact: applying or removing a code can flip it, so mount your payment surface off this field, never off a zero total — a checkout that charges nothing today but something later (a trial, a first-charge-only code) stays true.
The buyer's phone number, or null. Collected when the session publishes a phone_number requirement (the seller collects numbers), set through update, and recorded against the order. Buyer-typed and unverified — sellers who VERIFY numbers get the verify_phone next action instead, which writes to the buyer's account.
The promo code applied to the quote, or null. Set it via update; the discount shows up in the quote.
Where the SELLER sends the buyer after a completed purchase, when the checkout configuration this session was mounted from sets one. Always an absolute HTTP or HTTPS URL — anything else serializes as null. Distinct from return_url, which is the payment provider's return leg.
Where the buyer lands after an off-site payment step. Must be an absolute https URL without credentials (http is allowed for localhost).
Whether to offer promo code entry on this checkout: false on a membership transfer, a checkout with nothing due, or a one-off purchase — no code can apply — and when the seller disabled codes for it, or none exists to enter. A code already on the session still discounts either way.
open until a confirm succeeds (completed) or the session ages out (expired). Only an open session can be updated or confirmed. A completed session whose charge later decisively dies returns to open with the failure on last_confirm_error — the same session takes the retry.
Whether this checkout collects tax, and how its price reads when it does. null means no tax is collected here — skip calculate_tax entirely and ask for no more address than the payment method itself needs. exclusive means tax is ADDED to the quote, inclusive that the quote already contains it. Present before any address is known, so a surface can decide what to collect up front; the value is what this checkout expects to price with, and calculate_tax answers with the authoritative one once a location is known (tax behaviour varies by country).
The 3D Secure behavior the checkout configuration asks for, or null to use the plan's or the account's default.
The membership this checkout tops up (mem_…), or null for an ordinary purchase. Set at create only. Confirming charges the plan's price against that existing membership instead of creating a new one — no stock is taken, and for an expiring plan the paid time stacks onto what is left. The buyer must own it: confirm resolves it against the resolved buyer's own memberships and refuses anything else as not found.