feat(customers): accept typed agreement consents for seven documents - #990
feat(customers): accept typed agreement consents for seven documents#990bsiaotickchong wants to merge 1 commit into
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 go kotlin openapi php python ruby typescript Edit this comment to update them. They will appear in their respective SDK's changelogs. ✅ grid-typescript studio · code · diff
✅ grid-openapi studio · code · diff
✅ grid-ruby studio · code · diff
✅ grid-kotlin studio · code · diff
✅ grid-go studio · code · diff
✅ grid-python studio · code · diff
✅ grid-php studio · code · diff
✅ grid-cli studio · code · diff
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
|
| agreementConsents: | ||
| type: array | ||
| readOnly: true | ||
| description: >- | ||
| The customer's recorded acceptance of the End User Terms. Omitted until | ||
| The customer's recorded agreement acceptances, one entry per accepted | ||
| type holding that type's most recent acceptance. Empty until an | ||
| acceptance has been recorded. | ||
| items: | ||
| $ref: ./AgreementConsent.yaml |
There was a problem hiding this comment.
agreementConsents is described as an empty list before the first acceptance, but it is absent from Customer.required. Responses may therefore omit the field while still satisfying the schema, and generated clients will model it as optional. Consumers cannot rely on consistently receiving [] as documented.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/Customer.yaml
Line: 26-34
Comment:
**Consent list remains optional**
`agreementConsents` is described as an empty list before the first acceptance, but it is absent from `Customer.required`. Responses may therefore omit the field while still satisfying the schema, and generated clients will model it as optional. Consumers cannot rely on consistently receiving `[]` as documented.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| agreementConsents: | ||
| type: array | ||
| maxItems: 7 | ||
| description: >- | ||
| Evidence that the customer accepted one or more Grid agreements, at most | ||
| one entry per type. Unregulated platforms must record acceptance of the | ||
| Lightspark End User Terms before initiating customer-scoped transactions; | ||
| those transactions fail until that consent is recorded. Consents can be | ||
| supplied during customer creation or in a later customer update. | ||
| items: | ||
| $ref: ./AgreementConsentRequest.yaml |
There was a problem hiding this comment.
The request documentation says agreementConsents contains “one or more” entries, but the create and update arrays specify only maxItems. Schema-generated validation can therefore accept [], which records no consent and leaves the customer unprovisioned, causing later customer-scoped transactions to fail. Both request schemas should require at least one item.
Prompt To Fix With AI
This is a comment left during a code review.
Path: openapi/components/schemas/customers/CustomerCreateRequest.yaml
Line: 62-72
Comment:
**Empty consent arrays allowed**
The request documentation says `agreementConsents` contains “one or more” entries, but the create and update arrays specify only `maxItems`. Schema-generated validation can therefore accept `[]`, which records no consent and leaves the customer unprovisioned, causing later customer-scoped transactions to fail. Both request schemas should require at least one item.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.57b5f0d to
13447b4
Compare
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
|
Fixed the wire break, and addressed the review findings. The break is gone. Mutation-tested the guarantee: making the deprecated route return the list shape again fails its tests on both versions. Finding 1 (consent list optional) — valid, fixed. The backend emits Finding 2 (empty arrays allowed) — declining, this is deliberate. An empty
I did soften the create-request wording, which did say "one or more" — it now describes the list without implying a minimum. Verified: |
13447b4 to
f10d240
Compare

