Why
The Airwallex PERSONAL beneficiary was created with account_name set to the holder name the user typed, but first_name/last_name taken from KYC. If the user typed a different holder name, Airwallex got a beneficiary whose first and last name contradicted its account name.
What
-
BE:
-
splitHolderNamederives the first and last name from the typed holder name: the last word is the last name, and the rest is the first name. - KYC is still loaded. It gates on an approved KYC and supplies the address and country.
-
CreateBankBeneficiaryDto.accountNamenow needs at least two words, and the last word must contain a letter. Otherwise it returns 400accountName must include a first and last name. - The split runs before the provider call, outside the
trythat maps errors toPAYOUT_UNAVAILABLE.
-
-
FE:
- The add-bank screen enforces the same rule, with the same regex as the BE and an i18n error message. The holder field is still prefilled with the KYC name and can be edited.
- The Checking/Savings pills are now a proper radio group:
radiogroupcontainer,radio+accessibilityState.checked.
- No migration, no new column, and no change to the API shape beyond the stricter validation.
Tests
- BE:
yarn jest src/modules/fiat-payoutpasses (223 tests).yarn buildand eslint are clean. - FE:
pnpm jest src/components/withdraw src/utilspasses (112 tests).tscand eslint are clean. - Every new assertion is mutation-checked, including the edge cases
"Ada Lovelace ."(rejected) and"Ada . Lovelace"(accepted) on both sides.
Opus review gate: PASS after 2 rounds. Round 1 raised 1 should-fix (an unanchored two-word regex let a junk last name such as "-" through), which is fixed.
Parked, not fixed here:
- A generational suffix becomes the last name, for example
"John Smith Jr."gives last nameJr.. Whether to special-case it is a product decision. -
VerifiedName.firstName/lastName/fullNameare no longer read in production, butloadVerifiedNamestill raisesKYC_NAME_MISSING. Clean this up later. - The doc comment on
hasFirstAndLastName(fe/src/utils/bank-account-name.ts:11) overstates what it checks on its own.
Also related: staging now charges a payout fee of FIAT_PAYOUT_FEE_USD=3.00 (Airwallex charges $3 per transfer). This is env only, with no code change.