docs(sandbox): document the return-after-settlement quote source suffix - #1054
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 3 Skipped Deployments
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@greptile review |
|
Faraday reviewfastpass advisory - comment-only, never blocks a merge. To retire a finding, either fix it or reply explaining why it is wrong: a rebuttal gets an agree or disagree answer on the thread, and if you reply again after a disagreement we concede. Acknowledging it ("will fix") or resolving the thread does not retire it on its own. This comment is edited in place every round; inline findings still post as new comments each round. ⚠ Partial review: quote_verify did not run (quote_verify: all_unchecked); findings below were not quote-checked against the reviewed commit. Faraday score: 5/5 (converged - nothing blocking open) - 5 nothing blocking open | 4 non-blocking only | 3 one blocking open | 2 two | 1 a P0 or 3+ blocking; never drops without a new blocker
fastpass re-review: 2 resolved since last review. Converged - nothing new that blocks. 🦕 Congratulations @akanter - you caught a Zephyrosaurus! (common) That's your 3rd Zephyrosaurus!
View your collection: https://zeus.dev.dev.sparkinfra.net/#/dinodex/akanter Round history (2 rounds)
This summary supersedes the per-round summary blocks on the faraday reviews above; those are left in place as history and are not edited. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
|
⚡ Review rounds — updated in place, latest first. Round 8 · 028f672
Earlier rounds (7)Round 7 · 31f11f2
Revision 6
Revision 5
Revision 4
Revision 3
Revision 2
Revision 1
|
|
⚡ Review ledger Round 1
Round 2
Round 3
Round 4
Round 5
Round 6
Round 7
Round 8
Round 9
Round 10
Round 11
|
|
@greptile review |
|
Thanks @jklein24 — @pengying @shreyav, the nuance this PR ran into is that one suffix set means two different things depending on the account's role: the transfer table applies when the account funds an incoming transfer, the quote table when it's the destination of a payout, and the docs previously claimed one table covered both. Both tables now state their role, and the two error-scenario walkthroughs were using an account as a payout destination while labelling it with transfer meanings, so those were corrected against the sandbox suffix map. If you'd rather the two sets were disambiguated at the source instead of in prose, say so and I'll leave this unlanded. |
There was a problem hiding this comment.
⚠ Partial review: quote_verify did not run (quote_verify: all_unchecked); findings below were not quote-checked against the reviewed commit.
Suggestions (1) - minor/convention findings, collapsed to keep the review focused
- P3
mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx:250- The 'Sandbox Limitations' bullet still calls suffix 005 a 'timeout scenario' after the diff rewrote the same file's 005 walkthrough to describe a completed-then-reversed payout rather than a pend-then-fail timeout.
|
🦣 Congratulations @pengying - your substantive review earned a Steppe bison! (uncommon)
|
|
Should we have a reversal state in transactions? I feel like refund and reversal have different meanings. Unless an inbound transaction can only be reversed and not refunded? WDYT @shreyav |
|
@pengying To answer the "unless an inbound transaction can only be reversed" part directly — it can be both, which is why I think your instinct is right. Inbound reaches |
|
🦣 Congratulations @shreyav - your substantive review earned a Sthenurus! (uncommon)
View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/shreyav?section=ice-age |
|
The |
|
Picking up @akanter's call to make this work on the quote side: a plan is up for review at lightsparkdev/webdev#36252 (internal). Short version — the scenario goes on a new suffix |
|
📌 Bolt Status 2026-09-25 06:30:02 UTC — ⚡ Agent |
|
@akanter On "do we expose anything about individual legs failing" — today, essentially no, and your instinct about the status field looks right to me. What exists now. A transaction has exactly one Why that's worse than it sounds for return rates. The rail itself is asymmetric: The shape your comment implies. Keep Worth noting this subsumes the All of this is a spec change well outside this docs PR — happy to write it up as a proposal with the exact schema deltas if you want it costed before anyone commits. |
|
@akanter Fair — I was vague about "the leg." Concretely, here is how it already appears:
Recommendation: add a fiatTransaction:
paymentRail: ACH # PaymentRail — also fixes the incoming gap
status: RETURNED # leg-level, its own small enum
returnedAt: 2026-09-25T...
# deliberately NOT the NACHA R-codeThree reasons I'd do it this way rather than the alternatives:
What I would not do: add One honest caveat: this is additive and safe, but it's real surface area — a new object, a new enum, and a Happy to write the full proposal with exact file-level deltas — say the word (a typed reply; reactions don't reach me here). |
|
@jklein24 @peterrojs this changed after your approvals, so it needs another look. The return-after-settlement test is now suffix |
Adds suffix 006 to the transfer pattern table: a deposit that settles and completes, then is returned about 30 seconds later. The existing table stopped at 005, so there was no documented way to test money arriving and then being taken back. Names the failure reason a returned payout now reports on the quote table's 005 row, and says which table applies to which account role, since 006 means a late inbound return for a funding account and a user cancellation for a quote destination. Co-Authored-By: akanter <akanter@users.noreply.github.com>
The transfer table was introduced by prose claiming it applied "whether you are pushing funds to it or pulling funds from it", and the api-reference page said the same. That was already wrong for 002-005 and the new 006 row made it visible: a reader following the off-ramp walkthrough would pick 006 expecting a late return and get a user cancellation. The transfer table now states the role it covers up front, the two pages that introduced it no longer claim otherwise, and the ramps off-ramp note lists the quote suffixes its own account actually uses. That page renders the quote table now, so the destination case is documented where it is needed. Co-Authored-By: akanter <akanter@users.noreply.github.com>
The ramps "Failed conversions" steps used an external account as the off-ramp quote's destination while labelling 002 and 003 with the transfer-table meanings. A reader following them picked a suffix expecting insufficient funds or a closed account and got a quote execution failure or a six-minute pending payment. Both now state the quote-destination outcome, and the section says which role the accounts play. The payouts page had the same split: its pull scenario was right, its two push scenarios were not, so those now use 004 and 005 with the outcomes a payout destination actually produces. Co-Authored-By: akanter <akanter@users.noreply.github.com>
"Late return" is a NACHA term for a return sent past the two-business-day window, which usually needs a warranty claim. Suffix 006 simulates any return arriving after the deposit settled, regardless of the deadline, so the borrowed term promised semantics the sandbox does not model. Co-Authored-By: akanter <akanter@users.noreply.github.com>
The bullet named 005 as the sole timeout, which was already incomplete for the quote suffixes and became wrong once the same page described 005 as a completed-then-returned payout. Co-Authored-By: lightspark-faraday <lightspark-faraday@users.noreply.github.com>
Both describe a payment that completes before the money goes back, so a reader scanning for that scenario finds whichever table they are on and stops. The directions are opposite: one returns a payout sent, the other claws back a deposit received. Co-Authored-By: shreyav <shreyav@users.noreply.github.com>
…ttlement Co-Authored-By: akanter <akanter@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4dc8679 to
31f11f2
Compare
Co-Authored-By: akanter <akanter@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Summary
The sandbox suffix tables had no documented way to test the case that most often surprises an integration: money that arrives, settles, looks final, and is then taken back by the originating bank.
Adds
009to the quote patterns as a source-side suffix. When a quote pulls funds from an external account ending in009, the pull settles and the transaction completes. About 30 seconds later the originating bank returns it, the credited balance is taken back, and the transaction moves toFAILED. The note explains why that ordering matters: the deposit completes first, so any logic treating a completed incoming payment as final runs before the return arrives. It also names the two webhooks you receive, in order:INCOMING_PAYMENT.COMPLETED, thenINCOMING_PAYMENT.FAILED. Embedded Wallet destinations are excluded, since sandbox does not simulate the return for them.It is a new number because every quote suffix from
002to008already means something for a payout destination.The suffix tables apply to different account roles
A single set of suffixes means two different things depending on which side of a quote the account sits on, and nothing in the docs said so.
009source suffix.002–005.The error-scenario walkthroughs had the same confusion, using an account as a quote destination while labelling it with transfer meanings:
002is a quote execution failure (and it fails on the way to settlement, not on the execute call as the page claimed),003is the ~6-minute long payment.004and005with the outcomes a payout destination produces.009.Also names
PAYOUT_RETURNEDon the quote table's005row.Terminology
009is described as "Return after settlement", not "late return". "Late return" is a NACHA term for a return sent past the two-business-day window, which generally requires a warranty claim. This suffix simulates a return arriving after the deposit settled, with no deadline modelled either way.Test plan
Prose and table changes only — no OpenAPI edits, so no rebundle.
009outcome against the sandbox implementation: the suffix is read from the quote's source account, the return fails the transaction, and a quote crediting an internal account emitsINCOMING_PAYMENT.COMPLETEDthenINCOMING_PAYMENT.FAILED.002/003quote-destination behaviour against the sandbox suffix map.mint broken-linksreports the same results with and without this change.Original PR: #1052