Payments

This page explains what happens under the hood when your storefront takes a payment, so you understand the guarantees you're building on. For the step-by-step SDK calls, see Store; for the business-owner view of getting paid, see How You Get Paid.

You build two things: the UI, and a call to the checkout SDK. Everything after the customer clicks "pay" — the Stripe session, the customer record, the order/subscription row, retries, refunds — BusinessDash handles server-side.


The model: direct charges on connected accounts

Every org connects one Stripe account through Stripe Connect (Express). Your storefront's charges are created on that connected account (a "direct charge"), so the money settles to the org, and BusinessDash takes a small application_fee. There are two Stripe accounts in play — the org's connected account (its revenue) and BusinessDash's platform account (its own billing) — and the webhook tells them apart by event.account.

You never touch Stripe keys or the connected account id — the SDK is scoped to the org, and the server resolves the rest.


The checkout flow

The shape is the same for one-time purchases and subscriptions:

  1. Your site calls the SDK to start checkout:

    // One-time (cart → hosted checkout)
    const { stripeUrl } = await client.checkout.start(session.id)
    
    // Subscription (buyer must be signed in — see below)
    const { stripeUrl } = await client.subscriptions.startCheckout({
      subscriptionId: 'sub-plan-1',
    })
    
  2. Redirect the browser to stripeUrl. Stripe collects payment on its hosted page.

  3. Stripe returns the customer to your successUrl with a session_id.

  4. Your success page confirms the result:

    const status = await client.checkout.getStatus(session.id)
    // → { paymentStatus: 'paid' | 'unpaid' | 'no_payment_required', ... }
    

You render "thank you" on paid. That's the whole integration.


Source of truth: the webhook re-reads Stripe

BusinessDash never trusts a redirect or an event payload to decide what you got paid. When a payment completes, Stripe notifies BusinessDash's webhook, which re-fetches the current state directly from Stripe by id and writes the order or subscription from that. The same sync also runs eagerly when your success page calls getStatus, so state is usually already correct by the time the customer sees the page — the webhook is the backstop.

This gives you three guarantees without any work on your side:

  • Idempotent. A duplicated or replayed Stripe event is recorded once — inventory won't double-decrement, an invoice won't be marked paid twice.
  • Self-healing. A dropped notification is repaired by the next event's full re-sync.
  • Correct amounts. What's recorded is what Stripe actually captured, not what a payload claimed.

Customer-first (and why subscriptions require sign-in)

Before a durable purchase, BusinessDash creates the buyer's Stripe customer on the connected account and remembers the link, so repeat purchases, saved cards, and subscriptions all attach to the same customer.

Because that binding is keyed to a logged-in account, subscription checkout requires an authenticated buyer — client.subscriptions.startCheckout returns a 401 for an anonymous visitor. Wire up Auth first. One-time store checkout still works for guests (the order is the record); when the buyer is signed in, their purchases attach to their durable customer automatically.

A subscription CTA should only render for a signed-in visitor (or send them through sign-in first). One-time "Buy" buttons can stay available to guests.


What settles where

You handleBusinessDash handles
Storefront UI + the checkout SDK callStripe session creation on the connected account
Redirect to stripeUrlThe Stripe customer + the buyer↔customer binding
Reading getStatus on your success pageOrders, subscriptions, invoices — written from Stripe's truth
Sign-in before subscription checkoutIdempotency, retries, refunds, renewals, cancellations

The org connects Stripe once under Settings → Payments; after that, store purchases, subscriptions, invoices, bookings, and POS all settle to the same connected account.