Skip to content

docs(sandbox): document the return-after-settlement quote source suffix - #1054

Merged
akanter merged 8 commits into
mainfrom
09-23-sandbox-late-return-suffix
Sep 30, 2026
Merged

akanter merged 8 commits into
mainfrom
09-23-sandbox-late-return-suffix

Conversation

@akanter

@akanter akanter commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

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 009 to the quote patterns as a source-side suffix. When a quote pulls funds from an external account ending in 009, 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 to FAILED. 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, then INCOMING_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 002 to 008 already 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.

  • The transfer table covers an account that funds an incoming transfer. The quote table covers one that is the destination of a payout, plus the 009 source suffix.
  • Both tables now state their role up front, and the two pages that introduced the transfer table no longer claim it applies "whether you are pushing funds to it or pulling funds from it" — which was wrong for 002–005.
  • The ramps page renders the quote table too, so the off-ramp destination case is documented where a reader needs it.

The error-scenario walkthroughs had the same confusion, using an account as a quote destination while labelling it with transfer meanings:

  • Ramps "Failed conversions" — 002 is a quote execution failure (and it fails on the way to settlement, not on the execute call as the page claimed), 003 is the ~6-minute long payment.
  • Payouts "Testing Error Scenarios" — its pull scenario was correct; its two push scenarios were not. Those now use 004 and 005 with the outcomes a payout destination produces.
  • Payouts "Sandbox Limitations" — the instant-settlement bullet now lists each delayed outcome with its table, including 009.

Also names PAYOUT_RETURNED on the quote table's 005 row.

Terminology

009 is 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.

  • Verified the 009 outcome 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 emits INCOMING_PAYMENT.COMPLETED then INCOMING_PAYMENT.FAILED.
  • Verified the 002/003 quote-destination behaviour against the sandbox suffix map.
  • mint broken-links reports the same results with and without this change.

Original PR: #1052

@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated
grid-cards-demo Ignored Ignored Preview Sep 29, 2026 10:56pm UTC
grid-flow-builder Ignored Ignored Preview Sep 29, 2026 10:56pm UTC
grid-wallet-demo Ignored Ignored Preview Sep 29, 2026 10:56pm UTC

Request Review

Copy link
Copy Markdown

This stack of pull requests is managed by Graphite. Learn more about stacking.

@ls-bolt

ls-bolt Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

@greptile review

@greptile-apps

greptile-apps Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The documentation-only PR appears safe to merge; the previous contradictory suffix guidance has been corrected and no new actionable issue remains.

Summary

This PR clarifies that sandbox account suffixes have role-dependent meanings and documents the incoming-transfer 006 return-after-settlement scenario.

  • Adds the 006 transfer pattern, including balance reversal and webhook ordering.
  • Distinguishes incoming-transfer funding patterns from payout-destination quote patterns.
  • Corrects ramps and payout walkthroughs to use the appropriate suffix behavior.
  • Names PAYOUT_RETURNED for quote-destination suffix 005.

Reviews (3) · Last reviewed commit: "docs(sandbox): name suffix 006 for what ..."

Comment thread mintlify/ramps/platform-tools/sandbox-testing.mdx Outdated
Comment thread mintlify/snippets/sandbox-transfer-patterns.mdx Outdated
Comment thread mintlify/ramps/platform-tools/sandbox-testing.mdx Outdated
@lightspark-faraday

lightspark-faraday Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Faraday review

fastpass 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

5762e7f920e8 | 0 inline + 0 in-body finding(s) (0 new) | 1 suggestion(s) | 0 refuted pre-post | route_deep: false | fail-open: 2 events (top: posting_filter_skipped)

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!

Zephyrosaurus is known mostly from skull fragments found in Montana, named for the Greek god of the west wind. It was likely a small, fast herbivore similar to its close relatives.

View your collection: https://zeus.dev.dev.sparkinfra.net/#/dinodex/akanter

Round history (2 rounds)
round reviewed (UTC) commit score inline new
1 2026-09-23 05:10 3a52ea54a02e 4/5 2 2
2 2026-09-24 21:45 5762e7f920e8 5/5 0 0

This summary supersedes the per-round summary blocks on the faraday reviews above; those are left in place as history and are not edited.

@mintlify

mintlify Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Grid 🟢 Ready View Preview Sep 29, 2026, 10:57 PM

@akanter
akanter marked this pull request as ready for review September 24, 2026 20:44
Comment thread mintlify/ramps/platform-tools/sandbox-testing.mdx
@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

⚡ Review rounds — updated in place, latest first.

Round 8 · 028f672

  • Added quote destination suffix 008 (user cancellation while processing) to the quote table and the ramps note.
  • Explained on the thread why the ramps note now uses the quote suffixes.
Earlier rounds (7)

Round 7 · 31f11f2

  • Replaced transfer suffix 006 with quote source suffix 009 for return after settlement. The transaction ends FAILED with INCOMING_PAYMENT.COMPLETED, then INCOMING_PAYMENT.FAILED
  • Rebased onto main to pick up the docs build fix, which clears the Mintlify deployment failure

Revision 6

  • No code change this round — answered @pengying's reversal-metrics point in thread and offered to file it as a follow-up.
  • Lint Code & Documentation still red on the same unchanged upstream break; re-checked and @mintlify/auth-edge is still unpublished on the npm registry.

Revision 5

  • No code change this round. Replied to @pengying's Modern Treasury / Unit comparison in thread; the naming decision is still open for the spec, and this PR stays docs-only.
  • Lint Code & Documentation is still red on the unchanged upstream break (@mintlify/auth-edge 404s on the npm registry); re-checked just now and the package is still unpublished.

Revision 4

  • Added a note distinguishing transfer 006 from quote 005, after @shreyav read the two as the same test. Both describe a payment completing before the money goes back; the directions are opposite.

Revision 3

  • Removed internal dashboard links that the bolt reply tooling had appended to several comments on this public repo. No content changed.

Revision 2

  • Renamed suffix 006 from "Late return" to "Return after settlement". "Late return" is a NACHA term for a return past the two-business-day window; this suffix models a return after settlement with no deadline involved, so the borrowed term promised semantics the sandbox does not reproduce. PR title updated to match.
  • Rewrote the payouts page's instant-settlement bullet to list every delayed outcome, per Faraday's P3.

Revision 1

  • Rewrote the ramps "Failed conversions" scenarios: those accounts are the off-ramp quote's destination, so 002 is a quote execution failure and 003 is the ~6-minute long payment. Verified both against the sandbox suffix map rather than inferring from the table.
  • Found the same split on the payouts page — its pull scenario was correct, its two push scenarios carried transfer-table meanings. Those now use 004 and 005 with the outcomes a payout destination actually produces.
  • Swept both pages for any remaining "insufficient funds" / "account closed" wording tied to a destination account; none left.

@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

⚡ Review ledger

Round 1

  1. Conflicting destination suffix behavior — "Failed conversions" contradicts the new quote-destination table → FIXED: mintlify/ramps/platform-tools/sandbox-testing.mdx scenarios 1 and 2 now state the quote-destination outcomes (002 quote execution failed, 003 long payment), verified against the sandbox suffix map. Also fixed the same contradiction on mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx, which Greptile did not flag

Round 2

  1. P3 — the "Sandbox Limitations" bullet still calls suffix 005 a "timeout scenario" after this diff rewrote the same page's 005 walkthrough as a completed-then-reversed payout → FIXED (mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx:250): correct, and the bullet was already incomplete before this PR — it named 005 as the sole delayed outcome while quote 003 (~6 min) and quote 005 also resolve late. It now lists each delayed outcome with the table it belongs to.

Round 3

  1. @pengying: should there be a REVERSED state — refund and reversal have different meanings? → ANSWERED, NOT CHANGED HERE: correct that Grid conflates them. Inbound reaches REFUNDED through one refund track whether a bank clawed the money back or it went back voluntarily, and the code that distinguishes them is deliberately internal, so an integrator cannot currently tell them apart. That is an API-surface change rather than a docs one; offered to open it as a spec issue.

