सिर्फ़ एक बार $0.33 का KYC चलाएँ। वेरिफ़ाइड यूज़र वह Didit वेरिफ़िकेशन Didit वाले किसी भी दूसरे ऐप के साथ चुनिंदा जानकारी साझा करते हुए शेयर करता है, हर दोबारा उपयोग मुफ़्त। पाँच राष्ट्रीय eID आज लाइव हैं, और EUDI वॉलेट स्वीकृति जल्द आ रही है।
यूज़र की जेब में आइडेंटिटी। जो भी इसे स्वीकार करता है, उसके लिए मुफ़्त।
हर Didit KYC को अन्य Didit-पावर्ड ऐप्स के साथ एक हस्ताक्षरित रीयूज़ेबल KYC सत्यापन के रूप में शेयर किया जा सकता है। हर प्राप्त करने वाला प्लेटफ़ॉर्म इसे मुफ़्त में पढ़ता है। एक सत्यापन, हर वह व्यवसाय जो Didit स्वीकार करता है। मुफ़्त में शुरू करें।
यह कैसे काम करता है
साइन-अप से लेकर वेरिफाइड यूज़र तक, चार स्टेप्स में।
चरण 01 / 04
01
वर्कफ़्लो बनाएं
आप जो चेक चाहते हैं, उन्हें चुनें, ID, लाइवनेस, फेस मैच, सैंक्शन, एड्रेस, उम्र, फ़ोन, ईमेल, कस्टम प्रश्न। उन्हें डैशबोर्ड में एक फ़्लो में ड्रैग करें, या उसी फ़्लो को हमारे API पर पोस्ट करें। कंडीशंस पर ब्रांच करें, A/B टेस्ट चलाएं, किसी कोड की आवश्यकता नहीं है।
इंटीग्रेट करें
हमारे वेब, iOS, Android, React Native, या Flutter SDK के साथ नेटिवली एम्बेड करें। एक होस्टेड पेज पर रीडायरेक्ट करें। या बस अपने यूज़र को एक लिंक भेजें, ईमेल, SMS, WhatsApp, कहीं भी। चुनें कि आपके स्टैक के लिए क्या उपयुक्त है।
यूज़र फ़्लो से गुज़रता है
Didit कैमरा, लाइटिंग क्यू, मोबाइल हैंड-ऑफ और एक्सेसिबिलिटी को होस्ट करता है। जब यूज़र फ़्लो में होता है, तो हम वास्तविक समय में 200+ फ़्रॉड सिग्नलों को स्कोर करते हैं और आधिकारिक डेटा स्रोतों के खिलाफ हर फ़ील्ड को वेरीफाई करते हैं। दो सेकंड से भी कम समय में परिणाम।
आपको परिणाम मिलते हैं
रियल-टाइम साइंड वेबहुक आपके डेटाबेस को तब सिंक में रखते हैं जब कोई यूज़र अप्रूव, डिक्लाइन या रिव्यू के लिए भेजा जाता है। मांग पर API को पोल करें। या हर सेशन, हर सिग्नल का निरीक्षण करने और अपने तरीके से मामलों को मैनेज करने के लिए कंसोल खोलें।
रियूजेबल आइडेंटिटी के लिए बनाया गया · इंफ्रास्ट्रक्चर की तरह कीमत
एक KYC। उसके बाद हर प्लेटफॉर्म, मुफ़्त।
वास्तविक रियूजेबल आइडेंटिटी एक फ़ीचर नहीं है, यह एक सिस्टम है। इश्यू करना, होल्ड करना, प्रस्तुत करना, सेलेक्टिव डिस्क्लोजर, रिफ्रेश, रिवोकेशन। सब कुछ एक /v3/ सेशन के तहत।
पहली बार यूज़र $0.33 का स्टैंडर्ड बंडल पूरा करता है: ID दस्तावेज़, पैसिव लाइवनेस, फ़ेस मैच, डिवाइस और IP विश्लेषण। पूरा होने पर Didit वेरिफ़िकेशन पर हस्ताक्षर करता है, ताकि यूज़र उसे Didit वाले दूसरे ऐप्स के साथ साझा कर सके।
जन्म तिथि बताए बिना 18 से ज़्यादा उम्र साबित करें। पता बताए बिना देश साबित करें। प्राप्त करने वाला ऐप केवल वही फ़ील्ड पढ़ता है जो वह मांगता है, Didit द्वारा हस्ताक्षरित।
MitID, BankID स्वीडन, Finnish Trust Network, Smart-ID और Mobile-ID एक ही वर्कफ़्लो में लाइव हैं। जिन यूज़र्स के पास eID नहीं है, वे NFC चिप रीडिंग, लाइवनेस और फ़ेस मैच वाले दस्तावेज़ रूट से वेरिफ़ाई करते हैं। EUDI वॉलेट स्वीकृति जल्द आ रही है।
वॉलेट ऐप · iOSApp Storeवही क्रेडेंशियल, नया KYC नहीं
वॉलेट ऐप · AndroidGoogle Playवही क्रेडेंशियल, नया KYC नहीं
MitIDDK · राष्ट्रीय eIDआज लाइव
BankIDSE · राष्ट्रीय eIDआज लाइव
Smart-IDEE · LV · LT · BEआज लाइव
EUDI वॉलेटEU · जल्द आ रहा हैवही वर्कफ़्लो
openid4vp · sd-jwt vc6/6
04 · इश्यूअर · होल्डर · वेरिफायर
तीन भूमिकाएँ। एक क्रेडेंशियल।
इश्यूअर KYC के बाद क्रेडेंशियल पर साइन करता है। यूज़र इसे अपने वॉलेट में रखता है। वेरिफायर केवल डिस्क्लोज्ड फील्ड्स पर इश्यूअर के सिग्नेचर को वैलिडेट करता है। स्टैंडर्ड वेरिफिएबल-क्रेडेंशियल ट्रस्ट ट्रायंगल।
जारीकर्ता हस्ताक्षर · Diditडिस्क्लोज़ फ़ील्ड पर वेरिफाइड
05 · क्रेडेंशियल फ्रेशनेस
क्रेडेंशियल फ्रेशनेस, ऑटोमैटिक।
कंटीन्यूअस AML यूज़र को रोज़ाना री-स्क्रीन करता है। डॉक्यूमेंट की एक्सपायरी, नाम में बदलाव, प्रतिबंधों का उल्लंघन, सब कुछ क्रेडेंशियल पर ऑटोमैटिकली दिखाई देता है। प्रेजेंटेशन के समय पुराने क्रेडेंशियल रिजेक्ट कर दिए जाते हैं।
क्लियरक्रेडेंशियल सस्पेंडनया PEP हिटदोबारा स्क्रीन · क्रेडेंशियल ताज़ा
पहचान फ़ील्डनाम · DOB · देश
वेरिफाइडदोबारा स्क्रीन · क्रेडेंशियल ताज़ा
06 · प्राप्त करने के लिए मुफ्त
हर प्राप्त करने वाले प्लेटफॉर्म के लिए मुफ्त।
हर KYC के साथ इश्यूअन्स शामिल है। वॉलेट स्टोरेज यूज़र के डिवाइस पर होता है। प्रेजेंटेशन, सेलेक्टिव डिस्क्लोजर और सिग्नेचर वैलिडेशन सभी मुफ्त हैं, हमेशा के लिए। भारी-वॉल्यूम वाले अकाउंट्स पर प्रति यूज़र प्रति वर्ष $0.07 पर कंटीन्यूअस AML रिफ्रेश।
एक Didit एप्लिकेशन से पूरा हो चुका सेशन साझा करें और उसे दूसरे एप्लिकेशन में इंपोर्ट करें। प्राप्त करने वाला पक्ष व्यक्ति से दोबारा सत्यापन कराए बिना पूरा निर्णय पढ़ता है।
एक प्रॉम्प्ट में रीयूजेबल-आइडेंटिटी फ़्लो शिप करें।
Claude Code, Cursor, Codex, Devin, Aider या Replit Agent में पेस्ट करें। अपना स्टैक भरें। एजेंट वर्कफ़्लो, सेशन, साझा करने और इंपोर्ट करने की कॉल और हस्ताक्षरित webhook बनाता है।
didit-integration-prompt.md
# Didit Reusable KYC: verify a person once, share the finished session with another application
You are adding Reusable KYC to my_stack. A person completes one identity
verification; the finished session is then shared with a second Didit
application, which imports the full decision without running the checks
again. Every URL, header and enum value below is canonical. Do not paraphrase
or "improve" them.
## 0. What exists, and what does not
- Reuse is server to server, between two Didit applications: the source
application mints a share token for a finished session, the receiving
application redeems it. Both sides use their own x-api-key.
- There is NO reusable_identity object on the webhook or the decision, NO
metadata.request_fields or other selective-disclosure parameter, NO
workflow setting that "accepts" a credential, and NO revocation event. Do
not invent them. metadata on a session is free-form JSON that Didit echoes
back, nothing more. The receiving application gets the whole decision.
- This is not an EU Digital Identity (EUDI) Wallet integration. Didit does
not issue or accept EUDI Wallet credentials through these calls.
## 1. Provision
- Sign up: https://business.didit.me
- Source application: its API key. Receiving application: its API key and its
application id (a UUID: shown in the console, and sent as application_id
on every webhook that application receives). They are different
applications; sharing a session with the application that owns it is
refused.
## 2. Create the workflow for the first verification
POST https://verification.didit.me/v3/workflows/
-H "x-api-key: <source-api-key>"
-H "Content-Type: application/json"
{
"workflow_label": "KYC onboarding",
"features": [
{ "feature": "OCR" },
{ "feature": "LIVENESS" },
{ "feature": "FACE_MATCH" },
{ "feature": "IP_ANALYSIS" }
]
}
OCR is the ID Verification feature (uppercase, strict: ID_VERIFICATION is
rejected). Add { "feature": "AML" } for sanctions and PEP screening; it is
priced separately. Response: 201. The workflow id is uuid (workflow_id carries
the same value) and features comes back as one string, "OCR + LIVENESS + ...".
Create the workflow once and keep the id: every call makes a new one.
Prices: https://didit.me/pricing
## 3. Create a session
POST https://verification.didit.me/v3/session/
-H "x-api-key: <source-api-key>"
-H "Content-Type: application/json"
-d '{ "workflow_id": "<uuid from step 2>", "vendor_data": "<your user id>" }'
Response: 201 with session_id, session_token, url and status "Not Started".
Redirect the user to url (hosted flow) or open it in the Web, iOS, Android,
React Native or Flutter SDK. The field is named url on this response.
One unfinished session exists per workflow_id and vendor_data pair: calling
create again with the same pair answers 201 again with that same session.
Optional: callback, a URL the user's browser is sent back to when the flow
ends. It is a browser redirect, not a webhook: never trust its query string.
## 4. Webhook
Register a destination in the console (API & Webhooks), or over the API:
POST https://verification.didit.me/v3/webhook/destinations/
-H "x-api-key: <your-api-key>"
-H "Content-Type: application/json"
-d '{
"label": "Verification webhooks",
"url": "https://<your-public-host>/webhooks/didit",
"webhook_version": "v3",
"subscribed_events": ["status.updated", "data.updated"]
}'
label, url and subscribed_events are required. url must be a public HTTPS
address: Didit does not deliver to localhost or private addresses. Response:
201 with uuid and secret_shared_key. Store secret_shared_key as the webhook
secret (DIDIT_WEBHOOK_SECRET); it is unique to this destination. Remove a
destination with DELETE /v3/webhook/destinations/{uuid}/ (204).
What arrives:
- webhook_type is "status.updated" (the session changed status) or
"data.updated" (verification data was corrected after the fact)
- a destination receives the events of every session of the application,
so filter on workflow_id or vendor_data when several flows share it
- creating a session already sends status.updated with status
"Not Started". The decision key is present only when status is Approved,
Declined, In Review or Abandoned.
Verify every delivery:
Header: X-Signature-V2 (not X-Signature, not X-Signature-Simple)
Algorithm: HMAC-SHA256, hex digest, over the canonical JSON of the payload
(Python json.dumps(sort_keys=True, separators=(",", ":"),
ensure_ascii=False) after whole-valued floats become ints).
Never hash the raw request bytes under this header: that is
the older X-Signature.
Freshness: the signed body field timestamp is the dispatch time (Unix
seconds). Reject when abs(now - timestamp) > 300 seconds, and
reject when the X-Timestamp header does not equal it.
Idempotency: event_id is the same on every retry of one event, so store it
and skip a delivery you already processed. One session can
still send the same status under two event ids, and the
console's Try Webhook test deliveries carry no event_id, so
also make the handler safe to run twice for one
(session_id, status, webhook_type).
Compare: constant-time (crypto.timingSafeEqual)
Reference handler (Express). Keep the verification lines as written.
The handler is a fragment. Put this above it and app.listen(process.env.PORT)
below it. It needs Express and Node 21 or newer (an older Node rejects
every delivery). It expects a JSON body: answer 400 yourself if you accept
anything else on this route, and refuse to start without the secret.
const express = require("express");
const app = express();
const SECRET = process.env.DIDIT_WEBHOOK_SECRET; // secret_shared_key of the destination
// Your endpoint receives a signed payload
const crypto = require("node:crypto"); // ESM: import crypto from "node:crypto"
// X-Signature-V2 = HMAC over the canonical JSON, never the raw bytes. Match the sender byte for
// byte: keys sorted by code point, integers digit for digit, floats in Python's repr.
class Num { constructor(src) { this.src = src; } } // a number as written on the wire, not a double
const num = (s) => { if (/^-?\d+$/.test(s)) return BigInt(s).toString(); const n = +s; // ints stay exact
if (Number.isInteger(n)) return BigInt(n).toString(); const [m, e] = n.toExponential().split("e"); // 27.0 -> 27
return +e >= -4 ? String(n) : `${m}e-${String(-e).padStart(2, "0")}`; }; // 1e-05, not 0.00001
const byCodePoint = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)); // UTF-8 order = Python's
const canon = (v) => Array.isArray(v) ? `[${v.map(canon)}]` : v instanceof Num ? num(v.src)
: v && typeof v === "object" ? `{${Object.keys(v).sort(byCodePoint).map((k) => `${JSON.stringify(k)}:${canon(v[k])}`)}}`
: JSON.stringify(v);
// Read the body as text: express.json() would round 1000000000000000129 to a double first.
// Register this route ABOVE any global app.use(express.json()): the first parser to run
// consumes the stream, and a body it already parsed has lost the digits the signature covers.
app.post("/webhooks/didit", express.text({ type: "application/json" }), (req, res) => {
const exact = JSON.parse(req.body, (k, v, c) => typeof v === "number" ? new Num(c.source) : v); // Node 21+
const body = JSON.parse(req.body);
const mac = crypto.createHmac("sha256", SECRET).update(canon(exact), "utf8").digest("hex");
const sig = Buffer.from(String(req.headers["x-signature-v2"] ?? ""));
// Freshness comes from the signed body timestamp; the header alone is unsigned and replayable.
const ts = body.timestamp, fresh = String(ts) === req.headers["x-timestamp"]
&& Math.abs(Date.now() / 1000 - ts) <= 300;
if (!fresh || sig.length !== mac.length
|| !crypto.timingSafeEqual(sig, Buffer.from(mac))) return res.sendStatus(401);
const { session_id, status, webhook_type, vendor_data, decision } = body;
// decision is present on Approved, Declined, In Review and Abandoned.
res.sendStatus(200);
});
Status values (exact strings): Not Started, In Progress, Approved, Declined,
In Review, Resubmitted, Expired, Abandoned, Kyc Expired. Awaiting User only
appears on business verification sessions.
## 5. Read the decision
The same V3 decision reaches you two ways:
- webhook body: body.decision.id_verifications[]
- GET https://verification.didit.me/v3/session/{session_id}/decision/
-H "x-api-key: <your-api-key>"
This response IS the decision object. Read id_verifications at the top
level: there is no decision wrapper here.
Until the user finishes the ID step, status is "Not Started" or "In Progress"
and id_verifications is null, not an empty array. Guard for it.
The other feature results sit next to it as plural arrays: liveness_checks[],
face_matches[], ip_analyses[], aml_screenings[]. shared_from_session is null
on a session the person completed here.
## 6. Share the finished session (source application)
Only a session whose status is Approved, Declined or In Review can be shared.
POST https://verification.didit.me/v3/session/{session_id}/share/
-H "x-api-key: <source-api-key>"
-H "Content-Type: application/json"
-d '{ "for_application_id": "<receiving application id>", "ttl_in_seconds": 3600 }'
Response: 200 with share_token, for_application_id and session_kind ("user").
ttl_in_seconds: 60 to 86400, default 3600. Each call mints a new token; a
token cannot be revoked, it only expires. Send it to the receiving
application's backend, never to a browser.
## 7. Import it (receiving application)
POST https://verification.didit.me/v3/session/import-shared/
-H "x-api-key: <receiving-api-key>"
-H "Content-Type: application/json"
-d '{
"share_token": "<share_token from step 6>",
"trust_review": false,
"workflow_id": "<a workflow id of the receiving application>",
"vendor_data": "<user id on the receiving side>"
}'
share_token, trust_review and workflow_id are required. trust_review true
keeps the source status (Approved stays Approved); false puts the imported
session In Review so the receiving team decides. Response: 201 with the same
decision shape as step 5, a new session_id, and shared_from_session pointing
at the source session.
## 8. Errors to handle
The message is under detail for some errors and under the field name
(for_application_id, share_token) for others: read both.
- share, 400: "Cannot share a session with the same application."
- share, 400: "Target application does not exist."
- share, 400: "Only finished sessions ("Approved", "Declined", "In Review")
can be shared."
- import, 400 on share_token: "Invalid share token.", "Share token has
expired.", "This token is not valid for this application."
- import, 400: share_token, trust_review or workflow_id missing
- import, 403: "This session has already been shared with your
application." Mint a new token.
- import, 404: "Workflow does not exist for this application."
## 9. Hard rules
- base URL for v3 endpoints: verification.didit.me
- auth header: x-api-key, one key per application
- feature enum: OCR, LIVENESS, FACE_MATCH, IP_ANALYSIS, AML (uppercase)
- result path: decision.id_verifications[] in the webhook body and
id_verifications[] on the GET decision response
- webhook: X-Signature-V2 plus X-Timestamp, canonical JSON, freshness from
the signed body timestamp
## 10. Verify your integration
Sandbox (an application in sandbox mode: nothing is billed).
https://docs.didit.me/integration/sandbox-testing
- create the workflow, create a session, and read its decision: expect 201,
201 with url, and 200 with status "Not Started"
- to get a finished session without a person, call
POST https://verification.didit.me/v3/session/{session_id}/simulate/ with
your x-api-key and { "new_status": "Approved" }. It sets the status and
sends the webhook; the feature arrays stay null.
- share that session. With no second application yet, send a random UUID
as for_application_id and expect the 400 "Target application does not
exist.": that proves the call is wired. A full share and import needs
the second application's id and API key; do not fake that step.
- assert the webhook accepts a correctly signed payload and rejects a wrong
X-Signature-V2, a changed body, and a payload whose signed timestamp is
older than 300 seconds, even when X-Timestamp is refreshed
Docs:
- https://docs.didit.me/core-technology/reusable-kyc/overview
- https://docs.didit.me/sessions-api/create-session
- https://docs.didit.me/sessions-api/retrieve-session
- https://docs.didit.me/integration/webhooks
डिज़ाइन द्वारा कंप्लायंट
एक क्लिक में एक नया देश खोलें। हम मुश्किल काम करते हैं।
हम स्थानीय सहायक कंपनियाँ खोलते हैं, लाइसेंस सुरक्षित करते हैं, पेनेट्रेशन टेस्ट चलाते हैं, सर्टिफिकेशन हासिल करते हैं, और हर नए रेगुलेशन के साथ अलाइन करते हैं। एक नए देश में वेरिफिकेशन शिप करने के लिए, बस एक टॉगल फ्लिप करें। 220+ देश लाइव, हर तिमाही ऑडिट और पेन-टेस्टेड, एकमात्र आइडेंटिटी प्रोवाइडर जिसे EU सदस्य-राज्य सरकार ने औपचारिक रूप से इन-पर्सन वेरिफिकेशन से ज़्यादा सुरक्षित बताया है।
प्रति पहली वेरिफिकेशन, केवल एक बार जब कोई यूज़र Didit KYC बंडल के लिए भुगतान करता है।
Free
हर रिसीविंग प्लेटफ़ॉर्म पर। हर रीयूज़, हर प्रेजेंटेशन, हर सेलेक्टिव डिस्क्लोजर पर।
27
EU सदस्य देश। हर देश को 24 दिसंबर 2026 तक EUDI वॉलेट देना होगा, और Didit में EUDI वॉलेट स्वीकृति जल्द आ रही है।
5
आज लाइव राष्ट्रीय eID: MitID, BankID Sweden, Finnish Trust Network, Smart-ID और Mobile-ID।
तीन टियर, एक मूल्य सूची
मुफ़्त में शुरू करें। ज़रूरत के हिसाब से भुगतान करें। एंटरप्राइज़ तक स्केल करें।
हर महीने 500 मुफ़्त वेरिफिकेशन, हमेशा के लिए। फिर, केवल तभी भुगतान करें जब कोई मॉड्यूल चले। एंटरप्राइज़ के लिए कस्टम कॉन्ट्रैक्ट, डेटा रेज़िडेंसी और सर्विस लेवल एग्रीमेंट (SLAs) उपलब्ध हैं।