Skip to content

Fix KYC provider routing for users with unresolved country - #2521

Merged
MusabShakeel576 merged 1 commit into
masterfrom
claude/vibrant-cannon-8op2gb
Sep 15, 2026
Merged

MusabShakeel576 merged 1 commit into
masterfrom
claude/vibrant-cannon-8op2gb

Conversation

@MusabShakeel576

Copy link
Copy Markdown
Contributor

Summary

This PR fixes a critical issue where users with no stored country and undetectable IP geolocation were being incorrectly routed to the Didit (Rain) card provider, even when they should be routed to Wirex. The fix ensures that when country cannot be resolved, users are prompted to select their country before proceeding with card verification.

Key Changes

  • Export resolveRoutingCountry function: Made the country resolution logic available to the Didit session creation flow so both the client and server can reach the same routing decision.

  • Pass country code to Didit session: Modified createDiditSession to accept and send an optional countryCode parameter. This allows the backend to refuse card applications in markets where Wirex is the correct provider, preventing users from being permanently pinned to Rain.

  • Add country selection gate in card flow: Added a check in useCardSteps that routes users to the country selection screen when no country can be resolved (neither stored nor detected via IP lookup). This prevents silent fallback to Didit for unresolved users.

  • Handle CARD_PROVIDER_MISMATCH error: Added error handling in useDiditSession for the CARD_PROVIDER_MISMATCH response code (400), which occurs when the server refuses a card application because the user's country routes to Wirex. Users are redirected to the country selection screen to re-route correctly.

  • Add test coverage: Comprehensive test suite for resolveRoutingCountry covering stored country usage, IP lookup fallback, undefined resolution, and persistence behavior.

Notable Implementation Details

  • The country resolution is only sent to Didit for the 'card' flow, not for 'va' (virtual account) or 'onramp' flows, as those have their own country lists.
  • IP-detected countries are intentionally not persisted to the store, allowing users to confirm their actual residence on the country selection screen.
  • The fix addresses a specific edge case: newly created accounts with no stored country and failed IP detection would silently default to Didit, creating permanent Rain card customers that could never be corrected.

https://claude.ai/code/session_01Xq9bCus4z9sv4FH19v1xgu

The card flow falls back to Didit whenever it cannot resolve a country or
the routing call fails, because Didit is available everywhere. That was
safe while the server questioned nothing — and it was not: a Didit session
creates a card customer defaulting to Rain, and nothing ever rewrites it.
Users in markets Wirex is supposed to win (Thailand, Brazil, Kenya, the
US) were landing on Rain for good on the strength of one failed IP lookup.

Three changes, matching the server guard that now refuses these:

- The card flow sends its country on the Didit session, resolved by the
  same `resolveRoutingCountry` the routing call uses — so the server can
  refuse a Wirex market. Both callers must agree or the client is routed
  to Didit and then refused by it. The onramp and virtual account send
  none: they run off their own country lists and are not card
  applications.
- CARD_PROVIDER_MISMATCH sends the user to the country screen, exactly as
  the Sumsub side already does for the mirror case. It re-asks routing on
  the way through and persists the country picked, so the round trip
  settles instead of repeating; pushing straight at the Sumsub screen
  would only bounce off its own COUNTRY_REQUIRED.
- With no country resolvable at all, the card flow asks rather than
  guessing. Only reached when the IP lookup failed too — a country that
  resolves still goes straight through, so no one gains a step.

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

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown

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

2 Skipped Deployments
Project Deployment Actions Updated
solid-app Ignored Ignored Sep 15, 2026 8:17am UTC
solid-app-staging Ignored Ignored Sep 15, 2026 8:17am UTC

Request Review

@MusabShakeel576
MusabShakeel576 merged commit 183270d into master Sep 15, 2026
6 checks passed
@MusabShakeel576
MusabShakeel576 deleted the claude/vibrant-cannon-8op2gb branch September 15, 2026 08:52
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.

2 participants