Implement end-to-end Didit identity verification so users can verify their identity from the app. The flow uses SDK sessions: the backend creates a verification session, the frontend opens the Didit SDK (modal), and the backend receives results via webhook and persists status on the user.
ETA: 12hrs
Scope: Frontend (Next.js) only. Backend already expose POST /api/didit/create-session and POST /api/didit/webhook, and to persist identityVerificationStatus and identityVerificationAt on the User model.
Implementation Summary
| Layer |
Responsibility |
| Frontend API |
lib/api/didit.ts — createDiditSession() calls backend with shared api client (cookies). No Next.js API routes. |
| UI |
Settings → Identity tab: card showing status (Verified / Declined / In review) and a Verify identity button that opens the Didit SDK modal. |
| Types |
User (and API response types) include optional identityVerificationStatus and identityVerificationAt. |
Backend Contract (Expectations)
Create session
-
Endpoint: POST /api/didit/create-session
-
Auth: Required (e.g. session cookie or Bearer). Backend uses authenticated user id as vendor_data unless user_id is sent in body.
-
Request body (optional):
-
Response: Standard API wrapper; session payload in data:
{
"success": true,
"message": "Success",
"data": {
"session_id": "uuid",
"session_number": 1,
"session_token": "string",
"url": "https://verify.didit.me/session/<token>",
"vendor_data": "string",
"metadata": null,
"status": "Not Started",
"callback": "https://your-frontend.com/api/didit/callback",
"workflow_id": "uuid"
},
"meta": { "timestamp": "...", "requestId": "..." }
}
-
Note: The verification URL is in data.url, not data.verification_url. Frontend must map url → verification_url when normalizing the response.
User / GetMe response
- Endpoint:
GET /users/me (or equivalent) must return a user object that includes:
identityVerificationStatus: "Approved" | "Declined" | "In Review" | null
identityVerificationAt: ISO date string or null (set when status becomes Approved)
Types and References
Frontend types
lib/api/types.ts and types/user.ts — User
// Add to User interface
/** Didit identity verification: Approved | Declined | In Review | null */
identityVerificationStatus?: 'Approved' | 'Declined' | 'In Review' | null;
identityVerificationAt?: string | null;
lib/api/didit.ts
- Backend payload (internal):
DiditSessionData — session_id, session_token, url, status, optional session_number, vendor_data, metadata, callback, workflow_id.
- Public response:
DiditCreateSessionResponse — session_id, session_token, verification_url (mapped from url), status.
- Params:
CreateDiditSessionParams — optional user_id?: string.
SDK usage
- Package:
@didit-protocol/sdk-web
- API: Use
DiditSdk.shared, set onComplete, then sdk.startVerification({ url: verification_url }).
- onComplete result:
{ type: 'completed' | 'cancelled' | 'failed', session?: { sessionId, status }, error?: { message } }.
Files to Create
| File |
Purpose |
lib/api/didit.ts |
API client: createDiditSession(params?). Calls POST /api/didit/create-session, unwraps data, maps url → verification_url, throws if session_token or url missing. |
components/didit/DiditVerifyButton.tsx |
Client component: button that calls createDiditSession(), initializes Didit SDK with DiditSdk.shared and onComplete, runs startVerification({ url }). Handles loading, error state, and callbacks onSuccess, onError, onCancel. |
components/didit/IdentityVerificationSection.tsx |
Client component: card showing title/description, status badge (Verified / Declined / In review) and optional verified date, <DiditVerifyButton> when not Approved, and optional localhost hint (tunnel + FRONTEND_URL / DIDIT_CALLBACK_URL). Props: `user: GetMeResponse |
Files to Modify
| File |
Changes |
app/me/settings/SettingsContent.tsx |
Add Identity tab to settings tabs. Add <TabsContent value="identity"> that renders <IdentityVerificationSection user={userData} onVerificationComplete={fetchUserData} />. Ensure fetchUserData is stable (e.g. useCallback) and passed so that after verification the user data (including identityVerificationStatus) is refetched. |
lib/api/types.ts |
On User interface, add optional identityVerificationStatus?: 'Approved' | 'Declined' | 'In Review' | null and identityVerificationAt?: string | null. |
types/user.ts |
Same as above: add identityVerificationStatus and identityVerificationAt to the User type. |
Acceptance Criteria
References
- Didit: Quick Start, Web SDK, Webhooks
- Backend (NestJS):
src/modules/didit, src/config/didit.config.ts
- Integration doc (this repo):
DIDIT_INTEGRATION.md (flow, env vars, troubleshooting)
Dependencies
- npm:
@didit-protocol/sdk-web (already used by the implementation above).
Implement end-to-end Didit identity verification so users can verify their identity from the app. The flow uses SDK sessions: the backend creates a verification session, the frontend opens the Didit SDK (modal), and the backend receives results via webhook and persists status on the user.
ETA: 12hrs
Scope: Frontend (Next.js) only. Backend already expose
POST /api/didit/create-sessionandPOST /api/didit/webhook, and to persistidentityVerificationStatusandidentityVerificationAton the User model.Implementation Summary
lib/api/didit.ts—createDiditSession()calls backend with sharedapiclient (cookies). No Next.js API routes.User(and API response types) include optionalidentityVerificationStatusandidentityVerificationAt.Backend Contract (Expectations)
Create session
Endpoint:
POST /api/didit/create-sessionAuth: Required (e.g. session cookie or Bearer). Backend uses authenticated user id as
vendor_dataunlessuser_idis sent in body.Request body (optional):
{ "user_id": "<uuid>" }Response: Standard API wrapper; session payload in
data:{ "success": true, "message": "Success", "data": { "session_id": "uuid", "session_number": 1, "session_token": "string", "url": "https://verify.didit.me/session/<token>", "vendor_data": "string", "metadata": null, "status": "Not Started", "callback": "https://your-frontend.com/api/didit/callback", "workflow_id": "uuid" }, "meta": { "timestamp": "...", "requestId": "..." } }Note: The verification URL is in
data.url, notdata.verification_url. Frontend must mapurl→verification_urlwhen normalizing the response.User / GetMe response
GET /users/me(or equivalent) must return a user object that includes:identityVerificationStatus:"Approved"|"Declined"|"In Review"|nullidentityVerificationAt: ISO date string ornull(set when status becomes Approved)Types and References
Frontend types
lib/api/types.tsandtypes/user.ts— Userlib/api/didit.tsDiditSessionData—session_id,session_token,url,status, optionalsession_number,vendor_data,metadata,callback,workflow_id.DiditCreateSessionResponse—session_id,session_token,verification_url(mapped fromurl),status.CreateDiditSessionParams— optionaluser_id?: string.SDK usage
@didit-protocol/sdk-webDiditSdk.shared, setonComplete, thensdk.startVerification({ url: verification_url }).{ type: 'completed' | 'cancelled' | 'failed', session?: { sessionId, status }, error?: { message } }.Files to Create
lib/api/didit.tscreateDiditSession(params?). CallsPOST /api/didit/create-session, unwrapsdata, mapsurl→verification_url, throws ifsession_tokenorurlmissing.components/didit/DiditVerifyButton.tsxcreateDiditSession(), initializes Didit SDK withDiditSdk.sharedandonComplete, runsstartVerification({ url }). Handles loading, error state, and callbacksonSuccess,onError,onCancel.components/didit/IdentityVerificationSection.tsx<DiditVerifyButton>when not Approved, and optional localhost hint (tunnel + FRONTEND_URL / DIDIT_CALLBACK_URL). Props: `user: GetMeResponseFiles to Modify
app/me/settings/SettingsContent.tsx<TabsContent value="identity">that renders<IdentityVerificationSection user={userData} onVerificationComplete={fetchUserData} />. EnsurefetchUserDatais stable (e.g.useCallback) and passed so that after verification the user data (includingidentityVerificationStatus) is refetched.lib/api/types.tsUserinterface, add optionalidentityVerificationStatus?: 'Approved' | 'Declined' | 'In Review' | nullandidentityVerificationAt?: string | null.types/user.tsidentityVerificationStatusandidentityVerificationAtto theUsertype.Acceptance Criteria
createDiditSession()), then opens the Didit SDK modal with the returnedverification_url.identityVerificationAtis set.lib/api(sharedapiclient with cookies).FRONTEND_URLorDIDIT_CALLBACK_URLto avoid browser blocking the callback (Private Network Access).References
src/modules/didit,src/config/didit.config.tsDIDIT_INTEGRATION.md(flow, env vars, troubleshooting)Dependencies
@didit-protocol/sdk-web(already used by the implementation above).