modify /quotes and /quote/{quoteId}/execute for Embedded Wallet transfers#356
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✱ Stainless preview buildsThis PR will update the kotlin openapi python typescript Edit this comment to update them. They will appear in their respective SDK's changelogs. ✅ grid-openapi studio · code · diff
✅ grid-python studio · code · diff
✅ grid-typescript studio · code · diff
✅ grid-kotlin studio · code · diff
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
1889c01 to
ace9654
Compare
4159566 to
0634725
Compare
ace9654 to
fdaaf7d
Compare
0634725 to
83a5b13
Compare
83a5b13 to
444f5fe
Compare
fdaaf7d to
3f57f28
Compare
Greptile SummaryThis PR extends
Confidence Score: 4/5Safe to merge after fixing the contradictory restriction sentence in the execute endpoint description. One P1 documentation contradiction exists: the execute endpoint description says 'can only be used for internal account or direct-pull sources' immediately before granting Embedded Wallet access, which will mislead integrators. All other changes (schema structure, discriminator, stainless transforms) are correct and consistent with existing patterns. openapi/paths/quotes/quotes_{quoteId}_execute.yaml — contradictory restriction sentence at lines 7–8.
|
| Filename | Overview |
|---|---|
| openapi/paths/quotes/quotes_{quoteId}_execute.yaml | Adds optional Grid-Wallet-Signature header and Embedded Wallet description; opening restriction paragraph now contradicts the Embedded Wallet paragraph (P1). |
| openapi/components/schemas/common/PaymentEmbeddedWalletInfo.yaml | New schema for Embedded Wallet payment instructions; structure and discriminator are correct, but payloadToSign encoding format is undocumented (P2). |
| openapi/components/schemas/common/PaymentInstructions.yaml | Adds PaymentEmbeddedWalletInfo to the oneOf list and discriminator mapping; both entries are consistent and correct. |
| openapi/components/schemas/quotes/QuoteRequest.yaml | Adds guardrail documentation that immediatelyExecute: true is unsupported for Embedded Wallet sources; clear and accurate. |
| .stainless/stainless.yml | Adds PaymentEmbeddedWalletInfo.allOf[0] to the remove transforms, consistent with all other PaymentXxx schema variants. |
Sequence Diagram
sequenceDiagram
participant Client
participant GridAPI
Client->>GridAPI: POST /quotes (source: EMBEDDED_WALLET)
GridAPI-->>Client: 200 Quote with payloadToSign
Note over Client: Sign payloadToSign with session private key
Client->>GridAPI: POST /quotes/{quoteId}/execute + Grid-Wallet-Signature header
alt Signature valid
GridAPI-->>Client: 200 Quote executed
else Signature missing or invalid
GridAPI-->>Client: 401 Unauthorized
end
Prompt To Fix All With AI
This is a comment left during a code review.
Path: openapi/paths/quotes/quotes_{quoteId}_execute.yaml
Line: 7-8
Comment:
**Contradictory restriction in endpoint description**
The description opens with "This endpoint can only be used for quotes with a `source` which is either an internal account, or has direct pull functionality (e.g. ACH pull with an external account)." — but the very next paragraph grants Embedded Wallet sources access too. Any developer who reads only the first restrictive sentence will incorrectly conclude that Embedded Wallet–sourced quotes cannot use this endpoint.
The first limiting statement should be updated to include Embedded Wallet as a valid source type, or restructured so it doesn't contradict the paragraph that follows.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: openapi/components/schemas/common/PaymentEmbeddedWalletInfo.yaml
Line: 14-22
Comment:
**`payloadToSign` encoding format not documented**
The example value (`Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==`) is clearly base64, but the field description only says "Payload that must be signed" without stating whether the value is already base64-encoded or is raw bytes. In contrast, the `Grid-Wallet-Signature` header explicitly says "base64-encoded." Without clarifying this, integrators may sign the base64 string directly instead of signing the decoded bytes (or vice versa), silently producing an invalid signature. Adding `format: byte` and a one-sentence note on encoding would remove the ambiguity.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: sign Embedded Wallet transfers wit..." | Re-trigger Greptile
| This endpoint can only be used for quotes with a `source` which is either an internal account, | ||
| or has direct pull functionality (e.g. ACH pull with an external account). |
There was a problem hiding this comment.
Contradictory restriction in endpoint description
The description opens with "This endpoint can only be used for quotes with a source which is either an internal account, or has direct pull functionality (e.g. ACH pull with an external account)." — but the very next paragraph grants Embedded Wallet sources access too. Any developer who reads only the first restrictive sentence will incorrectly conclude that Embedded Wallet–sourced quotes cannot use this endpoint.
The first limiting statement should be updated to include Embedded Wallet as a valid source type, or restructured so it doesn't contradict the paragraph that follows.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/paths/quotes/quotes_{quoteId}_execute.yaml
Line: 7-8
Comment:
**Contradictory restriction in endpoint description**
The description opens with "This endpoint can only be used for quotes with a `source` which is either an internal account, or has direct pull functionality (e.g. ACH pull with an external account)." — but the very next paragraph grants Embedded Wallet sources access too. Any developer who reads only the first restrictive sentence will incorrectly conclude that Embedded Wallet–sourced quotes cannot use this endpoint.
The first limiting statement should be updated to include Embedded Wallet as a valid source type, or restructured so it doesn't contradict the paragraph that follows.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
embedded wallets are internal accounts
| payloadToSign: | ||
| type: string | ||
| description: >- | ||
| Payload that must be signed with the session private key of a | ||
| verified authentication credential on the source Embedded Wallet. | ||
| The resulting signature is passed as the `Grid-Wallet-Signature` | ||
| header on `POST /quotes/{quoteId}/execute` to authorize the | ||
| outbound transfer from the wallet. | ||
| example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg== |
There was a problem hiding this comment.
payloadToSign encoding format not documented
The example value (Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==) is clearly base64, but the field description only says "Payload that must be signed" without stating whether the value is already base64-encoded or is raw bytes. In contrast, the Grid-Wallet-Signature header explicitly says "base64-encoded." Without clarifying this, integrators may sign the base64 string directly instead of signing the decoded bytes (or vice versa), silently producing an invalid signature. Adding format: byte and a one-sentence note on encoding would remove the ambiguity.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/common/PaymentEmbeddedWalletInfo.yaml
Line: 14-22
Comment:
**`payloadToSign` encoding format not documented**
The example value (`Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==`) is clearly base64, but the field description only says "Payload that must be signed" without stating whether the value is already base64-encoded or is raw bytes. In contrast, the `Grid-Wallet-Signature` header explicitly says "base64-encoded." Without clarifying this, integrators may sign the base64 string directly instead of signing the decoded bytes (or vice versa), silently producing an invalid signature. Adding `format: byte` and a one-sentence note on encoding would remove the ambiguity.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
valid to add some additional description. Can you add a semi real example? Will it be a escaped json strong? Do they need to unescape it before signing?
There was a problem hiding this comment.
I can't determine the actual payload format from the spec alone — that depends on the backend implementation. But here's what needs to be answered and documented:
Key questions for the description:
- Is
payloadToSigna base64-encoded opaque blob, or base64-encoded JSON? - Do integrators sign the base64 string as-is, or decode it to raw bytes first, then sign?
The answer to (2) is the most critical thing to document. Based on common signing patterns, the typical expectation is: decode the base64 value to raw bytes, then sign those bytes. If that's correct, here's a suggested update:
| payloadToSign: | |
| type: string | |
| description: >- | |
| Payload that must be signed with the session private key of a | |
| verified authentication credential on the source Embedded Wallet. | |
| The resulting signature is passed as the `Grid-Wallet-Signature` | |
| header on `POST /quotes/{quoteId}/execute` to authorize the | |
| outbound transfer from the wallet. | |
| example: Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg== | |
| payloadToSign: | |
| type: string | |
| format: byte | |
| description: >- | |
| Base64-encoded payload to sign. Decode this value to raw bytes, then | |
| sign the bytes with the session private key of a verified | |
| authentication credential on the source Embedded Wallet. Base64-encode | |
| the resulting signature and pass it as the `Grid-Wallet-Signature` | |
| header on `POST /quotes/{quoteId}/execute`. | |
| example: eyJxdW90ZUlkIjoiMDFKWlhZWi0xMjM0NTY3ODkwIiwidGltZXN0YW1wIjoiMjAyNS0wMS0xNVQxMDozMDowMFoifQ== |
The example above decodes to {"quoteId":"01JZXYZ-1234567890","timestamp":"2025-01-15T10:30:00Z"} — a realistic-looking JSON blob. If the actual payload has a different structure (e.g., just a nonce, or includes an amount), replace this with whatever fields are actually present.
Once you confirm the signing contract (sign raw bytes vs. sign the base64 string), that one sentence is the most important thing to add.
Tip: You can customize Greptile's behavior for this repo with .greptile/rules and .greptile/config.
444f5fe to
a8ee2e2
Compare
a8ee2e2 to
abb4c24
Compare
abb4c24 to
edbb528
Compare
edbb528 to
9eb8049
Compare
3f57f28 to
11d622e
Compare

Endpoint changes
POST /quotes/{quoteId}/execute— accepts optionalGrid-Wallet-Signatureheader. Required when the quote's source is an Embedded Wallet; value is the signature over the quote'spaymentInstructions[].accountOrWalletInfo.payloadToSignwith the session private key of a verified credential on the source wallet.POST /quotes(response only) — when source is an Embedded Wallet,paymentInstructions[].accountOrWalletInfosurfaces a newEMBEDDED_WALLETvariant carryingpayloadToSign.Request / response
Quote response (Embedded Wallet source)
Execute
Resources
PaymentEmbeddedWalletInfo— new payment-instruction variant:{ accountType: EMBEDDED_WALLET, payloadToSign }PaymentAccountType— enum extended withEMBEDDED_WALLETPaymentInstructions.accountOrWalletInfo—oneOfgains the new variant and its discriminator mappingHierarchy
Guardrail
QuoteRequest.immediatelyExecute: trueis documented as unsupported for Embedded Wallet sources — thepayloadToSignisn't available at create-time, so the two-call flow (create quote → sign → execute) is mandatory.