Uh oh!
There was an error while loading. Please reload this page.
docs: make /quotes the single transfer path, deprecate /transfer-in and /transfer-out - #856
Conversation
Preview deployment for your docs. Learn more about Mintlify Previews.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
✱ Stainless preview builds for gridThis PR will update the cli go kotlin openapi php python ruby typescript
|
|
5fa9d79 to
5e4868dCompareGreptile SummaryThis PR makes quotes the documented path for same- and cross-currency transfers, deprecates the platform transfer endpoints, and removes the unimplemented agent transfer contract. It also updates generated OpenAPI/Stainless artifacts and consolidates payment guides, but the rewritten execution walkthrough omits the required SCA continuation.
Confidence Score: 4/5The PR should not merge until the payment walkthrough handles the SCA branch that can leave an executed quote awaiting authorization. The rewritten guide tells integrations that quote execution always begins transaction processing, while the changed flow reaches an existing endpoint contract that can instead require a follow-up authorization before any transfer starts. Files Needing Attention: mintlify/payouts-and-b2b/payment-flow/send-payment.mdx
|
| Filename | Overview |
|---|---|
| openapi/paths/quotes/quotes.yaml | Expands quote creation documentation and examples to cover same-currency transfers. |
| openapi/paths/transfers/transfer_in.yaml | Deprecates transfer-in and documents its request and response migration to quotes. |
| openapi/paths/transfers/transfer_out.yaml | Deprecates transfer-out and documents its request and response migration to quotes. |
| openapi/components/schemas/agents/AgentAction.yaml | Removes transfer-specific action details as part of the acknowledged agent API break. |
| openapi/components/schemas/agents/AgentActionType.yaml | Removes the acknowledged transfer-in and transfer-out action variants. |
| openapi/components/schemas/agents/AgentPermission.yaml | Removes the acknowledged agent transfer permission. |
| mintlify/payouts-and-b2b/payment-flow/send-payment.mdx | Consolidates payment walkthroughs around quotes but incorrectly presents execute as always advancing to processing, omitting SCA. |
| mintlify/platform-overview/core-concepts/quote-system.mdx | Reframes quotes as the unified transfer mechanism and retains separate SCA guidance. |
| .stainless/stainless.yml | Removes SDK resource mappings corresponding to the removed agent transfer contract. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Create quote] --> B{Immediately execute?}
B -->|No| C[Review quote]
C --> D[Execute quote]
B -->|Yes| E{SCA required?}
D --> E
E -->|No| F[Transaction processing]
E -->|Yes| G[PENDING_AUTHORIZATION]
G --> H[Authorize quote challenge]
H --> F
F --> I[Track transaction]
Prompt To Fix All With AI
### Issue 1
mintlify/payouts-and-b2b/payment-flow/send-payment.mdx:182-183
**SCA blocks transaction processing**
When SCA applies, `POST /quotes/{quoteId}/execute` returns `PENDING_AUTHORIZATION` without initiating the transfer, but this step says the quote always advances to `PROCESSING`, causing integrations to monitor a transaction that remains blocked instead of authorizing the quote.
```suggestionWhen SCA is not required, the quote comes back with `status` `PROCESSING` and the same`transactionId` it carried at creation. When SCA is required, it instead returns with`PENDING_AUTHORIZATION`; authorize the quote's `scaChallenge` with`POST /quotes/{quoteId}/authorize` to release the transfer.```---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "docs: trim the send-payment intro and st..." | Re-trigger Greptile
| The quote comes back with `status` `PROCESSING` and the same `transactionId` it carried at | ||
| creation. |
There was a problem hiding this comment.
SCA blocks transaction processing
When SCA applies, POST /quotes/{quoteId}/execute returns PENDING_AUTHORIZATION without initiating the transfer, but this step says the quote always advances to PROCESSING, causing integrations to monitor a transaction that remains blocked instead of authorizing the quote.
| The quote comes back with `status``PROCESSING` and the same `transactionId` it carried at | |
| creation. | |
| When SCA is not required, the quote comes back with `status``PROCESSING` and the same | |
| `transactionId` it carried at creation. When SCA is required, it instead returns with | |
| `PENDING_AUTHORIZATION`; authorize the quote's `scaChallenge` with | |
| `POST /quotes/{quoteId}/authorize` to release the transfer. |
Knowledge Base Used:Payments, quotes, and transfers API
Prompt To Fix With AI
This is a comment left during a code review.
Path: mintlify/payouts-and-b2b/payment-flow/send-payment.mdx
Line: 182-183
Comment:
**SCA blocks transaction processing**
When SCA applies, `POST /quotes/{quoteId}/execute` returns `PENDING_AUTHORIZATION` without initiating the transfer, but this step says the quote always advances to `PROCESSING`, causing integrations to monitor a transaction that remains blocked instead of authorizing the quote.
```suggestionWhen SCA is not required, the quote comes back with `status` `PROCESSING` and the same`transactionId` it carried at creation. When SCA is required, it instead returns with`PENDING_AUTHORIZATION`; authorize the quote's `scaChallenge` with`POST /quotes/{quoteId}/authorize` to release the transfer.```**Knowledge Base Used:**[Payments, quotes, and transfers API](https://app.greptile.com/lightspark/-/custom-context/knowledge-base/lightsparkdev/grid-api/-/docs/payments-and-quotes-api.md)---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.…858) > [!NOTE] > **Bottom of a three-PR stack**, based on `main` and mergeable on its own. #856 and #857 sit on top of it. Deliberately isolated so the sparkcore fix that depends on this enum isn't blocked behind the docs work above. ## The bug `WebhookType` describes itself as dot-notation that *"lets consumers route purely on type without inspecting `data.status`"*. The incoming family breaks that promise. `_get_incoming_webhook_type` (`sparkcore/grid/webhooks/webhook_handler.py:142`) collapses four states onto one event: ```python case (CREATED | PENDING | PROCESSING | SENT): return WebhookType.INCOMING_PAYMENT_DOT_PENDING ``` The outgoing twin 24 lines above maps `PROCESSING` to its own event. So a pull into an internal account fires `INCOMING_PAYMENT.PENDING` **twice**, and the second payload carries `"status": "PROCESSING"` inside an envelope typed `PENDING` — exactly the inspect-`data.status` case the contract says consumers should not need. Likely why it went unnoticed: the receive-operation path (ordinary deposits) does not appear to reach `PROCESSING`/`SENT`, so the collapse was harmless. `GK.GRID_INCOMING_TRANSACTION_REFACTOR` then routed send operations — which *do* pass through those states — into this function without extending it. ## This PR Contract only. Adds `INCOMING_PAYMENT.PROCESSING` to `WebhookType` and to the `IncomingPaymentWebhook` `type` enum, mirroring the outgoing family. **sparkcore does not emit the event yet.** Its `WebhookType` is generated from this spec, so this has to land before the emission fix can reference the new member. ## Follow-up in webdev, after this merges 1. Regenerate the grid-api Python SDK so `WebhookType.INCOMING_PAYMENT_DOT_PROCESSING` exists. 2. Split `PROCESSING | SENT` out of the `PENDING` case in `_get_incoming_webhook_type`. `SENT` belongs with `PROCESSING`, not `PENDING` — `gen_convert_send_op_to_incoming_transaction` already maps `SENT` onto status `PROCESSING` (`transaction.py:891`), so that is what makes the envelope agree with its payload. Note for whoever picks that up: it changes behavior for existing integrators, who currently receive two `PENDING` events and will start receiving `PENDING` then `PROCESSING`. A smaller instance of the same collapse is out of scope here: `_get_incoming_webhook_type` also folds `EXPIRED` into `INCOMING_PAYMENT.FAILED`. ## Validation | Check | Result | |---|---| | `make lint` | exit 0 — 0 errors | | `make build` + bundle sync | `openapi.yaml` / `mintlify/openapi.yaml` in sync | | oasdiff 1.16.0 vs `main` | no breaking changes — adding an enum value widens the contract | --- _Generated by [Claude Code](https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv)_ Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Same-currency transfers now route through the quote endpoint on the backend, so the docs should point integrators there. API reference: - Mark POST /transfer-in and POST /transfer-out `deprecated: true` and document the field-by-field migration to POST /quotes in each description. - Invert the note on POST /quotes that sent same-currency traffic to the transfer endpoints, and add a same-currency request example. - Update the Same-Currency/Cross-Currency tag descriptions to match. Guides: replace every transfer-in/transfer-out example with the equivalent POST /quotes call using `immediatelyExecute: true`, and update the surrounding prose and response payloads (a quote carries `transactionId` rather than being a transaction itself). Also mark the endpoints deprecated in the repo's agent-facing reference docs so tooling stops recommending them, and add a changelog entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
The first pass repeated the same "use /quotes instead" note on four pages, so a reader working through core concepts and then a payment guide hit it three times. Keep one canonical note on the quote system page, which is where the "when do I need a quote?" question is actually answered. Drop it from the two task guides — someone following those just needs the correct call — and from the transaction lifecycle page. Also collapse the lifecycle page's Same-Currency Transfers section. It existed because same-currency used to be a genuinely different API path; now that it is an ordinary quote, the two request blocks just re-showed the lifecycle walked through immediately above them. Replaced with a short paragraph and a link to the worked example. The API reference deprecation badges and the changelog entry carry the announcement for anyone arriving from the old endpoints. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
Two structural cleanups now that quotes are the single path. send-payment.mdx had two parallel ~140-line walkthroughs, one for same-currency and one for cross-currency, that both called POST /quotes. The split dated from when same-currency was a genuinely different API. Merged them into one "Send a payment" flow whose real fork is one-step (`immediatelyExecute`) versus two-step (review the rate, then execute) — which is the choice that actually exists, and is not the same question as whether the currencies differ. That also resolved two "Transaction statuses" tables which described the same statuses differently; they are now one reconciled table. The two-card Overview grid framing "two payment methods" is gone. 511 lines down to 369. Removed /agents/me/transfer-in and /agents/me/transfer-out outright rather than deprecating them: there is no handler for either in sparkcore, so nothing can be using them, and agent transfers will go through quotes when they are built. Removing the endpoints orphaned the rest of the transfer-shaped agent model, so that goes too: the TRANSFER_OUT and TRANSFER_IN action types (nothing could produce them), AgentTransferDetails and AgentAction.transferDetails, and the CREATE_TRANSFERS permission, which gated only these two endpoints — CREATE_QUOTES and EXECUTE_QUOTES cover the quote-based path. Stainless config and the agent guides follow. oasdiff reports 6 errors and 7 warnings for the removals, so this PR picks up the breaking-change label and needs API-reviewer sign-off. The workflow does not fail on findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
…out stub Review feedback: Pick between one-step and two-step execution on whether your UX shows the customer rates or fees, not on whether the currencies match. A same-currency transfer has no exchange rate but can still carry fees worth surfacing, so the two-step flow is a reasonable choice there too. Restore the original "Monitor completion" wording on the last step. Scope the page description to what the page covers. It is not limited to internal-to-external, so say any combination of internal and external accounts in either direction. UMA destinations use the same endpoint but this page carries no UMA example, so link out to the global-p2p guide rather than implying coverage. Drop the sandbox "Transferring out funds" section. Once it stopped naming /transfer-out it was one sentence pointing at the transfer-in patterns, so fold that into the patterns note, which now says the suffixes govern the external account in either direction. The "## Transfer in" heading stays so the existing #transfer-in link keeps resolving. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
…ome patterns The sandbox pages framed their content around transfer-in and transfer-out, which stopped being API concepts. On the API reference sandbox page, the "Transfer in" section opened by re-explaining how internal accounts get funded in production. Internal Accounts already covers that — the list endpoints, the funding payment instructions, and how to display them to a customer — so link there instead. What is genuinely sandbox-only is the fund endpoint, which is now the body of a "Funding an internal account" section, plus a line on using a quote to exercise the pull path. Moved the suffix table up under "Adding external accounts", next to the sentence that already tells you the last 3 digits pick the scenario. The suffix is a property of the account, not of a direction of travel. The payouts sandbox page had the same split: two POST /quotes blocks differing only in which side held the external account, with the suffix table between them. Now one "Testing Transfer Outcomes" section with the table first and a single example, noting you swap the two accountId values to test the other direction. Repointed the one inbound #transfer-in link. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
Review feedback. Shorten the page description to "Learn how to send payments between accounts", drop "any combination of" and "in either direction" from the intro sentence, and cut the "like bank returns" example from the pointer to the transaction lifecycle guide. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
18888f9 to
3f6d3b6CompareThere was a problem hiding this comment.
@k15z heads up we're deprecating the transfer api in favor of unifying everything into quotes
| @@ -74,46 +74,14 @@ Most transactions on Grid are completed in seconds. | |||
| ## Same-Currency Transfers | |||
There was a problem hiding this comment.
do we need to break out same currency transfers or can we delete the section?
🦣 Congratulations @pengying - your substantive review earned a Neolicaphrium! (common)
View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/pengying?section=ice-age |
| ## Same-Currency Transfers | ||
| Use the `/transfer-out` endpoint when sending funds in the same currency (no exchange rate needed). This is the simplest and fastest option for domestic transfers. | ||
| Use the `/quotes` endpoint when sending funds in the same currency (no exchange rate needed). Quotes cover same-currency and cross-currency transfers alike, so one integration handles both. |
There was a problem hiding this comment.
i don't know if we still need the distinction for same currency now
…e section Review feedback. The execute step claimed the quote always comes back PROCESSING. Where SCA applies it does not: the endpoint's own 200 description says the transfer is not initiated, the quote returns PENDING_AUTHORIZATION with an scaChallenge, and re-calling execute returns 409. An integration following the old text would have polled a transaction that never moves. Added the branch and the authorize call. Deleted the Same-Currency Transfers section from the transaction lifecycle page. It said same-currency follows the lifecycle above unchanged, which is the argument for not having a section. Its one concrete detail, the pullable external account requirement, is covered on the account model and quote system pages among others. Nothing links to the removed anchor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
The warning restated what quote-system.mdx already covers under Strong Customer Authentication, down to the 409 on re-calling execute. Kept the correction it carried — execute does not always come back PROCESSING — as one clause with a link, rather than a second copy of the mechanics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
Review feedback from @pengying: the same-currency distinction no longer earns its own section now that both go through POST /quotes. Deleting the snippet outright would have lost content, though. cross-currency.mdx covered none of immediatelyExecute, paymentRail or remittanceInformation, and remittanceInformation appears nowhere else in global-p2p — so a reader there would have lost the 80-character reference that rides along on ACH Addenda, FedNow/RTP, and wire OBI. Merged instead. cross-currency.mdx becomes accounts.mdx, covering any payment to an internal or external account with or without conversion. Its fork is one-step versus two-step execution, matching send-payment.mdx. Folded in the three fields above, and noted on the review step that immediatelyExecute skips it. Split "Funding with cryptocurrencies" into crypto-funding.mdx. It is about how a quote is funded rather than where it is sent, and it was the largest thing in the file. The global-p2p page dropped from three methods to two: to an account, or to an UMA address. Nothing linked to the retired anchors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TxsyZEDjQDt97rR3kd2kxv
Uh oh!
There was an error while loading. Please reload this page.
…857) > [!NOTE] > **Top of a three-PR stack:** #858 (spec) → #856 (transfer deprecation) → this. Base is `claude/transfer-api-deprecation-docs-6ycamq`, so the diff here is only the 3 files below. Each merge retargets this automatically. ## The gap Nothing in the docs said whether a given transfer produces an `INCOMING` or an `OUTGOING` transaction. Worse, the Transaction Lifecycle page contained **zero occurrences of the word "incoming"** — it described only the outgoing flow, despite `INCOMING_PAYMENT.*` webhooks existing and being referenced from six other pages. ## The rule The type is keyed on the **destination**, regardless of source: | Destination | `type` | Webhook family | |---|---|---| | Internal account | `INCOMING` | `INCOMING_PAYMENT.<STATUS>` | | External account | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` | | UMA address | `OUTGOING` | `OUTGOING_PAYMENT.<STATUS>` | Consequences worth spelling out, and now spelled out: - A pull from an external account into an internal account is `INCOMING`, even though the platform initiated it. - A transfer between two internal accounts is `INCOMING`. - A deposit that lands by paying an internal account's payment instructions is `INCOMING`, as is a payment received at a customer's UMA address. This mirrors the dispatch in `gen_convert_to_transaction` (`sparkcore/grid/objects/transaction.py:159`), which routes `EntGridReceiveOperation` to incoming unconditionally and branches a send operation on `gen_send_op_destination_is_internal_account`. That helper carries the same truth table in its docstring at `transaction.py:738`. The branch is gated on `GK.GRID_INCOMING_TRANSACTION_REFACTOR`, which is rolled out, so the table describes current behavior for all platforms. ## Changes - **`transaction-lifecycle.mdx`** — new **Incoming or outgoing** section at the top, ahead of the flow sections, since the type decides which lifecycle and webhook family apply. - **`transaction-lifecycle.mdx`** — split the webhook event table into outgoing and incoming families. The incoming list was missing entirely. Its `INCOMING_PAYMENT.PROCESSING` row corresponds to the enum value added in #858. - **`terminology.mdx`** — said the type was "from the platform's perspective", which does not tell a reader how to predict it. Now states the rule. - **`list-transactions.mdx`** — the *Filter by transaction type* section had the reader choosing `type=INCOMING|OUTGOING` with no way to know which their payout is. Now states the rule and links to the table. ## Two things this PR previously got wrong Recorded because both were corrected in place and a reviewer reading only the head would not see them: 1. An early revision claimed incoming transactions have no `PROCESSING` **state**. False — they do; both incoming converters map `display_status` through, and `gen_convert_send_op_to_incoming_transaction` maps `SENT` onto `PROCESSING` explicitly (`transaction.py:891`). Only the *webhook event* is missing. 2. The next revision then explained that missing event as an intentional design difference, which would have enshrined a bug. It is a sparkcore bug; #858 adds the enum and describes the emission fix. ## Validation - `make lint` exits 0 — 663 problems, unchanged from baseline (all pre-existing) - Docs-only: no files under `openapi/`, so the bundle, oasdiff, and SDK generation are untouched by this PR - The `#incoming-or-outgoing` anchor is linked from `list-transactions.mdx`; the heading carries no punctuation, so the slug is unambiguous --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The SCA surface moved after this guide was written; bring it current: - SCA login complete now requires `endUserIpAddress` and returns `sessionExpiresAt` (#780); the session-scope guidance now tells integrators to prompt re-login ahead of it. - Quote authorize documents `409 SCA_SESSION_REQUIRED` and `423 ACCOUNT_LOCKED` (#761); both join the error tables, and the snippet notes authorizing requires an active login session. - A challenge left to expire unsatisfied now fails the transaction with `failureReason: SCA_NOT_COMPLETED` and no funds moved (#762). - Trusted external accounts refuse `DELETE` with `409 BENEFICIARY_TRUSTED`; untrust first (#770). - The challenge lives on the quote, not the transaction — webhook consumers route via the transaction's `quoteId` (#701). - `POST /transfer-out` is deprecated in favor of `POST /quotes` with `immediatelyExecute: true` (#856); the transfer-out tab now says so.
The SCA surface moved after this guide was written; bring it current: - SCA login complete now requires `endUserIpAddress` and returns `sessionExpiresAt` (#780); the session-scope guidance now tells integrators to prompt re-login ahead of it. - Quote authorize documents `409 SCA_SESSION_REQUIRED` and `423 ACCOUNT_LOCKED` (#761); both join the error tables, and the snippet notes authorizing requires an active login session. - A challenge left to expire unsatisfied now fails the transaction with `failureReason: SCA_NOT_COMPLETED` and no funds moved (#762). - Trusted external accounts refuse `DELETE` with `409 BENEFICIARY_TRUSTED`; untrust first (#770). - The challenge lives on the quote, not the transaction — webhook consumers route via the transaction's `quoteId` (#701). - `POST /transfer-out` is deprecated in favor of `POST /quotes` with `immediatelyExecute: true` (#856); the transfer-out tab now says so.
Same-currency transfers now route through the quote endpoint on the backend. This makes
POST /quotesthe single documented path for moving money, deprecates the platform transfer endpoints, and removes the unbuilt agent ones.Note
This PR will pick up the
breaking-changelabel — see Breaking changes below. That is expected and comes from removing the agent transfer endpoints.Why
In
sparkcore, both platform transfer handlers now build aQuoteRequestand delegate togen_run_create_quote:sparkcore/grid/api_handlers/transfer_out.py:317(_gen_transfer_out_via_quotes)sparkcore/grid/api_handlers/transfer_in.py:327(_gen_transfer_in_via_quotes)Both map
amountontolockedCurrencySide: SENDING/lockedCurrencyAmountand setimmediatelyExecute: true. That mapping is what the migration notes here document.Two things this deliberately does not claim about the platform endpoints:
GRID_TRANSFER_IN_VIA_QUOTES/GRID_TRANSFER_OUT_VIA_QUOTES), and they still return aTransactionwith unchanged request/response shapes. Those are deprecated, not removed.API reference
deprecated: trueonPOST /transfer-inandPOST /transfer-out, each with a field-by-field migration toPOST /quotes. This renders a badge in Mintlify and propagates to the generated SDKs via Stainless — no.stainless/stainless.ymlchange needed for these, and removing the resources there would break the SDKs.POST /quotes, which previously read "If you are transferring funds in the same currency, use the/transfer-inor/transfer-outendpoints instead."sameCurrencyAccountToAccountrequest example, and updated the Same-Currency / Cross-Currency tag descriptions.Removed: agent transfer APIs
POST /agents/me/transfer-inandPOST /agents/me/transfer-outare removed outright rather than deprecated. There is no handler for either in sparkcore, so nothing can be using them, and agent transfers will go through quotes when they are built.Removing the endpoints orphaned the rest of the transfer-shaped agent model, so that goes too:
AgentActionType.TRANSFER_OUT/TRANSFER_INAgentTransferDetails+AgentAction.transferDetailsAgentPermission.CREATE_TRANSFERSCREATE_QUOTES/EXECUTE_QUOTEScover the quote path.stainless/stainless.ymland the agent guides (policies-and-permissions.mdx,approvals-and-audit.mdx) follow.Worth a reviewer's eye: removing the enum values and the permission goes a step beyond removing the two endpoints. It is the coherent end state if agent transfers become quotes, but it is the most opinionated part of this PR and the easiest piece to scale back.
Guides
Every transfer-in/transfer-out example is now the equivalent
POST /quotescall withimmediatelyExecute: true. The non-obvious part: a quote response is not a transaction, so response payloads and the "track status" steps readtransactionIdoff the quote.send-payment.mdx: 511 lines to 369. It had two parallel ~140-line walkthroughs, same-currency and cross-currency, that both calledPOST /quotes— a split dating from when same-currency was a genuinely different API. They are now one Send a payment flow whose real fork is one-step (immediatelyExecute) versus two-step (review the rate, then execute). That is the choice that actually exists, and it is not the same question as whether the currencies differ.That merge also resolved two
Transaction statusestables that described the same statuses differently — now one reconciled table. The two-card Overview grid framing "two payment methods" is gone.One deprecation notice, not four. A first pass repeated the same "use
/quotesinstead" note on four pages, so a reader going through core concepts and then a payment guide hit it three times. It now appears once, on the quote system page, where the "when do I need a quote?" question is answered. The API reference badges and the changelog carry the announcement for anyone arriving from the old endpoints.The transaction lifecycle page's Same-Currency Transfers section shrank from ~50 lines to a paragraph, for the same reason: its two request blocks re-showed the lifecycle walked through immediately above them.
Validation
make lint(lint.yml)make build+ bundle sync (openapi-build.yml)openapi.yaml/mintlify/openapi.yamlin sync, rebuild is deterministicopenapi-breaking-changes.yml)#same-currency-transferslinks to#send-a-paymentmint broken-linksrequires a TTY so it could not be run here; it is not a CI gate.Breaking changes
oasdiff reports 6 errors, all from the agent removals:
POST /agents/me/transfer-inandPOST /agents/me/transfer-out— path removed without deprecationCREATE_TRANSFERSenum value removed fromPOST /agentsandPATCH /agents/{agentId}/policyTRANSFER_IN/TRANSFER_OUTenum values removed from theagent-actionwebhookPlus 7 warnings for
transferDetailsdisappearing from agent action responses.The workflow does not fail the job on findings — it posts a sticky comment, adds the
breaking-changelabel, and notes that an API reviewer must approve. Since none of these endpoints or fields have a backend implementation, the breakage is theoretical, but the label is correct and the gate should be honored.Follow-up: grid-visualizer code generator
components/grid-visualizer/src/lib/code-generator.tsstill generates/transfer-out(L190) and/transfer-in(L215) sample code —canUseTransferOut/canUseTransferInshort-circuit ahead of the quote path at L107-111.This PR leaves that code alone and only marks the two endpoints Deprecated in
components/grid-visualizer/CLAUDE.md, so the doc stays accurate to what the tool emits today. Routing those branches through the quote path is a behavior change to the visualizer with its own testing surface, and belongs in a separate PR.