feat: add custody type and VASP link to external accounts - #829
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 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-go studio · code · diff
✅ grid-kotlin 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. |
# Conflicts: # mintlify/openapi.yaml # openapi.yaml # openapi/components/schemas/errors/Error400.yaml
## Summary Crypto-wallet external accounts were the only account family without a `beneficiary`. This PR adds one, following the fiat pattern — an `INDIVIDUAL`/`BUSINESS` `oneOf` discriminated by `beneficiaryType`. 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): 1. #827 — `/vasps` directory 2. **This PR** — `beneficiary` on crypto-wallet external accounts 3. #829 — `custodyType`/`vaspName` on external accounts ### Field requirements: exactly what is transmitted The individual variant is a new `WalletIndividualBeneficiary` with only **`fullName` + `countryOfResidence`** (both required) — the exact set transmitted as Travel Rule counterparty info. The generic `IndividualBeneficiary` couldn't be reused because it *requires* `birthDate`/`nationality`, which are never transmitted for wallets and would force platforms to collect a third party's date of birth (OpenAPI composition can't relax `required`). Optional PII fields were deliberately omitted: adding optional fields later is non-breaking, while accepting-but-ignoring PII invites needless collection. The `BUSINESS` variant reuses the existing `BusinessBeneficiary` (`legalName` required). ### Semantics (one deliberate divergence from fiat) - Fiat accounts require `beneficiary`. For wallets it is **optional for `FIRST_PARTY`** — when omitted, the customer's verified identity is used, so the dominant own-wallet case sends nothing extra. - **Required for `THIRD_PARTY`** wallets on platforms subject to counterparty requirements (e.g., EU Travel Rule and similar regimes) — enforced at runtime with `400 INVALID_INPUT`, not in the schema, since the requirement is platform-dependent. ### Changes - New `WalletBeneficiaryFields` fragment (the `beneficiary` property) composed into all seven wallet variants: `BASE_WALLET`, `ETHEREUM_WALLET`, `POLYGON_WALLET`, `PLASMA_WALLET`, `SOLANA_WALLET`, `SPARK_WALLET`, `TRON_WALLET` - New `WalletBeneficiaryOneOf` — the named individual/business union (matches the `*OneOf` house convention) - New `WalletIndividualBeneficiary` schema (`fullName` + `countryOfResidence`) - Stainless model entries for all three ### Out of scope - `LIGHTNING` external 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 build` bundles cleanly; `redocly lint` and `spectral lint` match the pre-existing baseline on `main` exactly (no new findings). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Lets a platform declare that a crypto-wallet external account is held at an exchange rather than self-custodied — the missing counterparty dimension for Travel Rule support.
ownershipTypestays orthogonal: your own Kraken account isVASP_HOSTED+FIRST_PARTY; a friend's MetaMask isSELF_CUSTODY+THIRD_PARTY.This is PR 3 of 3 for VASP counterparty support (Travel Rule). Merge after:
/vaspsdirectory (provides thevaspNamereferenced here)beneficiaryon crypto-wallet external accounts (the identity thatCOUNTERPARTY_USER_INFO_REQUIREDasks for)Changes
custodyTypeenum (SELF_CUSTODY|VASP_HOSTED) onExternalAccountCreateRequestandExternalAccount. Crypto wallets only; defaults toSELF_CUSTODY, so existing integrations are untouched.vaspName— the canonical name fromGET /vasps, mirroring how/discoveriesresults are passed back asbankName. Required whenVASP_HOSTED, rejected otherwise.400 COUNTERPARTY_USER_INFO_REQUIREDerror code: the destination needs beneficiary info before a transfer can proceed (fix the account, retry).SELF_CUSTODYwallets;VASP_HOSTEDaccounts never require it.CustodyType.Testing
make buildbundles cleanly;redocly lintandspectral lintmatch the pre-existing baseline onmainexactly (no new findings).🤖 Generated with Claude Code