Documentation Index
Fetch the complete documentation index at: https://docs.didit.me/llms.txt
Use this file to discover all available pages before exploring further.
This guide walks you through the complete flow for integrating Didit identity verification via API. Follow these steps to get up and running quickly.
Step 1: Get Your Credentials
From the Didit Console
- Go to Didit Console
- Create or select your organization
- Navigate to Settings → API Keys
- Copy your credentials:
- API Key – For authenticating API requests
- Webhook Secret Key – For verifying webhook signatures
Environment Variables
Add these to your .env file:
# Required
DIDIT_API_KEY=your_api_key_here
DIDIT_WEBHOOK_SECRET=your_webhook_secret_here
# Your workflow ID (from the Console)
DIDIT_WORKFLOW_ID=your_workflow_id_here
Step 2: Create a Workflow
Before creating sessions, you need a verification workflow. Workflows define what verification steps users go through.
Create in Console
- Go to Didit Console → Workflows
- Click Create Workflow
- Choose a base template:
| Template | Best For |
|---|
| KYC | Full identity verification with ID document |
| Adaptive Age Verification | Age verification with optional ID backup |
| Biometric Authentication | Re-verifying returning users |
| Address Verification | Proof of address verification |
- Add optional features:
| Feature | Description |
|---|
| NFC Verification | Read passport/ID chip data |
| Liveness Detection | Prevent spoofing with selfie video |
| Face Matching | Match selfie to document photo |
| Phone Verification | Verify phone number via SMS |
| Email Verification | Verify email address |
| AML Screening | Check against sanctions/PEP lists |
| Database Validation | Verify against government databases |
| Device & IP Analysis | Detect VPNs, proxies, geolocation |
- Copy your Workflow ID
Step 3: Create a Verification Session
Call the API to create a session for your user.
Request
curl -X POST https://verification.didit.me/v3/session/ \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"workflow_id": "your-workflow-id",
"callback": "https://yourapp.com/verification-complete",
"vendor_data": "user-123"
}'
Request Parameters
| Parameter | Required | Description |
|---|
workflow_id | ✅ Yes | Your workflow ID from the Console |
callback | ✅ Yes | URL to redirect user after verification |
vendor_data | ❌ Optional | Your internal user identifier (returned in webhooks) |
metadata | ❌ Optional | Custom JSON data stored with the session |
contact_details | ❌ Optional | User’s email/phone for prefill and notifications |
expected_details | ❌ Optional | Expected user details for cross-validation |
Full Example with All Options
curl -X POST https://verification.didit.me/v3/session/ \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"workflow_id": "11111111-2222-3333-4444-555555555555",
"callback": "https://yourapp.com/verification-complete",
"vendor_data": "user-123",
"metadata": {
"plan": "premium",
"signup_source": "mobile-app"
},
"contact_details": {
"email": "alex.sample@example.com",
"email_lang": "en",
"send_notification_emails": true,
"phone": "+15550101000"
},
"expected_details": {
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1990-01-01",
"expected_document_types": ["P", "ID"]
}
}'
expected_details.expected_document_types restricts the ID verification step
to specific document types. Allowed values: P (passport), ID (national
ID), DL (driver’s license), RP (residence permit), HIC (health
insurance card). Unknown values return 400.
Response
{
"session_id": "abc123-def456-ghi789",
"session_number": 1234,
"session_token": "eyJhbGciOiJIUzI1NiIs...",
"vendor_data": "user-123",
"metadata": {
"plan": "premium",
"signup_source": "mobile-app"
},
"status": "Not Started",
"workflow_id": "11111111-2222-3333-4444-555555555555",
"callback": "https://yourapp.com/verification-complete",
"verification_url": "https://verify.didit.me/session/abc123..."
}
Key Response Fields
| Field | Description |
|---|
session_id | Unique identifier for this session |
session_token | Token for SDK initialization |
verification_url | URL to redirect user or embed in iframe |
status | Current status (Not Started, In Progress, etc.) |
Step 4: Present Verification to User
Choose how to present the verification flow to your user:
Option A: Native SDK (Recommended for Mobile)
Use the session_token with our native SDKs for the best user experience:
// iOS
DiditSdk.shared.startVerification(token: sessionToken)
→ iOS SDK | Android SDK | React Native | Flutter
Option B: InContext Iframe (Recommended for Web)
Embed the verification in your page:
<iframe
src="{verification_url}"
style="width: 100%; height: 700px; border: none;"
allow="camera; microphone; fullscreen; autoplay; encrypted-media"
></iframe>
→ InContext Documentation
Option C: Redirect
Redirect the user to the verification URL:
window.location.href = verificationUrl;
→ Redirect Documentation
Option D: Mobile WebView
For mobile apps without native SDK:
// React Native
<WebView source={{ uri: verificationUrl }} />
→ WebView Documentation
Step 5: Receive Results
Via Webhook (Recommended)
Webhooks notify your server in real-time when verification status changes.
Setup:
- Configure your webhook URL in the Console
- Implement a webhook endpoint on your server
Example Webhook Payload:
{
"session_id": "abc123-def456-ghi789",
"status": "Approved",
"webhook_type": "status.updated",
"vendor_data": "user-123",
"workflow_id": "11111111-2222-3333-4444-555555555555",
"decision": {
"status": "Approved",
"id_verifications": [...],
"liveness_checks": [...],
"face_matches": [...]
}
}
Verify the Signature:
const crypto = require("crypto");
function verifyWebhook(body, signature, timestamp, secret) {
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - parseInt(timestamp)) > 300) {
return false; // Request too old
}
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature),
);
}
→ Full Webhooks Documentation
Via API (Optional)
You can also fetch results via API:
curl https://verification.didit.me/v3/session/{session_id}/decision/ \
-H "x-api-key: YOUR_API_KEY"
→ Retrieve Session API Reference
Complete Code Examples
Node.js / Express
const express = require("express");
const crypto = require("crypto");
const app = express();
// Create verification session
app.post("/api/verify", async (req, res) => {
const { userId } = req.body;
const response = await fetch("https://verification.didit.me/v3/session/", {
method: "POST",
headers: {
"x-api-key": process.env.DIDIT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
workflow_id: process.env.DIDIT_WORKFLOW_ID,
callback: `${process.env.APP_URL}/verification-complete`,
vendor_data: userId,
}),
});
const session = await response.json();
// Store session_id associated with user
await db.users.update({
where: { id: userId },
data: { verificationSessionId: session.session_id },
});
res.json({
verificationUrl: session.verification_url,
sessionToken: session.session_token,
});
});
// Handle webhook
app.post(
"/api/webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-signature-v2"];
const timestamp = req.headers["x-timestamp"];
if (
!verifyWebhook(
req.body,
signature,
timestamp,
process.env.DIDIT_WEBHOOK_SECRET,
)
) {
return res.status(401).json({ error: "Invalid signature" });
}
const payload = JSON.parse(req.body);
const { session_id, status, vendor_data } = payload;
// Update user's verification status
if (status === "Approved") {
db.users.update({
where: { id: vendor_data },
data: { isVerified: true, verifiedAt: new Date() },
});
}
res.json({ received: true });
},
);
app.listen(3000);
Python / FastAPI
from fastapi import FastAPI, Request, HTTPException
import httpx
import hmac
import hashlib
import os
import time
app = FastAPI()
@app.post("/api/verify")
async def create_verification(user_id: str):
async with httpx.AsyncClient() as client:
response = await client.post(
"https://verification.didit.me/v3/session/",
headers={
"x-api-key": os.environ["DIDIT_API_KEY"],
"Content-Type": "application/json"
},
json={
"workflow_id": os.environ["DIDIT_WORKFLOW_ID"],
"callback": f"{os.environ['APP_URL']}/verification-complete",
"vendor_data": user_id
}
)
session = response.json()
return {
"verification_url": session["verification_url"],
"session_token": session["session_token"]
}
@app.post("/api/webhook")
async def handle_webhook(request: Request):
body = await request.body()
signature = request.headers.get("x-signature-v2")
timestamp = request.headers.get("x-timestamp")
# Verify timestamp freshness
if abs(int(time.time()) - int(timestamp)) > 300:
raise HTTPException(status_code=401, detail="Request too old")
# Verify signature
expected = hmac.new(
os.environ["DIDIT_WEBHOOK_SECRET"].encode(),
body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
raise HTTPException(status_code=401, detail="Invalid signature")
payload = await request.json()
if payload["status"] == "Approved":
# Update user in database
pass
return {"received": True}
Session Statuses
| Status | Description |
|---|
Not Started | Session created but user hasn’t begun |
In Progress | User is currently completing verification |
In Review | Verification needs manual review |
Approved | Verification successful |
Declined | Verification failed |
Abandoned | User left without completing |
Expired | Session expired (default: 7 days) |
Next Steps
-
Choose your integration method:
-
Configure webhooks: Webhooks Guide
-
Customize your workflow: Workflows Documentation
-
Test in sandbox: Use test credentials before going live
Need Help?