# scripts

## CN-CNY bank code dataset

`build_cn_cny_bank_codes.py` builds the China lookup dataset,
`static/products/payments-direct-2/data-requirements/china-cny-ripple-bank-codes.json`.

CN-CNY was withdrawn from v2026.03, but the dataset is published anyway and
the Bank Codes utility reads it: the codes are available for reference ahead
of the corridor, as they are for Indonesia, Singapore and Vietnam.

```bash
python3 scripts/build_cn_cny_bank_codes.py          # dry run, prints counts
python3 scripts/build_cn_cny_bank_codes.py --write  # write the JSON
python3 scripts/build_cn_cny_bank_codes.py --check  # verify, write nothing
```

Source of truth is the `ripple-bank-codes` repo, read from a sibling checkout.
Run this after any CN/CNY change there, otherwise the published lookup drifts
from the master.

`--check` re-derives the dataset and compares it to the published JSON, exiting
non-zero if they disagree. It reports the difference per bank code rather than
as a line diff, since a line diff across 3,437 rows buries the change, and it
distinguishes a genuine content difference from a row-order or formatting one.

The CN master carries no Chinese bank names, so the script reconstructs them by
joining the Hanshan and LianLian partner mappings. Its own header documents that
join and the English-name fallback, which should match nothing; the script
prints the fallback count so a regression is visible.

## SG-SGD MEPS SWIFT codes

`build_singapore_swift_codes.py` builds
`static/products/payments-direct-2/data-requirements/singapore-swift-codes.json`
from the ADR, for the Bank Codes utility's Singapore entry.

```bash
python3 scripts/build_singapore_swift_codes.py          # dry run, prints counts
python3 scripts/build_singapore_swift_codes.py --write  # write the JSON
python3 scripts/build_singapore_swift_codes.py --check  # verify, write nothing
```

The PII v3 spec constrains `sg-meps.swiftCode` to "the DBS-supported Singapore
SWIFT code list published on Ripple Docs", but that list was never published.
`singapore-bank-codes.json` is a different thing: GIRO participant codes, which
are numeric and never match the BIC pattern the field enforces. The list the
spec means is the enumerated `fieldValues` of DBS's `CdtrAgt.FinInstnId.BICFI`
in `data-requirements/adr/SG/SGD/*/SG_SGD_RTGS/dbs-*.csv`, which is what this
script publishes.

The script refuses to publish if the six DBS use-case files disagree, if any
value is not BIC format, if a BIC repeats, or if the parsed list is empty, so a
source change fails loudly rather than quietly shipping.

Note that `SG_MEPS` is not yet an accepted `financialInstrumentType`, so this
list is published for reference ahead of the corridor, the same way Japan and
China CNY are.

## PH-PHP SWIFT codes (withdrawn)

`build_philippines_swift_codes.py` builds
`static/products/payments-direct-2/data-requirements/philippines-swift-codes.json`
from the Thunes ADR: 120 BICs, the list Paul Keller asked for in DLV-488
item 5 so that `swiftCode` is not free text.

PH-PHP was pulled from the 2026-09-30 release because Product wants both
Thunes and Chinabank live before launch. The dataset is therefore not in the
repo and the Bank Codes utility does not read it. The script is kept to
regenerate it when the corridor returns.

```bash
python3 scripts/build_philippines_swift_codes.py          # dry run
python3 scripts/build_philippines_swift_codes.py --write  # write the JSON
python3 scripts/build_philippines_swift_codes.py --check  # verify, write nothing
```

Note that the list covers Thunes only. Chinabank's ADR uses
`CdtrAgt.FinInstnId.Othr.Id`, a different identifier namespace, so a
Thunes-and-Chinabank corridor needs both resolved before this is republished.

## VN-VND Ripple Bank Codes

`build_vietnam_ripple_bank_codes.py` builds
`static/products/payments-direct-2/data-requirements/vietnam-ripple-bank-codes.json`
from the `ripple-bank-codes` repo, for the Bank Codes utility's Vietnam entry.

