Skip to content

Unify individual customer identification on idType/identifier/countryOfIssuance - #836

Merged
akanter merged 2 commits into
mainfrom
08-13-remove-individual-taxid-fields
Aug 14, 2026
Merged

Unify individual customer identification on idType/identifier/countryOfIssuance#836
akanter merged 2 commits into
mainfrom
08-13-remove-individual-taxid-fields

Conversation

@akanter

@akanter akanter commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Individual customers accepted two interchangeable identification vocabularies: taxIdType / taxIdentifier / taxIdCountryOfIssuance, and idType / identifier. Beneficial owners only ever had idType / identifier / countryOfIssuance. This drops the taxId* set so both resources speak one vocabulary.

Removed Replacement
taxIdType idType
taxIdentifier identifier
taxIdCountryOfIssuance countryOfIssuance

identifier now lives on the shared IndividualCustomerFields as writeOnly, which lets IndividualCustomerCreateRequest drop its duplicate declaration. taxIdentifier was not write-only, so the schema advertised a response field that is never populated; the unified field fixes that.

Other taxId-prefixed fields are untouched — BusinessInfo.taxId (EIN), BrlAccountInfoBase.taxId and BusinessBeneficiary.taxId (CPF/CNPJ) are a different concept with no idType counterpart.

No info.version bump: these fields have no integrator on them yet, and a bump would mean cutting a new dated servers.url path for a pre-adoption cleanup.

Changes

  • openapi/components/schemas/customers/IndividualCustomerFields.yaml — rename the three properties, mark identifier write-only
  • openapi/components/schemas/customers/IndividualCustomerCreateRequest.yaml — drop the now-duplicate idType / identifier block
  • openapi/components/schemas/errors/FieldError.yaml — example field name
  • mintlify/snippets/sandbox-verification.mdx — requirement prose, the RESOLVE_ERRORS sample, and the PATCH example
  • openapi.yaml, mintlify/openapi.yamlmake build output

Test plan

  • make build — exit 0, both bundles regenerated
  • make lint — exit 0, 0 errors; warning/info counts unchanged from main (658 problems, all pre-existing)
  • grep -rn "taxIdType\|taxIdentifier\|taxIdCountryOfIssuance" openapi/ mintlify/ — no matches

The consuming server change lands separately in webdev, which regenerates its Python models from this bundle. Merge this first.

Requested by @akanter

Original PR: #832

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

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

⚠️ Breaking OpenAPI changes detected

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