Summary
endUserTermsConsentfield withagreementConsents, a list carrying one entry per agreement, so each document's acceptance is recorded and auditable separately.AgreementTypeenum with the seven supported documents, and changesGET /customers/end-user-termsto return a catalog of all seven as{ data: [{ type, version, url }] }.The seven agreement types
AgreementTypeLIGHTSPARK_END_USER_TERMSLIGHTSPARK_E_SIGN_CONSENTLIGHTSPARK_PRIVACY_POLICYLEAD_E_SIGN_CONSENTLEAD_ACCOUNTHOLDER_AGREEMENTLEAD_PRIVACY_POLICYLEAD_CARDHOLDER_AGREEMENTEach consent entry carries
typeplus the four existing evidence fields (acceptedAt,ipAddress,termsVersion,acceptanceMethod), all required.termsVersionis theversionthe catalog returns for that type — versions are scoped per type, so a version valid for one agreement is not valid for another.Design decisions worth a reviewer's attention
The endpoint path is unchanged.
GET /customers/end-user-termskeeps its path and gains a list response (operationIdgetEndUserTerms→listAgreementDocuments). Renaming the path would be a second breaking change for no functional gain; happy to rename if you'd prefer to take both at once.The catalog is not a requirements list. Seven supported types does not mean every customer must accept all seven. Which documents are required, for which products and customers, is a legal decision this PR deliberately does not encode.
info.versionis intentionally not bumped. It tracks the published dated version — a live routing prefix, also hardcoded across the docs and the generated client — not each breaking merge. It has not moved since that rule landed in #679, across 36+breaking-changePRs. Thebreaking-changelabel and API-reviewer approval are the real gate; flagging it here so that decision is explicit rather than implied.Clients pinned to the dated version are not affected. The server change lands this shape on the
/grid/rcrelease-candidate surface only, leaving/grid/2025-10-13serving the existing contract. Cutting a new dated version is a separate, coordinated release.retrieve_end_user_termsin.stainless/stainless.ymlis left alone. It's a published SDK method name and its path is unchanged, so renaming it is an independent SDK-breaking decision. The three model mappings that pointed at now-deleted schemas are updated.Migration for existing consumers
LIGHTSPARK_END_USER_TERMS. Acceptance of one agreement never implies another, so the other six must be collected from each customer.Customer.agreementConsentsis read-only and returns the most recent acceptance per accepted type — an empty list until the first acceptance, where the old field was omitted.Changes: 21 files
openapi/components/schemas/customers/Agreement*.yaml— 6 new schemas (type, acceptance method, consent request/response, document, list response)openapi/components/schemas/customers/EndUserTerms*.yaml— 3 superseded schemas removed (EndUserTerms,EndUserTermsAcceptanceMethod,EndUserTermsConsentRequest);EndUserTermsConsentis kept and markeddeprecated: trueopenapi/components/schemas/customers/Customer{,CreateRequest,UpdateRequest}.yaml— field swapped to the listopenapi/paths/customers/customers_end-user-terms.yaml— catalog responseopenapi/webhooks/customer-update.yaml— 2 examples updated to matchCustomer.stainless/stainless.yml— model mappings repointedmintlify/— disclosures rewritten, snippet + changelog entry, regenerated bundlesRebase note
Rebased onto
main(6 commits, through #934 "bind one funding source per card"). Two conflicts, both resolved keeping each side:Customer.yaml— main still carried onlyendUserTermsConsent; this branch adds the deprecation marker plusagreementConsents. Took this branch's version, which contains both.mintlify/changelog.mdx— both sides added a new top entry. Kept both, main's card-refunds entry above this one.Verified after the rebase that main's card work survived intact (e.g.
CardTransaction.originalTransactionIdis present in the rebuilt bundle) alongside the seven-value enum and the deprecated field.Test plan
This repo has no test suite; it is spec + docs. Verified:
make buildbundles cleanly; both generated bundles regenerated and committed.make lintexits 0 with 2 warnings / 14 ignored — byte-identical to themainbaseline, confirmed by re-running lint on a stashed tree. No new lint problems.agreementConsentsand no longer exposeendUserTermsConsent; the 200 response resolves todata[]ofAgreementDocumentwith{type, version, url}all required; noEndUserTerms*schema remains;info.versionunchanged..stainlessmodel mappings, which are fixed here. Its remaining finding is the version-bump question addressed above.Public
Consent is now recorded per agreement type, and the agreements endpoint lists every supported document with its current version and URL.
Original PR: #954