Why
The card application failed on staging for a new user (2026-10-09). KeySecure /cardholder/apply answered 2012 · KYC submission name is illegal.
- KeySecure reads the cardholder name from the Sumsub applicant
fixedInfo.KycService.buildFixedInfohad prefilled that name from the signup name, which contained a Vietnamese diacritic. - A hyphen also triggers 2012. A name of letters and single spaces is accepted. This was confirmed by patching the applicant by hand on staging: the apply then succeeded and the row went to IN_REVIEW.
- Our code mapped every 2012 to
PROOF_OF_ADDRESS_REQUIREDand dropped the provider message. The app showed "Application on hold" with no button, and the user could do nothing.
What changes
-
Name rule
^[A-Za-z]+( [A-Za-z]+)*$applies in signup, profile edit and the card form, in the app and in the server DTOs (IsLatinName). The forms check on change. Sumsub gets the signup name only when it obeys the rule. -
The card form is separate from KYC. It always asks for every card detail: first and last name, gender, address with a required postcode, and phone. Nothing is prefilled from KYC. Before each apply the server writes these values to the Sumsub
fixedInfo. -
The last submitted values are stored in the new
keysecure_cardholders.profilecolumn (jsonb, nullable; migration1790500000002). GET returns them, so after a refusal the form opens prefilled. Resend posts the stored profile. -
A 2012 refusal is classified from its message into
NAME_INVALID,VERIFICATION_FAILED,ADDRESS_INVALID,PHONE_INVALIDorDETAILS_INVALID. The message itself is never stored or logged; only the code goes into the log. -
Fail kinds in the app: every fixable reason, including the legacy
PROOF_OF_ADDRESS_REQUIRED, shows "Update details". OnlyVERIFICATION_FAILEDandUNIQUE_NO_MISMATCHstay on hold.
Deploy order (important)
- Deploy the BE first.
- Ship the FE (OTA staging) right after.
Old app builds POST {} or a partial body. The new BE answers that with 400, so on an old build the user cannot apply or retry until the app updates. The new FE tolerates an old BE: profile defaults to null.
Release note: users whose stored name has accents (from signup, or from KYC sync of the ID) must retype it in plain letters before they can save the profile form.
Verification
- be: the keysecure-cardholder, sumsub, kyc, users, auth and common suites pass (458 tests).
yarn buildis clean. Every new test was mutation-checked. - fe: the cardholder, create-account and update-account suites pass.
pnpm type-checkandpnpm lintare clean. New tests were mutation-checked. - Opus gate: PASS after 2 rounds, with 0 blocking findings. The round-1 should-fixes were fixed:
profilenullable default,mode: 'onChange', and word boundaries inclassify2012. The Sumsub fixedInfo PATCH on a GREEN applicant was checked by hand on staging (HTTP 200, still GREEN, apply then succeeded). - After merge: run one staging E2E through the new code with an accented signup name, then submit "Nguyen Van A" and expect IN_REVIEW.