Errors (16)

  • POST /customers/external-accounts/{externalAccountId}/challenge — api path removed without deprecation [api-path-removed-without-deprecation].
  • POST /customers/external-accounts/{externalAccountId}/verify — api path removed without deprecation [api-path-removed-without-deprecation].
  • POST /platform/external-accounts/{externalAccountId}/challenge — api path removed without deprecation [api-path-removed-without-deprecation].
  • POST /platform/external-accounts/{externalAccountId}/verify — api path removed without deprecation [api-path-removed-without-deprecation].
  • POST webhook:agent-action — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:bulk-upload — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:card-funding-source-change — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:card-state-change — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:card-transaction — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:customer-update — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:incoming-payment — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:internal-account-status — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:invitation-claimed — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:outgoing-payment — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:test-webhook — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].
  • POST webhook:verification-update — removed the enum value EXTERNAL_ACCOUNT.STATUS_UPDATED of the request property allOf[#/components/schemas/BaseWebhook]/type [request-property-enum-value-removed].

Warnings (25)

Show sample
  • GET /customers — removed the optional property data/items/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance from the response with the 200 status [response-optional-property-removed].
  • GET /customers — removed the optional property data/items/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType from the response with the 200 status [response-optional-property-removed].
  • GET /customers — removed the optional property data/items/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier from the response with the 200 status [response-optional-property-removed].
  • POST /customers — removed subschema #3 from the oneOf[subschema #1: Individual Customer Create Request]/ request property allOf list [request-property-all-of-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType [request-property-removed].
  • POST /customers — removed the request property oneOf[subschema #1: Individual Customer Create Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier [request-property-removed].
  • POST /customers — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance from the response with the 201 status [response-optional-property-removed].
  • POST /customers — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType from the response with the 201 status [response-optional-property-removed].
  • POST /customers — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier from the response with the 201 status [response-optional-property-removed].
  • DELETE /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance from the response with the 200 status [response-optional-property-removed].
  • DELETE /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType from the response with the 200 status [response-optional-property-removed].
  • DELETE /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier from the response with the 200 status [response-optional-property-removed].
  • GET /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance from the response with the 200 status [response-optional-property-removed].
  • GET /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType from the response with the 200 status [response-optional-property-removed].
  • GET /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier from the response with the 200 status [response-optional-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType [request-property-removed].
  • PATCH /customers/{customerId} — removed the request property oneOf[subschema #1: Individual Customer Update Request]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier [request-property-removed].
  • PATCH /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance from the response with the 200 status [response-optional-property-removed].
  • PATCH /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType from the response with the 200 status [response-optional-property-removed].
  • PATCH /customers/{customerId} — removed the optional property oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier from the response with the 200 status [response-optional-property-removed].
  • POST webhook:customer-update — removed the request property allOf[subschema #2]/data/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdCountryOfIssuance [request-property-removed].
  • POST webhook:customer-update — removed the request property allOf[subschema #2]/data/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdType [request-property-removed].
  • POST webhook:customer-update — removed the request property allOf[subschema #2]/data/oneOf[subschema #1: Individual Customer]/allOf[#/components/schemas/IndividualCustomerFields]/allOf[subschema #1]/taxIdentifier [request-property-removed].

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

Copy link
Copy Markdown

This stack of pull requests is managed by Graphite. Learn more about stacking.

@akanter
akanter requested a review from pengying August 14, 2026 10:26
@akanter
akanter enabled auto-merge (squash) August 14, 2026 10:26
@github-actions

github-actions Bot commented Aug 14, 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): add countryOfIssuance/identifier/idType, remove tax fields in customers

go

feat(api): rename tax identifier fields to generic identifier fields in customer types

kotlin

feat(api): rename tax ID fields in IndividualCustomer

openapi

fix(api): rename tax ID fields to idType/identifier/countryOfIssuance in individual customer

php

feat(api): rename tax fields to id fields in individual customer models

python

feat(api): add country_of_issuance/id_type, remove tax_* fields in individual customer

ruby

fix(types): rename tax_id fields to id in IndividualCustomer models

typescript

fix(api): rename tax ID fields to countryOfIssuance/idType in customers
⚠️ 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@ff3ba87e6dd85e1476c0a941c629719721bafdec
⚠️ 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-typescript studio · conflict

Your SDK build had at least one note diagnostic.

⚠️ 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/0a0b21bb7654f728f2e49f85503472d4207be21a/grid-0.0.1-py3-none-any.whl
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 build 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-08-14 19:06:39 UTC

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR consolidates individual-customer identification onto idType, identifier, and countryOfIssuance, removing the parallel taxId* vocabulary.

  • Moves the write-only identifier property into the shared individual-customer fields schema.
  • Updates verification documentation and error examples to use the unified names.
  • Regenerates both committed OpenAPI bundles from the modular source schemas.

Confidence Score: 5/5

The PR appears safe to merge with the source schemas, generated bundles, and documentation consistently using the unified identification vocabulary.

The shared schema continues to support both create and update requests, intentionally excludes the sensitive identifier from responses, and the generated artifacts match the source changes.

Important Files Changed

Filename Overview
openapi/components/schemas/customers/IndividualCustomerFields.yaml Unifies the individual identification fields and correctly marks the sensitive identifier as write-only.
openapi/components/schemas/customers/IndividualCustomerCreateRequest.yaml Removes the now-redundant create-only declarations after moving them into the shared fields schema.
mintlify/snippets/sandbox-verification.mdx Updates verification requirements, errors, and the corrective PATCH example to the unified vocabulary.
openapi/components/schemas/errors/FieldError.yaml Updates the example field path to the replacement identifier name.
openapi.yaml Generated bundle consistently reflects the source-schema changes.
mintlify/openapi.yaml Generated Mintlify bundle remains synchronized with the root OpenAPI bundle.

Reviews (1): Last reviewed commit: "Unify individual customer identification..." | Re-trigger Greptile

The description said countryOfIssuance was required for NON_US_TAX_ID, but the
individual endpoints reject that type outright, so the documented combination
could never be submitted. Describe what individuals actually get: SSN and ITIN
are US-issued, so the field defaults to US and any other value is rejected.

Co-Authored-By: akanter <akanter@users.noreply.github.com>
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Aug 14, 2026 10:40am
grid-wallet-demo Ignored Ignored Preview Aug 14, 2026 10:40am

Request Review

@akanter
akanter merged commit 11ab113 into main Aug 14, 2026
10 checks passed
@akanter
akanter deleted the 08-13-remove-individual-taxid-fields branch August 14, 2026 18:59
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