Stripe Gave Platforms a Reason Code and an Undo Button for Account Rejections. Neither Existed a Year Ago.
Stripe's new unreject endpoint and specific fraud codes replace a dead-end "restricted" status that was quietly churning your own connected accounts.
If you run a platform on Stripe Connect — a marketplace, a vertical SaaS product that processes payments for its own merchant customers, anything where your revenue depends on someone else's account staying able to charge cards — you've had to reject a connected account at some point. Fraud, a stolen payment method, a merchant who took money and never shipped. Until this year, that decision was close to permanent. The account got a generic restricted status, a reason code that told you almost nothing, and no self-serve way back if you got it wrong. Across two 2026 releases, Stripe quietly fixed all three parts of that problem.
Reject the wrong merchant before this year, and your only recourse was a Stripe support ticket. There was no API call, no dashboard toggle, nothing your engineering team could ship to fix it — just a wait, while a connected account that may have done nothing wrong sat locked out of charges and payouts. For a platform business, that account is a paying customer. A merchant who can't process payments through you has no reason to keep paying your platform fee, so a wrongly rejected account wasn't just a fraud-ops mistake. It was involuntary churn with an extra step: first Stripe (or your own rule) cuts them off, then they leave, and neither event shows up anywhere near your actual churn dashboard because it never looked like a cancellation.
What actually changed, across three releases
None of this shipped as one feature. It's three separate changes, spread across the July 29 dahlia and September 30 endive API versions, that only make sense together. Taken apart, each looks like a minor parameter tweak. Taken together, they turn account rejection from a one-way door into something closer to a reviewable decision.
| What you could do | Before 2026 | As of endive (Sept 30, 2026) |
|---|---|---|
| Reason you pass when rejecting an account for fraud | A single generic fraud value | fraud_payment_method_casher, fraud_payment_method_tester, fraud_no_intent_to_fulfill, or fraud_other |
| Status shown on a rejected capability | restricted, with status_details: restricted_other | rejected, with one of 8 specific rejected_* codes |
| Whether you can tell who rejected it | No — same generic code whether Stripe or your platform made the call | Yes — rejected_platform_fraud vs. rejected_fraud, and the matching split on v1 disabled_reason |
| Reversing your own platform’s rejection | Not self-serve — required a Stripe support ticket | Self-serve via the new Unreject an account endpoint |
| Rejecting an account that still holds a balance | Returned an error until the balance was resolved | Allowed, with a payouts_action of pause or none |
Read top to bottom, that table is a single story: Stripe gave platforms better language to describe why they rejected someone, a way to see whether a rejection came from them or from Stripe itself, and — for the first time — a way to take the decision back without anyone at Stripe getting involved. The reversal piece is the one that actually changes a platform's risk calculus, because it means acting fast on a suspicious account no longer has to be a bet you can't walk back.
Why "restricted" was functionally a churn event, not a fraud control
The old restricted / restricted_other combination told you nothing actionable. It didn't say whether the account was flagged for fraud, a terms-of-service violation, an incomplete verification, or appearing on a sanctions list — all of which need a completely different response from your support team. And because the only way to reverse a mistake was a support ticket with no committed SLA, the practical incentive for most fraud-review teams was to escalate borderline accounts to rejection rather than risk letting a bad actor keep processing while a review dragged on. That's a rational call for the platform's fraud exposure. It's a bad one for the connected accounts caught on the wrong side of a judgment call, because there was no fast way back even once you'd confirmed the flag was wrong.
This is the same asymmetry we covered in our piece on Stripe's dynamic risk threshold, just one layer up the stack. That post is about payment-level false declines — a renewal blocked by an overly tight Radar setting. This is account-level: an entire merchant locked out, not just one charge. The economics behind both are the same shape. The Merchant Risk Council's 2026 survey of over 1,200 merchants across 35+ countries found actual fraud running at 3.0% of orders in 2025, while the total order rejection rate sat at 5.0% — a gap of roughly two points that's false positives, not fraud, blocked anyway. Account-level data specific to marketplaces isn't published the same way, but there's no reason to assume the mismatch disappears once the unit of review goes from a single charge to an entire merchant relationship. If anything, a wrongly rejected account is more expensive to get wrong, because the blast radius is every future transaction that account would have run, not one.
Order-level data, not account-level — but it's the same base-rate mismatch Stripe's new account rejection codes are built to make reversible. Source: Merchant Risk Council, 2026 Global Fraud Survey.
The codes themselves, and what each one is actually for
The eight new rejected_* status detail codes on Accounts v2 capabilities split cleanly into two questions a generic restricted_other could never answer: what went wrong, and who decided it did.
- rejected_fraud / rejected_platform_fraud — Stripe or your platform determined the account is fraudulent. The split tells your support team instantly whether a Stripe support ticket or your own fraud-review queue is the right next step.
- rejected_terms_of_service / rejected_platform_terms_of_service — a policy violation rather than fraud, which usually means a remediation conversation is possible, not just a lockout.
- rejected_incomplete_verification — the account never finished identity or business verification. This is the category most likely to be a false positive caused by a stuck document upload rather than any actual bad intent.
- rejected_listed — the account hit a sanctions or watchlist match, which is the one category where a platform generally shouldn't be the one deciding to reverse it.
- rejected_other / rejected_platform_other — the catch-all, same split by who called it.
The input side changed the same way. Calling Reject an account for suspected fraud used to accept one flat fraud value; now it requires picking fraud_payment_method_casher, fraud_payment_method_tester, fraud_no_intent_to_fulfill, or fraud_other, alongside a new credit reason and the existing terms_of_service and other. A "casher" — someone using the account to launder stolen payment method funds — and a "tester" — someone running small transactions to validate stolen card numbers — are different crimes requiring different evidence, and lumping them into one generic code is exactly what made a false-positive appeal so hard to build a case against. If your own review notes said "looked like testing" but your API call could only log "fraud," there was nothing specific on record to challenge later.
The balance problem that used to block you from acting at all
Before this year, calling Reject on an account holding a non-zero balance simply failed with an error. If your fraud-review process flagged an account that still had money sitting in its Stripe balance — which is the normal case, not the exception, since fraud gets caught while an account is actively processing — you couldn't reject it until that balance was resolved. That's a real delay stacked on top of a decision you'd already made, during which a confirmed-bad account could keep running transactions.
The fix, shipped in the same July 29 release as unreject, lets you reject regardless of balance and decide separately what happens to the money with a new payouts_action parameter: pause (the default, halting payouts) or none (letting scheduled payouts continue). That separation matters. Freezing the account's ability to charge new cards and freezing its ability to receive money it already earned are two different risk decisions, and forcing platforms to make both at once, on Stripe's old timeline, was never really about fraud control — it was an API limitation that happened to double as a fraud-control bottleneck.
What you can undo, and what you still can't
The Unreject an account endpoint only reverses rejections your platform initiated. A Stripe-initiated rejection — the account got caught by Stripe's own risk systems, independent of anything your fraud team flagged — still isn't something you can undo through this API. That boundary lines up with the platform_* vs. non-prefixed codes from the table above: if the status you're looking at is rejected_platform_fraud, you have a self-serve path. If it's rejected_fraud with no platform_ prefix, you're back to a support conversation, same as before this year.
That distinction is worth building into your own account-review tooling now, not after the first time someone on your team tries to unreject an account and gets a clean rejection from the API with no explanation. Check the capability's status_details code before routing an appeal — a platform_-prefixed reason goes to your own review queue with a self-serve fix available; anything else goes straight to a Stripe support ticket, because that's still the only path.
What to actually build now
- Stop logging rejections under one bucket. If your internal tooling still just marks an account "rejected" without capturing which of the eight new codes applied, you've thrown away the exact distinction Stripe built this release to give you.
- Route by the platform_ prefix. Build the branch described above into whatever tool your support or fraud team uses to look up a rejected account, so nobody wastes a day filing a support ticket for something they could have fixed themselves in one API call.
- Add an unreject path to your fraud-review workflow, not just your reject path. A team that can reject in one click and reverse it in zero clicks reviews faster and more conservatively than one that treats every rejection as final the moment it's made — the entire value of this release disappears if reversal still requires engineering to ship a new button six months from now.
- Separate the "stop charging" decision from the "stop paying out" decision using the new
payouts_actionparameter, rather than defaulting to pausing both every time, which is often more punitive than the specific risk requires.
This is, structurally, the same problem we've written about from the subscriber side in platform defensibility and in Stripe Organizations' customer sharing: a platform business sits on top of relationships that can break in ways its own dashboard never labels as churn. A connected account that leaves because you locked it out by mistake is gone for exactly the same commercial reason a subscriber who hits a confusing cancel flow is gone — nobody built a path back. It's also the same mechanism covered in our piece on Stripe's Balance Pay payout timing: Connect keeps shipping sharper controls for platforms, and each one is only as good as the operational process built around it. Run the numbers on how much a single wrongly rejected merchant account is worth to you in lost platform fees, using our churn calculator against your average connected-account revenue, before deciding whether the engineering work to wire up unreject properly is worth prioritizing this quarter. For most platform businesses charging a recurring fee on top of payment volume, the answer won't be close — and whether it's a connected merchant locked out by a fraud flag or a subscriber who hit a dead end in your cancellation flow, CancelFlow is built on the same principle this Stripe release finally caught up to: give someone a specific reason and a real way back, instead of a generic decline and a closed door.
Frequently asked questions
What happens when Stripe rejects a connected account?+
Charges and payouts on that account get disabled, its capabilities move into a restricted or (as of the Sept 30, 2026 endive API version) rejected state, and the account object's requirements.disabled_reason field records why. An account.updated event fires so your system can react. Before this release, the reason exposed to you was generic — just rejected.fraud, rejected.terms_of_service, or rejected.other — with no way to tell whether your own platform made that call or Stripe did.
Can I undo a connected account rejection in Stripe?+
Yes, if your platform made the rejection. Stripe shipped an Unreject an account endpoint in the July 29, 2026 dahlia API version that re-enables charges and payouts and reverts the account's application state. It only works on rejections your platform initiated — you still can't reverse a Stripe-initiated rejection through the API, and before this endpoint existed, reversing any rejection meant opening a support ticket and waiting.
What are Stripe's new specific fraud rejection reasons?+
As of the Sept 30, 2026 endive API version, the generic fraud value for the Reject an account endpoint's reason parameter is gone. You now pick from fraud_payment_method_casher, fraud_payment_method_tester, fraud_no_intent_to_fulfill, or fraud_other, plus a new credit reason, alongside the existing terms_of_service and other. The parameter also changed from a free-text string to an enum, so a request still passing the old fraud value now gets a 400 error.
Can I reject a Stripe connected account that still has a balance?+
Yes, as of the same July 29, 2026 release that added unreject. Previously, calling Reject an account on an account with a non-zero balance returned an error, forcing you to resolve the balance first — which delayed action on an account you'd already decided was a fraud risk. The new payouts_action parameter accepts pause (the default, which halts payouts) or none (which lets payouts continue), so you can act immediately and decide separately what happens to the money already sitting there.
Stop losing subscribers today
One script tag. One function call. A live cancellation flow in under 10 minutes.
Start free trial →