Skip to content
Vibe Coders

Stripe Connect vs Checkout: The Decision AI Tools Can't Make for You

If your app moves money on behalf of other users, Connect is mandatory and Checkout will not save you. A walk through the account-type decision, the AccountLink onboarding flow, application fees, and...

By WitsCode11 min read

A vibe coder building a marketplace asks Lovable for a Stripe integration. Lovable confidently scaffolds a Checkout session. The demo works. A seller signs up, a buyer clicks pay, Stripe charges the card, and the money lands. A week later the founder opens the Stripe dashboard and realises all of the money landed in their account. There is no automated way to pay the seller. They have been wiring payouts manually from their own bank. A month later the first chargeback comes in and it is billed to them, not the seller. A year later the IRS sends a 1099-K for the full gross merchandise volume of the platform, treating the founder as if every transaction was theirs. This is what happens when an AI coding tool picks the wrong Stripe product.

The core distinction is not a technical preference. It is a regulatory and product fact. If you are the only party receiving money from your users, Checkout is correct. If your application routes money between users, or pays out to anyone who is not you, Connect is required. No amount of clever code can paper over the difference, because the difference is who the merchant of record is and which entity the IRS and the card networks think is holding the funds. This article walks through the decision, the three Connect account types that vibe-coding tools rarely explain correctly, the AccountLink-based onboarding flow that they almost always get wrong, the application-fee mechanics that determine your unit economics, and the 1099-K reporting responsibility that will show up later regardless of whether you planned for it.

When Checkout is the right answer

Stripe Checkout is a hosted payment page. You create a Checkout Session on your server, redirect the user to the Stripe-hosted URL, and Stripe collects the card, charges it, and redirects back. The money lands in your Stripe balance and pays out to your bank. You are the merchant on the customer statement. You handle disputes, refunds, and tax reporting, because you are the one who sold something. This is the right model for a SaaS subscription where your app is the product, a digital download store where you are the seller, a one-person consultancy booking calls, or an ecommerce shop where every order ships from one warehouse. There is only one merchant involved, which is you. Nothing in the flow requires money to move to a third party.

The giveaway that Checkout is enough is that you can describe the payment in one sentence without using the word "and." A customer pays me for a subscription. A customer pays me for a PDF. A customer pays me for a physical product I ship. As soon as the sentence becomes "a customer pays me and then I pay a driver" or "a customer pays a creator through my platform," Checkout alone is structurally wrong and no amount of webhooks and bank transfers will make it right.

When Connect is structurally required

Stripe Connect is the platform product. It lets your application accept money on behalf of other Stripe accounts and route funds to them, optionally keeping a platform fee. Connect is required whenever your product has the word "marketplace" in its pitch deck, but it is also required for several cases that vibe-coded apps underestimate. If your product lets creators accept tips, that is Connect. If your SaaS lets customers accept payments from their own customers, that is Connect. If you split a booking fee with an event host, that is Connect. If a nonprofit receives donations through your platform, that is Connect. The federal rule of thumb is that if you touch money and you are not the final recipient, you are running a money transmission business, and Stripe Connect is the product that keeps you on the right side of that line without getting licensed yourself.

The honest test is to ask who gets the 1099 at the end of the year. If the answer is "each seller, for what they earned," you need Connect. If the answer is "only me, for everything that passed through," Checkout is correct and you are the sole merchant. AI coding tools cannot answer this test because they see a Stripe integration request and match it against the most common template in their training data, which is single-merchant checkout. They will cheerfully write you six months of code that works in demo and collapses the moment the business model actually starts flowing money.

The three account types AI tools blur together

Once you know you need Connect, the next decision is which account type to use, and this is where ranking articles get lazy. Stripe offers Standard, Express, and Custom connected accounts. These are not progressively better. They are progressively more work, and the right choice depends on how much of the compliance surface you are willing to own.