Round 4

  1. @akanter: how much of the ACH state machine should be exposed — RETURNED/REVERSED, eventually DISHONORED, DISHONOR_CONTESTED, and the reversal variants? → ANSWERED, NO CODE CHANGE: checked what exists before speculating. Only an ordinary return reaches the refund path today; dishonored and contested returns are diverted for manual handling and produce no transaction state at all, and the underlying bank statuses collapse before Grid sees them. So the actionable gap is the two unattended outcomes (returned deposit vs. voluntary refund); the dishonor chain has no automated behaviour to describe yet. Left as a spec discussion, not a docs change.

Round 5

  1. @akanter: REFUNDED usefully says only where the funds are; overload REVERSED as a Grid-specific "settled then unwound" state covering both an ACH reversal and a return → ANSWERED, NO CODE CHANGE: the distinction is derivable from data Grid already has — a settled-then-unwound transaction passes through COMPLETED first, a pre-settlement failure never does — so it needs no NACHA vocabulary at the boundary and no dishonor-chain states. Still a spec change rather than a docs one; left for the spec discussion.

Round 6

  1. @shreyav: does ACH pull use the quotes API? We already have a complete-then-return case — quote 005 → ANSWERED + DOCS IMPROVED: no, ACH pull is its own endpoint and the two suffix sets are matched independently. Quote 005 returns a payout you sent; transfer 006 claws back a deposit you received — opposite directions, so neither covers the other. But the question is itself evidence the two read as interchangeable, so the transfer snippet now names quote 005 as a near-miss and states which direction each moves money.

Round 7

  1. @pengying: Modern Treasury and Unit both use returned; neither has refunded — maybe returned == refunded, but we should use the industry's canonical language → ANSWERED, NO CODE CHANGE: agreed on canonical language, and the comparison supports splitting rather than renaming — both vocabularies carry returned and reversed as separate states, so returned is not a synonym for refunded. Noted two constraints for whoever takes the spec change: TransactionStatus is shared across both directions, and outbound already collapses REFUNDED into FAILED, so the value only surfaces on incoming. Also flagged that REFUNDED and REJECTED both already claim "and the payment was refunded".

