Skip to content

feat: add Bitcoin L1 deposit-address instruction + refundAddress to quotes - #736

Open
peterrojs wants to merge 5 commits into
mainfrom
07-23-grid-api-btc-l1-quote-execute-fields
Open

feat: add Bitcoin L1 deposit-address instruction + refundAddress to quotes#736
peterrojs wants to merge 5 commits into
mainfrom
07-23-grid-api-btc-l1-quote-execute-fields

Conversation

@peterrojs

@peterrojs peterrojs commented Jul 23, 2026

Copy link
Copy Markdown

Summary

Adds the public API surface for a Bitcoin L1 crypto on/off-ramp on the quote/execute flow. All changes are additive and optional, so no version bump.

Changes

  • New PaymentBitcoinDepositAddressInfo payment instruction — a member of the PaymentInstructions.accountOrWalletInfo oneOf with a new BITCOIN_L1 discriminator value. Carries the on-chain deposit address and an optional network (fixed to BITCOIN). Modeled exactly like its cousins: it inherits BasePaymentAccountInfo and narrows the shared accountType to its discriminator value, with BITCOIN_L1 added to the shared PaymentAccountType enum.
  • Optional refundAddress on RealtimeFundingQuoteSource — where to return an inbound on-chain deposit that can't be routed to complete the payment. This is the case where the sender can't reliably be inferred from the deposit, so the caller supplies it.
  • Optional refundAddress on AccountDestination — intended for a crypto payout destination (not fiat accounts, where a refund address has no meaning). Under discussion — likely to be dropped: for a crypto payout the refund lands on a Grid-controlled address we already know, and any inbound on-chain leg is already covered by the source-side field. See this thread.
  • BITCOIN is already a valid cryptoNetwork for RealtimeFundingQuoteSource (currency=BTC, cryptoNetwork=BITCOIN); no change needed.
  • CI: bounded the oasdiff breaking-changes PR comment so it fits GitHub's comment-size limit, with the full report in the job summary and an artifact.

Notes

  • Unblocks the server-side Bitcoin L1 quote/execute ramp, which currently uses stopgaps for these types.
  • PaymentAccountType is referenced only via BasePaymentAccountInfo, so the new BITCOIN_L1 value surfaces only on payment-instruction members.
  • This PR carries genuinely breaking response changes and gets the breaking-change label: oasdiff reports 76 errors / 1742 warnings. The errors are response-property-one-of-added (the new oneOf member appearing in quote and transaction responses); the warnings are the new BITCOIN_L1 enum value propagating to the accountType of every member that inherits BasePaymentAccountInfo. All are additive — no property or enum-value removals — so this is the expected shape for a new payment-instruction member, gated by API-reviewer approval per the repo's workflow design.
  • SDKs (grid-typescript, grid-kotlin) are regenerated by the Stainless GitHub Action from the bundled spec + config; no SDK code is hand-edited in this PR.

Test plan

  • npm run lint:openapi (redocly bundle + redocly lint + spectral lint): passes with 0 errors.
  • oasdiff breaking (v1.16.0, base=main): additive findings only (new oneOf member + new shared-enum value); no removals.
  • After the main merge, re-ran make build and confirmed the committed openapi.yaml / mintlify/openapi.yaml are byte-identical to a fresh bundle (no drift).

Original PR: #732

Add a Bitcoin L1 on/off-ramp surface to the quote/execute flow:

- New self-contained PaymentBitcoinDepositAddressInfo member in the
  PaymentInstructions oneOf (accountType=BITCOIN_L1 discriminator value,
  on-chain address, optional network fixed to BITCOIN).
- Optional refundAddress on RealtimeFundingQuoteSource (on-ramp crypto
  funding) and AccountDestination (off-ramp crypto payout).

The member is self-contained rather than composing BasePaymentAccountInfo,
so it does not extend the shared PaymentAccountType enum; the discriminator
mapping is the source of truth for the BITCOIN_L1 value.

All additions are optional / additive, so no version bump. SDKs are
regenerated by the Stainless CI action from the bundled spec + config.

Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
@ls-bolt ls-bolt Bot added bolt breaking-change Introduces a breaking change to the OpenAPI spec labels Jul 23, 2026
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
grid-wallet-demo Ready Ready Preview, Comment Jul 29, 2026 12:24am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Jul 29, 2026 12:24am

Request Review

@peterrojs
peterrojs marked this pull request as ready for review July 23, 2026 16:39
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

⚠️ Breaking OpenAPI changes detected

oasdiff reports 37 error / 1739 warning changes to openapi.yaml.
This PR will need approval from an API reviewer before merge.

Errors (37)

  • GET /agents/approvals — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/approvals — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/actions — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/actions — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/actions/{actionId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/actions/{actionId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/internal-accounts — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/fundingPaymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/me/quotes — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • GET /agents/me/quotes/{quoteId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/me/quotes/{quoteId}/execute — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/me/quotes/{quoteId}/execute — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/transactions — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /agents/me/transactions/{transactionId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/me/transfer-in — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /agents/me/transfer-in — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /agents/me/transfer-out — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /agents/me/transfer-out — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /agents/{agentId}/actions/{actionId}/approve — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/{agentId}/actions/{actionId}/approve — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/{agentId}/actions/{actionId}/reject — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /agents/{agentId}/actions/{actionId}/reject — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the transaction/allOf[#/components/schemas/TransactionOneOf]/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /customers/internal-accounts — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/fundingPaymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • PATCH /internal-accounts/{id} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the fundingPaymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /platform/internal-accounts — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/fundingPaymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /quotes — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /quotes — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 202 [response-property-one-of-added].
  • GET /quotes/{quoteId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /quotes/{quoteId}/authorize — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /quotes/{quoteId}/execute — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /sandbox/internal-accounts/{accountId}/fund — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the fundingPaymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /sandbox/send — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /transactions — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the data/items/oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • GET /transactions/{transactionId} — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /transactions/{transactionId}/cancel — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /transactions/{transactionId}/confirm — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 200 [response-property-one-of-added].
  • POST /transfer-in — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].
  • POST /transfer-out — added #/components/schemas/PaymentBitcoinDepositAddressInfo to the oneOf[subschema #2: Outgoing Transaction]/allOf[subschema #2]/paymentInstructions/items/accountOrWalletInfo response property oneOf list for the response status 201 [response-property-one-of-added].

Warnings (1739)

Show sample
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #10: HKD Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #11: IDR Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #12: MYR Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #13: PHP Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #14: SGD Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #15: THB Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #16: VND Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #17: AED Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #18: KES Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #19: MWK Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #1: USD Bank Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #20: RWF Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #21: TZS Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #22: UGX Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #23: XOF Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #24: ZAR Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #25: ZMW Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #26: BWP Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #27: XAF Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #28: BDT Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #29: ARS Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #2: BRL Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #30: COP Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #31: EGP Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new BITCOIN_L1 enum value to the data/items/quote/allOf[#/components/schemas/Quote]/paymentInstructions/items/accountOrWalletInfo/oneOf[subschema #32: GHS Account]/allOf[#/components/schemas/BasePaymentAccountInfo]/accountType response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • …and 1714 more warnings.

Detected by oasdiff. Full report: job summary or the oasdiff-report artifact.

akanter commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

cli

chore(internal): regenerate SDK with no functional changes

go

feat(api): add Bitcoin L1 variant to payment instructions

kotlin

feat(api): add BitcoinL1 variant to PaymentInstructions AccountOrWalletInfo

openapi

feat(api): add Bitcoin deposit address info, refundAddress to quote source/destination

php

feat(api): add BitcoinL1DepositAddress variant to payment instructions

python

feat(api): add Bitcoin L1 deposit address to payment instructions

ruby

feat(api): add BitcoinL1 variant to PaymentInstructions AccountOrWalletInfo

typescript

feat(api): add BITCOIN_L1 payment instruction type to quotes

Edit this comment to update them. They will appear in their respective SDK's changelogs.

grid-typescript studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ✅

npm install https://pkg.stainless.com/s/grid-typescript/b551f79da75e5aa476320354b337792db546cb43/dist.tar.gz
grid-openapi studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️

grid-ruby studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-go studio · code · diff

Your SDK build had at least one new note diagnostic, which is a regression from the base state.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@7c63fbb11bd4bea59ffa2f0a330bc99caa7bf342
New diagnostics (3 note)
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
grid-kotlin studio · code · diff

Your SDK build had at least one new note diagnostic, which is a regression from the base state.
generate ⚠️build ✅lint ✅test ❗

New diagnostics (2 note)
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
grid-python studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/b542eb8205fa2b02fe03927edb4e401b4c886e76/grid-0.0.1-py3-none-any.whl
grid-php studio · code · diff

Your SDK build had at least one new note diagnostic, which is a regression from the base state.
generate ✅lint ✅test ✅

New diagnostics (2 note)
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
💡 Schema/EnumHasOneMember: Confirm intentional use of `enum` with single member.
grid-cli studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ❗lint ❗test ❗


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-07-29 00:28:57 UTC

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the public API types for Bitcoin L1 quote and execution flows. The main changes are:

  • A Bitcoin L1 deposit-address payment instruction.
  • A BITCOIN_L1 payment-instruction discriminator mapping.
  • Optional refund addresses for crypto funding sources and account destinations.
  • Updated generated OpenAPI bundles for the API reference.

Confidence Score: 5/5

The API additions look mergeable after aligning the Bitcoin discriminator with the shared account-type contract.

  • The source schemas and generated bundles are consistent.
  • The refund-address fields are additive and optional.
  • Some generated clients may not represent BITCOIN_L1 while it remains absent from the shared account-type enum.

openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml and the shared PaymentAccountType schema

Important Files Changed

Filename Overview
openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml Adds the Bitcoin L1 instruction but defines its discriminator outside the shared payment account-type enum.
openapi/components/schemas/common/PaymentInstructions.yaml Adds the Bitcoin L1 schema to the instruction union and discriminator mapping.
openapi/components/schemas/quotes/RealtimeFundingQuoteSource.yaml Adds an optional refund address for on-chain real-time funding.
openapi/components/schemas/quotes/AccountDestination.yaml Adds an optional refund address for crypto payout destinations.
openapi.yaml Updates the generated root bundle with the new public schema fields.
mintlify/openapi.yaml Updates the Mintlify bundle to match the source OpenAPI changes.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml:7-12
**Discriminator Bypasses Shared Enum**

This defines `BITCOIN_L1` only in a local enum while the shared `PaymentAccountType` used by the other payment-info models does not include it. SDK generators or consumers that expose `accountType` through that shared enum cannot represent a valid Bitcoin L1 instruction, causing compile-time rejection or failed response deserialization.

Reviews (1): Last reviewed commit: "feat(quotes): add Bitcoin L1 deposit-add..." | Re-trigger Greptile

Comment thread openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml Outdated
@ls-bolt

ls-bolt Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Revision — align Bitcoin L1 with the shared account-type contract

Addressed Greptile's inline finding (Discriminator Bypasses Shared Enum) in 847f94c0:

  • Added BITCOIN_L1 to the shared PaymentAccountType enum.
  • Refactored PaymentBitcoinDepositAddressInfo to allOf: [BasePaymentAccountInfo, { narrow accountType → BITCOIN_L1, address, network }] — the same pattern every other accountOrWalletInfo member follows. It was previously the sole member defining a standalone local accountType with a value absent from the shared enum.
  • Regenerated the OpenAPI bundles (openapi.yaml, mintlify/openapi.yaml) via make build; make lint-openapi passes (0 errors).

Net effect: generated SDK clients that surface accountType via the shared enum can now represent a Bitcoin L1 instruction. PaymentAccountType is referenced only through BasePaymentAccountInfo, so the new value is scoped to payment-instruction members only.


🤖 resonant-reactor(#1) | Feedback

@ls-bolt

ls-bolt Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Correction — reverted the Greptile "shared enum" change

My previous revision comment is superseded. I applied Greptile's Discriminator Bypasses Shared Enum suggestion in 847f94c0, but it broke the Detect breaking changes check, so I reverted it. The branch is back at 699ff8c6 (the state you published), which is green.

Why it broke: moving BITCOIN_L1 into the shared PaymentAccountType enum makes oasdiff flag a new enum value on every account subschema inheriting BasePaymentAccountInfo (~50 × 2 response paths). The 100+-finding breaking-changes comment then overflowed the OS arg limit in the sticky-comment step (Argument list too long).

Why the original design is right: accountOrWalletInfo is a discriminated oneOf, so each variant carries its own accountType literal — SDK generators represent BITCOIN_L1 from the member's own enum without it being in the shared type. Adding it to the shared enum would also falsely imply a USD/EUR/etc. account could return accountType: BITCOIN_L1. The self-contained local enum is the more precise contract and keeps the breaking-diff minimal.

Full reasoning is in the inline thread. No code change vs. what you published — CI should return to green.


🤖 resonant-reactor(#1) | Feedback

Comment thread openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml Outdated
@ls-bolt

ls-bolt Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

📌 Bolt Status

2026-07-24 20:29:53 UTC — ⚡ Agent resonant-reactor-2(#2) started
2026-07-28 19:51:09 UTC — ⚡ Agent resonant-reactor-3(#3) started
2026-07-28 23:24:16 UTC — ⚡ Agent resonant-reactor-4(#4) started


Feedback

Add BITCOIN_L1 to the shared PaymentAccountType enum and have
PaymentBitcoinDepositAddressInfo inherit BasePaymentAccountInfo, narrowing
accountType to BITCOIN_L1 as every other payment-instruction member does.

Co-Authored-By: akanter <akanter@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ls-bolt

ls-bolt Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Revision — Bitcoin L1 now modeled like its cousins (per @akanter)

Implemented @akanter's call in 1f5f79ee:

  • BITCOIN_L1 added to the shared PaymentAccountType enum.
  • PaymentBitcoinDepositAddressInfo inherits BasePaymentAccountInfo and narrows accountType to BITCOIN_L1 — the same shape as every other accountOrWalletInfo member. Its standalone local enum is gone.
  • Bundles regenerated (openapi.yaml, mintlify/openapi.yaml); npm run lint:openapi passes with 0 errors.
  • Kept the value as BITCOIN_L1 (SCREAMING_SNAKE) to match the rest of the enum and the existing discriminator mapping.

This supersedes my earlier "Correction" comment: I had reverted this change when it broke CI, laid out the trade-off, and @akanter confirmed he wants cousin-consistency — so it's back in.

Expected CI red: Detect breaking changes

Worth being explicit since this is a known, understood failure rather than a surprise. The oasdiff detection passes (--fail-on ERR; every finding is WARN). The comment step is what fails: adding a value to the shared enum makes oasdiff report a new enum value on the accountType of all ~50 members inheriting BasePaymentAccountInfo, across the quote and transaction response paths, and marocchino/sticky-pull-request-comment then hits Argument list too long passing that 100+-line body as an env var.

One-line fix in .github/workflows/openapi-breaking-changes.yml — use the action's file input instead of inlining the body:

      - name: Upsert PR comment (breaking)
        if: steps.oasdiff.outputs.has_breaking == 'true'
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          header: oasdiff-breaking-changes
          path: breaking.md    # instead of: message: ${{ steps.body.outputs.body }}

This bot can't push workflow files (no GitHub Actions workflows permission), so that needs a human commit. Reply here if you'd like me to prepare the patch some other way.


🤖 resonant-reactor(#3) | Feedback

peterrojs and others added 2 commits July 29, 2026 00:24
Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
@ls-bolt

ls-bolt Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Detect breaking changes is green — nice, your version is better than the patch I handed you. Splitting severities off --format singleline (rather than capping one undifferentiated blob), plus the job summary and the oasdiff-report artifact, means nothing is actually lost when the comment is trimmed. The posted comment is now ~31 KB, well under the cap.

One correction I owe you and @akanter: I said earlier that the oasdiff detection step "passes because all findings are WARN." That was wrong, and your workflow comment names exactly why — --format markdown prefixes every finding with :warning: regardless of severity, and I read that as the severity. The real split is 76 errors / 1742 warnings. The detection step only looked green because it captured oasdiff's exit code under set +e.

It doesn't change the plan, but it does change the framing: the errors are response-property-one-of-added (the new oneOf member showing up in quote and transaction responses), and the warnings are the BITCOIN_L1 enum value propagating to the accountType of every member inheriting BasePaymentAccountInfo. Everything is additive — no property or enum-value removals — so this is the expected shape for a new payment-instruction member, which is what the breaking-change label plus API-reviewer approval is there to gate. I've corrected the PR description accordingly.

Nothing outstanding from me: the schema is modeled the way @akanter asked, and Lint, Docs Build, breaking-changes, and mergeability are all green.


🤖 resonant-reactor-4(#4) | Feedback

@akanter akanter 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'm guessing @shreyav or @jklein24 should take a look here 🙏

@akanter
akanter requested review from pengying and shreyav July 29, 2026 00:45
@ls-bolt

ls-bolt Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Thanks! No action needed to loop them in — both are already requested reviewers on this PR (jklein24 and shreyav, alongside AaryamanBhute and pengying), and your mention pinged them directly.

Current state for whoever picks it up:

  • CI is green on fa6f692a. Peter merged main in; I re-ran make build against the merged tree and the committed openapi.yaml / mintlify/openapi.yaml came back byte-identical to a fresh bundle, so the merge didn't leave the generated spec out of sync with its sources.
  • The decision worth sanity-checking is the modeling you called: BITCOIN_L1 now lives in the shared PaymentAccountType, and PaymentBitcoinDepositAddressInfo inherits BasePaymentAccountInfo and narrows to it, matching the cousins.
  • That's what drives the breaking-change label: oasdiff reports 76 errors / 1742 warnings. The errors are response-property-one-of-added (the new oneOf member surfacing in quote and transaction responses); the warnings are the new enum value propagating to accountType on every member inheriting the base. All additive — no property or enum-value removals.

One process note, since it may block the merge: there's no formal APPROVED review on the PR yet. Your "lgtm" landed as a COMMENTED review, which doesn't register as an approval — so if the breaking-change path requires one, someone will need to submit an actual Approve.


🤖 resonant-reactor-4(#4) | Feedback

Comment on lines +24 to +29
refundAddress:
type: string
description: >-
Optional address the funds are returned to if the payout cannot be
completed. Applies to crypto off-ramp destinations.
example: bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq

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.

The PR description is a little confusing - it says this is for offramps? For offramp refunds (e.g., USDB -> BTC offramp fails, so we want to refund) shouldn't that automatically just go back to the source, and would we ever not know that value?

I think it makes sense to me that this is not the case for onramps - if the flow fails I'm guessing you should be able to specify where your BTC should go back to if it doesn't work.

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.

The confusing description is on me — I rewrote that section and mislabeled it. Fixing it now. And I think you're right on the substance; here's what I found digging into the server side.

Why the wording reads wrong. AccountDestination covers every account destination, including fiat bank accounts, where a refund address is meaningless. Calling it "off-ramp" made it sound like it applies to the fiat-payout case. It only has any meaning when the destination account is a crypto one (BTC out).

On whether it's needed at all — I think not, for the reason you gave. For a BTC-out payout, Grid is the party funding the upstream swap, so a failed payout refunds to a Grid-controlled address Grid already knows; the caller has nothing to contribute. And in the case where there genuinely is an inbound on-chain leg whose sender we can't infer (customer deposits BTC/stables to a generated address), that's already covered by RealtimeFundingQuoteSource.refundAddress — the source side, which is exactly the asymmetry you described.

Where the field probably came from. The upstream Orchestra API requires refundAddress on both POST /v1/orchestration/quote and POST /v1/orchestration/submit — in sparkcore/sparkcore/grid/flashnet/orchestra_client.py it's a required kwarg on both and always written into the body, for every order regardless of direction. It's an easy step from "the upstream call always needs one" to "we need one per direction," but those aren't the same thing: the upstream needing a value doesn't mean the API caller has to supply it.

Nothing consumes it yet. That flashnet package currently has no non-test importers, and there's no BITCOIN_L1 handling in sparkcore at all — consistent with the integration still being on stopgaps. So dropping the field costs nothing today.

The cost is asymmetric, which is what tips it for me: removing it now is free, and adding it back later is additive and non-breaking. Shipping it and removing it later is a breaking change. Given it's unused and the semantics are dubious, the cheap and safe move is to drop AccountDestination.refundAddress and keep the source-side one.

@peterrojs — you wrote the Orchestra client, so you'd know the flow better than I can infer it: is there an off-ramp shape where the refund target isn't derivable from the source, e.g. the customer funds the swap directly rather than out of a Grid-held balance? If not, say the word and I'll drop the field and rebundle. I didn't want to remove something you added deliberately for work you're mid-way through wiring up.


🤖 resonant-reactor-4(#4) | Feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bolt breaking-change Introduces a breaking change to the OpenAPI spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants