Skip to content

Sync Grid Visualizer with PaymentRail enum - #351

Closed
claude[bot] wants to merge 2 commits into
mainfrom
docs/sync-20260418
Closed

Sync Grid Visualizer with PaymentRail enum#351
claude[bot] wants to merge 2 commits into
mainfrom
docs/sync-20260418

Conversation

@claude

@claude claude Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Syncs the Grid Visualizer with the new PaymentRail enum added in #347:

  • currencies.ts: Update payment rail values to use SCREAMING_SNAKE_CASE format matching the OpenAPI PaymentRail enum (e.g., FEDNOW instead of FedNow, FASTER_PAYMENTS instead of Faster Payments, SEPA_INSTANT instead of SEPA Instant, BANK_TRANSFER instead of Bank Transfer, MOBILE_MONEY instead of Mobile Money)
  • code-generator.ts: Add paymentRails array to generated external account creation requests, matching the documented workflow examples in .claude/skills/grid-api/references/workflows.md

Trigger

OpenAPI schema changes in commit 4d89702:

  • openapi/components/schemas/common/PaymentRail.yaml (new enum)
  • openapi/components/schemas/exchange_rates/ExchangeRate.yaml (added destinationPaymentRail)
  • openapi/components/schemas/quotes/AccountDestination.yaml (added optional paymentRail)

Test plan

  • Verify generated API code in Grid Visualizer uses correct enum values
  • Test external account creation flow shows paymentRails in request body

🤖 Generated with Claude Code

Update currencies.ts to use SCREAMING_SNAKE_CASE payment rail values
that match the PaymentRail enum in the OpenAPI spec (e.g., FEDNOW,
FASTER_PAYMENTS, SEPA_INSTANT, BANK_TRANSFER, MOBILE_MONEY).

Add paymentRails field to generated external account creation requests
in code-generator.ts to match documented workflow examples.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
claude Bot requested review from pengying and shreyav April 18, 2026 08:22
@vercel

vercel Bot commented Apr 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
grid-flow-builder Ready Ready Preview Jul 30, 2026 7:55pm
grid-wallet-demo Error Error Jul 30, 2026 7:55pm

Request Review

@greptile-apps

greptile-apps Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR syncs the Grid Visualizer with the new PaymentRail enum from PR #347, correctly updating all rail string values in currencies.ts to SCREAMING_SNAKE_CASE. However, the code-generator.ts change also injects paymentRails inside accountInfo in external account creation requests, and that field is defined only in response-side schemas (*AccountInfo) — not in the create-request schemas (*AccountInfoBase) used by POST /customers/external-accounts. This would produce example API calls that include an undocumented field, potentially causing 400 errors or misleading developers who copy the generated code.

Confidence Score: 4/5

The currencies.ts enum update is safe, but code-generator.ts injects a response-only field into create request bodies which would produce incorrect example code.

One P1 finding: paymentRails is injected into accountInfo for external account creation requests, but the field is absent from all create-request schemas (*AccountInfoBase). This generates misleading or broken example API calls, which is the core purpose of this visualizer. The P2 (enum values in prose) is minor. Score is 4 until the P1 is resolved.

components/grid-visualizer/src/lib/code-generator.ts — paymentRails field placement in buildAccountInfoBody

Important Files Changed

Filename Overview
components/grid-visualizer/src/data/currencies.ts Rail values updated to SCREAMING_SNAKE_CASE matching the PaymentRail enum; all new values (FEDNOW, WIRE, SEPA_INSTANT, FASTER_PAYMENTS, BANK_TRANSFER, MOBILE_MONEY, PAYNOW) are valid enum members.
components/grid-visualizer/src/lib/code-generator.ts Adds paymentRails to accountInfo in external account create requests, but this field exists only in response schemas (*AccountInfo), not create request schemas (*AccountInfoBase) — the generated example code would send an undocumented field to the API.

Sequence Diagram

sequenceDiagram
    participant UI as Grid Visualizer UI
    participant CG as code-generator.ts
    participant CUR as currencies.ts (PaymentRail enum)
    participant API as Grid API

    UI->>CG: generateSteps(source, destination)
    CG->>CUR: find(c => c.code === sel.code)
    CUR-->>CG: fiat.allRails (SCREAMING_SNAKE_CASE)
    CG->>CG: buildAccountInfoBody() sets info.paymentRails = allRails
    CG-->>UI: ApiStep with accountInfo.paymentRails
    UI->>API: POST /customers/external-accounts { accountInfo: { ..., paymentRails: [...] } }
    Note over API: paymentRails not in create schema, only in response schema
Loading

Comments Outside Diff (1)

  1. components/grid-visualizer/src/lib/code-generator.ts, line 309 (link)

    P2 Raw enum values in user-facing note text

    getJitPaymentMethod() now returns strings like "FEDNOW transfer" or "SEPA_INSTANT transfer" from fiat.instantRails[0], which appear directly in the step note shown to the user: "Trigger the payment by sending a SEPA_INSTANT transfer to the deposit address...". The previous human-readable names (FedNow, SEPA Instant) were better suited for this prose context.

    Consider either keeping a separate display-name map for prose use or adding a formatting helper that converts SEPA_INSTANTSEPA Instant for the note text.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: components/grid-visualizer/src/lib/code-generator.ts
    Line: 309
    
    Comment:
    **Raw enum values in user-facing note text**
    
    `getJitPaymentMethod()` now returns strings like `"FEDNOW transfer"` or `"SEPA_INSTANT transfer"` from `fiat.instantRails[0]`, which appear directly in the step note shown to the user: *"Trigger the payment by sending a SEPA_INSTANT transfer to the deposit address..."*. The previous human-readable names (`FedNow`, `SEPA Instant`) were better suited for this prose context.
    
    Consider either keeping a separate display-name map for prose use or adding a formatting helper that converts `SEPA_INSTANT``SEPA Instant` for the note text.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
This is a comment left during a code review.
Path: components/grid-visualizer/src/lib/code-generator.ts
Line: 51-57

Comment:
**`paymentRails` is a response-only field**

`paymentRails` is not part of the external account creation request schema. Every `*ExternalAccountCreateInfo` schema (e.g. `UsdExternalAccountCreateInfo`) extends `*AccountInfoBase`, and none of those base schemas include `paymentRails`. The field only appears in the response-side `*AccountInfo` schemas (e.g. `UsdAccountInfo`) that the API returns after creation.

Sending `paymentRails` inside `accountInfo` will either cause a 400 validation error or be silently ignored — either way it generates misleading example code for developers using this visualizer as a reference. The OpenAPI spec examples in `customers_external_accounts.yaml` also omit it from create request bodies.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: components/grid-visualizer/src/lib/code-generator.ts
Line: 309

Comment:
**Raw enum values in user-facing note text**

`getJitPaymentMethod()` now returns strings like `"FEDNOW transfer"` or `"SEPA_INSTANT transfer"` from `fiat.instantRails[0]`, which appear directly in the step note shown to the user: *"Trigger the payment by sending a SEPA_INSTANT transfer to the deposit address..."*. The previous human-readable names (`FedNow`, `SEPA Instant`) were better suited for this prose context.

Consider either keeping a separate display-name map for prose use or adding a formatting helper that converts `SEPA_INSTANT``SEPA Instant` for the note text.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Sync Grid Visualizer with PaymentRail en..." | Re-trigger Greptile

Comment on lines +51 to +57
// Add paymentRails for fiat currencies
if (sel.type === 'fiat') {
const fiat = currencies.find((c) => c.code === sel.code);
if (fiat && fiat.allRails.length > 0) {
info.paymentRails = fiat.allRails;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 paymentRails is a response-only field

paymentRails is not part of the external account creation request schema. Every *ExternalAccountCreateInfo schema (e.g. UsdExternalAccountCreateInfo) extends *AccountInfoBase, and none of those base schemas include paymentRails. The field only appears in the response-side *AccountInfo schemas (e.g. UsdAccountInfo) that the API returns after creation.

Sending paymentRails inside accountInfo will either cause a 400 validation error or be silently ignored — either way it generates misleading example code for developers using this visualizer as a reference. The OpenAPI spec examples in customers_external_accounts.yaml also omit it from create request bodies.

Prompt To Fix With AI
This is a comment left during a code review.
Path: components/grid-visualizer/src/lib/code-generator.ts
Line: 51-57

Comment:
**`paymentRails` is a response-only field**

`paymentRails` is not part of the external account creation request schema. Every `*ExternalAccountCreateInfo` schema (e.g. `UsdExternalAccountCreateInfo`) extends `*AccountInfoBase`, and none of those base schemas include `paymentRails`. The field only appears in the response-side `*AccountInfo` schemas (e.g. `UsdAccountInfo`) that the API returns after creation.

Sending `paymentRails` inside `accountInfo` will either cause a 400 validation error or be silently ignored — either way it generates misleading example code for developers using this visualizer as a reference. The OpenAPI spec examples in `customers_external_accounts.yaml` also omit it from create request bodies.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude fix this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e3191b4 — the paymentRails injection is removed, and code-generator.ts is now byte-identical to the base commit.

Confirmed the finding against current main before removing it. UsdExternalAccountCreateInfo and UsdAccountInfo both extend the same UsdAccountInfoBase; paymentRails is added only in the response wrapper:

# UsdAccountInfo.yaml  (response)
allOf:
- $ref: ./UsdAccountInfoBase.yaml
- required: [paymentRails]        # ← only here

# UsdExternalAccountCreateInfo.yaml  (create request)
allOf:
- $ref: ./BaseExternalAccountInfo.yaml
- $ref: ../common/UsdAccountInfoBase.yaml
- required: [beneficiary]         # ← no paymentRails

Worth noting the PR description justified this hunk by citing workflows.md. That reference no longer says so — main now states the opposite in two places, so there's nothing left to fix upstream:

  • .claude/skills/grid-api/SKILL.md: "Do not send paymentRails — Grid selects the rail and returns it on the created account."
  • .claude/skills/grid-api/references/account-types.md: "The rail is chosen by Grid and returned on the created account (the response paymentRails field) — it is not a request input."

The currencies.ts half is unaffected and still needed: main continues to carry 'FedNow' / 'SEPA Instant' / 'Bank Transfer' while the spec has the PaymentRail enum. I checked every value in the diff against PaymentRail.yamlACH, WIRE, RTP, FEDNOW, SEPA, SEPA_INSTANT, FASTER_PAYMENTS, BANK_TRANSFER, MOBILE_MONEY, PAYNOW, FAST are all valid members.


Generated by Claude Code

The visualizer was injecting paymentRails into the body of
POST /customers/external-accounts. That field is response-only:
*ExternalAccountCreateInfo and *AccountInfo both extend the same
*AccountInfoBase, and paymentRails is added only in the response
wrapper. Generated example calls therefore sent a field the create
endpoint does not accept.

The skill reference now states this explicitly ("Do not send
paymentRails - Grid selects the rail and returns it on the created
account"), so the workflow examples this change was originally
justified by no longer say what it claimed.

Also add railDisplayName() for rendering rails as prose. Moving
currencies.ts to PaymentRail enum values is correct for the data, but
those values reach the UI in four places - the JIT payment note, the
currency picker rail list, the rail dropdown, and the flow-path
captions - which would otherwise read "SEPA_INSTANT transfer". The
enum value stays the data; the display name is presentation only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMnjJ8yWJsui7jLqqrDrL4

shreyav commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Also addressed the P2 from the Greptile summary (raw enum values in prose), which had no review thread to reply to.

The scope was slightly wider than the original comment described. getJitPaymentMethod() was one of four places the rail value reaches the UI, so moving currencies.ts to enum values would have surfaced SEPA_INSTANT in all of them:

Site Before Would have become
code-generator.ts JIT note "sending a SEPA Instant transfer" SEPA_INSTANT
CurrencyPicker rail list "PayNow, FAST, Bank Transfer" PAYNOW, FAST, BANK_TRANSFER
InputCard rail dropdown "FedNow" FEDNOW
flow-path captions "Funds in via SEPA Instant" SEPA_INSTANT

Took the display-map approach suggested in the comment: railDisplayName() in currencies.ts, covering all 23 PaymentRail members, with an underscores-to-spaces fallback so a newly added rail degrades readably instead of breaking. Title-casing generically wasn't viable — it yields "Fednow", "Rtp", "Sepa Instant".

The enum value remains the data everywhere; railDisplayName() is applied only at render. Rail values passed to onSelect and into generated request bodies are untouched.

One thing I could not verify locally: npm ci fails in my environment because @central-icons-react requires CENTRAL_LICENSE_KEY, so I could not run the Next build. currencies.ts typechecks clean standalone under --strict, and the other four files are import-and-call-site changes only, but the Vercel preview build is the real check here.


Generated by Claude Code

@shreyav

shreyav commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

no longer relevant -- rail is not specified on create anymore

@shreyav shreyav closed this Jul 30, 2026
shreyav added a commit that referenced this pull request Jul 31, 2026
## What

Makes the Grid Visualizer's payment-rail selection functional. Today the
rail is decorative — the user picks one from a dropdown and it only
changes UI captions. This threads the choice into the generated `POST
/quotes` request as `destination.paymentRail`.

**Supersedes #351.**

## Why the `currencies.ts` rename is a prerequisite, not a cosmetic
change

`instantRails` / `allRails` currently hold human-readable strings
(`'FedNow'`, `'SEPA Instant'`, `'Bank Transfer'`, …). Those are not
values the API accepts, so **no rail could be sent at all** while the
data held display strings. Converting them to `PaymentRail` enum members
(`FEDNOW`, `SEPA_INSTANT`, `BANK_TRANSFER`, …) is what makes the feature
possible.

Because the enum values would otherwise render as `SEPA_INSTANT` at
users, this adds an exported `railDisplayName()` covering all 23 enum
members (with an underscores-to-spaces fallback) and applies it at the
four sites that surface a rail:

1. `code-generator.ts` — `getJitPaymentMethod()`, the "sending a FedNow
transfer" prose note
2. `CurrencyPicker.tsx` — `getRailsText()` and the `keywords` array in
`buildFiatItem` (keywords keep **both** enum and display forms, so
search still matches either)
3. `InputCard.tsx` — dropdown button label, dropdown menu items, static
`fiatRail` row
4. `flow-path.ts` — the "Funds in via X" / "Funds out via X" captions

**The enum value is the data; `railDisplayName()` is presentation
only.** No display string reaches a request body or `onSelect`/state.

The rename + display map is carried over from the closing PR on
`docs/sync-20260418` (`e3191b4`). Two currencies added to `main` since
that branch (El Salvador `SLV_ACCOUNT`, `CNY_ACCOUNT`) were converted
here as well.

## `paymentRail` vs `paymentRails` — the distinction #351 got wrong

| | |
|---|---|
| **`paymentRail`** (singular) | **Request** field, on quote
destinations only (`quotes/AccountDestination.yaml`). Optional —
omitted, Grid selects a default. |
| **`paymentRails`** (plural) | **Response**-only. Lives in
`*AccountInfo.yaml` wrappers, reporting what an account supports. Absent
from `*ExternalAccountCreateInfo` / `*AccountInfoBase`. |

#351 injected the plural into `POST /customers/external-accounts` bodies
— a field that endpoint does not accept. This PR introduces **no**
`paymentRails` anywhere (`grep -rn paymentRails src/` in the visualizer
returns nothing), and `buildAccountInfoBody` has no rail logic at all. A
short WHY comment at the emission site records the distinction.

## The source/destination asymmetry

The spec puts `paymentRail` on the **destination**, but the visualizer's
only rail selector was on the **Source** card. So this adds a
destination-side selection rather than reusing the source's:

- `useFlowBuilder.ts`: `destRail` state, `SET_DEST_RAIL` action,
`setDestRail` callback — mirroring `sourceRail` exactly. Defaults via
the existing `getDefaultRail()` on `SET_RECEIVE`, and recomputed on
`SWAP` (matching how `sourceRail` already behaves there).
- `page.tsx`: Destination `InputCard` now gets `rail` / `onRailChange`.
`InputCard` already supported these generically, so no component changes
were needed beyond the display-name calls.
- Options stay constrained to the currency's `allRails` via the existing
`getFiatRailOptions`, per "must be one of the rails supported by the
destination account."

The existing source rail is untouched and keeps its display purposes.

`flow-path.ts`'s "Funds out via X" caption now uses the selected
destination rail instead of always defaulting to `instantRails[0]` —
same user choice, so it should reflect it.

## Judgment call worth a second opinion

**`paymentRail` is emitted only for external destinations**, in addition
to the "fiat and a rail selected" conditions. Funds credited to a Grid
internal balance never traverse an external payment rail, so sending one
there would generate an example the API would likely reject. This also
matches how `flow-path.ts` already treats rails (the "Funds out via"
caption only renders for `!next.isInternal`). A destination can become
internal via **Swap**. Happy to drop the gate if reviewers disagree.

Note the UI still shows a Rail row on an internal fiat destination card
even though it no longer affects the body — consistent with how the
Source card already behaves for internal sources. Hiding it felt like
scope creep; flagging rather than fixing.

## Verification — please read

**I could not run the real build.** `npm ci` in
`components/grid-visualizer` fails because `@central-icons-react`
requires a `CENTRAL_LICENSE_KEY` env var that is not available in this
environment. **The Vercel preview build on this PR is the real check** —
`next build` / `next lint` and all `.tsx` typechecking are unverified
here.

What I *was* able to verify locally:

- **Strict typecheck of every dependency-free module** —
`code-generator.ts`, `flow-path.ts`, `currencies.ts`,
`settlement-rails.ts`, `account-types.ts`, `crypto.ts` under `strict:
true` with the `@/*` path mapping: clean. The `.tsx` files could not be
checked (missing `react` / `next` / icon types).
- **Behavioral smoke test** of the compiled pure logic:
- `paymentRail` appears in the quote body with the enum value, and
changing the selection changes it (`SEPA_INSTANT` → `SEPA`)
- key **omitted entirely** (not null/undefined) when no rail is
selected, when the destination is crypto, and when the destination is
internal
- across every rail of every currency, no non-enum-looking value is ever
emitted
- "Funds out via" follows the selection, falls back to the default, and
renders display names
- all 23 `PaymentRail` members are covered by the display map, and every
rail value in `currencies.ts` is a valid enum member
- **Spec claims re-verified** against
`openapi/components/schemas/quotes/AccountDestination.yaml`,
`common/PaymentRail.yaml`, and the `*AccountInfo` /
`*ExternalAccountCreateInfo` split.

There is no test suite in `grid-visualizer` (no `test` script, no test
files), so no tests were added or updated.

Not verified: actual rendering, dropdown interaction, and that
`CodePanel`'s `stepsKey` remount behaves as intended in the browser
(`destRail` was added to both the memo deps and the key, so stale code
should be impossible, but this is untested at runtime).

## Files changed

- `src/data/currencies.ts` — enum rename + `railDisplayName()`
- `src/hooks/useFlowBuilder.ts` — `destRail` state/action/setter
- `src/lib/code-generator.ts` — `destRail` param, `paymentRail`
emission, display names in the JIT note
- `src/lib/flow-path.ts` — `destRail` param, "Funds out via" uses it,
display names
- `src/app/page.tsx` — wires `destRail` to the Destination card and both
panels
- `src/components/CodePanel/CodePanel.tsx` — `destRail` prop, memo deps,
`stepsKey`
- `src/components/FlowPanel/FlowPanel.tsx` — `destRail` prop, memo deps
- `src/components/InputCard/InputCard.tsx` — display names
- `src/components/CurrencyPicker/CurrencyPicker.tsx` — display names

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MMnjJ8yWJsui7jLqqrDrL4)_

Co-authored-by: Claude <noreply@anthropic.com>
shreyav pushed a commit that referenced this pull request Aug 4, 2026
Rebased onto main. INR_ACCOUNT still only exposed vpa in the visualizer
and UPI in the docs, while InrAccountInfoBase documents NEFT and RTGS
alongside it, with accountNumber, ifsc, rail and bankName.

- account-types.ts: adds the four NEFT/RTGS fields and marks which rail
  each belongs to
- currencies.ts: allRails gains NEFT and RTGS, both PaymentRail members
- country-support.mdx: India lists all three rails
- external-accounts.mdx: splits the India tab into UPI and NEFT/RTGS
  examples
- Kotlin sample: vpa was required, so a NEFT payload could not be built.
  All five fields are now optional, matching the pattern already used
  for GBP and SGD in the same file.

The GTQ and JMD changes from the original revision are dropped: both
landed on main through later syncs, and account-types.ts already
carries them.

Also dropped "paymentRails" from the two request examples. That field
is response-only - InrExternalAccountCreateInfo composes
InrAccountInfoBase, which does not define it, while InrAccountInfo does.
Sending it is the same mistake #351 made. Note this is distinct from
"rail", which is a genuine request field on the base schema. The Note
now says so explicitly, since having both names in one payload invites
exactly this confusion.

New curl blocks use -u rather than -H 'Authorization: Basic ...', which
does not survive copy-paste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMnjJ8yWJsui7jLqqrDrL4
shreyav pushed a commit that referenced this pull request Aug 4, 2026
## Summary

`InrAccountInfoBase` documents three rails for India — UPI, NEFT and
RTGS — but the visualizer exposed only `vpa` and the docs only UPI. This
syncs both, plus the Kotlin sample.

Rebased onto current `main` (`a1cd310`); the conflict is resolved and
the branch is a single commit.

| File | Change |
|---|---|
| `account-types.ts` | `INR_ACCOUNT` gains `accountNumber`, `ifsc`,
`rail`, `bankName`, each marked with the rail it belongs to |
| `currencies.ts` | `allRails` gains `NEFT` and `RTGS`; label becomes
`UPI / Bank Account` |
| `country-support.mdx` | India row lists all three rails |
| `external-accounts.mdx` | India tab split into UPI and NEFT/RTGS
examples |
| `samples/kotlin/.../ExternalAccounts.kt` | all five fields optional,
so a NEFT payload can be built |

## What changed in the rebase

**GTQ and JMD are dropped.** The original revision fixed `GTQ_ACCOUNT`
fields and added `bankName` to `JMD_ACCOUNT`. Both landed on `main`
through later syncs — `account-types.ts` already carries them — so those
hunks are gone and this is INR-only. The title has been narrowed to
match.

**`paymentRails` removed from both request examples.** The original
added `"paymentRails": ["UPI"]` and `["NEFT"]` to the create bodies.
That field is **response-only**: `InrExternalAccountCreateInfo` composes
`BaseExternalAccountInfo` + `InrAccountInfoBase` + `beneficiary`, and
none of those define it, while `InrAccountInfo` (the response wrapper)
does. Sending it is the same mistake #351 made.

This is worth care because **`rail` and `paymentRails` are different
things** and both are in play here. `rail` is a genuine request field on
`InrAccountInfoBase` — singular, the rail you want to route over.
`paymentRails` is the plural array Grid returns. Having both names in
one payload is exactly how the earlier confusion happened, so the
`<Note>` now states it outright.

**New curl blocks use `-u`.** The original used `-H 'Authorization:
Basic $GRID_CLIENT_ID:$GRID_CLIENT_SECRET'`, which fails on copy-paste
twice over — single quotes block variable expansion, and Basic auth
needs `base64(user:pass)` rather than the raw pair. #793 is fixing the
other 85 instances of this repo-wide.

## Verification

- Both India JSON payloads parse
- MDX component tags and code fences balance
- `UPI`, `NEFT`, `RTGS` all confirmed as `PaymentRail` enum members
- `account-types.ts` and `currencies.ts` typecheck clean under
`--strict`
- No `paymentRails` remains anywhere in `external-accounts.mdx`
- GTQ and JMD entries verified byte-unchanged from `main`

**Not verified — needs a reviewer who can build:**

- **The Kotlin sample does not compile here.** `.accountNumber()`,
`.ifsc()`, `.rail()` and `.bankName()` need to exist on
`InrExternalAccountCreateInfo.Builder` in the pinned Grid SDK version.
The `optText(...)?.let { }` pattern itself matches what the same file
already does for GBP and SGD, and `optText` is imported, but whether the
SDK exposes those four setters is unconfirmed. **If the SDK predates the
INR schema change, this hunk will not build** — worth checking before
merge.
- No visual render check. `npm ci` fails in this environment
(`@central-icons-react` needs `CENTRAL_LICENSE_KEY`), and `make lint` is
broken on `main` regardless (`npx spectral lint` resolves to a stub
`spectral@0.0.0`). The Mintlify and Vercel previews are the real checks.

## Possible conflict

#793 rewrites 26 auth lines in `external-accounts.mdx`. Whichever of
these merges second may need a trivial rebase; the overlap is auth lines
only, not the India tab.

Co-authored-by: Claude <noreply@anthropic.com>
shreyav added a commit that referenced this pull request Aug 4, 2026
## Summary

`external-accounts.mdx` documented **21 of the 45** account types in
`ExternalAccountType`. Because the page reads as an enumeration — a tab
per country or rail — a developer scanning it would reasonably conclude
the other 24 aren't supported. This documents all of them.

Docs-only, one file, +927 lines. Generated bundles untouched.

**Coverage is now 45/45**, verified by diffing the `accountType` values
in the page against `account-types.ts`.

| Added | Types |
|---|---|
| 18 fiat tabs | `AED` `BDT` `BWP` `CNY` `DKK` `EGP` `GHS` `GTQ` `HKD`
`HTG` `IDR` `JMD` `MYR` `PKR` `SGD` `THB` `VND` `XAF` |
| Cryptocurrency tab | Ethereum L1, Base, Polygon, Solana, Tron, Plasma,
Lightning — it previously showed Spark alone |

## Scope grew during the work — worth knowing

I started from a list of 17 missing types. A mechanical diff against
`account-types.ts` found **24**: `DKK`, `HKD`, `IDR`, `MYR`, `SGD`,
`THB`, `VND` and `LIGHTNING` weren't on my list. Stopping at 17 would
have reproduced the same partial-coverage problem in a PR whose entire
purpose is fixing it, so all 24 are here.

## Where the content comes from

Nothing is inferred from existing examples — each type was read from its
schema:

- **Fields and required/optional split** — `<Ccy>AccountInfoBase.yaml`
- **Beneficiary shape** — `<Ccy>Beneficiary.yaml`, which is where the
real variation lives. Most need only `fullName`, but **AED** and **JMD**
also require an `address`, **GTQ** requires `countryOfResidence` and
`phoneNumber`, and **JMD** requires `phoneNumber`. Those are easy to
miss and produce confusing validation failures.
- **Per-chain asset support** — each `Payment<Chain>WalletInfo.yaml`.
Ethereum carries `USDC` and `USDT`; Base and Polygon are USDC-only.
Stated per chain rather than assumed uniform.
- **Dual-rail currencies** (BDT, CNY, EGP, GHS, PKR) get separate
bank-transfer and mobile-money examples, following the existing Colombia
and El Salvador tabs.

**No example sends `paymentRails`.** It's response-only, and three
separate PRs (#351, #661, and the original #359 lineage) got that wrong.
The single occurrence of it in this file remains where it belongs — the
`GET` **response** example.

Example people match the entries added to `currencies.ts` in #791, so
the docs and the visualizer describe the same fictional customers.

## Verification

- **All 54 curl payloads in the file parse as JSON** — not just the new
ones
- **Every `accountType` used is a valid `ExternalAccountType` member**
- **Coverage diff is empty**: no type in `account-types.ts` is
undocumented
- MDX component tags and code fences balance
- All new curl examples use `-u`, consistent with #793
- `openapi.yaml` and `mintlify/openapi.yaml` byte-identical to `main`

**Not verified:** no visual render. This is 927 lines of new tabs, so
the **Mintlify preview is the meaningful review** — worth checking that
the tab strip doesn't overflow badly now that it holds 32 tabs. `make
lint` was not run; it fails on `main` regardless (`npx spectral lint`
resolves to a stub `spectral@0.0.0`).

## One thing this surfaces

`SWIFT_ACCOUNT` is documented here but **absent from
`account-types.ts`**, so the visualizer still can't produce it. That's
the known gap from closed #775 — the entry was correct but unreachable
without widening `FiatCurrency` past a single `accountType`. Unchanged
by this PR, but the asymmetry is now visible: the docs describe a type
the visualizer can't build.

## Left out deliberately

I had also listed adding SWIFT to `account-model.mdx`. **That item
doesn't hold up.** My earlier check used the wrong path — the file is at
`platform-overview/core-concepts/account-model.mdx`, not `snippets/`.
Looking at the real file, it's an explicitly illustrative page showing 8
representative types, not an enumeration. Singling out SWIFT there would
recreate the curated-list problem rather than fix one. Left alone.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MMnjJ8yWJsui7jLqqrDrL4)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
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