Round 8

  1. @pengying: it's probably also useful to track metrics on the number of reversals a platform receives → AGREED, SEPARATE FOLLOW-UP: verified it's a real gap — the failure reasons that identify a return are deliberately excluded from the platform failure-rate metric (right call; a bank clawback isn't a service failure), and the NACHA return code is a mutation input and ops-only query, never a readable transaction field. So returns appear in neither that rate nor any counter of their own. Naming the state is the prerequisite for the metric, since a returned deposit and a voluntary refund are currently indistinguishable in the data. Offered to file it; not folded into this docs PR.

Round 9

  1. @akanter: do we expose anything about individual legs failing, and should ACH statuses share the Grid transaction's status field? → ANSWERED, NO CODE CHANGE: verified against the spec — one status + one failureReason per transaction, and the only per-leg detail is onChainTransaction (hash + network, success-only, no leg status) on the account source/destination. No fiat-rail equivalent. Also found a blocking asymmetry for return rates: paymentRail exists on OutgoingTransaction but nothing on IncomingTransaction or its sources reports one, so an inbound return can't even be attributed to ACH from the public surface. Proposed keeping the transaction-level verdict where it is and hanging rail state off the leg alongside onChainTransaction; offered to write it up with exact schema deltas.

Round 10

  1. Use industry-canonical status names (returned/reversed) over refunded → ADDRESSED: rail-level RETURNED/REVERSED status proposed in feat(transactions): add railDetails to transaction source and destination #1091. On this PR, the 009 return ends FAILED
  2. Track reversal counts per platform → ADDRESSED: countable from the rail-level status in feat(transactions): add railDetails to transaction source and destination #1091

Round 11

  1. Suffix definitions changed in the ramps note → NOT APPLICABLE: the account is a quote destination, so the quote table is what sandbox applies; the old note quoted the transfer-in table
  2. What about 008? → FIXED: added to sandbox-quote-patterns.mdx and the ramps note

@ls-bolt

ls-bolt Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

@greptile review

@jklein24 jklein24 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I know @pengying was thinking through some nuances with the test case suffixes so looping in him and @shreyav here too.

@ls-bolt ls-bolt Bot changed the title docs(sandbox): document the late-return account suffix docs(sandbox): document the return-after-settlement account suffix Sep 24, 2026
@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

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.

@lightspark-faraday lightspark-faraday Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠ 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.

Comment thread mintlify/snippets/sandbox-transfer-patterns.mdx Outdated
@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

🦣 Congratulations @pengying - your substantive review earned a Steppe bison! (uncommon)

This widespread bison appears repeatedly in Ice Age cave paintings.

Copy link
Copy Markdown
Contributor

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

@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

@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 REFUNDED through one refund track regardless of cause: a bank-initiated reversal is one trigger for that track, a voluntary send-back is another, and the resulting transaction looks identical either way. The signal that distinguishes them is the NACHA return code, which is deliberately internal and not on the API. So today an integrator genuinely cannot tell a clawback from a refund, and a REVERSED state (or a cause field on the existing refund object) would fix that — it's a spec change rather than a docs one, so I've kept it out of this PR. Say the word and I'll open it as a separate spec issue with this detail. @shreyav

@ls-bolt

ls-bolt Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

🦣 Congratulations @shreyav - your substantive review earned a Sthenurus! (uncommon)

A deep skull and robust single-toed feet distinguish this extinct short-faced kangaroo.

View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/shreyav?section=ice-age

@ls-bolt

ls-bolt Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

The Lint Code & Documentation failure is not from this change — the workflow's Install mint step runs npm i -g mint, and that install is currently broken upstream: mint depends on @mintlify/cli, which pulls @mintlify/auth-edge@0.0.51, and that package now 404s on the npm registry. The unrelated dp/card-pin-management branch failed identically a minute before this run, and this same branch passed twice earlier tonight on the same tooling. The actual lint (make lint → redocly + spectral) passes locally with 0 errors and no bundle drift; the mint binary is never invoked by it, so the step is dead weight in this job. Nothing to fix on this PR — it needs either an upstream republish or pinning/removing that step.

@ls-bolt

ls-bolt Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

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 009, since 006 is already taken on the quote/destination side, and this PR's 009 row will follow once the behaviour lands. Two things worth flagging that the investigation turned up: the suffix on a fund-in quote sits on the source account, and the current sandbox resolver only inspects the destination; and a fund-in quote has no transfer-in operation, so the return has to be expressed in send-operation terms rather than reusing the existing return task. Holding this docs PR until that behaviour is settled, so the 006 row doesn't imply coverage the quote path lacks.

@ls-bolt

ls-bolt Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

📌 Bolt Status

2026-09-25 06:30:02 UTC — ⚡ Agent shimmering-witness-5(#5) started
2026-09-25 16:15:05 UTC — ⚡ Agent shimmering-witness-6(#6) started

@ls-bolt

ls-bolt Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

@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 status and one failureReason, both describing the whole Grid transaction. The only per-leg detail anywhere is onChainTransaction (hash + network) hanging off AccountTransactionSource/AccountTransactionDestination and RealtimeFundingTransactionSource — and it's success-only, a settled crypto transfer, with no leg status or leg failure. There is no fiat-rail equivalent, so a returned ACH leg is currently invisible except as the whole transaction flipping to REFUNDED.

Why that's worse than it sounds for return rates. The rail itself is asymmetric: paymentRail is on OutgoingTransaction, but nothing on IncomingTransaction or its sources reports one. So for an inbound return an integrator can't even tell it was ACH from the API, let alone that the ACH leg specifically is what came back. Any "ACH return rate" computed from the public surface today would be guessing at both the numerator and the denominator.

The shape your comment implies. Keep status/failureReason as the transaction-level verdict, and put rail state where the rail already lives — on the source/destination leg, next to onChainTransaction. Something like a fiatTransaction/achTransaction sibling carrying the leg's own status and, for a return, its own reason. That gives you three things the single field can't: a Grid transaction that failed for a non-ACH reason stays distinguishable from one whose ACH leg was returned; return rates become computable per rail rather than inferred from a mixed status; and onChainTransaction already sets the precedent, so it isn't a new concept.

Worth noting this subsumes the REVERSED-vs-REFUNDED thread rather than replacing it: even with leg-level detail, the transaction-level state still has to say something when money that settled goes back, so that naming call still stands on its own. And per @pengying's point above, the leg-level reason is what makes a reversal metric countable instead of excluded.

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.

@ls-bolt

ls-bolt Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

@akanter Fair — I was vague about "the leg." Concretely, here is how it already appears:

IncomingTransaction and OutgoingTransaction each carry a source (TransactionSourceOneOf: ACCOUNT / UMA_ADDRESS / REALTIME_FUNDING), and Transaction carries a destination (TransactionDestinationOneOf: ACCOUNT / UMA_ADDRESS). Both discriminate on sourceType/destinationType. AccountTransactionSource and AccountTransactionDestination are the variants that name a bank or wallet via accountId, and each already hangs an onChainTransaction off itself for the crypto case — that object is the existing precedent for "detail about how this side actually moved."

Recommendation: add a fiatTransaction sibling to onChainTransaction on those two account variants. The external bank account is the side the ACH belongs to, and it's source on an inbound pull and destination on an outbound payout, so the same field placement covers both directions without a new concept. Shape:

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-code

Three reasons I'd do it this way rather than the alternatives:

  • It fixes the attribution gap as a side effect. paymentRail exists on OutgoingTransaction but has no incoming counterpart, so today an inbound return can't be attributed to ACH at all. Putting the rail on the leg gives both directions the same answer from one field, instead of adding a second top-level paymentRail to IncomingTransaction and leaving the two spellings to drift.
  • Return rate becomes a real query. "Returned ACH legs ÷ ACH legs" reads off one object. A transaction-level status can't express the denominator, because it never says which rail was involved.
  • It keeps the R-code internal, which was a constraint from the original brief. status: RETURNED is the partner-visible fact; the NACHA reason stays where it is.

What I would not do: add ACH_RETURNED to TransactionStatus. That enum is shared by both directions, REFUNDED and REJECTED already both claim "and the payment was refunded," and rail-specific values in a transaction-level field is exactly the mixing you flagged.

One honest caveat: this is additive and safe, but it's real surface area — a new object, a new enum, and a PaymentRail now appearing in two places. If we only ever want the metric and not the partner-facing detail, counting internally is much cheaper than a spec change, and worth deciding first.

Happy to write the full proposal with exact file-level deltas — say the word (a typed reply; reactions don't reach me here).

@ls-bolt ls-bolt Bot changed the title docs(sandbox): document the return-after-settlement account suffix docs(sandbox): document the return-after-settlement quote source suffix Sep 29, 2026
@ls-bolt

ls-bolt Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

@jklein24 @peterrojs this changed after your approvals, so it needs another look. The return-after-settlement test is now suffix 009 on the account a quote pulls from. I dropped the 006 row on the transfer table, because transfer-in is deprecated. The transaction ends FAILED (webhooks INCOMING_PAYMENT.COMPLETED, then INCOMING_PAYMENT.FAILED), not REFUNDED. The two quote snippets are the only files that changed this round, plus one bullet on the payouts sandbox page.

akanter and others added 7 commits September 29, 2026 21:01
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>
Comment thread mintlify/ramps/platform-tools/sandbox-testing.mdx Outdated
Comment thread mintlify/snippets/sandbox-quote-patterns.mdx
Co-Authored-By: akanter <akanter@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@akanter
akanter merged commit 8505f06 into main Sep 30, 2026
8 checks passed
@akanter
akanter deleted the 09-23-sandbox-late-return-suffix branch September 30, 2026 01:01

This branch was successfully deployed

1 active deployment
staging - mintlify — 028f6724 Deployed Sep 29, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants