feat: add beneficiary to crypto wallet external accounts - #828
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
|
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 ✅ grid-ruby studio · code
|
# Conflicts: # .stainless/stainless.yml
…iaries Matches what is actually transmitted for Travel Rule counterparty info (name + country of residence) instead of the generic beneficiary's birthDate/nationality requirements, which are not transmitted and would force platforms to collect a third party's date of birth.
Greptile SummaryThe PR adds an optional, discriminated individual-or-business beneficiary to all seven non-Lightning crypto-wallet external-account variants and registers the new models for SDK generation.
Confidence Score: 5/5The PR appears safe to merge with no concrete blocking or independently actionable non-blocking issues identified. The create-request unions reach all seven changed wallet schemas, the discriminator mappings resolve consistently in the generated bundles, and the intentionally optional and excluded cases match the documented scope.
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/common/WalletIndividualBeneficiary.yaml | Defines the wallet-specific individual beneficiary with the intended required identity fields and optional supporting details. |
| openapi/components/schemas/external_accounts/WalletBeneficiaryOneOf.yaml | Adds an internally consistent discriminated union whose mappings resolve correctly in the generated bundles. |
| openapi/components/schemas/external_accounts/WalletBeneficiaryFields.yaml | Defines the deliberately optional beneficiary property and documents the platform-dependent third-party requirement. |
| .stainless/stainless.yml | Registers all three new wallet beneficiary schemas as generated external-account SDK models. |
| openapi.yaml | The generated root bundle consistently includes the new schemas and all seven wallet compositions. |
| mintlify/openapi.yaml | The generated Mintlify bundle remains synchronized with the root OpenAPI bundle. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
C[External-account create request] --> U[ExternalAccountCreateInfoOneOf]
U --> W[Wallet external-account variant]
W --> F[WalletBeneficiaryFields]
F --> B{beneficiaryType}
B -->|INDIVIDUAL| I[WalletIndividualBeneficiary]
B -->|BUSINESS| O[BusinessBeneficiary]
W --> G[Bundled OpenAPI]
G --> S[Stainless-generated SDK models]
Reviews (1): Last reviewed commit: "Name the wallet beneficiary union Wallet..." | Re-trigger Greptile
| propertyName: beneficiaryType | ||
| mapping: | ||
| INDIVIDUAL: ../common/WalletIndividualBeneficiary.yaml | ||
| BUSINESS: ../common/BusinessBeneficiary.yaml |
There was a problem hiding this comment.
does this mean there'll be a business beneficiary as well?
There was a problem hiding this comment.
Er I mean is there a individual beneficiary we can resuse
There was a problem hiding this comment.
Huh i guess not I see a bunch of different types of beneficiaries depending on the country but not a generic one.
Do you think this one will be generic or is it only for wallets?
There was a problem hiding this comment.
yeah we went through the exercise of splitting up beneficiaries for individuals based on region reqs but we havent done that for business yet -- so reusing the existing business one and added a new one just for wallets w the minimum requirements
Drops the never-transmitted optional PII (birthDate, nationality, email, phoneNumber, address) from WalletIndividualBeneficiary — optional fields can be added back without breaking; collected-but-unused PII cannot be removed as easily. Documents the 400 INVALID_INPUT on missing required beneficiary.
Summary
Crypto-wallet external accounts were the only account family without a
beneficiary. This PR adds one, following the fiat pattern — anINDIVIDUAL/BUSINESSoneOfdiscriminated bybeneficiaryType.The beneficiary identifies who owns the wallet — the counterparty identity needed for Travel Rule data, independent of custody.
This is PR 2 of 3 for VASP counterparty support (Travel Rule):
/vaspsdirectorybeneficiaryon crypto-wallet external accountscustodyType/vaspNameon external accountsField requirements: exactly what is transmitted
The individual variant is a new
WalletIndividualBeneficiarywith onlyfullName+countryOfResidence(both required) — the exact set transmitted as Travel Rule counterparty info. The genericIndividualBeneficiarycouldn't be reused because it requiresbirthDate/nationality, which are never transmitted for wallets and would force platforms to collect a third party's date of birth (OpenAPI composition can't relaxrequired). Optional PII fields were deliberately omitted: adding optional fields later is non-breaking, while accepting-but-ignoring PII invites needless collection. TheBUSINESSvariant reuses the existingBusinessBeneficiary(legalNamerequired).Semantics (one deliberate divergence from fiat)
beneficiary. For wallets it is optional forFIRST_PARTY— when omitted, the customer's verified identity is used, so the dominant own-wallet case sends nothing extra.THIRD_PARTYwallets on platforms subject to counterparty requirements (e.g., EU Travel Rule and similar regimes) — enforced at runtime with400 INVALID_INPUT, not in the schema, since the requirement is platform-dependent.Changes
WalletBeneficiaryFieldsfragment (thebeneficiaryproperty) composed into all seven wallet variants:BASE_WALLET,ETHEREUM_WALLET,POLYGON_WALLET,PLASMA_WALLET,SOLANA_WALLET,SPARK_WALLET,TRON_WALLETWalletBeneficiaryOneOf— the named individual/business union (matches the*OneOfhouse convention)WalletIndividualBeneficiaryschema (fullName+countryOfResidence)Out of scope
LIGHTNINGexternal accounts — Travel Rule counterparty identity for Lightning flows in-band (payment-level), not via a stored account beneficiary. Flagging in case reviewers feel otherwise.Testing
make buildbundles cleanly;redocly lintandspectral lintmatch the pre-existing baseline onmainexactly (no new findings).🤖 Generated with Claude Code