
Stripe Connect in Production: Onboarding, KYC, Payouts & Reserves (2026)
Running Stripe Connect means onboarding sellers via single-use Account Links, watching the account.updated webhook until KYC clears and capabilities like card_payments turn on, then setting a payout schedule (daily, weekly, monthly, or manual). The catch: reserves and connected-account negative balances over 180 days are ultimately your platform's liability.
Running Stripe Connect in production: onboarding, payouts, and reserves
Running Stripe Connect in production means onboarding sellers through single-use Account Links, gating sales on the account.updated webhook until capabilities go active, choosing a payout schedule, and managing reserves so your platform doesn’t end up eating a seller’s negative balance. Architecture is a one-time decision; this is the part you operate every day.
If you read my marketplace payments with Stripe Connect post, you already made the two big architecture decisions: which account type your sellers get (Standard, Express, or Custom) and which charge type moves the money (direct or destination). You pick that once and live with it. This post is about everything that comes after — actually running Connect once real money starts moving.
One discipline carries straight over from the single-merchant world: the webhook is the source of truth, never a redirect or a hopeful client-side call. In Connect that webhook is account.updated, and if you internalize nothing else here, internalize that. I leaned on the same idea in webhooks vs polling vs API — Connect just raises the stakes, because here a missed signal can mean money moving toward an account that legally can’t receive it.
How do you onboard a seller with Account Links?
Your platform is responsible for collecting KYC information on every connected account and submitting it to Stripe via the API. You do not want to build those forms yourself — regulatory fields change constantly and you’d be re-shipping them forever. Use Stripe-hosted onboarding via Account Links, or the embedded account-onboarding components if you want it inside your own UI.
The flow is two steps. First you create the connected account (that’s the architecture decision from the other post). Then, for each onboarding session, you mint an Account Link and redirect the seller to it:
const accountLink = await stripe.accountLinks.create({
account: connectedAccountId,
type: 'account_onboarding',
refresh_url: 'https://yourapp.com/connect/refresh',
return_url: 'https://yourapp.com/connect/return',
});
// redirect the seller to accountLink.url
Two things trip people up. First, Account Link URLs are single-use — they expose personal information, so Stripe burns them after one visit. If the seller’s link expires or they hit your refresh_url, you mint a fresh one. Don’t cache the URL and reuse it; it won’t work. Second, you can prefill account info before onboarding (email, business name, country), but once you create the Account Link or Account Session, some of those fields lock for Standard and Express accounts. So prefill what you’re confident about, and don’t expect to overwrite it mid-flow.
For the exact requirement model and what Stripe collects, the identity verification docs are the canonical reference.
Onboarding a seller end to end
- Create connected accountAccount type decided in the architecture post (Standard/Express/Custom)
- Create Account LinkaccountLinks.create — single-use URL, redirect the seller to it
- Seller completes KYC / verificationHosted onboarding collects identity + business info; Stripe submits it
- Capabilities enabledcard_payments / transfers turn active once requirements are satisfied
- First payoutLonger hold on the first one, then the rolling schedule kicks in
When do capabilities actually turn on?
Here is the mistake I see most: the seller finishes onboarding, lands on your return_url, and your code marks them “ready to sell.” Wrong. Returning from onboarding is not proof of anything. The seller may have a verification still pending, a document under review, or a field they skipped.
Capabilities — card_payments, transfers, and friends — only turn on once the underlying KYC requirements are satisfied. The truth lives in two fields on the account: requirements (what Stripe still needs) and capabilities (what’s actually active). You read those off the account.updated webhook, not off the redirect.
// webhook handler — the source of truth
if (event.type === 'account.updated') {
const acct = event.data.object;
const cardPayments = acct.capabilities?.card_payments; // 'active' once requirements are satisfied
const stillDue = acct.requirements?.currently_due ?? [];
if (cardPayments === 'active' && stillDue.length === 0) {
// now it's safe to let this seller transact
}
}
And requirements are a moving target. As regulations roll out, Stripe keeps adding to what it collects — it was still updating requirement collection through April 1, 2026. A seller who was fully verified last quarter can show up in currently_due or eventually_due again. So treat those requirement fields as live state you re-check on every account.updated, not a one-time gate.
My decisive rule: don’t let a seller transact or receive a payout until the relevant capability reads active. Gate on the event, not the redirect. If you gate on the redirect, you’ll eventually push money toward an account that can’t legally receive it, and you’ll be the one untangling it.
Which payout schedule should you choose?
Once a seller can actually get paid, you decide when. The payout schedule is configurable per connected account or as a platform default, and you’ve got four options. Daily pays out N days after the charge — new US accounts default to a rolling ~2 business days. Weekly pays out on a chosen weekday via weekly_anchor. Monthly pays out on a chosen day of the month. Manual means nothing leaves until you trigger it with the payout API.
Setting it is one call:
await stripe.accounts.update(connectedAccountId, {
settings: {
payouts: {
schedule: { interval: 'weekly', weekly_anchor: 'friday' },
},
},
});
One thing to set expectations on with sellers: new accounts have a longer hold before the first payout — often ~7–14 days — before they settle into the rolling schedule. That’s not a bug, it’s Stripe building confidence in a fresh account. Tell your sellers upfront or your support inbox will tell you.
My opinion, having run this: weekly is the sane default for most marketplaces. It’s predictable for sellers (they know Friday money is coming), and it gives you a window to absorb refunds and disputes before funds leave the platform. Daily feels generous but it shrinks your buffer against the exact risk we’re about to talk about. Full mechanics live in the payouts to connected accounts docs.
Payout schedules: predictability vs your risk buffer
Weekly / Monthly (scheduled)
- Weekly: chosen weekday via weekly_anchor
- Monthly: chosen day of the month
- Predictable for sellers, easy to support
- Wider window to absorb refunds/disputes
- My default: weekly
Daily / Manual / Instant
- Daily: rolling ~2 business days (new US default)
- Manual: nothing moves until you call payouts.create
- Instant: ~30 min, any day, ~1.5% fee (confirm current)
- Thinner or zero dispute buffer
- Pair fast payouts with reserves, not trust
Should you offer Instant Payouts?
Instant Payouts send funds to an eligible debit card or bank account in about 30 minutes — any time, including weekends and holidays — for an extra fee (≈1.5% as of 2026, confirm current). Platforms can let connected accounts tap their balance right after a successful charge instead of waiting for the schedule.
It’s the same payout API, with a method flag:
await stripe.payouts.create(
{ amount: 5000, currency: 'usd', method: 'instant' },
{ stripeAccount: connectedAccountId },
);
Sellers love it, and for gig-style or cash-flow-sensitive marketplaces it’s a genuine differentiator. But be clear-eyed about what it does to your risk: instant payouts move money out before your dispute and refund window has closed. That successful charge can still be reversed next week, except the cash is already gone. So if you offer instant payouts, pair them with reserves and sensible per-seller limits — never raw trust. Fast money out is a feature; fast money out with no buffer is how a platform eats a negative balance.
The part founders miss: reserves and who eats a negative balance
This is the section I wish someone had sat me down for early.
Reserves hold back part of a connected account’s balance to cover future refunds and disputes. They’re on by default for platforms created after January 31, 2017 — so if you started recently, you already have them whether you thought about them or not.
Here’s the part founders miss. If a connected account stays negative for more than 180 days, Stripe automatically pulls from your platform reserves to zero it out. Read that again: the seller racked up chargebacks, drained their own balance, went negative, and disappeared — and after 180 days, your platform is the one that pays. In Connect, the platform is the ultimate backstop. There is no “the seller’s problem” line item; legally and financially, it rolls up to you.
You manage this with connected-account reserves and risk controls (Radar for Platforms). The move is to set reserves on risky sellers — high refund rates, new accounts moving large volume, categories prone to disputes — rather than discovering the liability after the money’s gone. Model worst-case seller fraud and chargebacks into your reserve policy before you scale onboarding, not after the first five-figure negative balance shows up. The connected-account reserves docs cover the controls.
How money actually flows in Connect
The platform-liability trap
FAQ: Connect operations questions I get asked
Why did my Account Link stop working? Because the URL is single-use — it exposes personal info, so Stripe burns it after one visit. Mint a fresh one via your refresh_url flow. Never cache and reuse Account Link URLs.
Why can a seller log in but not get paid? Logging in proves nothing about KYC. Capabilities like card_payments and transfers only turn active once the verification requirements are satisfied. Check the account’s requirements.currently_due on account.updated — there’s almost certainly something still due.
Why is the first payout so slow? New accounts have a longer hold before the first payout, often ~7–14 days, then settle into the rolling schedule. It’s expected behavior, not a misconfiguration. Set the seller’s expectations upfront.
Can I just turn reserves off? You can ask, but you shouldn’t want to. Reserves exist precisely because you’re liable for negative balances over 180 days. Turning them off doesn’t remove the liability — it removes your protection against it. Manage reserves; don’t disable them.
How do I change a seller’s payout timing? stripe.accounts.update with settings.payouts.schedule, either per account or as a platform default that new accounts inherit.
Ship it with reserves in mind
The operational loop of Connect is short and you’ll run it for every seller you onboard: create the account, onboard via single-use Account Links, gate on capabilities via account.updated, pick a payout schedule, and manage reserves for the negative-balance risk. That’s the whole job.
My closing conviction, earned with real money moving: in Connect the platform is the backstop, full stop. So treat the account.updated webhook and your reserve policy as first-class infrastructure — designed, monitored, and load-tested — not as afterthoughts you bolt on once something breaks. The platforms that get burned are the ones that treated onboarding as the hard part and reserves as a checkbox. It’s the other way around.
And if you’re still standing up your base Stripe integration, my how to integrate Stripe into your SaaS guide is the foundation everything here sits on.