Standard accounts are the lowest-liability option. The connected user creates a full Stripe account, sees Stripe branding throughout, and logs into their own Stripe Dashboard to see their earnings, disputes, and tax forms. You, the platform, never see any of their personal details. Stripe handles identity verification, disputes, customer support for payout questions, and all tax reporting, including 1099-K filing. The trade-off is that the seller-facing experience has Stripe's branding stamped on it and your sellers need to be comfortable managing a Stripe account. Standard is the right default for platforms where sellers are businesses that already understand payments.

Express accounts are the pragmatic middle path and are what most consumer marketplaces should pick. The onboarding flow is hosted by Stripe but co-branded with your platform name, so sellers see something that feels like your product with a small "secured by Stripe" attribution. Stripe still handles KYC, identity verification, and 1099-K filing. Sellers get a limited Express Dashboard for payout history and tax documents, not the full merchant-facing Stripe Dashboard. The onboarding is faster than Custom because you are not building UI for it, and faster than Standard because the connected user is not creating a separate full Stripe relationship. This is the sweet spot for gig platforms, creator economies, service marketplaces, and anyone whose sellers are individuals rather than businesses.

Custom accounts are the white-label option and are the most dangerous choice for a vibe-coded product. You take over the entire onboarding UX and the compliance obligations that come with it. Sellers never see Stripe branding. You build the forms that collect identity information, you handle disputes, you are the first line of support for payout failures, and in many configurations you become responsible for 1099-K reporting unless you specifically opt into Stripe's tax filing service. Custom is the right choice for embedded finance products and fintechs that are deliberately acquiring these obligations as part of their product differentiation. It is the wrong choice for a founder who asked an AI tool to "make it flexible" and got Custom because the word sounded appealing. If you are reading this article trying to decide, you want Express.

The single piece of code that AI tools most consistently botch is the AccountLink-based onboarding flow. Here is how it actually works. On your server, when a new seller signs up, you call the Stripe API to create a connected account object with the seller's type, country, and email. Stripe returns an account ID. You persist that account ID against your user in your own database, not in localStorage, not in a cookie, because you will need it for every subsequent operation on that seller.

Next, you create an AccountLink for that account. The AccountLink call takes the account ID, a refresh URL, a return URL, and a type of account_onboarding. Stripe returns a single-use URL that expires in a few minutes, and you redirect the seller to it. They land on a Stripe-hosted form that collects identity and bank information appropriate to their country and account type. When they finish, Stripe redirects them to your return URL. When the link expires mid-flow, which happens often because users leave the tab open, Stripe redirects to your refresh URL, and your refresh URL is expected to mint a new AccountLink and redirect the user back into the flow.

The mistakes AI tools make here are consistent. They treat the AccountLink URL as reusable and store it, so the second user to click it gets a stale URL. They omit the refresh URL entirely, so expired-link users hit a dead end. They call accounts.retrieve immediately after the redirect and assume the account is ready, when in reality Stripe needs webhook events to flip certain capability flags. They skip the webhook listener for account.updated, which is the event that tells you when a seller has completed verification or has new requirements due. The seller finishes onboarding, goes to sell something, and your UI still shows "onboarding incomplete" because nothing told the database that the state changed. They also hardcode the account type as Custom because it appeared in an example somewhere, saddling a founder with a compliance load that they neither wanted nor were capable of carrying.

The correct pattern after the seller returns is to retrieve the account object and check three fields: charges_enabled, payouts_enabled, and details_submitted. If requirements.currently_due contains anything, you must generate a fresh AccountLink and send the seller back through, because Stripe is asking for more information. You should never let a seller list an item or accept a payment until charges_enabled is true, because the PaymentIntent will fail with a capabilities error and the buyer will see a broken checkout.

How money actually moves: application_fee_amount

Once a seller is onboarded, the next question is how payments are structured, and this is where the application_fee_amount parameter becomes the centre of your unit economics. Stripe Connect offers three charge models. Direct charges create the PaymentIntent on the connected account directly, with the customer paying the seller and the platform taking a fee. Destination charges create the PaymentIntent on the platform account with a transfer_data.destination field that routes the net funds to the connected account. Separate charges and transfers let you charge the platform first and then distribute to multiple connected accounts afterwards, which is useful when a single cart contains items from several sellers.

