Zero to first sale - storefront
From your Stripe keys to a seller paid out: the storefront shape end to end, where buyers pay on the seller's own Stripe account and your fee comes to you.
This guide takes an app from no selling at all to a paid, fulfilled and refunded sale in the storefront shape, then live. In the storefront shape the buyer pays the seller: Stripe charges on the seller's own Stripe account (a direct charge) and sends your fee to you. The seller owns their refunds and disputes, and Stripe's processing fee is the seller's unless you choose to pay it.
Running a marketplace instead, where your app takes the money and pays sellers out? Follow Zero to first sale: marketplace. The two guides share their steps; the differences are called out in each.
Note
What you can use today. Every console step and server route below
works now. The SDK screens and hooks (<SellerHome>, <SellerItems>,
<BuyButton>, <SellerSales> and the rest) are in
@buildbase/sdk
1.2.0 and later. You can also call the routes named on each module's page
from your own screens.
Before you start
- A BuildBase app with the SDK installed (installation) and two test users you can sign in as: one seller, one buyer.
- A Staging environment to test in (step 0). It takes Stripe test keys only, so nothing real is charged.
- A Stripe account. In the Stripe Dashboard, in test mode (the mode of your test keys), turn Connect on and complete your platform profile.
- A webhook endpoint on your server for BuildBase events, if your server acts on sales (webhooks).
- Selling open for your app. If Billing, Selling says Selling is not open for this app yet, contact BuildBase support.
Storefront and marketplace side by side
| Storefront (this guide) | Marketplace | |
|---|---|---|
| Who the buyer pays | The seller, on the seller's Stripe account | Your app, which sends the seller's share |
| Your fee | Sent to you by Stripe from each charge | Kept from the charge on your account |
| Refunds and disputes | The seller's (you can refund too) | Yours only |
| Stripe's fees | The seller's, or yours if you choose | Yours |
| Stripe Tax | On each seller's account, which each seller sets up | On your account |
| Carts across sellers | One Stripe page per seller, in turn | One Stripe page for the whole cart |
| Seller's countries | Countries Stripe supports for sellers in your region | A narrower list Stripe can pay out to |
| Seller gives email | No | Yes |
0. Open Staging
Everything up to step 12 happens in a Staging environment. In the console, choose Staging in the environment switcher at the top, or add it there with Add environment (owners and admins). Staging keeps its own users, settings and Stripe keys apart from Production, and takes Stripe test keys only. Point your app at it with its environment key (environments), so the seller and buyer you sign in as in steps 5 and 7 are Staging users.
No Staging environment yet? Environments are switched on per app as the platform rolls them out: yours has them once the console shows Environments under Settings > General. Until then, your Production environment accepts Stripe test keys too. Make your first test sale there with your test keys (steps 1 to 12, with a Test keys badge on Selling), then switch to your live keys there in step 13.
1. Save your Stripe test keys in Staging
In the console, in Staging, open Billing, Credentials and save your Stripe test
secret and publishable keys. Selling and Item types appear in the
Billing menu, under Selling, once they are saved. Staging refuses a
live key: "Staging accepts Stripe test keys only (sk_test_ and pk_test_).
Live keys belong in production."

2. Set selling up as a storefront
Open Billing, Selling. The Overview tab is a checklist of seven steps, each saved on its own:

- Your Stripe account is ready. Press Check my Stripe account: your secret key works, Connect is on and your platform profile is complete.
- How selling works. Choose Storefront: the buyer pays the seller. The choice locks once the first seller joins, because each seller's Stripe account is made for it.
- Money. Set your fee (a percent, a fixed part and a minimum) and who pays Stripe's fee. Choose what happens to your fee on a refund, and whether Stripe Tax works out tax at checkout. In the storefront shape, Stripe Tax runs on each seller's account, so each seller completes Stripe Tax's settings in Stripe; leave it off for a first sale.
- Who can sell. People, workspaces or both; their countries; your currencies; whether you approve each seller by hand.
- Receive your sellers' Stripe events. Press Set it up for me, then Create the endpoint. In the storefront shape every sale happens on a seller's account, so this Connect endpoint is how payments, refunds, disputes and subscription renewals reach your app.
- Your terms and policies. Link your seller terms and refund policy
(both required), and your fee disclosure, buyer terms and privacy policy,
each a full
https://address, and set your Order page so buyers get a receipt email. - Turn on selling. In Staging it runs on your test keys: nothing real is charged.


