Skip to main content
Every verification session moves through a series of statuses. Understanding them helps you monitor user progress, automate compliance decisions, and optimize conversion.

All Status Values

Every status is an exact string returned by the Didit API and webhooks. Always use strict string matching (e.g., === "In Review") in your code — these values are case-sensitive and include spaces.
StatusString ValueDescription
Not Started"Not Started"Session created, user hasn’t opened the link
In Progress"In Progress"User is actively completing verification
Approved"Approved"All checks passed — identity verified
Declined"Declined"One or more checks failed
In Review"In Review"Flagged for manual compliance review
Resubmitted"Resubmitted"User asked to redo specific steps
Expired"Expired"Session timed out before user opened the link
Abandoned"Abandoned"User started but didn’t finish in time
KYC Expired"Kyc Expired"Previously approved session exceeded KYC expiration

Session Statuses

API value: "Not Started"The session has been created via the API but the user has not opened the verification link yet.
  • What to do: Wait for the user to begin, or send a reminder if too much time passes.
  • Transitions to: "In Progress", "Expired"
API value: "In Progress"The user has opened the link and is actively completing verification steps (document capture, liveness, etc.).
  • What to do: No action needed — the user is working through the flow.
  • Transitions to: "Approved", "Declined", "In Review", "Abandoned"
API value: "Approved"All verification checks passed successfully. The user’s identity has been verified.
  • What to do: Grant the user access, update their profile, and store the decision data.
  • Webhook includes: Full decision object with all feature results.
  • Transitions to: "Kyc Expired" (if a KYC expiration policy is configured)
API value: "Declined"One or more verification checks failed. The user did not pass verification.
  • What to do: Notify the user. Optionally request a resubmission if the issue is fixable.
  • Webhook includes: Full decision object with warnings explaining the failure.
  • Transitions to: "Resubmitted" (if a reviewer requests it)
API value: "In Review"Automated checks flagged warnings that need human review. A compliance reviewer must make the final decision.
  • What to do: A reviewer should open the session in the Console and approve, decline, or request resubmission.
  • Webhook includes: Full decision object with warnings.
  • Transitions to: "Approved", "Declined", "Resubmitted"
API value: "Resubmitted"A reviewer has requested that the user redo specific verification steps (e.g., retake a blurry document photo).
  • What to do: Wait for the user to complete the resubmitted steps. The system will automatically re-evaluate.
  • Webhook includes: resubmit_info object with the list of features to redo and reasons.
  • Transitions to: "Approved", "Declined", "In Review"
API value: "Expired"The session timed out before the user opened the verification link.
  • What to do: Create a new session and send the user a fresh link.
  • Terminal status — no further transitions.
API value: "Abandoned"The user started but did not finish the verification within the allowed timeframe.
  • What to do: Send a reminder or create a new session.
  • Terminal status — no further transitions.
API value: "Kyc Expired"A previously approved session has exceeded the configured KYC expiration period (e.g., 12 months).
  • What to do: Request the user to re-verify by creating a new session.
  • Terminal status — no further transitions.

Status Transitions

FromToTrigger
"Not Started""In Progress"User opens the verification link
"Not Started""Expired"Session TTL elapses before the user opens the link
"In Progress""Approved"All automated checks pass
"In Progress""Declined"One or more checks fail
"In Progress""In Review"Checks flag warnings requiring human review
"In Progress""Abandoned"User doesn’t finish within the timeframe
"In Review""Approved"Reviewer manually approves
"In Review""Declined"Reviewer manually declines
"In Review""Resubmitted"Reviewer requests specific steps to be redone
"Declined""Resubmitted"Reviewer requests specific steps to be redone
"Resubmitted""Approved"Resubmitted steps pass all checks
"Resubmitted""Declined"Resubmitted steps fail
"Resubmitted""In Review"Resubmitted steps flag new warnings
"Approved""Kyc Expired"KYC expiration policy triggers

Terminal vs Non-Terminal