Regardless of which model you pick, the platform fee is set through the application_fee_amount field, expressed as an integer in the smallest currency unit of the transaction. An application_fee_amount of 500 on a USD charge means five dollars goes to the platform balance and the remainder goes to the connected account, minus Stripe's own processing fee. For subscriptions on Connect, the equivalent field is application_fee_percent on the subscription object, which takes a percentage rather than a fixed amount. The fee cannot exceed the charge amount minus Stripe fees, and setting it too high will cause charge creation to fail.

The reason this matters at the decision stage, not at the implementation stage, is that application_fee_amount must be set at the moment the PaymentIntent or subscription is created. There is no retroactive fee. If your AI-generated code omitted it or hardcoded it at zero because no one told the model what your take rate should be, every transaction that has already happened has routed the full amount to the seller and you have no protocol-level way to claw your fee back without issuing a transfer in the reverse direction, which is awkward and looks bad. Knowing what your take rate is before you write a line of integration code is not a technical decision but a business one that the vibe-coding tool cannot make for you.

1099-K reporting and who sends the form

The final piece of the decision, the one that shows up in January and ruins a founder's month, is 1099-K reporting. In the United States, payment settlement entities are required to file a 1099-K with the IRS and with the recipient for anyone who receives payments through the platform above a threshold. That threshold has been falling. Federal thresholds moved from twenty thousand dollars and two hundred transactions down to five thousand dollars for 2024 calendar year filings, two thousand five hundred for 2025, and six hundred for 2026 and beyond, following the IRS phase-in. Several states, including Massachusetts and Vermont, have had a six hundred dollar threshold for years regardless of the federal number.

For Standard connected accounts, Stripe files the 1099-K directly to the connected account and you, the platform, are not involved in tax reporting. For Express, Stripe also files the 1099-K, though your platform settings determine some of the metadata on the form. For Custom, the default position is that you, the platform, are responsible for the filing, because you control the experience and Stripe cannot assume they are the payment settlement entity. Stripe offers a 1099 service as part of Connect tax reporting that you can opt into for Custom, and most Custom platforms do, because building IRS-compliant 1099 filing from scratch is not a reasonable thing to do.

The reason this comes up at the Connect versus Checkout decision is that founders using Checkout-plus-manual-wire to pay sellers sometimes discover at tax time that their own personal or company 1099-K from Stripe shows the gross volume of the platform, because Stripe sees them as the sole recipient. They then have to deduct the amounts paid out to sellers as expenses, which requires those sellers to have provided W-9s, which most of them have not, and the founder ends up with a tax reporting mess that Connect would have prevented automatically. The tax structure of your payments is an architectural decision, not an afterthought.

Where WitsCode fits

Lovable, Bolt, and Cursor will happily generate a Stripe Connect integration if you ask for one, but what they produce is almost never production-ready. The AccountLink flow will be missing its refresh URL. The webhook listener for account.updated will be absent or commented out. The application_fee_amount will be hardcoded to zero or omitted. The account type will be whichever one appeared in the model's most recent training example. The database will not be storing account IDs reliably and certainly will not be tracking capability status over time. This is the gap where vibe-coded apps silently lose revenue and accumulate regulatory exposure for months before anyone notices.

WitsCode runs a Connect implementation engagement that closes this gap. We pick the right account type based on your actual seller profile and jurisdictional footprint, wire the AccountLink onboarding flow with correct refresh behaviour, build the webhook listeners for account.updated, capability.updated, payout.failed, and charge.dispute.created, install the application-fee configuration matched to your take rate, and verify end-to-end payout in test mode before anything touches production. If you are a vibe coder staring at a half-built marketplace and wondering whether your payments layer will survive the first real seller, that is the conversation to have before you ship.

The Connect-versus-Checkout decision is the one call in your payments stack that cannot be refactored later without customer pain.

Get weekly field notes.

Practical writing on shipping products, straight to your inbox. No spam.

Need help with this?

MVP Development

We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.

Talk to us

Want to discuss vibe coders for your business?

Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.