Sumsub KYC Sharing

Import verified identity data from another Sumsub-integrated platform instead of requiring users to re-verify their identity.

Overview

When your users have already completed KYC verification on another platform that uses Sumsub, you can import their verified data using a share token. This eliminates redundant verification while still allowing you to collect any additional information your platform requires.

How it works:

  1. You obtain a share token from the platform where the applicant originally completed KYC (generated via Sumsub's API)
  2. You call the sharing endpoint with the token and applicant info
  3. Due imports the available data from Sumsub and creates a KYC submission (see Individual KYC process for how to work with submissions)
  4. If all submission requirements are satisfied, the submission completes automatically
  5. If additional data is needed, a submission remains open for you to complete via the API

Note: Sharing imports data — it does not guarantee KYC approval. The applicant will still go through Due's verification process. Listen for transfers.kyc.sumsub.status_changed webhook to receive the final KYC decision.

Important: Sumsub Data Sharing Limitations

When the response returns status: "resubmission_pending", it means some required data is missing — either because Sumsub didn't share it or because you didn't provide it in the request.

Sumsub controls what applicant data can be shared. Even if an applicant completed full KYC verification on another platform, Sumsub may not share:

  • Certain document types
  • Specific identity fields
  • Questionnaire responses
  • Verification results for particular checks

This is determined by Sumsub's policies and the original verification level. Due has no control over what data Sumsub chooses to share.

What this means for your integration

  1. Always handle resubmission_pending — Even with a valid share token from a fully verified user, you may still need to collect additional data

  2. Don't assume sharing will succeed — The err_kyc_sharing_not_possible error means Sumsub rejected the sharing request entirely. Have a fallback to standard KYC

  3. The submission shows what's missing — When sharing partially succeeds, the submission's requirements indicate exactly what data Sumsub didn't provide and what you need to collect

Prerequisites

  • Account must be individual type (business accounts not supported)
  • Account must not have an existing KYC status of passed or failed
  • Valid Sumsub share token generated via Sumsub's Generate Share Token API

Request

POST /v1/kyc/sharing/sumsub

Headers

HeaderRequiredDescription
AuthorizationYesBearer token.
Due-Account-IdYesThe account ID to perform KYC for.

Body

{
  "shareToken": "st_abc123...",
  "applicantInfo": {
    "nationality": "US",
    "phone": "+14155551234"
  },
  "questionnaire": {
    "templateId": "declarationsApi",
    "answers": [
      { "id": "is_pep", "value": "false" },
      { "id": "is_sanction", "value": "false" },
      { "id": "is_crime", "value": "false" }
    ]
  }
}

Required applicantInfo fields:

Due is legally required to collect the following data from applicants, which Sumsub currently cannot share:

  • nationality — Country of citizenship (ISO 3166-1 alpha-2)
  • phone — Contact phone number (E.164 format)
  • Tax residence country — Taken from the account's country field (set when calling Create account)

Parameters

FieldTypeRequiredDescription
shareTokenstringYesThe Sumsub share token.
applicantInfoobjectNoApplicant information. If omitted, submission will remain open for you to provide required data.
questionnaireobjectNoPre-filled questionnaire answers.

Why provide applicantInfo and questionnaire?

The shared Sumsub data may not include all the information your platform requires. When the sharing process creates a submission, the applicantInfo and questionnaire you provide are pre-filled into that submission. This means:

  • If all submission requirements are satisfied by the combination of Sumsub data + your pre-filled data, the submission completes automatically and the response returns status: "completed"
  • If some requirements are still missing, the response returns status: "resubmission_pending" with a submissionId for you to complete via the submissions API

Example:

If you provide applicantInfo and questionnaire, and Sumsub shares all required documents, the submission completes automatically.

If any data is missing — whether because you didn't provide it or because Sumsub didn't share it — the response is status: "resubmission_pending" and you need to complete the submission via the API.

Response

{
  "status": "completed",
  "submissionId": "ksub_..."
}
FieldTypeDescription
statusstringcompleted or resubmission_pending
submissionIdstringSubmission ID (always present)

Response Status Values

StatusDescriptionNext Step
completedAll submission requirements satisfied, submission completedAwait KYC decision via transfers.kyc.sumsub.status_changed webhook.
resubmission_pendingAdditional data neededComplete the submission via the submissions API.

Completing a Pending Submission

When the response status is resubmission_pending, the submission data is also sent via the transfers.kyc.submission.created webhook (see below). To fetch the submission manually:

response = requests.get(
    f'https://api.due.network/v1/kyc/submissions/{submission_id}',
    headers={
        'Authorization': f'Bearer {access_token}',
        'Due-Account-Id': account_id
    }
)
submission = response.json()

The requirements field shows what data needs to be provided. See the Individual KYC process guide for details on completing submissions.

Webhook Events

See Using Webhooks for general webhook setup and verification.

transfers.kyc.submission.created

Sent when a submission is created but requirements are not fully satisfied.

{
  "id": "wh_evt__...",
  "type": "transfers.kyc.submission.created",
  "data": {
    "ownerId": "acct_...",
    "submission": {
      "id": "ksub_...",
      "applicantId": "acct_...",
      "status": "open",
      "info": {
        "nationality": "US",
        "phone": "+14155551234"
      },
      "requirements": [],
      "documents": [],
      "questionnaires": [
        {
          "templateId": "declarationsApi",
          "answers": [
            { "id": "is_pep", "value": "false" },
            { "id": "is_sanction", "value": "false" },
            { "id": "is_crime", "value": "false" }
          ]
        }
      ]
    }
  },
  "occurredAt": "2026-02-04T22:28:35.398380671Z",
  "attemptedAt": "2026-02-04T22:28:35.40067069Z"
}

Errors

CodeHTTP StatusMessage
err_kyc_sharing_invalid_account_type422Only individual accounts are supported.
err_kyc_sharing_invalid_status409Sharing is unavailable for this account (kyc status = %status%).
err_kyc_sharing_state_terminal409Sharing reached its terminal state.
err_kyc_sharing_not_possible422Sharing is not possible.

Error Details

err_kyc_sharing_invalid_account_type

KYC sharing is only available for individual accounts. Business accounts must use the standard KYC flow.

err_kyc_sharing_invalid_status

The account already has a completed KYC with status passed or failed. Sharing cannot override an existing KYC decision.

err_kyc_sharing_state_terminal

The sharing process encountered an unexpected state and cannot proceed. Contact support if this occurs.

err_kyc_sharing_not_possible

Sumsub does not allow this applicant's data to be shared. There are many reasons Sumsub may reject a sharing request — invalid token, applicant not eligible for sharing, compliance restrictions, and others. When this occurs, the user must complete standard KYC verification instead.

Example Integration

RESULT=$(curl -s -X POST "https://api.due.network/v1/kyc/share/sumsub" \
  -H "Authorization: Bearer YOUR_API_KEY" \                                               
  -H "Due-Account-Id: ACCOUNT_ID" \                 
  -H "Content-Type: application/json" \                                                       
  -d '{                                                           
    "shareToken": "st_abc123...",
    "applicantInfo": {
      "nationality": "US",
      "phone": "+1234567890"
    }
  }')

STATUS=$(echo "$RESULT" | jq -r ".status")

# Step 2 - Check result
if [ "$STATUS" = "completed" ]; then
  # Submission completed — await transfers.kyc.sumsub.status_changed webhook for KYC decision
  echo "Pending review"
elif [ "$STATUS" = "resubmission_pending" ]; then
  # Some required data is missing — complete the submission
  echo "Submission ID: $(echo "$RESULT" | jq -r ".submissionId")"
  echo "Action: complete_submission"
else
  CODE=$(echo "$RESULT" | jq -r ".code")
  if [ "$CODE" = "err_kyc_sharing_not_possible" ]; then
    # Sumsub rejected sharing — fall back to standard KYC
    echo "Sharing rejected — start standard KYC"
  else
    echo "Error: $RESULT"
  fi
fi
import requests

API_BASE = "https://api.due.network"
API_KEY = "YOUR_API_KEY"

def onboard_with_shared_kyc(account_id: str, share_token: str, user_info: dict) -> dict:
    try:
        response = requests.post(
            f"{API_BASE}/v1/kyc/share/sumsub",
            headers={
                "Authorization": f"Bearer {API_KEY}",
                "Due-Account-Id": account_id,
                "Content-Type": "application/json"
            },
            json={
                "shareToken": share_token,
                "applicantInfo": {
                    "nationality": user_info["nationality"],
                    "phone": user_info["phone"]
                }
            }
        )
        response.raise_for_status()
        result = response.json()

        if result["status"] == "completed":
            # Submission completed — await transfers.kyc.sumsub.status_changed webhook for KYC decision
            return {"status": "pending_review"}

        if result["status"] == "resubmission_pending":
            # Some required data is missing — complete the submission
            return {
                "status": "incomplete",
                "submission_id": result["submissionId"],
                "action": "complete_submission"
            }

    except requests.HTTPError as e:
        error = e.response.json()
        if error.get("code") == "err_kyc_sharing_not_possible":
            # Sumsub rejected sharing — fall back to standard KYC
            return {
                "status": "sharing_rejected",
                "action": "start_standard_kyc"
            }
        raise