The checkout deep-link contract
The checkout deep-link contract
Why a table hands off rather than links straight to checkout
The hosted checkout is addressed by an opaque, organization-scoped session token
(/billing/checkout/{token}), minted by POST /api/v1/checkout-sessions for a specific org. A
public pricing table is pre-customer — a marketing-page visitor has no organization yet — so
the table cannot mint a session. Instead its CTA hands off to the operator's own checkout /
signup entry point, carrying the chosen plan, currency and interval; that authenticated entry
(which has the org in hand) then calls POST /api/v1/checkout-sessions to mint the real hosted
checkout URL.
This is the honest hosted-vs-embeddable boundary:
- The public pricing table hands off (it has no org).
- The paywall links straight to the hosted checkout — it already knows the org, so it
reuses the
UpgradeGate's pre-built/billing/checkout/{token}deep-link.
The CTA target
Each table sets a CTA target (cta_url_template). The chosen values are substituted for the
placeholders, URL-encoded:
| Placeholder | Value |
|---|---|
{plan} |
the plan key (the annual key when yearly is selected) |
{currency} |
the selected ISO currency |
{interval} |
month or year |
{price} |
the price in minor units |
https://app.example.com/signup?plan={plan}¤cy={currency}&interval={interval}
→ https://app.example.com/signup?plan=team¤cy=EUR&interval=month
A target with no placeholders instead gets the values appended as a query string
(?plan=…¤cy=…&interval=…&price=…, merged with any query it already carries).
Resolution order
Deny-by-default, so a CTA is always a valid link:
- the table's own
cta_url_template, when set; - otherwise the configured
billing.storefront.checkout_url(CBOX_BILLING_STOREFRONT_CHECKOUT_URL); - otherwise the app-root path — a relative link, so a table with no configured target stays fully self-contained (no external host in its CTA).
What the operator's checkout entry receives
Your authenticated checkout/signup route reads the plan + currency + interval, resolves the visitor's (new or existing) organization, and calls:
POST /api/v1/checkout-sessions { org, plan, currency, return_url }
→ { url: "https://your-host/billing/checkout/<token>", expires_at }
then redirects the customer to that url. From there the hosted checkout owns the payment.
A/B experiment attribution
When a table is served under a running A/B pricing experiment, the
CTA additionally carries an attribution triple — cbox_exp (experiment key), cbox_var (the
assigned variant id) and cbox_vid (the anonymous visitor id). Forward these to
POST /api/v1/checkout-sessions as experiment / variant / visitor and the conversion is
attributed back to the variant (checkout started, then completed on settlement), idempotently.
See conversion attribution.