feat(cards): bind one funding source per card - #934
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
✱ Stainless preview builds for gridThis PR will update the cli kotlin php ruby Edit this comment to update them. They will appear in their respective SDK's changelogs. ⏳ grid-typescript studio⏳ grid-openapi studio⏳ grid-ruby studio⏳ grid-kotlin studio⏳ grid-go studio⏳ grid-python studio⏳ grid-php studio⏳ grid-cli studio⏳ These are partial results; builds are still running. This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
|
@greptile review |
|
| - customerId | ||
| - form | ||
| - fundingSources | ||
| - fundingSource |
There was a problem hiding this comment.
This required-field rename from fundingSources to fundingSource changes the request from an array to a string, making it a breaking contract change. The repository requires breaking changes to bump info.version and use a matching new servers.url, but both remain 2025-10-13. Existing clients using that versioned endpoint can therefore receive an incompatible contract without a new API version to migrate to.
Context Used: CLAUDE.md (source)
Knowledge Base Used: Grid API contract
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/cards/CardCreateRequest.yaml
Line: 5
Comment:
**API version is unchanged**
This required-field rename from `fundingSources` to `fundingSource` changes the request from an array to a string, making it a breaking contract change. The repository requires breaking changes to bump `info.version` and use a matching new `servers.url`, but both remain `2025-10-13`. Existing clients using that versioned endpoint can therefore receive an incompatible contract without a new API version to migrate to.
**Context Used:** CLAUDE.md ([source](https://github.com/lightsparkdev/grid-api/blob/main/CLAUDE.md))
**Knowledge Base Used:** [Grid API contract](https://app.greptile.com/lightspark/-/custom-context/knowledge-base/lightsparkdev/grid-api/-/docs/api-contract.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.8010cda to
7b347ec
Compare
165dda9 to
262c543
Compare
|
@greptile review |
| Update request for `PATCH /cards/{id}`. At least one of `state`, | ||
| `fundingSources`, `maxSpendPerTransaction`, `maxSpendPerDay`, or | ||
| `fundingSource`, `maxSpendPerTransaction`, `maxSpendPerDay`, or | ||
| `maxTransactionsPerDay` must be supplied. `state` |
There was a problem hiding this comment.
Transaction limit property missing
CardUpdateRequest still lists maxTransactionsPerDay as an accepted update, and the PATCH examples send it, but the request schema does not define that property. Generated clients and schema validators therefore cannot represent this documented transaction-limit update.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/cards/CardUpdateRequest.yaml
Line: 3-5
Comment:
**Transaction limit property missing**
`CardUpdateRequest` still lists `maxTransactionsPerDay` as an accepted update, and the PATCH examples send it, but the request schema does not define that property. Generated clients and schema validators therefore cannot represent this documented transaction-limit update.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.262c543 to
acbe107
Compare
acbe107 to
49981f9
Compare
|
@greptile review |
Jira: ENG-11660 under ENG-11645
What this does
The cards API let a platform bind an ordered list of internal accounts to a card, and the docs said Authorization Decisioning would try them in that order. The server never did that. It pulls from one account, the oldest active binding, and a failed hold does not fall through to the next one.
This PR makes the contract match: a card has exactly one
fundingSource. ThefundingSourcesarray is gone from the card resource, the create request, and the update request. Breaking change with no alias, decided by Danny on 2026-09-09.Changes
Card,CardCreateRequest:fundingSourceis a required string, the internal account id that funds the card.CardUpdateRequest:fundingSourceis an optional string that replaces the bound account. It cannot be combined withstate: CLOSED. To stop spending, freeze the card.GET /cards?accountId=returns cards whosefundingSourceis that account.--funding-sources <list>becomes--funding-source <id>oncards createandcards update. An empty value is rejected instead of sending an empty PATCH.What has to land with this
The server accepts the array today. The webdev change that reads
fundingSource, rejects a second source, and raisesFUNDING_SOURCE_INELIGIBLEas documented merges in the same window, along with the dashboard and the observatory sandbox card canary that still send the array.Verification
make buildandmake lintpass.cd cli && npm testpasses, 80 tests. A repo-wide grep forfundingSources,priority order, andat least one sourcereturns only the guide's URL slug.