3. Design an item type
Open Billing, Item types, choose New item type and start from
the ready-made Service or commission type: a fixed price, a message for
the buyer and work the seller delivers by hand. Name it Coaching
session (key coaching-session), work through the sections and press
Publish v1. Item types never touch Stripe, so they are the same in both
shapes.

More in item types.
4. Add the seller screens to your app
Install Stripe's Connect loader and pass it to the provider:
npm install @stripe/connect-jsimport { ApiVersion } from '@buildbase/sdk';
import { SaaSOSProvider } from '@buildbase/sdk/react';
import { loadConnectAndInitialize } from '@stripe/connect-js/pure';
import '@buildbase/sdk/css';
export function BuildBaseProvider({ children }: { children: React.ReactNode }) {
return (
<SaaSOSProvider
serverUrl="https://api.console.buildbase.app"
version={ApiVersion.V1}
orgId="your-org-id"
loadConnectAndInitialize={loadConnectAndInitialize}
// auth and your other props as in the installation guide
>
{children}
</SaaSOSProvider>
);
}Allow https://connect-js.stripe.com and https://js.stripe.com in your
Content-Security-Policy's script-src and frame-src. Then give sellers a
page with their account, their items and their sales:
'use client';
import {
SellerHome,
SellerItems,
SellerSales,
useSaaSAuth,
} from '@buildbase/sdk/react';
export default function SellingPage() {
const { user } = useSaaSAuth();
return (
<>
<SellerHome subject={{ user: true }} defaultDisplayName={user?.name} />
<SellerItems
subject={{ user: true }}
itemTypeKeys={['coaching-session']}
/>
<SellerSales subject={{ user: true }} />
</>
);
}5. Onboard a seller
Sign in to your app as the seller and open the selling page. Start selling shows your fee and who pays Stripe's fee; the seller picks their country and the name buyers see (no email: a storefront seller's Stripe account is their own contact). Stripe's onboarding opens inside your app; in Staging, on your test keys, it accepts Stripe's test values. Back in your app the seller reads Can sell and Can get paid.

The seller shows under Billing, Selling, Sellers. If you approve sellers by hand, open the row's menu (...) and choose Approve.

6. Publish an item
As the seller, press New item in <SellerItems> and fill in an item of
Coaching session: a title, a price of $45.00, under Add a
message the message the buyer reads after paying, and, under Add
something you deliver, what the seller will do. Press Publish
(Send for review when you approve items). If you approve items, approve
it from its row's menu under Billing, Selling, Items, Needs
review; the seller gets the Item Approved email.

7. A buyer pays
The shop page is the same in both shapes:
'use client';
import {
BuyButton,
formatMinorAmountIntl,
usePublishedItems,
} from '@buildbase/sdk/react';
export default function ShopPage() {
const { items } = usePublishedItems({ typeKey: 'coaching-session' });
return items.map((item) => {
const variant = item.variants[0];
const price = variant.prices[0];
return (
<div key={item._id}>
<h2>{item.title}</h2>
{/* some prices have no fixed amount */}
{price.amount !== undefined && (
<p>{formatMinorAmountIntl(price.amount, price.currency)}</p>
)}
<BuyButton
itemId={item._id}
variantId={variant.id}
priceId={price.id}
/>
</div>
);
});
}Sign in as the buyer and press the button. Stripe's page opens on the
seller's Stripe account; in Staging, pay with Stripe's test card
4242 4242 4242 4242, any future date and any CVC.

Back on your page, useMyOrder(orderId, { waitForPayment: true }) shows
the order once paid. Your server gets order.created, then grant.created
and order.paid; the buyer gets the Order Receipt email.

8. Where the money went
Stripe charged the buyer on the seller's account and sent your fee to your account as an application fee. The order page under Billing, Selling, Orders shows the total, your fee and the seller's share.

9. Fulfil the order
A line whose item includes a benefit the seller delivers by hand (kind: 'manual') waits on the seller (fulfilment: 'due'). <SellerItems>
adds it under Add something you deliver when the item type allows it,
as it does a licence key and something your app delivers (webhook_only);
your own screen or server can save it with the item too. An item with only
a message reads Nothing to send. In <SellerSales> the
seller opens the sale and presses Mark as sent with a note the buyer
reads. You can do the same with Mark fulfilled on the order page. Your
server gets order.fulfilled.

10. Refund it
In the storefront shape the seller can refund from <SellerSales>, and
so can you, from the order page or your server
(POST /api/v1/server/commerce/orders/:id/refund). The seller's Stripe
balance pays the refund, and your fee on the refunded part goes back to
them unless you chose to keep it under Money. Your server gets
order.refunded.

A buyer who disputes the charge is answered in the seller's own Stripe Dashboard; the order shows the dispute until the bank decides.
11. Payouts
Stripe pays the seller's balance to their bank on their payout schedule.
The seller sees Payouts and balance inside <SellerHome>; you see each
seller's balance and latest payouts on their page under Sellers. Your
server gets payout.created, payout.paid and payout.failed. Your fees
land in your own Stripe balance and are paid out on your schedule.

12. Tick off the go-live list
In Staging, the Overview tab's Before going live list checks the setup steps, selling on, policy pages, tax on sales, the Connect endpoint's events, a clean Reconcile, a seller who can sell, a test sale and a test refund. The last item, Going live, reads In Production: going live happens in your Production environment.

13. Go live in Production
Switch to Production with the environment switcher at the top of the console. Production keeps its own settings and item types, so set selling up there as you did in Staging (steps 2 and 3). Save your live keys under Billing, Credentials (until you do, Selling shows a Test keys badge; with live keys it reads Live), complete your platform profile in Stripe live mode, set up the live Connect webhook endpoint (Set it up for me), run the Stripe check again and turn selling on. Live keys reads Not yet open until live selling is open for your app; contact BuildBase support to open it. Each seller finishes Stripe's onboarding again in live mode, and with Stripe Tax on, completes its settings on their own live account. More in test in Staging, then go live.

When something stops you
| What you see | Why | What to do |
|---|---|---|
| Selling is not open for this app yet | Selling is off for your app on the platform | Contact BuildBase support |
SELLER_COUNTRY_NOT_ALLOWED | A country you do not allow | Allow it under Who can sell |
CHECKOUT_REFUSED, tax_not_ready | Stripe Tax is on but not set up on the seller's account | The seller completes Stripe Tax's settings in Stripe, or turn tax off |
SELLER_CANNOT_SELL | The seller is paused, or Stripe needs more from them | The seller finishes what <SellerHome> asks; or resume them under Sellers |
| Payments or renewals never arrive | The Connect endpoint is missing events | Selling, Settings, "Your sellers' Stripe events": Set it up for me |
REFUND_FAILED | Stripe made no refund | Read the reason in the seller's Stripe account; nothing was returned |
| Live keys refused under Billing, Credentials in Staging | Staging takes Stripe test keys only (sk_test_, pk_test_) | Save your live keys in Production |
SELLING_UNAVAILABLE: This environment sells with Stripe test keys only | A live key in a non-production environment such as Staging | Use test keys there; go live in Production |
SELLING_UNAVAILABLE with live keys | Live selling is not open for your app yet | Contact BuildBase support, or save your test keys again |
Next steps
- Carts across sellers - how a storefront cart is paid one seller at a time.
- Coupons, bundles, options, bookings, affiliates and shipping.
- Zero to first sale: marketplace.