End-to-End DocV Integration

End-to-end examples for all Predictive Document Verification (DocV) flows—Document Verification, Secondary Document Capture, Selfie Intelligence, and Selfie Reverification—covering the Evaluation API, SDK/Hosted launch, webhooks, and final decision.

Before you begin

Get your API key and SDK key from the API & SDK Keys page in the RiskOS™ Dashboard.

Configure a workflow with a Document Request step to trigger DocV as a step-up enrichment.

Create and publish a Capture App flow in the RiskOS™ Dashboard for your target flow type (Document Verification, Secondary Document Capture, Selfie Intelligence, or Selfie Reverification).

Configure a webhook endpoint to receive evaluation_completed and case_notes_added events.

Integrate the Predictive DocV SDK (for native SDK flows) or configure a Hosted Flow (for web-based flows).

📘

Note:

This guide uses Sandbox endpoints. Replace riskos.sandbox.socure.com with riskos.socure.com when you move to production.


Choose a flow type

Predictive DocV supports four flow types. Each follows the same integration pattern (evaluate → step-up → capture → webhook → decision) but differs in what the consumer captures and what the enrichment response contains.

Flow typeWhat the consumer capturesEnrichment response objectWhen to use
Document VerificationGovernment-issued ID + selfiedocumentVerificationOnboarding, KYC, full identity verification
Secondary Document CaptureSupporting documents (utility bills, bank statements, etc.)secondaryDocumentProof of address, compliance, fraud review
Selfie IntelligenceLive selfie onlyselfieIntelligenceAge checks, liveness verification, trust & safety
Selfie ReverificationLive selfie compared to a prior DocV headshotselfieReverificationReturning user re-authentication, high-risk transactions

Choose an integration method

For each flow type, you can launch the capture experience using a native SDK or the Hosted Capture App:

MethodDescriptionBest for
Native SDK (iOS, Android, React Native, Web)Embed the DocV capture UI directly in your app using the DocV SDK.Mobile-first apps that need a tightly integrated experience.
Hosted Capture App (URL / QR / SMS)Redirect the consumer to Socure's hosted web-based Capture App via URL, QR code, or SMS link. No SDK integration required.Web-first flows, desktop-to-mobile handoff, or when you prefer a no-SDK approach.

Both methods use the same Evaluation API call and return the same webhook events and enrichment responses. The difference is in Step 4 — how the consumer accesses the capture flow.



Integration steps

All four DocV flow types follow the same seven-step pattern. Flow-specific differences are called out inline.

sequenceDiagram
    participant App as Your App
    participant RiskOS as RiskOS™
    participant DocV as DocV Capture
    participant Consumer

    App->>RiskOS: POST /api/evaluation (PII + docv.config)
    Note right of RiskOS: Evaluation pauses at<br/>Document Request step
    RiskOS-->>App: decision: REVIEW, status: ON_HOLD<br/>docvTransactionToken, url, qrCode

    alt Native SDK (iOS, Android, React Native, Web)
        App->>DocV: Launch SDK with docvTransactionToken
        DocV->>Consumer: Present capture UI
    else Hosted Capture App (URL / QR / SMS)
        App->>Consumer: Send capture link (URL, QR, or SMS)
        Consumer->>DocV: Open Capture App
    end

    alt Document Verification
        Consumer->>DocV: ID front + ID back + selfie
    else Secondary Document Capture
        Consumer->>DocV: Upload supporting document
    else Selfie Intelligence / Selfie Reverification
        Consumer->>DocV: Capture live selfie
    end

    DocV->>RiskOS: Submit captured media
    Note right of RiskOS: Workflow resumes

    loop During capture
        RiskOS-->>App: Webhook: case_notes_added
    end

    RiskOS-->>App: Webhook: evaluation_completed (ACCEPT / REJECT)

    App->>App: Route consumer based on decision

Step 1: Configure the DocV flow

Create and publish a Capture App flow for your target flow type in the RiskOS™ Dashboard under Settings > DocV App > Flow. Each flow type presents a different capture experience to the consumer:

Flow typeCapture screens
Document VerificationSplash → Consent → ID front → ID back → Selfie → Confirmation
Secondary Document CaptureSplash → Consent → Document upload (camera or file) → Preview → Confirmation
Selfie IntelligenceSplash → Consent → Selfie capture → Selfie preview → Confirmation
Selfie ReverificationConsent → Selfie capture → Selfie preview → Confirmation

After publishing, note the use_case_key assigned to your flow. You pass this value in the API call to select the correct flow. If you omit use_case_key, RiskOS™ uses the flow marked as Default.

See Capture App configuration for setup instructions, or configure a Hosted Flow for a web-based experience.


Step 2: Call the evaluation API

Submit consumer PII to the RiskOS™ evaluation endpoint. Include the docv configuration object to specify your Capture App flow settings.

curl --location 'https://riskos.sandbox.socure.com/api/evaluation' \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data-raw '{
    "id": "APP-123456",
    "timestamp": "2025-07-31T15:00:10.761Z",
    "workflow": "consumer_onboarding",
    "data": {
      "individual": {
        "given_name": "John",
        "family_name": "Smith",
        "date_of_birth": "1989-05-07",
        "phone_number": "+19998887777",
        "address": {
          "line_1": "1234 N College Ave",
          "locality": "New York City",
          "major_admin_division": "NY",
          "country": "US",
          "postal_code": "10001"
        },
        "docv": {
          "config": {
            "document_type": "license",
            "send_message": true,
            "language": "en-us",
            "redirect": {
              "method": "POST",
              "url": "https://example.com/docv"
            }
          }
        }
      }
    }
  }'
FieldTypeRequiredDescriptionExample
docv.config.document_typeStringOptionalDocument type to capture."license" or "passport"
docv.config.use_case_keyStringOptionalSpecifies the Capture App flow. If omitted, RiskOS™ uses the flow marked as Default."my_docv_flow"

The following fields are common to all flow types:

FieldTypeRequiredDescriptionExample
idStringRequiredCustomer-defined unique identifier for the request. Must be unique per evaluation. Reuse may cause re-run behavior and impact results."APP-123456"
workflowStringRequiredThe name of the RiskOS™ workflow to execute."consumer_onboarding"
docv.config.send_messageBooleanOptionalSet to true to send an SMS link to the consumer.true
docv.config.languageStringOptionalLanguage code for the Capture App."en-us"
docv.config.redirectObjectOptionalWhere to redirect the consumer after capture completes.{ "method": "POST", "url": "https://..." }
📘

Note:

If use_case_key contains an invalid value, the SDK returns an Invalid Request error.


Step 3: Receive the docvTransactionToken

When the workflow includes a Document Request step, RiskOS™ pauses the evaluation and returns a response with these indicators:

  • decision is "REVIEW"
  • status is "ON_HOLD"
  • eval_status is "evaluation_paused"
  • data_enrichments contains an object where enrichment_provider is "SocureDocRequest"
{
  "id": "APP-123456",
  "workflow": "consumer_onboarding",
  "eval_id": "d48bcc0e-ab3c-43a4-b03e-67208458ec62",
  "decision": "REVIEW",
  "status": "ON_HOLD",
  "eval_status": "evaluation_paused",
  "data_enrichments": [
    {
      "enrichment_provider": "SocureDocRequest",
      "status_code": 200,
      "response": {
        "data": {
          "docvTransactionToken": "1e89eec0-f7a3-4210-b74b-a76bc9556c50",
          "url": "https://verify.socure.com/#/dv/1e89eec0-f7a3-4210-b74b-a76bc9556c50",
          "qrCode": "data:image/png;base64,iVBORw0KGgo..."
        },
        "referenceId": "3639f9ad-e1fe-4e3e-9202-18faf20ace56"
      }
    }
  ]
}

Extract the handoff assets from data_enrichments[n].response.data:

FieldTypeDescriptionExample
docvTransactionTokenStringAlways returned. Pass this token to the DocV SDK to start document capture."1e89eec0-f7a3-4210-b74b-a76bc9556c50"
urlStringDirect URL to the Capture App. Use for Hosted flows or redirect flows."https://verify.socure.com/#/dv/1e89eec0-f7a3-4210-b74b-..."
qrCodeStringBase64-encoded PNG for desktop-to-mobile handoff (Hosted and web flows). May not be returned."data:image/png;base64,iVBORw0KGgo..."
📘

Note:

Persist the eval_id and docvTransactionToken in your backend. You need the eval_id to correlate the webhook result with this evaluation.

This response is identical for all four flow types. The use_case_key you specified in Step 2 determines what the consumer sees during capture.


Step 4: Launch the capture experience

Pass the docvTransactionToken to the DocV SDK or redirect the consumer to the Hosted Capture App. The use_case_key from Step 2 controls which capture flow the consumer sees — the launch code is the same regardless of flow type.

func startDocVCapture(token: String) {
    let options = SocureDocVOptions(
        publicKey: "YOUR_SDK_KEY",
        docVTransactionToken: token,
        presentingViewController: self,
        useSocureGov: false
    )

    SocureDocVSDK.launch(options) { (result: Result<SocureDocVSuccess, SocureDocVFailure>) in
        switch result {
        case .success(let success):
            print("Capture complete. Session token: \(success.deviceSessionToken ?? "N/A")")
        case .failure(let failure):
            print("Capture failed: \(failure.error)")
        }
    }
}
ParameterTypeRequiredDescriptionExample
publicKeyStringRequiredThe SDK key obtained from the RiskOS™ Dashboard, used to authenticate and initialize the DocV SDK."YOUR_SDK_KEY"
docVTransactionTokenStringRequiredToken from the evaluation response."1e89eec0-..."
presentingViewControllerUIViewControllerRequiredThe view controller that presents the SDK.self
useSocureGovBoolOptionalSet to true for GovCloud. Defaults to false.false
📘

Note:

After the capture experience launches, the consumer completes document capture without further backend interaction. RiskOS™ automatically resumes the paused evaluation when capture finishes or the session expires.


Step 5: Consumer completes verification

The consumer interacts with the capture UI presented by the SDK or Hosted Capture App. No backend action is required during this step — the SDK handles the entire capture flow based on the use_case_key.

Flow typeWhat the consumer captures
Document VerificationFront and back of a government-issued ID, then a selfie
Secondary Document CaptureSupporting document (camera capture or file upload)
Selfie IntelligenceLive selfie
Selfie ReverificationLive selfie (compared to a prior DocV headshot)

Step 6: Handle webhooks

RiskOS™ sends webhook events to your configured endpoint as the capture progresses and when the evaluation completes. See DocV webhooks for the full event reference.

Capture progress events (case_notes_added)

These lightweight events track capture milestones. They do not contain PII.

EventApplicable flow typesDescription
Process InitiatedAllConsumer has been redirected to the Capture App.
Capture App OpenedAllConsumer opened the Capture App.
Document Front UploadedDocument VerificationFront image of the document has been uploaded.
Document Back UploadedDocument VerificationBack image of the document has been uploaded.
Document Selfie UploadedDocument Verification, Selfie Intelligence, Selfie ReverificationSelfie image has been uploaded.
Documents Upload SuccessfulAllAll required images have been uploaded.
Session CompleteAllThe capture session has completed.
Consent DeclinedAllThe consumer declined consent (terminal).
Session ExpiredAllThe capture session expired (terminal).
📘

Note:

Filter case_notes_added events by checking that data.reviewer_id equals "Webhook". This excludes notes added by manual reviewers.

Final evaluation result (evaluation_completed)

After capture and verification complete, RiskOS™ delivers the final decision via the evaluation_completed webhook. The top-level data.decision (uppercase: ACCEPT, REVIEW, REJECT) represents the workflow decision. The enrichment-specific result is nested inside data.data_enrichments.

{
  "event_type": "evaluation_completed",
  "event_id": "3b31289c-2d4a-4107-80bc-dda63031d5a0",
  "event_at": "2025-07-17T01:20:01Z",
  "data": {
    "eval_id": "11111111-2222-3333-4444-555555555555",
    "id": "client-transaction-12345",
    "workflow": "consumer_onboarding",
    "eval_status": "evaluation_completed",
    "decision": "ACCEPT",
    "status": "CLOSED",
    "sub_status": "Accept",
    "data_enrichments": [
      {
        "enrichment_provider": "SocureDocRequest",
        "response": {
          "status": "SESSION_COMPLETE",
          "data": {
            "docvTransactionToken": "7d6ad42b-f804-4255-b25e-268b8a77c86f",
            "url": "https://verify.socure.com/#/dv/7d6ad42b-f804-4255-b25e-268b8a77c86f"
          }
        }
      }
    ]
  }
}

The enrichment-specific response object varies by flow type and is covered in Step 7.


Step 7: Process the final decision

Match the eval_id from the webhook payload to the evaluation you stored in Step 3, then route the consumer based on the top-level decision:

DecisionAction
ACCEPTThe consumer passed verification. Grant access or proceed with onboarding.
REJECTThe consumer failed verification. Deny access or escalate for manual review.
REVIEWThe evaluation requires manual review. Do not treat this as a final decision — it indicates an intermediate state.
function handleEvaluationWebhook(payload: EvaluationCompletedEvent) {
  const { eval_id, decision } = payload.data;

  // Correlate with the stored evaluation
  const evaluation = lookupEvaluation(eval_id);

  if (decision === "ACCEPT") {
    completeOnboarding(evaluation.userId);
  }

  if (decision === "REJECT") {
    denyAccess(evaluation.userId);
  }
}

Enrichment response by flow type

The data_enrichments array in the evaluation_completed webhook contains the flow-specific enrichment result. The enrichment object name and structure differ by flow type:

The enrichment response contains a documentVerification object:

{
  "enrichment_provider": "Socure",
  "enrichment_name": "Socure Document Verification",
  "response": {
    "referenceId": "ed6a5077-b272-4a75-8c21-b284e10927cd",
    "documentVerification": {
      "decision": {
        "name": "standard",
        "value": "accept"
      },
      "reasonCodes": ["I831", "I836"],
      "documentType": {
        "type": "Drivers License",
        "country": "USA",
        "state": "NY"
      }
    }
  }
}
FieldTypeDescriptionExample
decisionObjectThe DocV decision (accept, review, reject, or resubmit).{ "name": "standard", "value": "accept" }
reasonCodesArrayReason codes explaining the decision.["I831", "I836"]
documentTypeObjectDetails about the captured document (type, country, state).{ "type": "Drivers License", "country": "USA", "state": "NY" }
📘

View all reason codes:

For the complete catalog of reason codes and their descriptions, open the Reason Codes page in the RiskOS™ Dashboard.

Handle resubmit and cancel scenarios

Resubmit: If the enrichment returns a resubmit decision, the workflow may route to a resubmit outcome. Start a new evaluation for the consumer. Tailor the user-facing message based on the reasonCodes returned (for example, prompting the consumer to use a different document type or improve lighting conditions). Limit retry attempts to prevent infinite loops.

Cancel: If the capture session expires (Session Expired) or the consumer declines consent (Consent Declined), the workflow resumes with a terminal-negative outcome. You can configure your workflow to automatically cancel the evaluation using a Condition step or Decision Rules step — no manual intervention required.

Re-attempt after expiration: When a capture session expires, RiskOS™ can generate a new docvTransactionToken within the same evaluation. Configure your workflow to trigger a re-attempt after Session Expired instead of canceling, which preserves the original evaluation context.

📘

Note:

You can automate both Cancel and Resubmit decisions in your workflow. See DocV Webhooks for details on how case_notes_added events interact with workflow execution.



Integration checklist

After completing your integration, confirm the following in your Sandbox environment:

All flow types

Evaluation API returns decision: "REVIEW", status: "ON_HOLD", and eval_status: "evaluation_paused" with a SocureDocRequest enrichment
Backend extracts and stores the eval_id and docvTransactionToken
Capture experience launches (SDK or Hosted Capture App) and presents the correct flow
Webhook endpoint receives case_notes_added events during capture
Webhook endpoint receives the evaluation_completed event with a final decision
Application correctly routes on ACCEPT and REJECT decisions

Flow-specific checks

Document Verification: The DocV SDK or Hosted Capture App presents the ID + selfie capture UI, and the enrichment response contains a documentVerification object
Secondary Document Capture: The Capture App presents the document upload interface, and submitted documents are retrievable via GET /api/evaluation/{eval_id}/documents
Selfie Intelligence: The Capture App presents the selfie-only flow, and the enrichment response contains a selfieIntelligence object with predictedAge
Selfie Reverification: The previous_reference_id is included in the request, and the enrichment response contains a selfieReverification object with the previousReferenceId

Use DocV Sandbox testing to simulate specific verification outcomes by passing predefined docvTransactionToken values.


Troubleshooting

See DocV Troubleshooting & FAQs for a full list of FAQs and troubleshooting scenarios.

SymptomCauseResolution
Evaluation returns decision: "REVIEW" but no SocureDocRequest in data_enrichmentsThe workflow does not include a Document Request step.Add a Document Request step to your workflow in the RiskOS™ dashboard.
SDK returns invalidDocvTransactionToken errorThe token has expired or was already consumed.Generate a new token by calling the evaluation API again. Tokens are single-use.
No evaluation_completed webhook receivedThe capture session expired, or the webhook endpoint is not registered.Verify your webhook URL in the RiskOS™ dashboard. Check for Session Expired in case_notes_added events.
SDK returns cameraPermissionDeclinedThe consumer denied camera access.Prompt the consumer to enable camera permissions in device settings.
Selfie Reverification returns an errorMissing or invalid previous_reference_id.Verify that additional_context.previous_reference_id contains a valid UUID from a prior accepted DocV evaluation.
Capture App shows the wrong flow typeThe use_case_key references a different flow.Verify the use_case_key matches the intended flow in Settings > DocV App > Flow in the RiskOS™ Dashboard.

Related resources