KYC: Feature - SumSub SDK integration - #2165
Merged
JohnathanWhite merged 1 commit intoAug 13, 2026
Merged
Conversation
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
3 times, most recently
from
May 12, 2026 20:27
ccdbe11 to
69c9860
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
5 times, most recently
from
May 21, 2026 13:28
9c14d4a to
bd34d72
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
from
May 22, 2026 13:09
bd34d72 to
9726f26
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
8 times, most recently
from
June 5, 2026 14:07
586b5e2 to
cdf165a
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
7 times, most recently
from
July 23, 2026 18:48
d785663 to
b2556e0
Compare
cmgustavo
marked this pull request as ready for review
July 23, 2026 18:52
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
3 times, most recently
from
July 30, 2026 19:12
fc9a5f3 to
c28c63f
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
5 times, most recently
from
August 3, 2026 20:44
34c2cd4 to
67d59ba
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
7 times, most recently
from
August 12, 2026 17:41
63d3000 to
79700d8
Compare
cmgustavo
force-pushed
the
feat/sumsub-sdk-integration-01
branch
from
August 12, 2026 18:55
79700d8 to
e9315ba
Compare
JohnathanWhite
approved these changes
Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Native identity verification (KYC) using the SumSub React Native MobileSDK (
@sumsub/react-native-mobilesdk-module).The backend exposes two signed
/api/v2RPC methods on thebitpayUserfacade (same channel as Device Intelligence'sgetDeviceAccessToken):BitPayIdApi.apiCall)getKycAccessToken{}nullwhen the user is not eligiblegetKycStatus{}KycStatusResponseobject (path,provider,tier,status,activeAttempt,legacy,applicantId)The signed token identifies the user server-side — no
userIdand nolevelNameare sent; the backend picks the level.Architecture
Backend object is the single source of truth
getKycStatusreturns the whole KYC object and we store it verbatim inSUMSUB.kyc[network]. There is no pre-mapped status field: every UI state is derived from the stored object insumsub.selectors.ts, so the mapping lives in exactly one place.Two separate status vocabularies
These are intentionally kept in separate fields because they are different vocabularies:
getKycStatus.status(camelCase):notStarted,inProgress,pendingReview,requiresAction,onHold,approved,rejected,suspended→ stored inSUMSUB.kyc..status(PascalCase):Initial,Incomplete,Pending,Approved,TemporarilyDeclined,FinallyRejected→ stored inSUMSUB.sdkStatus.sdkStatusis only a fallback signal while the backend lags behind a just-finished session (still reportsnotStarteduntil an applicant is submitted / the webhook lands). It is cleared automatically once the backend advances pastnotStarted.Derivation (
sumsub.selectors.ts)deriveKycUiState(kyc, sdkStatus)→KycUiState(notStarted | actionRequired | denied | inReview | success). The backend wins; while it's stillnotStartedthe SDK status fills the gap. Unknown in-flight backend states fall back toinReview(safe default — never a false verified/denied). Terminal SDK outcomes are capped atinReviewuntil the backend confirms.isKycEligibleToStart(kyc, sdkStatus)— the single gate for the "Get Verified" / "Verify Identity" prompt:path === 'sumsub'&&provideris null/unset or'sumsub'&&status === 'notStarted'&&tier === -1&& no in-progress SDK session. Thepath/providercheck excludes users of the previous (legacy) KYC provider; a fresh eligible user comes back withprovider: null(assigned only once they engage SumSub), so null counts as SumSub.Changes
apiCall('getKycAccessToken', {}). Backend returnsnullfor users with no shopper product / shopper tier 1 / already holding KYC tier ≥1; the app detects this and does not launch the SDK (no error shown). Silent token refresh viaonTokenExpired.apiCall('getKycStatus', {}), stored verbatim. Dispatched on app init (fetchInitialUserData), post-pairing (startPairAndLoadUser), and when the Verify Identity screen opens — so the status survives app restarts (SUMSUBis persisted) and reflects reviews completed outside the app. After the SDK closes it re-fetches the backend and, if the backend hasn't caught up, remembers the SDK's own status insdkStatus.isKycEligibleToStart), not once-only. A manual dismiss sticks for the session and the modal returns on the next launch. CTA →VerifyIdentity.KycBannerGate(already-started states), Settings → Security → Verify Identity, and the Profile Settings status pill.VerifyIdentity.SecureAccounttakes acontext: 'login' | 'signup'param;Login/VerifyEmailroute accordingly.VerifyIdentityrenders perKycUiState: first-time onboarding (notStarted),Action required+ "Resume Application" (actionRequired),In Review,Denied, andSuccess.SUMSUB—kyc+sdkStatusper network; reset on logout.Info.plist.Test Cases
1. Get Verified modal (eligible user)
getKycStatusreturnspath:"sumsub",provider:null,tier:-1,status:"notStarted").VerifyIdentity.2. Other entry points
3. SDK launch & permissions (iOS)
4. Happy path
getKycStatus; once the backend confirms, the banner/pill reflect the verified state.5. Status sync across restart (backend authoritative)
getKycStatusre-fetches the authoritative object → the banner/screen reflect it without reopening the SDK.6. Cancel mid-flow (backend-lag fallback)
Incomplete).notStarted, but the app remembers the SDK status separately, so:VerifyIdentityshows "Action required on your application" + "Resume Application" (NOT the first-time onboarding).7. Not-eligible users (no prompt)
pathis notsumsub, or whoseprovideris a different (non-null, non-sumsub) provider, gets no modal/prompt.8. Token refresh
onTokenExpired; the flow continues.Known / pending
onHoldandsuspendedcurrently fall into theinReviewdefault; their intended UI mapping is TBD (pending product confirmation) and can be given explicit cases later.