docs: make /quotes the single transfer path, deprecate /transfer-in and /transfer-out - #856
docs: make /quotes the single transfer path, deprecate /transfer-in and /transfer-out#856shreyav wants to merge 6 commits into
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 Edit this comment to update them. They will appear in their respective SDK's changelogs. ⏳ grid-typescript studio⏳ grid-openapi studio⏳ grid-ruby studio⏳ grid-go studio⏳ grid-kotlin studio⏳ grid-python studio⏳ grid-php studio⏳ grid-cli studio⏳ These are partial results; builds are still running. This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
|
5fa9d79 to
5e4868d
Compare
Greptile 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.
```suggestion
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.
```
---
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.
```suggestion
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](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
3f6d3b6
Compare
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.