Zoi ID के साथ बनाएं
एक होस्ट पर दो API, छह भाषाओं में टाइप्ड क्लाइंट, होस्टेड फ़्लो और सैंडबॉक्स। पूरी गाइड पढ़ने के लिए खुली है, और सैंडबॉक्स कुंजियां अर्ली एक्सेस के साथ मिलती हैं।
बेस URLhttps://kyc.zoi.network
क्विकस्टार्ट
- 1
सेशन बनाएं
आपका बैकएंड अपनी पार्टनर कुंजी के साथ
POST /v1/partner/sessionsको कॉल करता है। - 2
फ़्लो चलाएं
क्लाइंट टोकन SDK को दें, या
verificationUrlब्राउज़र में खोलें। - 3
नतीजा पाएं
वेबहुक का हस्ताक्षर जांचें, फिर पहचान ID और उसकी स्थिति सेव करें।
curl https://kyc.zoi.network/v1/partner/sessions \
-H "Authorization: Bearer $ZOI_ID_PARTNER_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: signup-user_42" \
-d '{ "externalUserId": "user_42", "level": "standard", "appId": "com.example.app" }'दो API
पार्टनर API
सर्वर से सर्वर, /v1/partner के अंतर्गत। अपनी पार्टनर कुंजी Bearer टोकन के रूप में भेजें। इसे कभी ऐप में न रखें।
क्लाइंट API
SDK इसे /v1/client के अंतर्गत इस्तेमाल करता है। यह एक क्लाइंट टोकन भेजता है जो एक सेशन के लिए 60 मिनट चलता है।
नियम
- समय epoch मिलीसेकंड में होता है, उन फ़ील्ड में जिनका नाम
Atपर ख़त्म होता है। - तारीख़ें
YYYY-MM-DDमें होती हैं। अनजान हिस्सेXXहोते हैं, जैसे1990-XX-XX। - कुछ बनाने या तय करने वाले POST अनुरोध
Idempotency-Keyहेडर स्वीकार करते हैं। कुंजियां 24 घंटे रखी जाती हैं। - सेशन में बदलाव के साथ अपेक्षित रिविज़न भेजा जाता है। अगर वह बदल गया है, तो आपको
revision_conflictमिलता है।
सेशन फ़्लो
आपका बैकएंड सेशन बनाता है। SDK कदम चलाता है। सर्वर क्रम जांचता है और कोई कदम बहुत जल्दी आए तो step_not_allowed लौटाता है।
1. अपने बैकएंड से सेशन बनाएं
उसी यूज़र के लिए फिर से कॉल करने पर खुला सेशन जारी रहता है और नया क्लाइंट टोकन मिलता है।
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: 6f1c2a9e-signup-42
{
"externalUserId": "user_42",
"level": "standard",
"locale": "en",
"appId": "com.example.app"
}
200 OK
{
"sessionId": "ses_...",
"clientToken": "...",
"clientTokenExpiresAt": 1767225600000,
"status": "created",
"apiBaseUrl": "https://kyc.zoi.network",
"resumed": false
}2. SDK जो कदम चलाता है
- 01
सेशन और बाक़ी ज़रूरी कदम पढ़ें।
GET /v1/client/session
- 02
सहमति दर्ज करें, साथ में चेहरे की तुलना के लिए अलग और वैकल्पिक चुनाव।
POST /v1/client/consent
- 03
ऐप और डिवाइस जांचें। नतीजा फ़ैसले का हिस्सा बनता है।
POST /v1/client/attestation/challenge, POST /v1/client/attestation
- 04
दस्तावेज़ भेजें: MRZ स्कैन के बाद चिप पढ़ें, या फ़ोटो भेजें।
POST /v1/client/document/mrz-scan, POST /v1/client/document/chip/challenge, POST /v1/client/document/chip or POST /v1/client/document/photos
- 05
जब ऐप सिर की हरकतें दिखाए, तब सामने वाले कैमरे से एक छोटा वीडियो रिकॉर्ड करें।
POST /v1/client/liveness/challenge, POST /v1/client/liveness
- 06
निवास का देश भेजें, और एन्हांस्ड स्तर पर पता भी।
POST /v1/client/profile
- 07
सिर्फ़ पते की ज़रूरत होने पर: दस्तावेज़ अपलोड करें, फिर पते की पुष्टि करें। अगर पहचान दस्तावेज़ से पता पहले ही मिल गया हो, तो यह कदम छूट जाता है।
POST /v1/client/address/document, POST /v1/client/address/confirm
- 08
सिर्फ़ फ़ंड की ज़रूरत होने पर: जवाब सेव करें, पॉलिसी मांगे तो दस्तावेज़ जोड़ें, फिर कदम पूरा करें।
POST /v1/client/funds/answers, POST /v1/client/funds/document, POST /v1/client/funds/remove, POST /v1/client/funds/complete
- 09
दो सवालों के जवाब दें: क्या आप राजनीतिक रूप से प्रमुख व्यक्ति हैं, और क्या आप अपनी ओर से काम कर रहे हैं।
POST /v1/client/declarations
- 10
मौजूदा रिविज़न के साथ सबमिट करें।
POST /v1/client/submit
यूज़र किसी अपने-आप आए नतीजे की इंसानी समीक्षा भी मांग सकता है (POST /review-request) या सहमति वापस ले सकता है, जिससे सेशन रद्द होता है और उसकी फ़ाइलें तुरंत मिटती हैं (POST /withdraw)।
पते का प्रमाण और फ़ंड का स्रोत
पहचान से आगे सत्यापन के लिए POST /v1/partner/sessions में requirements जोड़ें। address पते का प्रमाण मांगता है। source_of_funds पूछता है कि पैसा कहां से आता है, और source_of_wealth कुल संपत्ति और वह कैसे बनी, यह भी पूछता है। फ़ंड वाली ये दोनों वैल्यू मिलकर एक कदम हैं, और दोनों address के साथ जोड़ी जा सकती हैं।
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
{
"externalUserId": "user_42",
"level": "standard",
"appId": "com.example.app",
"requirements": ["address", "source_of_funds"],
// Optional. Without them your partner default applies, else ours.
"addressPolicy": { "maxAgeDays": 90, "signedOnly": false },
"fundsPolicy": { "evidence": "optional", "currency": "EUR" }
}वैकल्पिक पॉलिसी
पॉलिसी न हो तो आपका पार्टनर डिफ़ॉल्ट लागू होता है, वरना हमारा। सेशन बनते समय पॉलिसी उसमें कॉपी हो जाती है।
addressPolicy:maxAgeDays(डिफ़ॉल्ट 90, 1 से 366),acceptedTypes(डिफ़ॉल्ट: यूटिलिटी, टेलीकॉम और बैंक दस्तावेज़, टैक्स दस्तावेज़, सरकारी पत्र और निवास प्रमाण पत्र) औरsignedOnly(डिफ़ॉल्ट false)।fundsPolicy:questions,evidence(none,optionalयाrequired, डिफ़ॉल्टnone),acceptedTypes,maxAgeDays(डिफ़ॉल्ट 180),currency(ISO 4217, डिफ़ॉल्ट USD) और रेंज के लिएbrackets।- दूसरी ज़रूरतों वाला कोई खुला सेशन जो अभी सबमिट नहीं हुआ, रद्द हो जाता है और नया सेशन शुरू होता है, ठीक स्तर बदलने की तरह।
- हर नतीजे को सैंडबॉक्स सिनेरियो से टेस्ट करें, जैसे
address_signed_pdf,address_document_review,funds_signed_documentsऔरfunds_review।
फ़ॉलो-अप सेशन
ऐसे यूज़र के लिए सिर्फ़ ज़रूरतों का सत्यापन करें जिसकी पहचान आपके पास पहले से सक्रिय है। requirements के साथ reuseIdentity: true भेजें।
- यूज़र सहमति देता है और सिर्फ़ नए कदम पूरे करता है। दस्तावेज़, सेल्फ़ी या घोषणाएं दोबारा नहीं मांगी जातीं।
- मंज़ूरी पर पहचान अपनी ID, सत्यापन की तारीख़ और वैधता बनाए रखती है, और उसे नया नतीजा मिलता है। आपको
session.approvedऔरidentity.updatedमिलते हैं। - सक्रिय पहचान के बिना कॉल का जवाब 409
step_not_allowedहोता है। - इसे अपने रिस्क नियमों से शुरू करें, जैसे कोई बड़ी जमा राशि, PEP फ़्लैग या जोखिम वाला देश। आपके नियम आपके बैकएंड में, एक ही जगह रहते हैं।
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: edd-user_42-2026-11
{
"externalUserId": "user_42",
"appId": "com.example.app",
"requirements": ["source_of_funds", "source_of_wealth"],
"reuseIdentity": true,
"fundsPolicy": { "evidence": "required" }
}
// No active identity for user_42:
409 { "error": { "code": "step_not_allowed", ... } }नतीजे और स्कोप
मंज़ूर सेशन में address और funds होते हैं, और पहचान हर एक का सबसे नया नतीजा रखती है। सारांश वाले फ़ील्ड हर स्कोप के साथ आते हैं। ब्योरे के लिए स्कोप चाहिए।
- स्कोप
address: पते की लाइनें। इसके बिना आपकोverified,method,evidenceLevel,documentType,documentDate,verifiedAtऔरcountryमिलते हैं। - स्कोप
financial_data:answers,documentsऔरfindings। इसके बिना आपकोkinds,evidenceLevel,reviewed,documentCountऔरverifiedAtमिलते हैं। यह कभीeligibilityका हिस्सा नहीं होता। evidenceLevelकी वैल्यूhigh,medium,lowयाnoneहोती है। पते के तरीके, सबसे मज़बूत पहले:wallet,id_document,signed_pdf,official_code,document_reviewऔरdeclared।- दस्तावेज़ API से नहीं भेजे जाते। जब एनवायरनमेंट के पास
financial_dataस्कोप हो, तो कंप्लायंस भूमिका वाले सदस्य डैशबोर्ड में फ़ंड के स्रोत वाले दस्तावेज़ों के पेज देख सकते हैं। हर बार देखना लॉग होता है।
"session": {
"id": "ses_...",
"status": "approved",
"requirements": ["address", "source_of_funds"],
"reusesIdentity": false,
"address": {
"verified": true,
"method": "signed_pdf",
"evidenceLevel": "high",
"documentType": "bank_statement",
"documentDate": "2026-10-14",
"verifiedAt": 1767225600000,
"country": "DE",
// scope "address"
"address": { "line1": "Musterstrasse 12", "city": "Berlin", "postalCode": "10115", "country": "DE" }
},
"funds": {
"kinds": ["source_of_funds"],
"evidenceLevel": "medium",
"reviewed": true,
"documentCount": 2,
"verifiedAt": 1767225600000,
// scope "financial_data"
"answers": {
"employmentStatus": "employed",
"income": { "min": 50000, "max": 100000, "currency": "EUR" },
"sources": ["salary", "savings"],
...
},
"documents": [
{ "documentType": "payslip", "documentDate": "2026-10-31", "amount": 5200, "currency": "EUR",
"signature": "valid", "signedByKnownIssuer": true, "nameMatch": "match", "findings": [], ... },
...
],
"findings": []
}
}वेब फ़्लो
SDK नहीं? यूज़र को हमारे होस्ट किए गए पेज पर भेजें। यह वही API, वही जाँच और वही रिव्यू कतार इस्तेमाल करता है।
1. लिंक पाएँ
POST /v1/partner/sessions से verificationUrl मिलता है। काम पूरा होने पर यूज़र को वापस भेजने के लिए redirectUrl दें। यह आपके रजिस्टर किए गए redirect origins में से किसी एक से शुरू होना चाहिए।
POST /v1/partner/sessions
Authorization: Bearer <partner key>
Content-Type: application/json
{
"externalUserId": "user_42",
"level": "standard",
"locale": "en",
"appId": "com.example.app",
"redirectUrl": "https://example.com/kyc/done"
}
200 OK
{
"sessionId": "ses_...",
"clientToken": "...",
"verificationUrl": "https://kyc.zoi.network/verify/#token=...&lang=en",
...
}- क्लाइंट टोकन URL के fragment में,
#के बाद होता है। ब्राउज़र fragment कभी सर्वर को नहीं भेजते, इसलिए टोकन लॉग में याRefererहेडर में नहीं आता। पेज इसे पढ़ता है, एड्रेस बार से हटाता है और सिर्फ़ मेमोरी में रखता है। - 19 भाषाओं में से एक चुनने के लिए fragment में
langजोड़ें। इसके बिना पेज ब्राउज़र की भाषा इस्तेमाल करता है। - रीलोड करने पर टोकन खो जाता है। अपने बैकएंड से उसी सेशन के लिए नया लिंक बनाएँ।
- पेज सहमति के साथ
channel: "web"भेजता है। ब्राउज़र पहचान दस्तावेज़ की चिप नहीं पढ़ सकते, इसलिए वेब सेशन दस्तावेज़ की फ़ोटो या डिजिटल ID वॉलेट इस्तेमाल करते हैं। ये डिवाइस जांच छोड़ देते हैं, और वेब से आई दस्तावेज़ की फ़ोटो का फ़ैसला हमेशा प्रशिक्षित समीक्षक करता है। - कंप्यूटर पर पेज एक QR कोड दिखाता है ताकि यूज़र फ़ोन पर जारी रख सके।
2. जब यूज़र काम पूरा कर ले
फ़्लो खत्म होने पर (भेजा गया, रद्द हुआ या अंतिम स्थिति), पेज यह संदेश इनमें से हर मौजूद चीज़ को भेजता है: window.ReactNativeWebView, window.webkit.messageHandlers.zoiId, window.ZoiIdAndroid और window.opener। फिर यह zoiIdSession और zoiIdStatus जोड़कर redirectUrl खोलता है।
संदेश या redirect पैरामीटर पर कभी भरोसा न करें। सिर्फ़ अपने webhook या GET /v1/partner/sessions/:id पर भरोसा करें।
// Sent to each bridge that exists:
// window.ReactNativeWebView.postMessage(JSON string)
// window.webkit.messageHandlers.zoiId.postMessage(object)
// window.ZoiIdAndroid.postMessage(JSON string)
// window.opener.postMessage(object, "<origin of your redirectUrl>")
// (popups only, and only when the session has a redirectUrl)
{
"source": "zoi-id",
"type": "finished", // or "cancelled"
"sessionId": "ses_...",
"status": "processing" // the session status at that moment
}
// Then, if redirectUrl was set (the page uses the one stored with the
// session, never one from the address bar):
https://example.com/kyc/done?zoiIdSession=ses_...&zoiIdStatus=processing3. वेबव्यू सेटिंग
Android WebView
javaScriptEnabled और domStorageEnabled चालू करें और mediaPlaybackRequiresUserGesture को false करें। आपके ऐप को CAMERA अनुमति मिलने के बाद WebChromeClient में onPermissionRequest पर RESOURCE_VIDEO_CAPTURE की अनुमति दें। फ़ोटो वाले विकल्प के लिए फ़ाइल चुनने की सुविधा जोड़ें।
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.settings.mediaPlaybackRequiresUserGesture = false
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
// Only after your app holds Manifest.permission.CAMERA.
if (request.resources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE))
} else {
request.deny()
}
}
override fun onShowFileChooser(
view: WebView, callback: ValueCallback<Array<Uri>>, params: FileChooserParams,
): Boolean {
// Open a picker and pass the result to callback (photo fallback).
return true
}
}iOS WKWebView
iOS 14.3 या नया। allowsInlineMediaPlayback को true करें और अपने ऐप में NSCameraUsageDescription जोड़ें। iOS 15 और नए वर्ज़न में आप कैमरा अनुमति का फ़ैसला UI delegate में कर सकते हैं।
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
let webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self // iOS 15+: decide camera access below
func webView(_ webView: WKWebView,
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
decisionHandler(origin.host == "kyc.zoi.network" ? .grant : .deny)
}
// Info.plist: NSCameraUsageDescriptionReact Native WebView
mediaCapturePermissionGrantType="grant", allowsInlineMediaPlayback और javaScriptEnabled सेट करें। आपके ऐप को कैमरा अनुमति चाहिए।
<WebView
source={{ uri: verificationUrl }}
javaScriptEnabled
allowsInlineMediaPlayback
mediaCapturePermissionGrantType="grant"
onMessage={(event) => {
const message = JSON.parse(event.nativeEvent.data);
if (message.source === "zoi-id") {
// Close the webview, then ask your backend for the real status.
}
}}
/>कैमरा अनुमतियों और clickjacking की वजह से iframe सपोर्ट नहीं हैं। ब्राउज़र टैब, पॉपअप या वेबव्यू इस्तेमाल करें।
स्थितियां
सेशन
created- सेशन बना है, अभी कुछ अपलोड नहीं हुआ।
in_progress- सहमति दी गई, कदम अपलोड हो रहे हैं।
processing- सबमिट हो गया, जांच चल रही है।
review- प्रशिक्षित समीक्षक का इंतज़ार।
approved- अंतिम। पहचान सत्यापित है।
rejected- अंतिम। कारण कोड देखें।
resubmit- यूज़र को requiredSteps के कदम दोबारा करने होंगे।
expired- समय पर अंतिम फ़ैसला नहीं हुआ।
cancelled- पार्टनर, यूज़र या डेटा मिटाने से रद्द।
पहचान
active- इस्तेमाल लायक़।
suspended- रुकी हुई, जैसे किसी नए प्रतिबंध मेल के बाद।
expired- दस्तावेज़ या सत्यापन की अवधि ख़त्म। नया सेशन दोबारा सत्यापित करता है।
revoked- अंतिम।
SDK
React Native (Expo) SDK आपको टाइप्ड API क्लाइंट, NFC चिप रीडिंग और डिवाइस जांच देता है। यह हेडलेस है, इसलिए अपनी स्क्रीन और कैमरे पर पूरा कंट्रोल आपके ऐप के पास रहता है। अपने सर्वर के लिए TypeScript, Python, Go, PHP, Java और Ruby के टाइप्ड क्लाइंट इस्तेमाल करें।
import { ZoiIdClient, nextStep } from "@zoi/id-sdk";
// clientToken and apiBaseUrl come from your backend (POST /v1/partner/sessions).
const client = new ZoiIdClient({ baseUrl: apiBaseUrl, clientToken });
const session = await client.getSession();
switch (nextStep(session)) {
case "consent": /* show the notice and the biometric choice */ break;
case "document": /* chip read or photos */ break;
case "liveness": /* record the video */ break;
case "address": /* upload a document, then confirm the address */ break;
case "funds": /* answers, then documents when the policy asks */ break;
case "submit": await client.submit(session.revision); break;
case "done": /* wait for your backend to get the webhook */ break;
}वेबहुक
जब कोई सेशन या पहचान बदलती है, हम वेबहुक भेजते हैं। सामग्री पर भरोसा करने से पहले हमेशा हस्ताक्षर जांचें।
- हर वेबहुक में
Zoi-Id-Signatureहेडर होता है:t=unix seconds,v1=hex। v1, आपके वेबहुक सीक्रेट से टेक्स्टt.raw bodyका HMAC-SHA256 है। JSON पार्स करने से पहले वाली कच्ची बॉडी इस्तेमाल करें।- जब सीक्रेट बदला जा रहा हो, हेडर में हर सक्रिय सीक्रेट के लिए एक
v1होता है। अगर कोई भी मेल खाए, तो वेबहुक स्वीकार करें। - अगर
tअभी के समय से 300 सेकंड से ज़्यादा दूर है, तो उसे अस्वीकार करें। - नाकाम डिलीवरी 72 घंटे तक दोबारा की जाती है। हर बार नए
tके साथ फिर से हस्ताक्षर होता है। - पहचानों में
revisionहोता है। कोई इवेंट तभी लागू करें जब उसका रिविज़न आपके रखे हुए से नया हो।
POST <your webhook URL>
Zoi-Id-Signature: t=1767225600,v1=5f2b...e9
{
"v": 1,
"eventId": "evt_...",
"type": "identity.suspended",
"createdAt": 1767225600000,
"object": "identity",
"externalUserId": "user_42",
"identity": {
"identityId": "idn_...",
"revision": 7,
"status": "suspended",
"level": "standard",
"verifiedAt": 1764547200000,
"validUntil": 1859155200000,
"ageOver18": true,
"captureMethod": "nfc"
}
}इवेंट के प्रकार
session.processingsession.reviewsession.approvedsession.rejectedsession.resubmitsession.expiredsession.cancelledidentity.updatedidentity.suspendedidentity.reinstatedidentity.expiredidentity.revoked
TypeScript में हस्ताक्षर जांचें
import { createHmac, timingSafeEqual } from "node:crypto";
const TOLERANCE_SECONDS = 300;
export function verifyZoiIdSignature(
rawBody: string,
header: string | null,
secret: string,
nowSeconds = Math.floor(Date.now() / 1000),
): boolean {
if (!header) return false;
let t: string | undefined;
const signatures: Buffer[] = [];
for (const part of header.split(",")) {
const [key, value] = part.trim().split("=");
if (!value) continue;
if (key === "t") t = value;
if (key === "v1" && /^[0-9a-f]+$/i.test(value)) signatures.push(Buffer.from(value, "hex"));
}
if (!t || !/^\d+$/.test(t) || signatures.length === 0) return false;
if (Math.abs(nowSeconds - Number(t)) > TOLERANCE_SECONDS) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((sig) => sig.length === expected.length && timingSafeEqual(sig, expected));
}
// Example handler: read the raw body first, parse JSON only after the check.
export async function POST(request: Request) {
const rawBody = await request.text();
const ok = verifyZoiIdSignature(rawBody, request.headers.get("Zoi-Id-Signature"), process.env.ZOI_ID_WEBHOOK_SECRET!);
if (!ok) return new Response("bad signature", { status: 400 });
const event = JSON.parse(rawBody);
// Store event.eventId to skip duplicates, then apply it if the revision is newer.
return new Response(null, { status: 204 });
}Go में हस्ताक्षर जांचें
package zoiid
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strconv"
"strings"
"time"
)
const toleranceSeconds = 300
// VerifySignature checks the Zoi-Id-Signature header against the raw body.
func VerifySignature(rawBody []byte, header, secret string, now time.Time) bool {
var t string
var sigs [][]byte
for _, part := range strings.Split(header, ",") {
key, value, ok := strings.Cut(strings.TrimSpace(part), "=")
if !ok || value == "" {
continue
}
switch key {
case "t":
t = value
case "v1":
if b, err := hex.DecodeString(value); err == nil {
sigs = append(sigs, b)
}
}
}
ts, err := strconv.ParseInt(t, 10, 64)
if err != nil || len(sigs) == 0 {
return false
}
if d := now.Unix() - ts; d > toleranceSeconds || d < -toleranceSeconds {
return false
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(t + "."))
mac.Write(rawBody)
expected := mac.Sum(nil)
for _, sig := range sigs {
if hmac.Equal(sig, expected) {
return true
}
}
return false
}इवेंट फ़ीड
GET /v1/partner/events पिछले 30 दिनों के सभी इवेंट लौटाता है, सबसे पुराना पहले। अगला पेज पढ़ने के लिए आख़िरी nextCursor को after में भेजें। लंबी रुकावट के बाद, या यह पक्का करने के लिए कि कुछ छूटा नहीं, इसका इस्तेमाल करें।
GET /v1/partner/events?after=<nextCursor>&limit=100
Authorization: Bearer <partner key>
200 OK
{
"items": [ /* webhook payloads, oldest first */ ],
"nextCursor": "..." // null when there is nothing more
}फ़्रॉड रिपोर्ट
जब कोई तय हो चुका सेशन फ़्रॉड निकले, तो हमें बताएं, जैसे किसी चार्जबैक के बाद। रिपोर्ट से हम ग़लत मंज़ूरियों को मापते हैं। ये सेशन, पहचान या यूज़र का नतीजा नहीं बदलतीं।
- स्कोप
sessions:write। सिर्फ़ तय हो चुके सेशन के लिए (मंज़ूर या अस्वीकार)। फ़ैसले से पहले कॉल का जवाब 409 होता है। - ख़ाली बॉडी
confirmed_fraudको श्रेणीotherके साथ रिपोर्ट करती है।statusकी वैल्यूsuspected_fraudभी हो सकती है, या अपनी रिपोर्ट वापस लेने के लिएcleared। - श्रेणियां:
forged_document,impostor,deepfake_or_replay,synthetic_identity,account_takeoverऔरother।clearedके साथ कोई श्रेणी नहीं। noteहमारे एनालिस्ट के लिए खुला टेक्स्ट है, ज़्यादा से ज़्यादा 1000 अक्षर। इसमें कभी नाम, दस्तावेज़ नंबर या कोई और निजी डेटा न डालें।- नई रिपोर्ट का जवाब 201 होता है। वही रिपोर्ट दोबारा भेजने पर सेव की गई रिपोर्ट 200 के साथ लौटती है। सुरक्षित तरीके से दोबारा कोशिश करने के लिए
Idempotency-Keyभेजें। हर सेशन पर ज़्यादा से ज़्यादा 20 रिपोर्ट। - यही रिपोर्ट डैशबोर्ड में सेशन के पेज पर बस एक क्लिक दूर है।
POST /v1/partner/sessions/ses_.../fraud-reports
Authorization: Bearer <partner key>
Content-Type: application/json
Idempotency-Key: chargeback-8812
{
"status": "confirmed_fraud",
"category": "impostor",
"note": "Chargeback on the first deposit"
}
201 Created
{
"id": "flb_...",
"sessionId": "ses_...",
"status": "confirmed_fraud",
"category": "impostor",
"noteKept": true,
"createdAt": 1767225600000
}डेटा मिटाना
DELETE /v1/partner/users/:externalUserId यूज़र का डेटा तब मिटाता है जब वह खाता बंद करे या डेटा मिटाने को कहे। जवाब बताता है कि अभी क्या मिटा, और क्या रखा गया, क्यों और कब तक।
DELETE /v1/partner/users/user_42
Authorization: Bearer <partner key>
200 OK
{
"deleted": ["images", "chip_files", "video", "personal_data", "address"],
"retained": [
{ "category": "dedup_keys", "reason": "fraud_prevention", "until": 1924992000000 },
{ "category": "sanctions_screening_records", "reason": "legal_obligation", "until": 2082758400000 }
],
"backupsPurgedWithinDays": 30
}एरर
हर एरर का ढांचा एक जैसा है और हर कोड का HTTP स्टेटस तय है।
{
"error": {
"code": "step_not_allowed",
"message": "This step is not allowed now.",
"requestId": "req_..."
}
}| कोड | HTTP | मतलब |
|---|---|---|
bad_request | 400 | अनुरोध अनुबंध से मेल नहीं खाता। |
unauthorized | 401 | कुंजी या टोकन नहीं है या ग़लत है। |
token_expired | 401 | क्लाइंट टोकन की मियाद ख़त्म हो गई। अपने बैकएंड से नया बनाएं। |
forbidden | 403 | यह कुंजी यह काम नहीं कर सकती। |
not_found | 404 | ऐसा कोई सेशन या यूज़र नहीं है। |
session_closed | 409 | सेशन अंतिम है। अब और अपलोड नहीं। |
step_not_allowed | 409 | ग़लत क्रम, या अभी इस कदम की ज़रूरत नहीं। |
revision_conflict | 409 | सेशन का रिविज़न बदल गया। फिर से पढ़ें। |
idempotency_conflict | 409 | एक ही Idempotency-Key किसी दूसरे अनुरोध के साथ इस्तेमाल हुई। |
challenge_expired | 410 | चुनौती की मियाद ख़त्म हो गई या पहले इस्तेमाल हो चुकी। नई मांगें। |
payload_too_large | 413 | अपलोड बहुत बड़ा है। |
unsupported_media_type | 415 | यह फ़ाइल प्रकार स्वीकार नहीं है। |
rate_limited | 429 | बहुत ज़्यादा अनुरोध। बाद में फिर कोशिश करें। |
internal | 500 | हमारी तरफ़ कुछ गड़बड़ हुई। |
dependency_unavailable | 503 | जिस सेवा की हमें ज़रूरत है, वह बंद है। बाद में फिर कोशिश करें। |
कारण कोड
जब दोबारा भेजना हो या अस्वीकार हो, तो सेशन में reasonCodes होते हैं। हर कोड के लिए अपना अनुवादित संदेश दिखाएं। यूज़र को कभी कच्चा कोड न दिखाएं।
consent_missingconsent_withdrawnattestation_faileddocument_expireddocument_unreadabledocument_not_supporteddocument_suspected_tamperingdocument_number_visiblechip_verification_failedchip_proof_missingchip_data_mismatchmrz_invalidphoto_qualityface_not_foundface_mismatchliveness_failedunderagelocation_not_supportedresidence_not_supportedsanctions_matchpep_reviewduplicate_identitypossible_duplicatedeclaration_requires_reviewuser_requested_reviewreviewer_otheraddress_unreadableaddress_document_too_oldaddress_document_not_acceptedaddress_name_mismatchaddress_signature_requiredfunds_document_unreadablefunds_document_too_oldfunds_document_not_acceptedfunds_more_evidencefunds_evidence_rejected