A field teardown for anyone building split payments on a platform — and how to catch each one before it hits a real payout.
Most Stripe Connect integrations demo perfectly and then lose money in production, because the failure modes don't show up until real volume, real retries, and real disputes arrive. Here are the four I see most, ranked by blast radius, with the check that catches each one.
A network blip makes your server retry a PaymentIntent/charge create. Without an Idempotency-Key, Stripe happily creates two. The customer is charged twice; you eat the refund and the dispute.
Catch it: every create/capture call carries a stable idempotency key derived from your order id (not a random per-attempt UUID). Test it by firing the same request twice and asserting one charge.
Webhooks retry, arrive out of order, and duplicate. Teams update ledger state directly from whichever event lands, so a late payment_intent.succeeded overwrites a charge.refunded, and your books disagree with Stripe.
Catch it: verify the signature, dedupe on event id, and make every handler idempotent and order-independent (reconcile to the object's current state, don't blindly apply the delta). Reconcile against the Stripe API as the source of truth on a schedule.
The charge topology decides who owes the fee, who bears refunds, and who's liable for disputes. Pick "destination charge" when you meant "separate charge + transfer" (or vice-versa) and you discover the mismatch during your first chargeback, when the money's already moved. Catch it: decide topology from the liability and fee model you want, before writing code — then assert refunds and disputes debit the correct account in test mode with a real dispute simulation.
Holding funds and releasing on a milestone (via transfers or separate charges) is where marketplaces lose the most: a released transfer fails silently, a payout lands in the wrong connected account, or funds sit undelivered because a transfer was never retried.
Catch it: treat every release as a state machine with an audit row, reconcile transfer/payout status back to your ledger, and alert on any release that's been "pending" past an SLA. Never consider a milestone "paid" until the connected account's balance transaction confirms it.
The pattern across all four: the money moves in a distributed system, so every step needs idempotency, reconciliation, and an audit trail — not just a happy-path call. That's the same discipline I put into ThumbGate, an open-source firewall for AI agents that fails closed on risky actions and publishes exactly where its guarantees end.
If you're building or hardening Stripe Connect and any of the above made you check your code, I do this as fixed-scope contract work: a written teardown of where your integration can lose money, ranked by blast radius, with the fixes. Igor Ganapolsky — LinkedIn · igor@thumbgate.ai · $120–150/hr.