CategoryStatusesMeaning
Terminal"Approved", "Declined", "Kyc Expired"Final decision — session won’t change again
Non-Terminal"Not Started", "In Progress", "Resubmitted"Still active — awaiting user action or processing
Actionable"In Review"Requires manual intervention from your team
Inactive"Expired", "Abandoned"Ended without a verification decision

Handling Statuses in Your Code

Use webhooks or the Retrieve Session API to react to status changes.
Statuses are exact, case-sensitive strings with spaces. For example, "In Review" (not "in_review" or "IN_REVIEW"). Always use strict equality (===) when matching.
// All possible status string values:
// "Not Started" | "In Progress" | "Approved" | "Declined" |
// "In Review"   | "Resubmitted" | "Expired"  | "Kyc Expired" | "Abandoned"

async function handleWebhook(webhook) {
  const { status, vendor_data: vendorData } = webhook;

  switch (status) {
    case "Not Started":
      // Session created but user hasn't opened the link yet
      break;

    case "In Progress":
      // User is actively completing verification steps
      break;

    case "Approved":
      // All checks passed — grant access
      await db.users.update(vendorData, {
        verified: true,
        verifiedAt: new Date(),
        decision: webhook.decision,
      });
      break;

    case "Declined":
      // Verification failed — notify user
      await db.users.update(vendorData, {
        verificationStatus: "declined",
        declineReasons: webhook.decision?.warnings,
      });
      break;

    case "In Review":
      // Needs manual review by compliance team
      await db.users.update(vendorData, {
        verificationStatus: "pending_review",
      });
      break;

    case "Resubmitted":
      // User will redo specific steps
      await db.users.update(vendorData, {
        verificationStatus: "resubmission_pending",
        resubmitInfo: webhook.resubmit_info,
      });
      break;

    case "Abandoned":
      // User started but didn't finish — send reminder
      await sendReminderEmail(vendorData);
      break;

    case "Expired":
    case "Kyc Expired":
      // Session expired — create a new one
      await createNewSession(vendorData);
      break;
  }
}

Resubmission

The Resubmitted status lets your compliance team give users a second chance without creating a new session.
1

Reviewer initiates resubmission

From the Console, open an In Review or Declined session and click Request Resubmission. Select which steps need to be redone.
2

Previous data is archived

The system resets the selected features and marks prior data as previous_attempt — preserving the full audit trail.
3

User is notified

If an email is available, the user receives a localized email with a direct link to resume.
4

User redoes specific steps

The user only repeats the steps that were flagged — not the entire verification.
5

System re-evaluates

Once complete, the session automatically transitions to "Approved", "Declined", or "In Review".

Resubmission Webhook Payload

{
  "session_id": "uuid-of-the-session",
  "status": "Resubmitted",
  "resubmit_info": {
    "nodes_to_resubmit": [
      { "node_id": "feature_ocr", "feature": "OCR" },
      { "node_id": "feature_liveness", "feature": "LIVENESS" }
    ],
    "reasons": {
      "feature_ocr": "Document image is blurry or unreadable",
      "feature_liveness": "Liveness check score below threshold"
    }
  }
}

Which Features Can Be Resubmitted?

Any feature with a non-approved status: Declined, In Review, Not Finished, Not Started, or Expired.
You can request resubmission multiple times on the same session. Each cycle archives the previous attempt data, giving you complete visibility into the user’s verification history.

Best Practices

Monitor In Review

Set up alerts (email or Slack) in your Didit Console to get notified when sessions need manual review.

Prefer Resubmission

If the issue is fixable (blurry photo, wrong document side), request a resubmission instead of declining. This improves conversion.

Track Drop-offs

High Abandoned or Expired rates may indicate UX friction. Consider adjusting session TTL or improving user guidance.

Idempotent Handlers

Webhooks may be retried. Use session_id as a unique key to ensure you process each status change only once.
Always verify webhook signatures before processing payloads. Didit provides three methods: X-Signature, X-Signature-V2 (recommended), and X-Signature-Simple. See Webhooks for details.