Create a Checkout session
Starts a subscription by sending the customer through hosted or embedded Checkout. The session carries the price, the trial and the URLs to return to, and the subscription is created once the first payment succeeds.
Parameters
| Parameter | Description |
|---|---|
| cancel_urlstring (uri)required | Where the buyer is sent if they leave the payment without completing it. Must be an absolute URL. At most 2083 characters. |
| price_idstringrequired | Id of the recurring price the subscription is created on. |
| success_urlstring (uri)required | Where the buyer is sent after completing the payment. Must be an absolute URL. At most 2083 characters. |
| countrystring | nulloptional | The buyer's ISO 3166-1 alpha-2 country, if known. Stored on the customer only when they have no country yet, so VAT applies to the first charge. Never overwrites an existing country. At most 2 characters. |
| coupon_codestring | nulloptional | Code of a coupon to apply. Must be active and eligible for this price. A redemption is counted only when the first payment settles. At most 64 characters. |
| customer_emailstring (email) | nulloptional | Email for a new customer, created with the session. A new customer is always created; BillKit never matches an existing one by email. Exactly one of customer_id and customer_email. Must be a valid email address. |
| customer_idstring | nulloptional | Id of an existing customer to check out. Exactly one of customer_id and customer_email. |
| customer_namestring | nulloptional | Name for the customer created from customer_email. Refused alongside customer_id. At most 255 characters. |
| metadataobject | nulloptional | Key-value pairs stored on the session and echoed on it and on the checkout.session.completed event. BillKit does not interpret them. At most 50 keys. |
| payment_methodenum | nulloptional | The one payment method to offer. Must be in the price's payment_methods, and must be able to start a mandate, so directdebit is refused. When omitted, the methods the price allows and the account can accept are offered. Must be omitted when ui_mode is embedded. One of creditcard, directdebit, ideal, eps, applepay, paypal. |
| trial_days_overrideinteger | nulloptional | Trial length in days for this checkout, replacing the price's trial_days. 0 removes the price's trial. At most twice the price's trial_days, or 28 when that is under 14. Refused for a metered price. Between 0 and 180. |
| ui_modeenumoptional | hosted creates the payment now and returns a url to redirect the buyer to. embedded returns a client_secret for the embedded checkout element, where the buyer picks the payment method. One of hosted, embedded. Defaults to "hosted". |
Returns
A Checkout session with status: “open”. In hosted mode, redirect the customer to url with a 303. In embedded mode url is null and client_secret is set instead: hand it to the Checkout Element. The secret works for 30 minutes and is never returned by a later GET. cancel_url is required either way.
Identify the customer with exactly one of customer_id or customer_email. The email creates a new customer every time and never matches an existing one. Send country when you know where the buyer is. It fills in the customer’s country if they have none, and never overwrites one they already have. VAT on the first charge is worked out from that country, and the hosted flow never asks the buyer for it, so a hosted checkout for a customer with no country charges no VAT.
payment_method is for hosted sessions only and must be on the price’s payment_methods list. directdebit is refused with a 400, because SEPA Direct Debit cannot be the first payment; charge by iDEAL or EPS and the renewals go by direct debit. A hosted session for a customer whose first payment from an earlier checkout is still in progress returns 409 operation_pending until that one resolves.
This is how subscriptions are created. There is no endpoint that creates one directly, because a subscription needs a payment mandate and the mandate is what Checkout collects. The subscription does not exist yet when this call returns; it is created when the first payment succeeds, and checkout.session.completed is your signal to provision the account. If a hosted session’s payment fails or is abandoned at the provider, the session moves to expired and emits checkout.session.expired. A failed payment, not an abandoned one, also emits payment.failed, with no subscription_id. An embedded session stays open after a failed attempt, whether declined on the spot or after 3-D Secure, so the buyer can try another method until it expires.
Send an Idempotency-Key header. This endpoint can move money, and a retried create without a key can
produce a second session and a second charge.
Test it
Run it with a bk_test_ key, open the url it returns, and choose paid at Mollie’s test-mode status selector. BillKit has no test card numbers of its own; Mollie owns that half, and lists them on its Testing page. Then inspect the events it produced in the console under Developers → Events.
Errors
| Status | Cause |
|---|---|
| 400 | The request was refused (type: invalid_request_error): a required parameter is missing (parameter_missing), one failed validation (parameter_invalid) or is not one the operation takes (parameter_unknown), and param names it. |
| 401 | No credential, or one that does not authenticate. |
| 402 | The account is suspended (tenant_suspended), or the payment provider refused a charge or refund the call made (type: payment_error, code: payment_refused). |
| 403 | Authenticated, but not allowed: missing scope (insufficient_scope), a key of the wrong mode (mode_mismatch), or a refused origin. Needs the checkout_sessions:write scope. |
| 404 | No such object in this account and mode. |
| 409 | Conflicts with the object's current state (state_conflict, or a more specific code), or an operation still in flight (operation_pending). |
| 413 | The request body is larger than the API accepts. |
| 429 | Rate limited. Retry-After says when to try again. |
| 500 | Something failed on BillKit's side (type: api_error). Retry with the same Idempotency-Key. |
| 502 | The payment provider failed or did not answer. |
| 503 | Temporarily unable to serve. reason says whether the request was attempted. |
Other checkout operations
- List one shots GET /v1/checkout/one_shot
- Create one-shot payment POST /v1/checkout/one_shot
- Get one-shot payment GET /v1/checkout/one_shot/{one_shot_id}
- Get checkout session GET /v1/checkout/sessions/{checkout_id}
BillKit