withToken()). A secret-key (admin) client may instead pass { customer } to create the session for another customer; add { email } too when that customer has no Kerne user row (an externally-managed customer - Kerne needs an email to create one at the provider).
The subscription itself is created asynchronously once the provider confirms payment - not synchronously when this call returns.
Where the redirect goes
Checkout success and cancel (and the portal return, see Portal & cancel) all resolve unconditionally to the hosted portal (apps/portal):
portal_redirect_url if you’ve set one, otherwise app_url. Configure either through the tenant configuration endpoint (not yet wrapped by @kerne/server - call it directly with your own token, same auth as the rest of this self-service API):
portal_redirect_url is optional - only set it if the portal should send the user somewhere other than app_url once a flow finishes.
Auth callbacks (verify email, reset password, magic link) resolve the same way - unconditionally
to the portal, which then hands off to
portal_redirect_url or app_url.Headless (embedded card, Stripe only)
checkout() is the redirect path - the provider hosts the card form. For an embedded card form you build yourself, there are two server methods. They are Stripe-only, and there is no React prebuilt for this - @kerne/react’s useCheckout / <PricingTable> are redirect-oriented.
-
createSetupIntent()- a Stripe SetupIntent for your own Stripe.js / Payment Element form. No redirect, no charge. -
Confirm
clientSecretclient-side with Stripe.js (stripe.confirmSetup(...)/stripe.confirmCardSetup(...)). That returns a Stripe payment method id. -
createSubscriptionHeadless()- attach that payment method and start the subscription, no browser involved.This is admin-gated (secret key). The payment method id is re-verified against Stripe server-side, so it can’t be used to skip payment collection - it requires one Stripe already confirmed belongs to this customer. Passemailwhencustomerhas no matching Kerne user row.
For CI or a seed script with no browser to confirm a SetupIntent, pass
testCardToken (e.g.
"tok_visa") instead of stripePaymentMethodId - it mints a fresh payment method server-side on
each call. Stripe test mode only; rejected otherwise.
