Skip to content

feat: add VASP directory endpoint - #827

Merged
shreyav merged 6 commits into
mainfrom
shreyav/vasps-directory
Aug 19, 2026
Merged

feat: add VASP directory endpoint#827
shreyav merged 6 commits into
mainfrom
shreyav/vasps-directory

Conversation

@shreyav

@shreyav shreyav commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a VASP directory: GET /vasps, cursor-paginated. Each entry is { vaspName, url }vaspName is the value a platform passes back when declaring a VASP-hosted counterparty, and url lets a picker UI confirm the right entity.

This is PR 1 of 3 for VASP counterparty support (Travel Rule):

  1. This PR/vasps directory
  2. feat: add beneficiary to crypto wallet external accounts #828beneficiary on crypto-wallet external accounts
  3. feat: identify the VASP that custodies a crypto wallet account #829custodyType/vaspName on external accounts

Shape decisions

  • No search param. Matches the sibling directory endpoints (/discoveries, /uma-providers), which are paginated and filtered client-side. Integrators can cache the directory and search it locally.
  • Names, not opaque IDs. Consistent with /discoveries, where the returned bankName is the value passed back on account creation. The provider's declare-counterparty call takes only its own identifier, so the exposed name is a Grid-side key that the backend maps back — which also keeps the surface portable if the provider set changes.
  • A single name field. The provider returns both a common name and a registered legal name; the legal name earns its place only as a uniqueness tiebreaker, and it is worse for display ("Payward, Inc." for Kraken). Ships one recognizable name plus url.
  • No totalCount. The upstream search returns no total, so it could never be populated.

Changes

  • GET /vasps (limit, cursor) under a new VASPs tag
  • Vasp and VaspListResponse schemas
  • Stainless vasps resource block (list method) so the endpoint flows into the documented spec and SDKs
  • Sidebar icon (globe) for the VASPs group in the Mintlify API reference

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

@mintlify

mintlify Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

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

Project Status Preview Updated (UTC)
Grid 🟢 Ready View Preview Aug 13, 2026, 9:10 PM

@vercel

vercel Bot commented Aug 13, 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 19, 2026 11:19pm
grid-wallet-demo Ignored Ignored Preview Aug 19, 2026 11:19pm

Request Review

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

github-actions Bot commented Aug 13, 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 vasps list endpoint

go

feat(api): add vasps resource with list endpoint

kotlin

feat(api): add vasps resource

openapi

feat(api): add VASPs resource with list endpoint

php

feat(api): add vasps resource

python

feat(api): add vasps resource

ruby

feat(api): add vasps resource

typescript

feat(api): add vasps resource
⚠️ 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 "warning" 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@e2eafd1ba385dfd08e05e56b65a7ea18c8e88a96
⚠️ 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 warning 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/fd47ab0b0bf6d0800828a0107ecd7eb46c8b3836/grid-0.0.1-py3-none-any.whl
⚠️ grid-php studio · code

Your SDK build had at least one "warning" 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-19 23:36:54 UTC

@github-actions github-actions Bot removed the breaking-change Introduces a breaking change to the OpenAPI spec label Aug 14, 2026
shreyav added a commit that referenced this pull request Aug 14, 2026
## 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)
Adds url for picker confirmation, drops totalCount (Striga's search
returns no total, so it could never be populated). Keeps a single name
field: the provider's declare-counterparty call takes only its own id,
so the exposed name is a Grid-side key that sparkcore maps back.
Matches the sibling directory endpoints (/discoveries, /uma-providers),
which are paginated fetch-and-filter-locally; integrators can cache the
directory and search it client-side.
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds an authenticated, cursor-paginated VASP directory to the modular and bundled OpenAPI specifications.

  • Defines the Vasp and VaspListResponse schemas and exposes GET /vasps.
  • Registers the resource for Stainless-generated SDKs.
  • Adds the VASPs API-reference tag and corresponding Mintlify sidebar icon.

Confidence Score: 5/5

The PR appears safe to merge with no actionable defects identified.

The modular source, generated bundles, Stainless mapping, response schemas, and Mintlify styling are mutually consistent, while the intentionally omitted total count and deferred counterparty consumer are explicitly covered by the PR scope.

Important Files Changed

Filename Overview
openapi/paths/vasps/vasps.yaml Defines the authenticated list operation with bounded cursor-pagination parameters and standard error responses.
openapi/components/schemas/vasps/Vasp.yaml Defines the required VASP name and website fields used by directory entries.
openapi/components/schemas/vasps/VaspListResponse.yaml Defines a cursor-pagination envelope with data, hasMore, and an optional nextCursor.
openapi/openapi.yaml Registers the VASPs tag and modular /vasps path in the source specification.
.stainless/stainless.yml Maps the new VASP models and list operation into generated SDK resources.
mintlify/style.css Adds a sidebar icon rule using an existing globe asset and the established API-tag selector pattern.
openapi.yaml Correctly bundles the new endpoint and schemas from the modular source.
mintlify/openapi.yaml Mirrors the generated root bundle for local Mintlify API-reference rendering.

Reviews (1): Last reviewed commit: "Fix stale filter wording in the VASP lis..." | Re-trigger Greptile

@shreyav
shreyav merged commit 11c8b77 into main Aug 19, 2026
12 checks passed
@shreyav
shreyav deleted the shreyav/vasps-directory branch August 19, 2026 23:31
shreyav added a commit that referenced this pull request Aug 20, 2026
## Summary

Follow-up to #827. `Vasp.url` was marked required, but the upstream
directory returns an empty string for it on most entries, so it can't be
promised. Drops it from `required` and softens the description to "when
known".

## 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)

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Ux8rU9Sm2sNFD1FUafY1wV)_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants