← Marketplace Payouts & Connected Accounts
Build Marketplace Payouts & Connected Accounts on nextjs-prisma-postgres
Two-sided marketplace money on Stripe Connect Accounts V2 — charge-type architecture, hosted onboarding/KYC, fulfillment holds and payout timing, refunds and disputes against connected accounts, negative balances, and the US 1099 reporting surface — as a receipt-backed build pack for your own coding agent.
Marketplace money on Stripe Connect is four irreversible decisions wearing a trench coat: which charge model you use, who is merchant of record, who eats a chargeback, and whether you can hold funds at all. Get one wrong and the fix is not a refactor — it is re-onboarding every seller under a different agreement. This pack is a receipt-verified Next.js + Prisma + Stripe **Connect Accounts V2** spine — charge-model architecture, hosted KYC onboarding, fulfillment holds, proportional refunds, dispute and negative-balance handling, a five-bucket money ledger that provably conserves, and a US 1099 reconciliation surface — that your own coding agent builds in a few sessions instead of you learning each of those four decisions from a support ticket. Verification is fully hermetic: 18 acceptance checks against a dummy Stripe key, locally-signed webhook payloads and a real Postgres 17 in Docker, with no Stripe account involved.
Example use cases
- **A services marketplace paying tradespeople after the job is signed off** — needs a fulfillment window between the buyer's card being charged and the plumber being paid, which rules out destination charges entirely and is the single decision most agent-built marketplaces get backwards.
- **A vertical B2B marketplace whose suppliers are small companies that cannot pass full card-payments onboarding** — recipient-only accounts can receive transfers but *cannot* take direct charges, a constraint that surfaces halfway through onboarding if nobody checked it first.
- **A rentals or equipment platform that already shipped destination charges** and has now discovered it needs a damage-claim window before the owner is paid — this pack is the architecture it should have started from, and the decision table explains exactly what the migration costs.
- **A US creator marketplace crossing 200 payouts a year to one seller**, suddenly inside 1099-K territory with no idea whether the reportable amount is gross or net (it is gross, before your commission, before Stripe's fees, before refunds).
- **A solo founder whose agent confidently wrote `stripe.accounts.create({type: 'express'})`** — the shape Stripe deprecated in December 2025 — and who wants the current Accounts V2 shape as a tested contract rather than as a second opinion.
Scale envelope
The shipped architecture is one Railway-hosted Postgres 17 plus one Next.js instance, with Stripe as the system of record and the database holding four small tables (`Seller`, `Order`, `LedgerEntry`, `ConnectEvent`).
- **What it comfortably handles:** engineering estimate from the write shape, not a load-tested benchmark — on the order of **10,000–50,000 orders per month across a few thousand sellers**. The reasoning: an order writes about seven ledger rows across its whole life (three at capture, two for the Stripe fee, two at release) and generates three to four webhook events. At 50,000 orders a month that is roughly 350,000 short single-row inserts and ~175,000 webhook transactions — an average of one every fifteen seconds, with bursts. Each webhook is one short interactive transaction, not a job. A single small Postgres instance is not the constraint at this volume.
- **First ceiling — and it is financial, not technical: platform float.** Under this pack's charge model, buyer funds sit on *your* Stripe balance for the whole hold window. With the default 7-day hold, you are permanently carrying roughly **seven days of gross merchandise value** on your Stripe balance — at $10,000/day GMV that is about $70,000 of float you cannot spend. This is a deliberate consequence of the architecture (it is also what makes a fulfillment hold possible at all), and it is the number to model before you launch, not after.
**Upgrade path:** shorten `HOLD_DAYS` in `src/config/marketplace.ts`, or move to destination charges and give up holds entirely — the decision table in `ARCHITECTURE.md` D2 spells out exactly what that trade costs.
- **Second ceiling — release batching against Stripe's write rate limits.** One release is one `POST /v1/transfers`. If you release in a nightly batch you will saturate Stripe's write throughput long before Postgres notices, and the failure looks like rate-limit errors on a job that worked fine at half the volume.
**Upgrade path:** spread releases across the day (each order already carries its own `holdUntil`, so a per-minute sweep is a smaller change than a nightly batch) rather than raising concurrency against Stripe.
- **Third ceiling — Postgres connections**, and it shows up from customer-facing page and API traffic rather than from webhooks, once you scale the Next.js app past a couple of instances. Postgres's own default is `max_connections = 100`.
**Upgrade path:** a connection pooler (PgBouncer, or Railway's own pooling) in front of Postgres, then a vertical Postgres upgrade. No application changes: the ledger is append-only and nothing assumes a connection count.
- **What it does not scale into without new work:** multiple sellers per order, multi-currency, and cross-border payouts. All three are explicit non-goals in `PRD.md` because each changes the money model enough to need its own verification, and an unverified money path is worse than an absent one.
**What it costs to skip the pack:** not modelled here, deliberately. This pack has no receipt yet, so there is no measured build volume to reprice, and inventing one would break the same honest-economics rule everything else on this page follows. The sibling `saas-billing-tax` pack — same shape, smaller surface — measured about $6.55 of tokens per verification run and models out at roughly $100–390 for an unguided top-tier-model build. This pack is larger. That is as far as the evidence goes today; the receipt will say the rest.
The reason to buy is not token arithmetic. It is that the four bugs named in the table above are *money* bugs in a system holding other people's money, and money bugs are found by sellers, buyers, and eventually your bank.
What you get
A running Next.js service that is the complete money spine of a two-sided marketplace on Stripe Connect, built on **Accounts V2** — the shape Stripe shipped in December 2025 and now recommends for new platforms, which is not the shape any model was trained on.
**Features**
- **Charge-model architecture, decided and enforced.** The pack commits to separate charges and transfers, encodes the full decision table for direct and destination charges (settlement merchant, fee payer, dispute liability, required seller capability, whether a hold is even possible), and fails the build if the payment params drift toward a different model.
- **Seller onboarding on Accounts V2**: `POST /v2/core/accounts` with recipient transfer capability, platform fee and loss responsibility, Express dashboard — and hosted KYC via `POST /v2/core/account_links`. **No custom identity form**, deliberately: Stripe revises KYC continuously against UK/EU AML rules, and V2 does not even expose requirement collection as a create-time choice.
- **Seller state derived from capability status**, never from the V1-only `charges_enabled` / `payouts_enabled` booleans — including the state everyone forgets, where transfers work but payouts do not and money piles up in the seller's Stripe balance unable to reach their bank.
- **Fulfillment holds** implemented the only way they actually work under this charge model: buyer funds sit on the platform balance and the transfer *is* the release, gated by an ordered decision function (open dispute beats everything, and the operator's force flag bypasses exactly one check).
- **Refunds as two calls** — refund the platform charge, reverse the transfer proportionally — with the destination-charge params that would be wrong here (`reverse_transfer`, `refund_application_fee`) asserted absent.
- **Disputes and negative balances**: liability sits with the platform under this model and no setting moves it. The pack books Stripe's provisional debit when the dispute opens, does **not** claw back the seller until the dispute actually closes as lost, and then surfaces the shortfall the platform will eat if the seller has already spent the money.
- **A five-bucket money ledger with a conservation law.** Every action's entries sum to exactly zero, so the marketplace cannot invent or lose a cent without a test failing — checked in memory *and* in Postgres.
- **A US 1099 reconciliation surface**: gross (not net, not refund-adjusted) volume bucketed by calendar year in the platform's reporting timezone, with the restored federal $20,000/200 threshold and the sub-federal state thresholds flagged per seller.
- **Idempotent, signature-verified webhooks across two endpoints** (platform-scoped and Connect-scoped), with ledger entries written inside the same transaction as the event row.
- **Acceptance suite + `verify.sh`**: 18 receipt-grade checks, all hermetic — dummy Stripe key, locally-signed payloads, real Postgres 17 in Docker, no live Stripe account anywhere.
- **A manual checklist for everything code cannot do**: Connect enablement, 1099 enrollment and W-9 outreach, negative-balance policy, state filing, and the legal review that holding buyer funds actually requires.
**Screens / surfaces**
- `/marketplace` — seller onboarding state with requirement count and a continue button, order list with state and hold countdown, per-order ledger reconciliation (loud when it does not sum to zero), negative-balance banner. Tailwind 4 + shadcn/ui, pinned.
- Stripe-hosted onboarding (identity, documents, bank details, AML — all Stripe's).
- Stripe Express dashboard for sellers (payout history, bank details).
- API: `POST /api/sellers/onboard`, `GET /api/sellers/status`, `POST /api/orders`, `POST /api/orders/[id]/{release,refund}`, `POST /api/stripe/webhook`.
How it works
01
Buy the pack
Instant download: PRD, architecture decisions, task graph, acceptance tests, scaffold, and per-phase prompts.
02
Feed it to your agent
Claude Code or Cursor builds inside the pinned scaffold — no context needed beyond the pack itself.
03
Verify
Run the pack's acceptance script. It checks the same things our verification harness checked.
nextjs-prisma-postgres versions lock
| node | 24.18.1 |
| next | 16.2.12 |
| react | 19.2.8 |
| react-dom | 19.2.8 |
| stripe | 22.4.0 |
| stripe-api-version | 2026-07-29.dahlia |
| prisma | 7.9.1 |
| @prisma/client | 7.9.1 |
| @prisma/adapter-pg | 7.9.1 |
| typescript | 5.9.3 |
| vitest | 4.1.10 |
| tailwindcss | 4.3.3 |
| @tailwindcss/postcss | 4.3.3 |
| shadcn | 4.16.1 |
| tailwind-merge | 3.6.0 |
| clsx | 2.1.1 |
| class-variance-authority | 0.7.1 |
| @types/node | 24.3.0 |
| @types/react | 19.2.2 |
| @types/react-dom | 19.2.2 |
| postgres | 17.10 |
Prescribed services
- Railway — Railway referral credits
Disclosure: some links on this page are affiliate links. We may earn a commission if you sign up through them, at no extra cost to you. We only link to services the pack actually verified against.