Skip to content

feat(customers): accept typed agreement consents for seven documents - #954

Draft
ls-bolt[bot] wants to merge 1 commit into
mainfrom
09-11-grid-api-agreement-consents
Draft

feat(customers): accept typed agreement consents for seven documents#954
ls-bolt[bot] wants to merge 1 commit into
mainfrom
09-11-grid-api-agreement-consents

Conversation

@ls-bolt

@ls-bolt ls-bolt Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replaces the single endUserTermsConsent field with agreementConsents, a list carrying one entry per agreement, so each document's acceptance is recorded and auditable separately.
  • Adds an AgreementType enum with the seven supported documents, and changes GET /customers/end-user-terms to return a catalog of all seven as { data: [{ type, version, url }] }.
  • Spec + docs only. Backend, migration, and generated-client work follow in separate PRs.

The seven agreement types

Document AgreementType
Lightspark Terms of Service (End User Terms) LIGHTSPARK_END_USER_TERMS
Lightspark E-SIGN consent LIGHTSPARK_E_SIGN_CONSENT
Lightspark Privacy Policy LIGHTSPARK_PRIVACY_POLICY
Lead E-SIGN consent LEAD_E_SIGN_CONSENT
Lead Accountholder Agreement LEAD_ACCOUNTHOLDER_AGREEMENT
Lead Privacy Policy LEAD_PRIVACY_POLICY
Lead Cardholder Agreement LEAD_CARDHOLDER_AGREEMENT

Each consent entry carries type plus the four existing evidence fields (acceptedAt, ipAddress, termsVersion, acceptanceMethod), all required. termsVersion is the version the 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-terms keeps its path and gains a list response (operationId getEndUserTermslistAgreementDocuments). 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.version is 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-change PRs. The breaking-change label 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/rc release-candidate surface only, leaving /grid/2025-10-13 serving the existing contract. Cutting a new dated version is a separate, coordinated release.

retrieve_end_user_terms in .stainless/stainless.yml is 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

  • Acceptance already recorded under the old field maps only to LIGHTSPARK_END_USER_TERMS. Acceptance of one agreement never implies another, so the other six must be collected from each customer.
  • On update, supplying consents records additional acceptances; evidence already on file for other types is untouched. Omitting the field changes nothing.
  • Customer.agreementConsents is 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 — 4 superseded schemas removed
  • openapi/components/schemas/customers/Customer{,CreateRequest,UpdateRequest}.yaml — field swapped to the list
  • openapi/paths/customers/customers_end-user-terms.yaml — catalog response
  • openapi/webhooks/customer-update.yaml — 2 examples updated to match Customer
  • .stainless/stainless.yml — model mappings repointed
  • mintlify/ — disclosures rewritten, snippet + changelog entry, regenerated bundles

Test plan

This repo has no test suite; it is spec + docs. Verified:

  • make build bundles cleanly; both generated bundles regenerated and committed.
  • make lint exits 0 with 2 warnings / 14 ignored — byte-identical to the main baseline, confirmed by re-running lint on a stashed tree. No new lint problems.
  • Parsed the bundle and asserted: the enum holds exactly 7 unique values; all 5 consent fields are required; all three customer schemas expose agreementConsents and no longer expose endUserTermsConsent; the 200 response resolves to data[] of AgreementDocument with {type, version, url} all required; no EndUserTerms* schema remains; info.version unchanged.
  • An automated review pass caught the stale .stainless model 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.

@mintlify

mintlify Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Grid 🟢 Ready View Preview Sep 11, 2026, 11:17 PM

@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated
grid-flow-builder Ignored Ignored Preview Sep 11, 2026 11:16pm UTC
grid-wallet-demo Ignored Ignored Preview Sep 11, 2026 11:16pm UTC

Request Review

@ls-bolt ls-bolt Bot added the bolt label Sep 11, 2026
@github-actions github-actions Bot added the breaking-change Introduces a breaking change to the OpenAPI spec label Sep 11, 2026
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ Breaking OpenAPI changes detected

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

Errors (12)

  • POST /customers — added #/components/schemas/EndUserTermsConsent to the oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent request property allOf list [request-property-all-of-added].
  • POST /customers — added #/components/schemas/EndUserTermsConsent to the oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent request property allOf list [request-property-all-of-added].
  • POST /customers — the oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent request property type/format changed from object/to/`` [request-property-type-changed].
  • POST /customers — the oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent request property type/format changed from object/to/`` [request-property-type-changed].
  • GET /customers/end-user-terms — removed the required property url from the response with the 200 status [response-required-property-removed].
  • GET /customers/end-user-terms — removed the required property version from the response with the 200 status [response-required-property-removed].
  • PATCH /customers/{customerId} — added #/components/schemas/EndUserTermsConsent to the oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent request property allOf list [request-property-all-of-added].
  • PATCH /customers/{customerId} — added #/components/schemas/EndUserTermsConsent to the oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent request property allOf list [request-property-all-of-added].
  • PATCH /customers/{customerId} — the oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent request property type/format changed from object/to/`` [request-property-type-changed].
  • PATCH /customers/{customerId} — the oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent request property type/format changed from object/to/`` [request-property-type-changed].
  • POST webhook:customer-update — added #/components/schemas/EndUserTermsConsent to the allOf[subschema #2]/data/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/Customer]/endUserTermsConsent request property allOf list [request-property-all-of-added].
  • POST webhook:customer-update — added #/components/schemas/EndUserTermsConsent to the allOf[subschema #2]/data/oneOf[subschema #2: Business Customer]/allOf[#/components/schemas/Customer]/endUserTermsConsent request property allOf list [request-property-all-of-added].

Warnings (18)

Show sample
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/acceptanceMethod [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/acceptedAt [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/ipAddress [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/termsVersion [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/acceptanceMethod [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/acceptedAt [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/ipAddress [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #2: Business Customer Create Request]/allOf[#/components/schemas/CustomerCreateRequest]/endUserTermsConsent/termsVersion [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/acceptanceMethod [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/acceptedAt [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/ipAddress [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/termsVersion [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/acceptanceMethod [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/acceptedAt [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/ipAddress [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #2: Business Customer Update Request]/allOf[subschema #1: Customer Update Request]/endUserTermsConsent/termsVersion [request-property-removed].
  • POST webhook:customer-update — removed #/components/schemas/EndUserTermsConsentRequest from the allOf[subschema #2]/data/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/Customer]/endUserTermsConsent request property allOf list [request-property-all-of-removed].
  • POST webhook:customer-update — removed #/components/schemas/EndUserTermsConsentRequest from the allOf[subschema #2]/data/oneOf[subschema #2: Business Customer]/allOf[#/components/schemas/Customer]/endUserTermsConsent request property allOf list [request-property-all-of-removed].

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

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

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

cli

feat(api): replace endUserTermsConsent with agreementConsents in customers

go

feat(api): add agreement consents field, update end user terms response in customers

kotlin

feat(api): add agreementConsents/AgreementType, remove endUserTermsConsent, rename consent models

openapi

feat(api): expand to multiple agreement types in customers resource

php

feat(api): add agreement consent models, remove end user terms, update customer types

python

feat(api): replace end_user_terms with multi-agreement support in customers resource

ruby

feat(api): add agreement models/types, remove end_user_terms models, update customer types

typescript

feat(api): add agreement consent types, remove endUserTerms types, update customers methods

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 new note diagnostic, which is a regression from the base state.
generate ✅build ⏭️lint ⏭️test ⏭️

New diagnostics (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
grid-openapi studio · code · diff

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

New diagnostics (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
grid-ruby 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 (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
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 (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
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@ecb6ed2f32059c3fb2cae6a25881b04b9f9a3997
New diagnostics (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
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 ⏭️

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 (3 note)
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
💡 Schema/DeprecatedWithoutMessage: Confirm schema is deprecated and add missing deprecation details if needed.
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-09-11 23:20:36 UTC

@ls-bolt

ls-bolt Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Revision log — updated in place, latest first.

Revision 1

Reworked: endUserTermsConsent is now deprecated rather than removed, since platforms in production are already sending it.

  • Restored on CustomerCreateRequest, CustomerUpdateRequest, and Customer with deprecated: true, following openapi/README.md's deprecation guidance. It is equivalent to one agreementConsents entry of type LIGHTSPARK_END_USER_TERMS.
  • Responses carry both shapes, so existing readers keep working while integrators migrate.
  • Sending both fields in one request is rejected rather than silently resolved.
  • Changelog and the disclosures page now state the field is deprecated and that consent already recorded is migrated automatically — nothing to re-collect.

make build + make lint clean, still byte-identical to the main baseline (2 warnings / 14 ignored). The seven-value enum and the catalog response are unchanged.

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.

1 participant