```bash
python3 scripts/build_vietnam_ripple_bank_codes.py          # dry run
python3 scripts/build_vietnam_ripple_bank_codes.py --write  # write the JSON
python3 scripts/build_vietnam_ripple_bank_codes.py --check  # verify, write nothing
```

VN-VND uses Ripple Bank Codes rather than a partner's own codes, so one
identifier covers TP Bank, Tranglo and Thunes. Published early for testing:
`VN_BANK_PAYOUT` is not yet an accepted `financialInstrumentType`, and the
pii-service change that swaps VN's `swiftCode` for an RBC-accepting `bankCode`
is not merged.

Not to be confused with the retired `vietnam-bank-codes.json`, which held
domestic NAPAS codes. Those are Tranglo's own namespace, pulled live from their
API by the payout service, and are not what a customer sends.

The source CSV does not quote its fields, so a bank name containing a comma
splits across columns and shifts the rest of the row. 10 of 95 rows are
affected. The script parses positionally against the `VN` country_code marker
and rejoins the name, rather than using a plain CSV reader, which would
silently truncate those names. Remove that handling once the source is fixed.

## Corridor data requirements pages

`generate_corridor_pages.py` builds the six v2026.03 African corridor pages
(GH, NG, RW, UG, ZA, ZM) under
`products/payments-direct-2/@v2026.03/api-docs/integration-resources/emea/`.
`corridor_page_sources.py` holds the source readers and the Markdoc table
helper.

```bash
python3 scripts/generate_corridor_pages.py            # regenerate all six
python3 scripts/generate_corridor_pages.py GH ZA      # regenerate some
python3 scripts/generate_corridor_pages.py --check     # verify, write nothing
```

Requires `pyyaml`. Paths resolve relative to the script, so it works from any
checkout of the RPD2 monorepo; set `RPD2_ROOT` if your checkout lives
elsewhere.

`--check` re-derives every page and diffs it against what is on disk, exiting
non-zero if they disagree. Run it after either source system changes to find
out whether the published pages have gone stale.

### Sources and precedence

| Content | Source of truth |
|  --- | --- |
| Identity requirements | PII v3 spec (`pii-service` `payment-participants.yaml`) |
| Financial instrument requirements | PII v3 spec |
| Transaction requirements, purpose codes | ADR (`data-requirements/adr`) |


Deviations between the two are expected, and PII v3 wins for identity and
financial instrument data. The ADR is the PII v2 view: its `Cdtr.*` and
`Dbtr.*` fields are ISO 20022 renderings of data that v3 carries inside the
identity and financialInstrument objects. PII v3 does not use the ISO field
names, so those fields are deliberately absent from the generated pages.
`Purp.Cd` is the only ADR field set on the payment itself, and v3 names it
`purposeCode`.

Nothing is inferred. A constraint absent from both sources is omitted rather
than guessed at, and the table helper refuses to emit a table with no rows, so
a broken lookup fails loudly instead of publishing an empty section.

Two tables in `generate_corridor_pages.py` are hand-maintained rather than read
from a source system, each with a comment citing where it came from:

- `LIVE_PARTNERS` restricts each corridor to the partners that actually serve
it. The ADR also carries files for partners that are not live, and without
this their requirements would leak into the published tables.
- `SUPPORTED_USE_CASES` records the commercially supported use cases. DRE
carries routing rules for all six use cases in every African corridor, but
routing config is not the same as a supported offering. ZA is C2B2C only.


### Known upstream defect

In every African corridor the ADR has the description, help text and
`maxLength` attached to the wrong one of `CdtrAgt.FinInstnId.Nm` and
`CdtrAgt.FinInstnId.Othr.Id`. The enum values prove the swap: `Othr.Id` carries
codes while `Nm` carries names. The lengths are wrong too, with `Nm` capped at
20 while 17 of its own 47 values run longer, up to 49 characters. Raised with
CPE 2026-09-09. This does not affect the generated pages, which take bank name
and bank code from the PII v3 financial instrument schema, but it will matter to
anything that reads those two ADR fields.