Skip to content

feat: add Bitcoin L1 deposit-address payment instruction - #736

Merged
peterrojs merged 8 commits into
mainfrom
07-23-grid-api-btc-l1-quote-execute-fields
Jul 30, 2026
Merged

feat: add Bitcoin L1 deposit-address payment instruction#736
peterrojs merged 8 commits into
mainfrom
07-23-grid-api-btc-l1-quote-execute-fields

Conversation

@peterrojs

@peterrojs peterrojs commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the public API surface for a Bitcoin L1 crypto on/off-ramp on the quote/execute flow: a new BITCOIN_L1 payment instruction. 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.
  • 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.

Deferred: refundAddress

Earlier revisions added an optional refundAddress to both AccountDestination and RealtimeFundingQuoteSource. Both are now removed and deferred to a follow-up:

  • AccountDestination (thread) — a failed crypto payout returns funds to a Grid-controlled address that's already known, so the caller has nothing to supply. The field would also have surfaced on fiat account destinations, where a refund address is meaningless.
  • RealtimeFundingQuoteSource (thread) — a raw address bypasses external-account whitelisting and approval (ExternalAccount.status, plus the trust/untrust flow). Referencing an external account is the better model, but ExternalAccountType has no Bitcoin L1 type yet, so that needs its own change.

Deferring costs nothing today — nothing consumes these fields yet — and re-adding either is additive/non-breaking, whereas shipping and then removing would be breaking.

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.
  • Carries genuinely breaking response changes and gets the breaking-change label. 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 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.
  • Confirmed no refundAddress remains in openapi/, openapi.yaml, or mintlify/openapi.yaml.
  • After the main merge, re-ran make build and confirmed the committed bundles are byte-identical to a fresh build (no drift).
  • ⚠️ Bolt pushes do not trigger this repo's pull_request OpenAPI workflows, so the checks on the latest commits have not re-run — see the note in the comments.

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-flow-builder Ready Ready Preview Jul 30, 2026 10:01pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
grid-wallet-demo Ignored Ignored Preview Jul 30, 2026 10:01pm

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 / 1776 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 (1776)

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 1751 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
⚠️ grid-openapi studio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️

grid-ruby studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅build ✅lint ✅test ✅

⚠️ grid-go studio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@956da95c5c562318d0a3804179d9a4f7a22ceee4
⚠️ grid-kotlin studio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
generate ⚠️build ✅lint ✅test ❗

⚠️ grid-python studio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/6dd57bd9db7b508dc76814d2066d102534e173bb/grid-0.0.1-py3-none-any.whl
grid-typescript studio · conflict

Your SDK build had at least one note diagnostic.

grid-php studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅lint ✅test ✅

⚠️ grid-cli studio · code

Your SDK build had a failure in the test CI job, which is a regression from the base state.
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-30 23:10:51 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
2026-07-30 21:02:00 UTC — ⚡ Agent resonant-reactor-5(#5) started
2026-07-30 23:06:15 UTC — ⚡ Agent resonant-reactor-6(#6) 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 thread openapi/components/schemas/quotes/AccountDestination.yaml Outdated
Comment thread openapi/components/schemas/quotes/RealtimeFundingQuoteSource.yaml Outdated
A failed crypto payout returns funds to a Grid-controlled address that is
already known, so the caller has nothing to supply. An inbound on-chain leg
whose sender cannot be inferred is covered by the funding source's
refundAddress. Keeping the field only on the source side also avoids
offering it on fiat account destinations, where a refund address is
meaningless.

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

ls-bolt Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Revision — dropped AccountDestination.refundAddress (780a4976)

Per @akanter's and @jklein24's threads, the destination-side refund field is removed:

  • openapi/components/schemas/quotes/AccountDestination.yaml — field deleted; both bundles regenerated. Deletion-only diff (3 files, −14 lines). make lint-openapi clean locally.
  • refundAddress now exists only on RealtimeFundingQuoteSource — the one case where the refund target genuinely can't be inferred.
  • Rationale in this thread: a failed crypto payout refunds to a Grid-controlled address we already know, and AccountDestination also covers fiat accounts where a refund address is meaningless.

⚠️ The green checkmark on this commit is misleading — please don't read it as CI passing.

My push did not trigger the OpenAPI workflows. The only check runs attached to 780a4976 are Graphite / mergeability_check and Vercel Preview Comments; the newest OpenAPI Breaking Changes / Lint / Documentation Build runs are still against the previous head fa6f692a. The overall rollup therefore reports SUCCESS while the checks that actually matter here never ran on this diff.

Cause is the GitHub App push restriction, not the workflow config — the pull_request path filters (openapi.yaml, openapi/**) do match this commit, and gh workflow run is also blocked for me (HTTP 403: Resource not accessible by integration).

To get real signal, someone with push access needs to nudge the branch — an empty commit (git commit --allow-empty -m "ci: retrigger") or any trivial push will do it. I'd expect it to pass (the change is a pure deletion and lints clean locally), and the breaking-changes report should actually shrink, but that's a prediction, not a verified result — worth confirming before merge.

@jklein24 — the source-side field is still open on your other thread; I've laid out options there rather than guessing, since I can't see the Slack thread you referenced.


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

A raw address bypasses external-account whitelisting, and there is no
Bitcoin L1 external-account type to reference yet. Ship the BITCOIN_L1
payment instruction on its own and model the refund target once the
external-account direction is settled.

Co-Authored-By: jklein24 <jklein24@users.noreply.github.com>
Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ls-bolt ls-bolt Bot changed the title feat: add Bitcoin L1 deposit-address instruction + refundAddress to quotes feat: add Bitcoin L1 deposit-address payment instruction Jul 30, 2026
Resolves the conflicts in the generated openapi.yaml / mintlify/openapi.yaml
bundles by rebuilding them from the merged source rather than hand-merging.
The conflict was additive on both sides: main added USDT to a payment-instruction
assetType enum at the same offset where this branch appends the new BITCOIN_L1
schema.

Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
@ls-bolt

ls-bolt Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Revision: main merged, conflicts resolved

  • Merged main (fe6b43d). mergeable has gone CONFLICTINGMERGEABLE.
  • The conflicts were only in the two generated bundles: main added USDT to a payment-instruction assetType enum at the same offset where this branch appends PaymentBitcoinDepositAddressInfo. Both sides additive at one spot. Resolved by rebuilding from the merged source rather than hand-merging openapi.yaml / mintlify/openapi.yaml — verified a fresh make build is byte-identical to what's committed, and that the two bundles match each other.
  • refundAddress: no change needed from me — @peterrojs had already pushed the source-side removal in 6f1c00d per the thread decision. Confirmed no refundAddress remains in openapi/, openapi.yaml, or mintlify/openapi.yaml.
  • Net diff vs main is exactly the BITCOIN_L1 instruction plus the CI workflow change.
  • Resolved both refundAddress threads — the code they anchored to no longer exists.

Note — the ⚠️ line in the test plan is now stale. The pull_request OpenAPI workflows did run on this push: Detect breaking changes, both Build OpenAPI Documentation jobs, and both Lint Code & Documentation jobs are green, along with Mintlify Deployment and preview. Worth dropping that line from the description.


🤖 relayed-relay(#1) | Feedback

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.

Thanks for fixing this :-)

@peterrojs
peterrojs merged commit 81b7513 into main Jul 30, 2026
12 checks passed
@peterrojs
peterrojs deleted the 07-23-grid-api-btc-l1-quote-execute-fields branch July 30, 2026 23:06
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.

3 participants