---
name: didit-best-practises
description: Best practices for integrating Didit identity verification platform. Use when implementing KYC/identity verification with Didit, setting up verification workflows, configuring webhooks, integrating web/mobile apps, or migrating from Sumsub to Didit. Triggers on Didit API integration, verification sessions, ID verification, liveness checks, AML screening, face matching, and KYC implementation.
---
# Didit Integration Best Practices
## Quick Reference
| Resource | URL |
|----------|-----|
| API Base | `https://verification.didit.me/v3/` |
| Console | `https://business.didit.me/` |
| Docs | `https://docs.didit.me/reference/` |
## Integration Workflow
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 1. Console │────▶│ 2. Backend │────▶│ 3. Frontend │
│ Setup │ │ Integration │ │ Integration │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
Create App Create Session Open Session URL
Get API Key Handle Webhooks Handle Callback
Configure Workflow Retrieve Results Update UI
```
## 1. Console Setup
### Create Application
1. Log in to Didit Business Console
2. Create new Application (workspace for project/environment)
3. Navigate to Verifications → Settings (⚙️) → Copy API Key
### Configure Workflow
Select verification features based on requirements:
| Feature | Use Case |
|---------|----------|
| ID Verification | Document verification (220+ countries) |
| Liveness | Prevent spoofing/deepfakes |
| Face Match 1:1 | Compare selfie to document photo |
| AML Screening | Watchlist/PEP database checks |
| NFC Verification | Enhanced security via NFC chip |
| Age Estimation | Age verification without full KYC |
| Proof of Address | Residential address verification |
## 2. Backend Integration
### Authentication
All requests require `x-api-key` header:
```typescript
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'x-api-key': process.env.DIDIT_API_KEY
};
```
### Create Verification Session
```typescript
// POST https://verification.didit.me/v3/session/
const createSession = async (userId: string, callbackUrl: string) => {
const response = await fetch('https://verification.didit.me/v3/session/', {
method: 'POST',
headers,
body: JSON.stringify({
workflow_id: process.env.DIDIT_WORKFLOW_ID,
vendor_data: userId, // Your internal user ID
callback: callbackUrl // Redirect URL after verification
})
});
const { session_id, url } = await response.json();
// Store session_id, redirect user to url
return { session_id, url };
};
```
### Retrieve Session Status
```typescript
// GET https://verification.didit.me/v3/session/{session_id}
const getSession = async (sessionId: string) => {
const response = await fetch(
`https://verification.didit.me/v3/session/${sessionId}`,
{ headers }
);
return response.json();
};
```
### Webhook Handler
```typescript
// Webhook payload structure
interface DiditWebhook {
session_id: string;
status: 'Approved' | 'Declined' | 'In Review' | 'Expired';
vendor_data: string;
// Additional verification data based on workflow
}
app.post('/webhooks/didit', async (req, res) => {
const payload: DiditWebhook = req.body;
switch (payload.status) {
case 'Approved':
await updateUserVerificationStatus(payload.vendor_data, 'verified');
break;
case 'Declined':
await handleDeclinedVerification(payload);
break;
case 'In Review':
await flagForManualReview(payload.vendor_data);
break;
}
res.status(200).send('OK');
});
```
## 3. Frontend Integration
### Web Integration
Redirect user to session URL or embed in iframe:
```typescript
// Redirect approach (recommended)
window.location.href = sessionUrl;
// Popup approach
window.open(sessionUrl, 'didit-verification', 'width=500,height=700');
```
### Mobile Integration (React Native)
```tsx
import { WebView } from 'react-native-webview';
const VerificationScreen = ({ sessionUrl }: { sessionUrl: string }) => (
);
```
### Mobile Integration (iOS Swift)
```swift
import WebKit
class VerificationViewController: UIViewController {
private var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
config.mediaTypesRequiringUserActionForPlayback = []
webView = WKWebView(frame: view.bounds, configuration: config)
webView.customUserAgent = "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36"
view.addSubview(webView)
if let url = URL(string: sessionUrl) {
webView.load(URLRequest(url: url))
}
}
}
```
### Mobile Integration (Android)
```kotlin
val webView = findViewById(R.id.webview)
webView.settings.apply {
javaScriptEnabled = true
mediaPlaybackRequiresUserGesture = false
}
webView.webChromeClient = WebChromeClient()
webView.settings.userAgentString = "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36"
webView.loadUrl(sessionUrl)
```
## Verification Statuses
| Status | Description | Action |
|--------|-------------|--------|
| Not Started | Session created, user hasn't begun | Wait or send reminder |
| In Progress | User actively verifying | Wait for completion |
| Approved | Verification successful | Grant access |
| Declined | Verification failed | Show reason, allow retry |
| In Review | Manual review required | Wait for compliance team |
| Expired | Session timed out | Create new session |
| Abandoned | User didn't complete | Send follow-up |
| KYC Expired | Previous KYC expired | Request re-verification |
## Best Practices
### Security
- Store API key in environment variables, never in code
- Validate webhook signatures if available
- Use HTTPS for all callback URLs
- Implement rate limiting on your webhook endpoint
### User Experience
- Show clear instructions before redirecting to verification
- Handle all status states in your UI
- Provide retry options for declined verifications
- Show progress indicators during verification
### Error Handling
```typescript
try {
const session = await createSession(userId, callbackUrl);
} catch (error) {
if (error.status === 401) {
// Invalid API key
} else if (error.status === 429) {
// Rate limited - implement exponential backoff
} else if (error.status === 400) {
// Invalid request - check workflow_id
}
}
```
### Rate Limits
- Free workflows: 10 sessions/minute
- Paid workflows: 600 sessions/minute
- Implement exponential backoff on 429 responses
## White Label Configuration
Customize verification UI in Console → White Label:
- Colors: buttons, text, panels, backgrounds
- Typography: custom fonts
- Logos: square and rectangular formats
- Custom domain: host on your domain instead of verify.didit.me
## Migration from Sumsub
See [references/sumsub-migration.md](references/sumsub-migration.md) for detailed migration guide.
**Key differences:**
- Didit uses `x-api-key` header (Sumsub uses different auth)
- Session-based flow vs applicant-based
- Simpler webhook payload structure
- Built-in white-label support
## Resources
- [API Reference](https://docs.didit.me/reference/)
- [Webhook Configuration](https://docs.didit.me/reference/webhooks)
- [Verification Statuses](https://docs.didit.me/reference/verification-statuses)
- [Mobile Integration](https://docs.didit.me/reference/ios-android)