Skip to main content
The recommended implementation creates Stripe Checkout on your server, returns the public Checkout Session ID and URL to the browser, registers that ID with Biqli, and redirects only after registration succeeds.

Prerequisites

Before writing Checkout code:
  • connect the intended Stripe account and environment to the workspace;
  • enable conversion tracking;
  • configure the website hostname and a Biqli publishable key;
  • install @biqli/analytics in the browser or use the global script;
  • keep the Stripe secret key on your server;
  • decide whether the flow is a one-time payment, paid subscription, or subscription with trial.

Create Checkout on the server

This Express-style example accepts an authenticated customer and creates a one-time Checkout Session. Validate product and price choices on the server rather than trusting the browser.
The response may contain the cs_... ID and Checkout URL. It must not contain your Stripe secret key.

Register and redirect in the browser

If storeStripeSession() fails, show a retryable error before redirecting. Do not continue and assume the success page can repair attribution later. The browser SDK generates an idempotency key for this registration. A repeated exact request is safe. Reusing an identity for another click or reusing an idempotency key with different data is rejected.

One-time payment behavior

For mode: 'payment':
  • checkout.session.completed creates a sale only when payment_status is paid;
  • amount_total is recorded as integer minor units;
  • the Checkout Session ID is the durable Biqli invoice identity for this path;
  • PaymentIntent attribution is stored when Stripe includes it;
  • an unpaid completion establishes mapping but creates no sale.

Delayed payment methods

Some payment methods complete Checkout before payment settles.
  • checkout.session.completed can leave the mapping in an awaiting-payment state.
  • checkout.session.async_payment_succeeded records the one-time sale after settlement.
  • checkout.session.async_payment_failed marks the mapped Checkout failed and records no sale.
Do not create a provisional sale in your return page. Wait for Stripe’s final event.

Declines, 3DS, cancellation, and abandonment

Stripe Payment Links and Pricing Tables create the Checkout Session inside Stripe, often after the browser has left the part of your application that knows bq_id. That means the recommended exact pre-redirect registration is not automatically available. Do not assume that installing the Stripe App makes arbitrary Payment Link sales attributable. Use one of these approaches:
  1. Prefer a server-created Checkout Session and register its cs_... ID.
  2. If your application already knows a verified customer email, create one pending mapping immediately before launch and rely on the unique-email fallback only when one eligible candidate exists.
  3. Build a trusted server-side attribution flow and use Biqli’s generic sale API after verifying Stripe’s webhook yourself.
The email fallback is not suitable when multiple people, tabs, attempts, or workspaces can share the same email candidate. Biqli rejects ambiguity instead of guessing.

Embedded Checkout and custom frontends

Embedded Checkout uses the same principle: create the session on your server and call storeStripeSession() as soon as the browser receives the session ID, before the customer can complete payment. If you build directly with PaymentIntents rather than Checkout Sessions, preserve bq_id in your trusted order record and use the server tracking API after verified payment. The managed app’s browser registration endpoint accepts Checkout Session IDs, not arbitrary PaymentIntent IDs.

Keep product data authoritative

Biqli records the paid Stripe amount and currency. Subscription product labels come from invoice line data included in the allowed event payload. Biqli does not make a separate Product or Price lookup just to decorate conversion activity. Use Stripe as the authority for Checkout price, tax, discounts, and final amount. Never calculate the recorded sale from a browser-submitted display price.

Production checklist

  • Use stripe_environment: 'live' with cs_live_... sessions.
  • Use the live Stripe account ID connected to the intended workspace.
  • Use an allowed production hostname and the production workspace publishable key.
  • Keep all secret keys and Checkout creation on the server.
  • Register before every redirect, including retry and upgrade flows.
  • Test one real low-value payment and refund before sending production traffic.
For subscriptions and trials, continue with Subscription lifecycle.