For the complete documentation index, see llms.txt. This page is also available as Markdown.

Shared-token KYC reuse

Onboard users whose KYC your platform already completed in its own Sumsub tenant, by sharing the verified applicant with UR through a Sumsub share token. UR copies the applicant, validates the data, a

This page documents the shared-token onboarding path: your platform runs a clone of UR's KYC workflow in your own Sumsub tenant, and once a user is approved you share that applicant with UR using a Sumsub share token. UR imports the applicant into UR's Sumsub tenant, validates the shared data, and takes the user to a Live UR Account.

Use this path when you already operate a Sumsub tenant and want to avoid making the user redo KYC. If you do not run a Sumsub tenant, use Managed Custody SDK KYC instead (UR hosts the Sumsub relationship and the SDK runs KYC on the user's device).

Shared-token reuse requires your partnerId to be provisioned for shared-token mode and paired with UR's Sumsub tenant. Coordinate with your dedicated integration channel before pointing production traffic at it. See §8 Prerequisites.

1. How it works

The compliance-grade KYC (including NFC document authentication) happens in your Sumsub tenant, running a workflow that UR clones from its own KYC level definitions during onboarding. That is the point at which the regulatory checks are performed.

When you hand the approved applicant to UR:

  1. Your backend mints a single-use share token scoped to UR's Sumsub clientId, valid for a short TTL (about 20 minutes).

  2. Your backend calls UR's handoff endpoint with that token.

  3. UR copies the applicant into UR's own Sumsub tenant (Sumsub "Copy Applicant") and performs data-level validation on the copied profile: completeness (all required fields present), document images and NFC data present, and eligibility (nationality / residency / age / document expiry). UR does not re-run AML/PEP or re-verify the documents; your cloned workflow already did that.

  4. UR returns a conclusive verdict for the attempt: passed, incomplete (remediable; the user must supply what's missing), or a non-remediable terminal rejection.

  5. On passed, the user signs Form A and your backend submits; UR provisions the account and activates it. On incomplete, the user completes the missing level in your Sumsub workflow and you hand off again.

Shared-token reuse is available for both account models:

Managed Custody (this page's primary flow)
External Wallet Access

Signing

Partner Auth (EIP-191), identity in X-Ur-Id header

Partner Auth (EIP-191), urId in the request body

Handoff endpoint

POST /api/fma/v1/kyc/reuse-share-token

POST /api/v1/sumsub/reuse-share-token

Poll / submit

/api/fma/v1/kyc/check, /kyc/form-a-info, /kyc/sign-form, /kyc/submit

/api/v1/sumsub/kyc-check, /api/v1/sumsub/kyc-submit

Form A signer

UR-managed custodial wallet

The user's own wallet

The rest of this page describes the Managed Custody flow. See §7 External Wallet variant for the differences.

2. End-to-end sequence

3. Integration walkthrough

3.1 Complete KYC in your Sumsub workflow

Run the user through the UR-cloned workflow in your Sumsub tenant. Present the required data-sharing declaration before identity verification and record the user's agreement; this is the user-facing legal basis for sharing the applicant with UR (see the required KYC disclosure). Only hand off applicants whose review answer is GREEN.

3.2 Create the UR Account

Call POST /api/fma/v1/create-account with X-External-User-Id and the user's email. UR mints (or reuses) the URID, provisions the UR-managed wallet, and returns sessionId, urId, evmAddress, and state = PartnerDataIngestion. You do not pass a Sumsub applicantId here; the applicant is delivered later through the handoff endpoint.

3.3 Mint a share token

After the applicant is GREEN, mint a single-use Sumsub share token scoped to UR's clientId. Mint a fresh token for every handoff attempt; Sumsub invalidates a token once it is used.

3.4 Hand off the applicant

Call POST /api/fma/v1/kyc/reuse-share-token with the shareToken in the body and X-Ur-Id set to the returned urId. UR previews the token (does not consume it), copies the applicant, validates the data, and returns a conclusive verdict synchronously:

  • status = passed: proceed to Form A.

  • status = incomplete with missingFields: the user must complete the missing data in your workflow, then hand off again with a new token.

  • A terminal rejection (e.g. AGE_UNDER_18, NATIONALITY_RESTRICTED): the session cannot proceed; this is non-remediable.

You may either read this synchronous response or consume the fma.kyc.reuse_check.result webhook (see §6.1); both carry the same verdict.

3.5 Poll completeness (optional)

POST /api/fma/v1/kyc/check with sessionId returns the last handoff attempt's verdict as a pure read (complete, state, missingFields). Use it as a fallback to the webhook. Poll every 30 seconds to 2 minutes; stop after /kyc/submit succeeds.

GET /api/fma/v1/kyc/form-a-info?sessionId=… returns the exact Form A text, its formAVersion, and a textHash. Display the text to the user and capture consent. If missingFields is non-empty, do not proceed.

3.7 Sign Form A

POST /api/fma/v1/kyc/sign-form with sessionId and the textHash from the previous step. UR signs Form A with the user's UR-managed custodial wallet and advances the session toward Register.

3.8 Submit

POST /api/fma/v1/kyc/submit with sessionId. UR runs the final register against the banking core asynchronously. When the account activates, UR sends the fma.account.result webhook with status = activated, and the UR Account reaches Live.

4. API reference

All endpoints use Partner Auth (EIP-191) as described in Managed Custody Mode §2.2. User-scoped endpoints identify the user with X-Ur-Id (or X-External-User-Id).

4.1 Create account

POST /api/fma/v1/create-account

Field
Required
Description

email

Yes

User email.

nationality

No

ISO-3166 alpha-3.

residency

No

ISO-3166 alpha-3.

dob

No

YYYY-MM-DD.

documentExpiry

No

YYYY-MM-DD.

Only email (plus the X-External-User-Id header) is required at this endpoint. nationality / residency / dob / documentExpiry are optional here; partners may submit them later via /kyc/sync-data, and the eligibility gates are deferred to /kyc/check, which re-validates over the merged staging snapshot before /kyc/submit.

Identity: send X-External-User-Id. Response data: sessionId, urId, evmAddress, state (PartnerDataIngestion for shared-token).

4.2 Hand off share token

POST /api/fma/v1/kyc/reuse-share-token · identity: X-Ur-Id

Field
Required
Description

shareToken

Yes

Single-use Sumsub share token, forClientId = UR's clientId.

Response data:

Field
Description

status

passed, incomplete, or terminal.

applicantId

The imported applicant ID in UR's tenant (present once copied).

attempt

1-indexed handoff attempt within this session.

missingFields

Present on incomplete; machine paths of the gaps.

The top-level envelope code is the authoritative outcome; data.status mirrors it: passedcode = 0; incompletecode = 20004; terminal (non-remediable) → a numeric eligibility code (30010 / 30011 / 30012, see §9). On both incomplete and terminal the envelope carries the non-zero business code and data.status set to the matching discriminator; branch on whichever your integration prefers.

4.3 Check

POST /api/fma/v1/kyc/check · identity: X-Ur-Id · body { "sessionId": "…" }

Pure read of the last handoff verdict. Response data: state, complete (bool), missingFields.

4.4 Get Form A

GET /api/fma/v1/kyc/form-a-info?sessionId=… · identity: X-Ur-Id

Response data: formAVersion, text, textHash (echo text/textHash into sign-form). This endpoint returns only these three fields.

4.5 Sign Form A

POST /api/fma/v1/kyc/sign-form · identity: X-Ur-Id · body { "sessionId": "…", "textHash": "0x…" }

Response data: state, signature, signerAddress (UR-managed wallet).

4.6 Submit

POST /api/fma/v1/kyc/submit · identity: X-Ur-Id · body { "sessionId": "…" }

Response data: state, queued. Register proceeds asynchronously; wait for the fma.account.result webhook.

5. Verdict & session state model

One handoff call = one attempt on one share token. Remediable failures are attempts within a living session; only non-remediable verdicts end the session.

Verdict
Session
What the user does next

passed

Advances to SignFormA

Sign Form A, submit

incomplete

Unchanged; attempt recorded

Complete the missing level in your workflow, mint a new token, hand off again

terminal (non-remediable)

Ends (subsequent handoffs return NO_ACTIVE_SESSION)

Nothing; the user is not eligible

The incomplete loop above is a retry within one onboarding session, driven by you. It is a different mechanism from the operations-initiated retry on Retry KYC, which applies to a user who is already onboarded and starts with POST /api/fma/v1/kyc/session/create after an fma.additional_kyc.required webhook.

6. Webhook contract

Webhooks are delivered per Webhooks (envelope {event, data, timestamp}, EIP-191 signed, X-Webhook-Request-Id idempotency). Subscribe your partnerId to both event types below. Two further events, fma.additional_kyc.required and fma.additional_kyc.completed, cover operations-initiated retries after the user is live; subscribe to those as well and see Retry KYC.

6.1 fma.kyc.reuse_check.result

The async mirror of a handoff attempt's verdict. Sent for passed and incomplete (terminal verdicts are not webhooked in v1). Idempotency business key: {urId}:kyc:reuse_check:{attempt}.

On status = passed, missingFields / requiredLevels are omitted. Partners that only act on remediation may ignore passed.

6.2 fma.account.result

Sent when the account activates after submit. Payload:

7. External Wallet variant

For External Wallet Access, the user holds their own wallet. The flow is the same, with these differences:

  • Auth / identity: Partner Auth signs the raw body; the urId travels in the request body, not the X-Ur-Id header.

  • Handoff: POST /api/v1/sumsub/reuse-share-token with { shareToken, urId }. The first handoff lazily creates the onboarding session.

  • Poll: POST /api/v1/sumsub/kyc-check.

  • Submit / Form A: POST /api/v1/sumsub/kyc-submit; the user signs Form A with their own wallet (there is no custodial signer).

The fma.kyc.reuse_check.result and fma.account.result webhooks are identical.

8. Prerequisites

One-time setup, coordinated with your UR integration channel:

  1. Partner pairing. Your platform and UR are configured as Donor / Recipient in Sumsub so your share tokens are accepted by UR's tenant.

  2. Cloned workflow. UR shares its KYC level definitions and Sumsub clones UR's KYC workflow (GPS / questionnaire / passport + NFC / liveness) into your tenant. Run users through this workflow so the shared applicant carries every field UR validates.

  3. Provisioning. Your partnerId is set to fmaMode = shared-token with a per-partner sourceKey, your signer address is registered, and your webhook subscriptions include fma.kyc.reuse_check.result and fma.account.result.

  4. Declaration. Your KYC flow presents the required data-sharing declaration and records the user's agreement before identity verification.

  5. Sandbox. Validate end to end against the testnet base URL before production.

9. Error codes

Business errors are returned with HTTP 200 and a non-zero code in the response envelope.

Code
Meaning
Action

20003

Invalid / missing parameter (e.g. shareToken, X-Ur-Id)

Fix the request.

20004

Session incomplete

Read missingFields; remediate and hand off again.

20011

Share token invalid

Mint a fresh single-use token (tokens invalidate on use).

30031

No active KYC session

Call /create-account first, or the session already ended (terminal).

30032

Session on the wrong channel

Confirm the partner is in shared-token mode.

30008

Identity already active in another session

The same identity is active in another session; resolve the existing one before reusing the identity.

30010

Nationality restricted (message: NATIONALITY_RESTRICTED)

Non-remediable eligibility rejection; the user is not eligible.

30011

Residency unsupported (message: RESIDENCY_UNSUPPORTED)

Non-remediable eligibility rejection; the user is not eligible.

30012

Age under 18 (message: AGE_UNDER_18)

Non-remediable eligibility rejection; the user is not eligible.

The eligibility codes are numeric in the envelope code; the string labels (NATIONALITY_RESTRICTED etc.) appear only in the human-readable message.

Last updated