> ## 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.

# लेन-देन सबमिशन SDK - क्लाइंट-साइड KYT

> Didit SDK से स्कोप्ड token के साथ लेन-देन सबमिट करें: स्वचालित डिवाइस इंटेलिजेंस, स्पूफ-प्रूफ बाइंडिंग और वॉलेट स्वामित्व फ़्लो।

The Didit SDKs can submit [monitored transactions](https://docs.didit.me/hi/transaction-monitoring/transactions.md) directly from the end-user's device, including [Travel Rule](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md) transfers and crypto screening.
आपका बैकएंड एक अल्पकालिक, सीमित-दायरे वाला टोकन जारी करता है; बाकी काम SDK करता है।
यह अपने-आप डिवाइस इंटेलिजेंस जोड़ता है, और जब Travel Rule ट्रांसफ़र के लिए वॉलेट स्वामित्व का प्रमाण चाहिए, तो वह उसी समय वह फ़्लो शुरू कर देता है।
आवश्यक सत्यापन सत्र को कभी अपने-आप शुरू नहीं किया जाता - वह रिस्पॉन्स में वापस आता है, ताकि आपका ऐप उसे अपने Didit सत्यापन इंटीग्रेशन से शुरू करे; नीचे [आवश्यक उपयोगकर्ता कार्रवाइयाँ](#आवश्यक-उपयोगकर्ता-क्रियाएँ) देखें।

## अवलोकन

क्लाइंट-साइड सबमिशन तीन गारंटियों पर आधारित है:

* **स्पूफिंग-रोधी विषय बंधन।** टोकन को जारी करते समय एक `vendor_data` (आपकी उपयोगकर्ता ID) तक सीमित किया जाता है। इसके साथ सबमिट किए गए हर लेन-देन की सब्जेक्ट पहचान इसी बंधन से सर्वर-साइड पर लागू होती है, इसलिए छेड़छाड़ किया गया क्लाइंट किसी दूसरे उपयोगकर्ता की ओर से सबमिट नहीं कर सकता, और payload में कभी क्रेडेंशियल भेजने की ज़रूरत नहीं पड़ती।
* **अपने-आप डिवाइस इंटेलिजेंस।** SDK एक डिवाइस फ़िंगरप्रिंट इकट्ठा करता है और उसे सबमिशन के साथ भेजता है, और Didit IP पता व user agent सर्वर-साइड पर निकालता है। संयुक्त डिवाइस संदर्भ लेन-देन के सब्जेक्ट से अपने-आप जुड़ जाता है, बिना किसी अतिरिक्त लाइब्रेरी, अलग डिवाइस टोकन या आपकी ओर से किसी अतिरिक्त व्यवस्था के। इससे डिवाइस-आधारित [नियम](https://docs.didit.me/hi/transaction-monitoring/rules.md) और सत्रों व लेन-देन के बीच डिवाइस-आधारित सहसंबंध संभव होते हैं।
* **अपने-आप शुरू होने वाला वॉलेट-स्वामित्व प्रमाण।** जब बनाया गया लेन-देन माँगता है कि अंतिम उपयोगकर्ता किसी वॉलेट पर नियंत्रण साबित करे, तो रिस्पॉन्स में `wallet_ownership` प्रकार का `action_required` ब्लॉक आता है और SDK उसी समय वह फ़्लो खोल देता है, फिर पूरा होने पर लेन-देन को ताज़ा करता है - आपको बार-बार जाँच करने वाले लूप या लिंक डिलीवरी खुद नहीं बनानी पड़ती। एक आवश्यक `verification_session` कार्रवाई अलग है: उसे कभी अपने-आप शुरू नहीं किया जाता, और वह उसी ब्लॉक में वापस आती है ताकि आपका ऐप उसे अपने Didit सत्यापन इंटीग्रेशन से शुरू करे।

> [!NOTE]
>
> सर्वर-साइड [`POST /v3/transactions/`](https://docs.didit.me/hi/transaction-monitoring/transactions) वह सही विकल्प बना रहता है जब कोई अंतिम उपयोगकर्ता मौजूद न हो: बैक-ऑफ़िस ट्रांसफ़र, बैच इम्पोर्ट, या आपके अपने सिस्टम द्वारा रिपोर्ट की गई घटनाएँ।
> दोनों रास्ते एक ही लेन-देन रिकॉर्ड बनाते हैं, एक ही नियम चलाते हैं और एक ही [webhook](https://docs.didit.me/hi/transaction-monitoring/webhooks.md) भेजते हैं।

## प्रवाह

**1. लेन-देन टोकन जारी करें**

आपका बैकएंड `POST /v3/transactions/sdk-token/` को आपकी API कुंजी और उपयोगकर्ता के `vendor_data` के साथ कॉल करता है, और लौटाया गया `sdk_token` आपके ऐप को देता है।

**2. डिवाइस से सबमिट करें**

ऐप SDK पर `submitTransaction` कॉल करता है, जो payload को `X-Transaction-Token` हेडर के साथ और अपने-आप होने वाले डिवाइस एनरिचमेंट के साथ `POST /v1/transactions/` पर भेजता है।

**3. कोई आवश्यक कार्रवाई संभालें**

यदि `action_required.type` `wallet_ownership` है, तो SDK विजेट अपने-आप खोलता है, फिर `GET /v1/transactions/{transaction_id}/` के ज़रिए लेन-देन ताज़ा करता है।
यदि यह `verification_session` है, तो SDK कुछ भी शुरू नहीं करता - `action_required` पढ़ें और उसके `session_token` (या वेब पर `url`) से अपना सत्यापन फ़्लो शुरू करें।

## लेन-देन टोकन जारी करना

अपने बैकएंड से `POST /v3/transactions/sdk-token/` के ज़रिए टोकन जारी करें - `/v3/` लेन-देन endpoint के बाकी हिस्सों की तरह API कुंजी प्रमाणीकरण का उपयोग करें।

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/sdk-token/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_data": "user-042",
    "ttl_seconds": 900,
    "max_uses": 3
  }'
```

```json theme={null}
{
  "sdk_token": "q7Zt...urlsafe",
  "expires_at": "2026-07-07T12:15:00Z"
}
```

| फ़ील्ड | प्रकार | विवरण |
| - | - | - |
| `vendor_data` | string | **ज़रूरी।** आपकी आंतरिक पहचान, इस टोकन के दायरे में आने वाले अंतिम उपयोगकर्ता की। इस टोकन के साथ सबमिट किए गए हर लेन-देन की सब्जेक्ट पहचान इसी मान से लागू होती है। |
| `ttl_seconds` | integer | सेकंड में टोकन की अवधि। डिफ़ॉल्ट `900` (15 मिनट) है; अधिकतम `86400` (24 घंटे)। |
| `max_uses` | integer | वैकल्पिक। इस टोकन के साथ सफल सबमिशन की अधिकतम संख्या। TTL के भीतर असीमित उपयोग के लिए छोड़ दें। |

camelCase उपनाम (`vendorData`, `ttlSeconds`, `maxUses`) भी स्वीकार किए जाते हैं, जैसे `/v3/` API के अन्य हिस्सों में।

> [!WARNING]
>
> **अपनी API कुंजी कभी किसी ऐप में शामिल न करें।**
> API कुंजी आपके बैकएंड पर ही रहती है और टोकन जारी करती है; डिवाइस तक केवल अल्पकालिक `sdk_token` जाता है।
> हर उपयोगकर्ता सत्र के लिए नया टोकन जारी करें, लंबे समय तक चलने वाले टोकन दोबारा इस्तेमाल न करें, और जब अपेक्षित सबमिशन की संख्या पता हो तो `max_uses` को सख़्त रखें।

## डिवाइस से सबमिट करना

SDK `X-Transaction-Token` हेडर में टोकन के साथ `POST /v1/transactions/` पर पोस्ट करते हैं।
वायर पेलोड camelCase में होता है; `submitTransaction` मेथड इसे आपके लिए बनाते हैं, इसलिए इसके साथ सीधे तभी काम करना पड़ता है जब आप अपने HTTP क्लाइंट से endpoint को कॉल करते हैं:

```bash theme={null}
curl -X POST https://verification.didit.me/v1/transactions/ \
  -H "X-Transaction-Token: SDK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "txnId": "wd-2026-07-07-0042",
    "type": "travelRule",
    "info": {
      "direction": "out",
      "amount": "0.25",
      "currency": "ETH",
      "currencyType": "crypto",
      "cryptoParams": { "crypto_chain": "ETH" }
    },
    "subject": { "fullName": "Jane Doe" },
    "counterparty": {
      "fullName": "Ana Diaz",
      "paymentMethod": { "type": "unhosted_wallet", "accountId": "0xBeneficiaryWallet01" }
    },
    "travelRule": {
      "status": "AWAITING_COUNTERPARTY",
      "beneficiaryData": { "wallet_address": "0xBeneficiaryWallet01", "name": "Ana Diaz" }
    },
    "includeCryptoScreening": true
  }'
```

हर टॉप-लेवल फ़ील्ड अपने [`POST /v3/transactions/`](https://docs.didit.me/hi/transaction-monitoring/transactions) के समतुल्य फ़ील्ड से मैप होता है:

| वायर फ़ील्ड | `/v3/` समतुल्य | नोट्स |
| - | - | - |
| `txnId` | `transaction_id` | **ज़रूरी।** आपके द्वारा दिया गया लेन-देन का अद्वितीय पहचानकर्ता। |
| `txnDate` | `transaction_at` | ISO-8601 टाइमस्टैम्प; डिफ़ॉल्ट रूप से अभी का समय। |
| `zoneId` | `time_zone` | IANA टाइम ज़ोन id, जैसे `Europe/Madrid`। |
| `type` | `transaction_category` | **ज़रूरी।** `finance`, `kyc`, `travelRule`, `userPlatformEvent`, `gamblingBet`, और अन्य श्रेणियाँ। |
| `info` | `transaction_details` | **ज़रूरी।** `direction`, `amount`, `currency` (ज़रूरी), साथ ही `currencyType`, `amountInDefaultCurrency`, `defaultCurrencyCode`, `paymentDetails`, `paymentTxnId`, `type` (कार्रवाई प्रकार), `cryptoParams`। |
| `subject`, `counterparty` | `subject`, `counterparty` | प्रतिभागी: `type` (इकाई प्रकार), `externalUserId`, `fullName`, `firstName`, `lastName`, `dob`, `address`, `institutionInfo`, `device`, `paymentMethod` (`type`, `accountId`, `issuingCountry`)। यदि counterparty का `paymentMethod.type` `unhosted_wallet` है, तो गंतव्य को स्व-होस्टेड घोषित किया जाता है - देखें [नीचे](#स्व-होस्टेड-वॉलेट-घोषित-करना)। |
| `props` | `custom_properties` | कस्टम की-वैल्यू जोड़े, जिन्हें नियमों में `custom_values.<key>` के रूप में उपयोग किया जा सकता है। |
| `travelRule` | `travel_rule_details` | `status`, `protocol`, `required`, `obligationsCount`, `originatorData`, `beneficiaryData`, `metadata`; जब भी आप यह ब्लॉक भेजते हैं, `status` ज़रूरी है, अन्यथा अनुरोध `400` के साथ विफल हो जाता है। Travel Rule सक्षम होने पर, Didit आपके भेजे गए किसी भी `status` को अनदेखा करता है और विनिमय स्वयं संचालित करता है। |
| `includeCryptoScreening` | `include_crypto_screening` | प्रति-लेन-देन क्रिप्टो स्क्रीनिंग ओवरराइड। |

रिस्पॉन्स वही snake\_case लेन-देन विवरण है जो `/v3/` endpoints में होता है, साथ में `action_required` ब्लॉक:

```json theme={null}
{
  "uuid": "22222222-3333-4444-5555-666666666666",
  "txn_id": "wd-2026-07-07-0042",
  "transaction_type": "travelRule",
  "direction": "OUTBOUND",
  "status": "APPROVED",
  "amount": "0.25",
  "currency": "ETH",
  "travel_rule": {
    "uuid": "33333333-4444-5555-6666-777777777777",
    "status": "UNCONFIRMED_OWNERSHIP",
    "required": true
  },
  "action_required": {
    "type": "wallet_ownership",
    "url": "https://verify.didit.me/wallet-ownership/3s9x...urlsafe",
    "widget_session_id": "77777777-8888-9999-aaaa-bbbbbbbbbbbb",
    "expires_at": "2026-07-07T13:00:00Z"
  }
}
```

### स्व-होस्टेड वॉलेट घोषित करना

ऊपर के उदाहरण में गंतव्य को उपयोगकर्ता के अपने स्व-होस्टेड वॉलेट के रूप में घोषित किया गया है: प्रतिपक्ष का `paymentMethod.type` `unhosted_wallet` है।
यह घोषणा बदल देती है कि [Travel Rule विनिमय](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md#घोषित-स्व-होस्टेड-वॉलेट) कैसे चलता है:

* Didit प्रतिपक्ष-VASP रूटिंग को पूरी तरह छोड़ देता है - स्व-होस्टेड वॉलेट के पीछे कोई VASP नहीं होता - और ट्रांसफ़र को सीधे `UNCONFIRMED_OWNERSHIP` में बनाता है।
* जब आपकी [Travel Rule सेटिंग्स](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md#सेटअप) में `auto_wallet_verification` चालू हो (डिफ़ॉल्ट), तो [वॉलेट-स्वामित्व विजेट](https://docs.didit.me/hi/transaction-monitoring/wallet-ownership-widget.md) सत्र स्वचालित रूप से बनता है और ऊपर के रिस्पॉन्स की तरह ही `action_required` में लौटाया जाता है।
* SDK विजेट को स्वचालित रूप से लॉन्च करता है; जैसे ही उपयोगकर्ता वॉलेट पर नियंत्रण साबित करता है, ट्रांसफ़र नाम मिलान चलाता है और `COMPLETED` पर आगे बढ़ता है, या जब नाम वॉलेट के एड्रेस बुक धारक से मेल नहीं खाता तो `COUNTERPARTY_MISMATCHED_DATA` पर।

घोषणा के बिना, Didit इसके बजाय [रेल्स](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md#अवलोकन) को क्रम से आज़माता है और स्वामित्व प्रवाह पर तभी लौटता है जब कोई प्रतिपक्ष VASP नहीं मिलता।
जब भी आपके प्रोडक्ट को पहले से पता हो कि निकासी का लक्ष्य उपयोगकर्ता का अपना वॉलेट है, तब वॉलेट की घोषणा करें - इससे विफल रूटिंग पास बच जाता है और उपयोगकर्ता सीधे प्रूफ़ प्रवाह में पहुँच जाता है।

### विषय प्रवर्तन

तीन चीज़ें हमेशा टोकन द्वारा तय की जाती हैं, पेलोड द्वारा नहीं:

* वह एप्लिकेशन जिसके तहत लेन-देन बनाया जाता है।
* विषय की पहचान: पेलोड में `subject.externalUserId` को अनदेखा कर दिया जाता है और उसकी जगह टोकन का `vendor_data` लिया जाता है।
* विषय का डिवाइस संदर्भ (नीचे देखें); टकराव होने पर सर्वर से प्राप्त फ़ील्ड्स `subject.device` में दी गई किसी भी चीज़ पर भारी पड़ते हैं।

इस endpoint से `401` का अर्थ है कि टोकन अस्वीकार हुआ: अनुपस्थित, अज्ञात, रद्द, `max_uses` से अधिक उपयोग, या समय-सीमा समाप्त।
समय-सीमा समाप्त टोकन के रिस्पॉन्स में त्रुटि विवरण में हमेशा शब्द `expired` होता है, और इसी से SDK `expired_token` को `invalid_token` त्रुटियों से अलग पहचानते हैं।

### लेन-देन वापस पढ़ना

`GET /v1/transactions/{transaction_id}/` उसी `X-Transaction-Token` प्रमाणीकरण के साथ वही विवरण लौटाता है।
लॉन्च किए गए कार्रवाई प्रवाह के पूरा होने या उसकी विंडो बंद होने के बाद SDK इसे स्वचालित रूप से कॉल करते हैं, ताकि अंतिम स्थिति कभी किसी एक इवेंट या सूचना पर निर्भर न रहे।
टोकन वैध रहने तक किसी भी समय `status` और `action_required` दोबारा जाँचने के लिए इसे स्वयं उपयोग करें; अपने बैकएंड से, [`GET /v3/transactions/{transaction_id}/`](https://docs.didit.me/hi/transaction-monitoring/transactions) वही रिकॉर्ड लौटाता है।

## स्वचालित डिवाइस इंटेलिजेंस

हर सबमिशन के साथ आपकी ओर से कोई इंटीग्रेशन कार्य किए बिना डिवाइस इंटेलिजेंस भी जाती है:

* SDK गोपनीयता-सुरक्षित डिवाइस फ़िंगरप्रिंट एकत्र करता है (`didit-fp-v2` स्कीमा: प्लेटफ़ॉर्म और नेविगेटर सिग्नल, एक स्थायी डिवाइस id, बॉट स्कोर, और एक संयुक्त हैश) और उसे अनुरोध के साथ भेजता है।
* Didit IP पता, यूज़र एजेंट और accept-language को कनेक्शन से ही सर्वर-साइड पर निकालता है, इसलिए इन्हें पेलोड से जाली नहीं बनाया जा सकता।

मिला हुआ परिणाम विषय प्रतिभागी के डिवाइस संदर्भ में सामान्यीकृत होता है और डिवाइस ग्राफ़ में अपसर्ट किया जाता है, वही ग्राफ़ जिसमें KYC सत्र भी डेटा डालते हैं।
इससे आपके पूरे उपयोगकर्ता आधार में लेन-देन डिवाइस के आधार पर आपस में जोड़े जा सकते हैं ("related by device")। यह डिवाइस और नेटवर्क सिग्नल [नियमों](https://docs.didit.me/hi/transaction-monitoring/rules.md) और [IP समृद्धिकरण](https://docs.didit.me/hi/transaction-monitoring/ip-enrichment.md) में भेजता है, और स्वयं लेन-देन विवरण में [कंसोल](https://docs.didit.me/hi/transaction-monitoring/console.md) पर दिखाई देता है।

सर्वर से सबमिट किए गए `/v3/` लेन-देन हर प्रतिभागी के लिए स्पष्ट `device_context` ऑब्जेक्ट भेजते रह सकते हैं; SDK पथ पर आपको उसी डेटा का अधिक मज़बूत रूप बिना किसी अतिरिक्त प्रयास के मिलता है।

## आवश्यक उपयोगकर्ता क्रियाएँ

कुछ लेन-देन तभी पूरे हो सकते हैं जब अंतिम उपयोगकर्ता पहले कोई कार्रवाई करे। कोई नियम सत्यापन सत्र माँग सकता है, या कोई Travel Rule स्थानांतरण इस बात का प्रमाण माँग सकता है कि गंतव्य वॉलेट वास्तव में उपयोगकर्ता का ही है।
दोनों स्थितियाँ एक ही जगह दिखती हैं - सबमिट रिस्पॉन्स (और लेन-देन की हर बाद की रीड) के `action_required` ब्लॉक में:

```json theme={null}
"action_required": {
  "type": "verification_session",
  "url": "https://verify.didit.me/session/...",
  "session_id": "11111111-2222-3333-4444-555555555555",
  "session_token": "SESSION_TOKEN",
  "status": "Not Started"
}
```

```json theme={null}
"action_required": {
  "type": "wallet_ownership",
  "url": "https://verify.didit.me/wallet-ownership/3s9x...urlsafe",
  "widget_session_id": "77777777-8888-9999-aaaa-bbbbbbbbbbbb",
  "expires_at": "2026-07-07T13:00:00Z"
}
```

| प्रकार | कब दिखता है | उपयोगकर्ता क्या करता है |
| - | - | - |
| `verification_session` | एक [नियम कार्रवाई](https://docs.didit.me/hi/transaction-monitoring/rules.md) ने अतिरिक्त उपयोगकर्ता सत्यापन माँगा और लेन-देन `AWAITING_USER` पर चला गया। | होस्टेड सत्यापन सत्र पूरा करता है (जैसे बायोमेट्रिक पुनः जाँच), जिसे आपका ऐप लॉन्च करता है - नीचे [सत्यापन सत्र लॉन्च करना](#सत्यापन-सत्र-लॉन्च-करना) देखें। |
| `wallet_ownership` | Travel Rule स्थानांतरण को अंतिम उपयोगकर्ता से वॉलेट नियंत्रण का प्रमाण चाहिए - गंतव्य को [स्व-होस्टेड वॉलेट घोषित](#स्व-होस्टेड-वॉलेट-घोषित-करना) किया गया था (`UNCONFIRMED_OWNERSHIP`), या किसी आउटबाउंड स्थानांतरण में कोई प्रतिपक्ष VASP नहीं मिला - और आपकी [Travel Rule सेटिंग्स](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md#सेटअप) में `auto_wallet_verification` सक्षम है। Didit लेन-देन से जुड़ा [वॉलेट-स्वामित्व विजेट](https://docs.didit.me/hi/transaction-monitoring/wallet-ownership-widget.md) सत्र अपने आप बनाता है। | संदेश पर हस्ताक्षर (समर्थित चेन पर), स्क्रीनशॉट, या स्व-घोषणा के माध्यम से वॉलेट नियंत्रण सिद्ध करता है, जैसा आपकी Travel Rule सेटिंग्स अनुमति दें, लेकिन स्वतः बने सत्र पर कभी Satoshi test से नहीं - इसे SDK आपके लिए अपने आप लॉन्च करता है। |

यदि दोनों एक ही लेन-देन पर लागू हो सकते हैं, तो `wallet_ownership` को प्राथमिकता मिलती है, क्योंकि स्वामित्व प्रमाण न होने पर Travel Rule का आदान-प्रदान स्वयं रुक जाता है।
लंबित कार्रवाई हल होते ही `action_required` `null` हो जाता है।
मौजूदा `remediation` फ़ील्ड पिछली संगतता के लिए रखा गया है; मानक ब्लॉक `action_required` ही है।

### ऑटो-लॉन्च अनुबंध

`autoLaunchAction` (डिफ़ॉल्ट `true`) केवल `wallet_ownership` कार्रवाई को ऑटो-लॉन्च करता है:

* **Web** - SDK के अपने ओवरले मोडल में खुलता है, और पूरा होने का पता origin-validated मैसेजिंग के साथ सीमित लेन-देन पोल से लगता है (कभी केवल एक इवेंट पर निर्भर नहीं)।
* **iOS / Android** (और React Native तथा Flutter रैपर, जो नेटिव SDK को सौंपते हैं) - `useNativeWalletOwnership` के `true` होने पर (डिफ़ॉल्ट), SDK के **नेटिव वॉलेट-स्वामित्व अनुभव** (SwiftUI / Jetpack Compose) के रूप में दिखता है, फिर `SFSafariViewController` / Chrome Custom Tab, और अंत में डिफ़ॉल्ट ब्राउज़र पर लौटता है। प्रवाह बंद होने या ऐप के फ़ोरग्राउंड में लौटने के बाद SDK लेन-देन को अपने आप दोबारा पढ़ता है।

`verification_session` कार्रवाई कभी ऑटो-लॉन्च नहीं होती: यह हमेशा `action_required` में आती है, ताकि आपका ऐप उसे अपने Didit सत्यापन इंटीग्रेशन से शुरू करे।

> [!WARNING]
>
> वॉलेट-स्वामित्व विजेट को कभी किसी एम्बेडेड मोबाइल webview के अंदर रेंडर न करें - वॉलेट डीप लिंक उससे बाहर नहीं निकल सकते और प्रमाण प्रवाह अटक जाता है।
> ऑटो-लॉन्च के समय SDK पहले से सही ब्राउज़र सतह का उपयोग करते हैं; यदि आप `url` स्वयं संभालते हैं, तो यह नियम बनाए रखें।
> विवरण के लिए [वॉलेट-स्वामित्व विजेट गाइड](https://docs.didit.me/hi/transaction-monitoring/wallet-ownership-widget.md#लौटाया-गया-url-खोलें) देखें।

SDK का अपना ऑटो-लॉन्च किया गया वॉलेट-स्वामित्व प्रवाह पूरा होने या बंद होने के बाद, वह लेन-देन को दोबारा पढ़ता है और ताज़ा परिणाम आपके `onActionCompleted` कॉलबैक को देता है।
`verification_session` कार्रवाई इस चक्र का हिस्सा नहीं है, क्योंकि उसे आपका ऐप लॉन्च करता है - अगला भाग देखें।

### सत्यापन सत्र लॉन्च करना

जब `action_required.type` `verification_session` हो, तो `result.actionRequired` से ब्लॉक पढ़ें और उसे अपने मौजूदा Didit सत्यापन इंटीग्रेशन को सौंपें:

```typescript Web theme={null}
if (result.actionRequired?.type === "verification_session") {
  DiditSdk.shared.startVerification({ url: result.actionRequired.url });
}
```

```swift iOS theme={null}
if actionRequired.type == "verification_session" {
    try await DiditSdk.shared.startVerification(token: actionRequired.sessionToken)
}
```

```kotlin Android theme={null}
if (actionRequired.type == "verification_session") {
    DiditSdk.startVerification(token = actionRequired.sessionToken) { result ->
        // handle the verification result
    }
}
```

```typescript React Native theme={null}
if (actionRequired.type === "verification_session") {
  await startVerification(actionRequired.sessionToken);
}
```

```dart Flutter theme={null}
if (actionRequired.type == 'verification_session') {
  await DiditSdk.startVerification(actionRequired.sessionToken);
}
```

सत्यापन प्रवाह पूरा होने के बाद, लेन-देन की ताज़ा स्थिति पाने के लिए `GET /v1/transactions/{transaction_id}/` कॉल करें (या [लेन-देन webhook](#webhooks) का इंतज़ार करें)।

### उदाहरण: उच्च-मूल्य निकासी के लिए बायोमेट्रिक अतिरिक्त जाँच

यह प्रवाह अपने सबसे अच्छे रूप में है: जोखिम भरे लेन-देन - बड़ी राशि, नए लाभार्थी, नए डिवाइस - को उसी व्यक्ति की बायोमेट्रिक पुनः जाँच के पीछे रखें, जिसे आपने ऑनबोर्डिंग के समय सत्यापित किया था।

अकाउंट टेकओवर ठीक ऐसा ही दिखता है: सही पासवर्ड, सही 2FA कोड (फ़िशिंग या SIM स्वैप से प्राप्त), और ऐसे वॉलेट पर निकासी जिसे आपने पहले कभी नहीं देखा।
उस बिंदु तक हर क्रेडेंशियल-आधारित बचाव विफल हो चुका होता है।
चेहरे पर आधारित सुरक्षा अब भी विफल नहीं हुई है: हमलावर लाइवनेस-जाँची गई सेल्फ़ी पास नहीं कर सकता, जिसे वैध मालिक के KYC ऑनबोर्डिंग में लिए गए चेहरे से मेल खाना होगा।

**1. नियम एक बार कंसोल में बनाएँ**

**Transactions → Rules → Create Rule**: शर्त `amount gte 5000`, कार्रवाई **Change status → `AWAITING_USER`**, और कार्रवाई पर अपना **बायोमेट्रिक प्रमाणीकरण** वर्कफ़्लो चुनें।
चाहें तो अन्य जोखिम शर्तें जोड़ें - पहली बार का प्रतिपक्ष, नया डिवाइस फ़िंगरप्रिंट, IP देश में बदलाव - अतिरिक्त शर्तों या अतिरिक्त नियमों के रूप में।

**2. निकासी हमेशा की तरह सबमिट करें**

आपके सबमिशन कोड में कोई बदलाव नहीं होता। जब नियम लागू होता है, तो रिस्पॉन्स `status: "AWAITING_USER"` और `verification_session` प्रकार का `action_required` ब्लॉक लेकर आता है:

```json theme={null}
{
  "status": "AWAITING_USER",
  "action_required": {
    "type": "verification_session",
    "url": "https://verify.didit.me/session/...",
    "session_id": "11111111-2222-3333-4444-555555555555",
    "session_token": "SESSION_TOKEN",
    "status": "Not Started"
  }
}
```

**3. पुनः जाँच लॉन्च करें**

`session_token` (या `url`) को अपने मौजूदा Didit सत्यापन इंटीग्रेशन को सौंपें, ठीक वैसे ही जैसा [सत्यापन सत्र लॉन्च करना](#सत्यापन-सत्र-लॉन्च-करना) में है।
चूँकि सत्र उसी `vendor_data` के लिए बनता है जो लेन-देन का विषय है, Didit के पास ऑनबोर्डिंग से उपयोगकर्ता का सत्यापित संदर्भ चेहरा पहले से है - स्वीकृत लाइवनेस सेल्फ़ी, पासपोर्ट चिप फ़ोटो, या दस्तावेज़ का पोर्ट्रेट।
उपयोगकर्ता एक लाइव सेल्फ़ी लेता है; Didit उस संग्रहीत संदर्भ के विरुद्ध लाइवनेस और 1:1 चेहरा मिलान चलाता है। दस्तावेज़ दोबारा स्कैन नहीं होता, कोई दोबारा ऑनबोर्डिंग नहीं होती - केवल उन लेन-देन पर कुछ सेकंड की असुविधा, जो इसके हकदार हैं।

**4. परिणाम के अनुसार निपटारा करें**

सत्र पूरा होने पर लेन-देन अपने आप दोबारा मूल्यांकित होता है: पुनः जाँच पास होने पर `APPROVED`, विफल होने पर `DECLINED`, और दोनों स्थितियों में `transaction.status.updated` webhook भेजा जाता है (लेन-देन की टाइमलाइन में `reason: remediation_completed`)।
आपका ऐप परिणाम `onActionCompleted` जैसे कॉलबैक, `GET /v1/transactions/{transaction_id}/`, या webhook के ज़रिए पाता है।

यह इसलिए काम करता है क्योंकि KYC ऑनबोर्डिंग, बायोमेट्रिक दोबारा जाँच और लेन-देन का निर्णय एक ही प्लेटफ़ॉर्म पर चलते हैं: ऑनबोर्डिंग के समय लिया गया चेहरा स्टेप-अप के लिए संदर्भ है, डिवाइस ग्राफ़ सेशन को लेन-देन से जोड़ता है, और नियम इंजन इन सबको आपस में जोड़ता है। इसके लिए किसी विक्रेता-विशिष्ट ग्लू की, चेहरे की छवि का कोई निर्यात या बायोमेट्रिक्स के लिए कोई अलग अनुबंध नहीं चाहिए।
बायोमेट्रिक दोबारा जाँच का शुल्क मानक बायोमेट्रिक प्रमाणीकरण सुविधा के रूप में ([\$0.10](https://docs.didit.me/hi/getting-started/pricing.md)) तभी लगता है जब वह वास्तव में चलती है।

## वेब SDK

`submitTransaction` अभी Web SDK singleton पर उपलब्ध है:

```typescript theme={null}
import { DiditSdk } from "@didit-protocol/sdk-web";

const result = await DiditSdk.shared.submitTransaction({
  transactionToken: sdkToken, // minted by your backend via POST /v3/transactions/sdk-token/
  transaction: {
    txnId: "wd-2026-07-07-0042",
    txnDate: new Date().toISOString(),
    zoneId: "Europe/Madrid",
    category: "travelRule",
    details: {
      direction: "out",
      amount: "0.25",
      currency: "ETH",
      currencyType: "crypto",
      paymentDetails: "ETH withdrawal to self-hosted wallet",
      cryptoParams: { crypto_chain: "ETH" }
    },
    subject: {
      type: "individual",
      fullName: "Jane Doe"
      // no externalUserId needed: the subject identity comes from the token
    },
    counterparty: {
      type: "individual",
      fullName: "Ana Diaz",
      paymentMethod: {
        type: "unhosted_wallet",
        accountId: "0xBeneficiaryWallet01"
      }
    },
    travelRule: {
      status: "AWAITING_COUNTERPARTY", // ignored when Travel Rule is enabled: Didit drives the exchange
      beneficiaryData: {
        wallet_address: "0xBeneficiaryWallet01",
        name: "Ana Diaz"
      }
    },
    includeCryptoScreening: true
  },
  autoLaunchAction: true, // default: auto-launches wallet_ownership only; verification_session comes back in result.actionRequired for you to launch
  onActionCompleted: (refreshed) => {
    console.log(refreshed.status, refreshed.travelRuleStatus);
  }
});

console.log(result.transactionId, result.status, result.actionRequired?.type);
```

परिणाम `{ transactionId, status, travelRuleStatus?, actionRequired? }` के रूप में आता है।
SDK-स्तर के payload में आप `category`, `details` और `customProperties` लिखते हैं; SDK इन्हें wire aliases (`type`, `info`, `props`) पर अपने आप मैप कर देता है।

त्रुटियाँ `DiditTransactionError` के ज़रिए टाइप की जाती हैं:

```typescript theme={null}
import { DiditSdk, DiditTransactionError } from "@didit-protocol/sdk-web";

try {
  await DiditSdk.shared.submitTransaction({ transactionToken, transaction });
} catch (error) {
  if (error instanceof DiditTransactionError) {
    switch (error.type) {
      case "expired_token": // mint a fresh token and retry
        break;
      case "invalid_token": // rejected: unknown, revoked, or over max_uses
        break;
      case "validation": // inspect error.fieldErrors for per-field details
        break;
      case "network": // retry with backoff
        break;
    }
  }
}
```

## नेटिव SDK

> [!NOTE]
>
> नेटिव `submitTransaction` API iOS और Android SDK 4.1.0 के साथ आता है (और React Native तथा Flutter के वे रिलीज़ भी, जो इसे पिन करते हैं)।
> Web SDK के विपरीत, नेटिव payloads सीधे wire फ़ील्ड नामों का उपयोग करते हैं: `type`, `info` और `props`।

```swift Swift theme={null}
import DiditSDK

let payload = DiditTransactionPayload(
    txnId: "wd-2026-07-07-0042",
    type: "travelRule",
    info: DiditTransactionInfo(
        direction: "out",
        amount: 0.25,
        currency: "ETH",
        currencyType: "crypto",
        cryptoParams: ["crypto_chain": "ETH"]
    ),
    subject: DiditTransactionParticipant(type: "individual", fullName: "Jane Doe"),
    counterparty: DiditTransactionParticipant(
        type: "individual",
        fullName: "Ana Diaz",
        paymentMethod: DiditTransactionPaymentMethod(type: "unhosted_wallet", accountId: "0xBeneficiaryWallet01")
    ),
    travelRule: DiditTravelRuleInfo(
        status: "AWAITING_COUNTERPARTY", // required by the API; ignored when Travel Rule is enabled
        beneficiaryData: ["wallet_address": "0xBeneficiaryWallet01", "name": "Ana Diaz"]
    ),
    includeCryptoScreening: true
)

let result = try await DiditSdk.shared.submitTransaction(
    transactionToken: sdkToken,
    transaction: payload,
    options: DiditTransactionOptions(
        autoLaunchAction: true,           // default
        useNativeWalletOwnership: true,   // default: native flow, browser fallback
        onTransactionUpdated: { refreshed in
            print(refreshed.status ?? "", refreshed.travelRuleStatus ?? "")
        }
    )
)

print(result.transactionId, result.status ?? "", result.actionRequired?.type ?? "none")
// Errors: DiditTransactionError .invalidToken / .expiredToken / .validation(fieldErrors) / .network
```

```kotlin Kotlin theme={null}
import me.didit.sdk.DiditSdk
import me.didit.sdk.transactions.*

val payload = DiditTransactionPayload(
    txnId = "wd-2026-07-07-0042",
    type = "travelRule",
    info = DiditTransactionInfo(
        direction = "out",
        amount = 0.25,
        currency = "ETH",
        currencyType = "crypto",
        cryptoParams = mapOf("crypto_chain" to "ETH")
    ),
    subject = DiditTransactionParticipant(type = "individual", fullName = "Jane Doe"),
    counterparty = DiditTransactionParticipant(
        type = "individual",
        fullName = "Ana Diaz",
        paymentMethod = DiditTransactionPaymentMethod(
            type = "unhosted_wallet",
            accountId = "0xBeneficiaryWallet01"
        )
    ),
    travelRule = DiditTravelRule(
        status = "AWAITING_COUNTERPARTY", // required by the API; ignored when Travel Rule is enabled
        beneficiaryData = mapOf("wallet_address" to "0xBeneficiaryWallet01", "name" to "Ana Diaz")
    ),
    includeCryptoScreening = true
)

// suspend fun - call from a coroutine; DiditSdk.initialize() must have run first
val result = DiditSdk.submitTransaction(
    transactionToken = sdkToken,
    transaction = payload,
    options = DiditTransactionOptions(
        autoLaunchAction = true,          // default
        useNativeWalletOwnership = true,  // default: native flow, Custom Tab fallback
        onTransactionUpdated = { refreshed ->
            Log.d("Didit", "${refreshed.status} ${refreshed.travelRuleStatus}")
        }
    )
)

Log.d("Didit", "${result.transactionId} ${result.status} ${result.actionRequired?.type}")
// Errors: sealed DiditTransactionException - InvalidToken / ExpiredToken / Validation(fieldErrors) / Network
```

```typescript React Native theme={null}
import {
  submitTransaction,
  getTransaction,
  DiditTransactionError,
} from "@didit-protocol/sdk-react-native";

const result = await submitTransaction(sdkToken, {
  txnId: "wd-2026-07-07-0042",
  type: "travelRule",
  info: {
    direction: "out",
    amount: 0.25,
    currency: "ETH",
    currencyType: "crypto",
    cryptoParams: { crypto_chain: "ETH" },
  },
  subject: { type: "individual", fullName: "Jane Doe" },
  counterparty: {
    type: "individual",
    fullName: "Ana Diaz",
    paymentMethod: { type: "unhosted_wallet", accountId: "0xBeneficiaryWallet01" },
  },
  travelRule: {
    status: "AWAITING_COUNTERPARTY", // required by the API; ignored when Travel Rule is enabled
    beneficiaryData: { wallet_address: "0xBeneficiaryWallet01", name: "Ana Diaz" },
  },
  includeCryptoScreening: true,
}, {
  autoLaunchAction: true, // default
  onTransactionUpdated: (refreshed) => {
    console.log(refreshed.status, refreshed.travelRuleStatus);
  },
});

console.log(result.transactionId, result.status, result.actionRequired?.type);
// Errors: DiditTransactionError with code invalid_token | expired_token | validation | network
```

```dart Flutter theme={null}
import 'package:didit_sdk/sdk_flutter.dart';

final result = await DiditSdk.submitTransaction(
  sdkToken,
  DiditTransactionPayload(
    txnId: 'wd-2026-07-07-0042',
    type: 'travelRule',
    info: DiditTransactionInfo(
      direction: 'out',
      amount: 0.25,
      currency: 'ETH',
      currencyType: 'crypto',
      cryptoParams: {'crypto_chain': 'ETH'},
    ),
    subject: DiditTransactionParticipant(type: 'individual', fullName: 'Jane Doe'),
    counterparty: DiditTransactionParticipant(
      type: 'individual',
      fullName: 'Ana Diaz',
      paymentMethod: DiditTransactionPaymentMethod(
        type: 'unhosted_wallet',
        accountId: '0xBeneficiaryWallet01',
      ),
    ),
    travelRule: DiditTravelRule(
      status: 'AWAITING_COUNTERPARTY', // required by the API; ignored when Travel Rule is enabled
      beneficiaryData: {'wallet_address': '0xBeneficiaryWallet01', 'name': 'Ana Diaz'},
    ),
    includeCryptoScreening: true,
  ),
  options: DiditTransactionOptions(
    autoLaunchAction: true, // default
    onTransactionUpdated: (refreshed) {
      debugPrint('${refreshed.status} ${refreshed.travelRuleStatus}');
    },
  ),
);

debugPrint('${result.transactionId} ${result.status} ${result.actionRequired?.type}');
// Errors: DiditTransactionException with code invalid_token | expired_token | validation | network
```

हर SDK `getTransaction(transactionToken, transactionId)` भी उपलब्ध कराता है, ताकि उसी token से लेन-देन दोबारा पढ़ा जा सके। लॉन्च किए गए कार्रवाई फ़्लो के बाद SDK इसे अपने आप कॉल करते हैं, और आप इसे किसी भी समय खुद कॉल कर सकते हैं।

मोबाइल पर डिवाइस फ़िंगरप्रिंट ट्रांसपोर्ट पहले से ही सभी SDK नेटवर्क कॉल पर लागू होता है, इसलिए लेन-देन सबमिशन अपने आप वही डिवाइस इंटेलिजेंस साथ ले जाते हैं।

## SDK के बिना

SDK जो कुछ करते हैं, वह सब सामान्य HTTPS है, इसलिए यहाँ किसी भी चीज़ के लिए SDK ज़रूरी नहीं है।
दो समतुल्य इंटीग्रेशन तरीके हैं:

**केवल सर्वर-साइड (बिल्कुल कोई token नहीं)।** अपनी API कुंजी के साथ अपने बैकएंड से [`POST /v3/transactions/`](https://docs.didit.me/hi/management-api/transactions/create) से सबमिट करें। रिस्पॉन्स (और हर बाद की `GET /v3/transactions/{transaction_id}/`) वही `action_required` ब्लॉक लेकर आता है। आप हर प्रतिभागी के लिए स्पष्ट `device` संदर्भ भी पास कर सकते हैं, क्योंकि आपके लिए उसे इकट्ठा करने वाला कोई SDK नहीं है।

**क्लाइंट-साइड, अपने HTTP स्टैक के साथ।** [`POST /v3/transactions/sdk-token/`](https://docs.didit.me/hi/management-api/transactions/sdk-token) से token बनाएँ, फिर डिवाइस से `X-Transaction-Token` हेडर के साथ [`POST /v1/transactions/`](https://docs.didit.me/hi/management-api/transactions/submit-sdk) और [`GET /v1/transactions/{transaction_id}/`](https://docs.didit.me/hi/management-api/transactions/get-sdk) कॉल करें। वही subject binding और सर्वर-साइड IP/user-agent व्युत्पत्ति लागू होती है।

इसके बाद `action_required` को स्वयं संभालें:

| `action_required.type` | क्या करना है |
| - | - |
| `wallet_ownership` | `url` उपयोगकर्ता तक पहुँचाएँ और उसे **वास्तविक ब्राउज़र इंटरफ़ेस** में खोलें: वेब पर सामान्य टैब, मोबाइल पर `SFSafariViewController` / Chrome Custom Tabs, या ईमेल लिंक या QR कोड के ज़रिए अलग से। इसे कभी भी एम्बेडेड webview के अंदर न दिखाएँ, क्योंकि वॉलेट deep links उससे बाहर नहीं निकल सकते। |
| `verification_session` | उपयोगकर्ता को `url` पर भेजें, जो मानक Didit होस्टेड सत्यापन पेज है, या `session_token` को उस किसी भी Didit सत्यापन इंटीग्रेशन में डालें जो आप पहले से चलाते हैं। |

और बिना किसी client callback के पूरा होने का पता लगाएँ:

* **Webhooks (अनुशंसित)।** जब लंबित कार्रवाई लेन-देन को हल करती है तो `transaction.status.updated` फ़ायर होता है, और हर exchange ट्रांज़िशन पर `travel_rule.status.updated` फ़ायर होता है। दोनों में इतनी जानकारी होती है कि बिना पोलिंग के आप अपने रिकॉर्ड अपडेट कर सकें।
* **Polling।** लेन-देन को दोबारा पढ़ें (आपके बैकएंड से `/v3/` के ज़रिए, या token मान्य रहने तक token के साथ `/v1/` के ज़रिए): हल हो जाने पर `action_required` वापस `null` हो जाता है, और `status` / `travel_rule.status` परिणाम दिखाते हैं।

इस डिज़ाइन में कोई एक-बारी निर्भरता नहीं है: विजेट, सत्यापन सत्र और आपका बैकएंड सभी एक ही स्थायी लेन-देन स्थिति पर पहुँचते हैं, इसलिए बंद टैब या छूटे हुए webhook को हमेशा लेन-देन दोबारा पढ़कर वापस पाया जा सकता है।

## Webhooks

आपके बैकएंड को रिपोर्ट करने के लिए ऐप की ज़रूरत नहीं है।
जब सबमिट किया गया लेन-देन उपयोगकर्ता की कार्रवाई माँगता है, तो [लेन-देन webhook](https://docs.didit.me/hi/transaction-monitoring/webhooks.md) - `transaction.created` या `transaction.status.updated` - वही `action_required` ब्लॉक शामिल करता है, ताकि आपके सिस्टम को लंबित कार्रवाई की जानकारी रहे, भले ही फ़्लो पूरा होने से पहले ऐप बंद हो जाए।
`verification_session` कार्रवाई के साथ `AWAITING_USER` स्टेटस आता है, लेकिन `wallet_ownership` कार्रवाई अपने आप लेन-देन का स्टेटस नहीं बदलती, इसलिए स्टेटस के बजाय `action_required` पढ़ें।
Travel Rule ट्रांज़िशन अतिरिक्त रूप से [`travel_rule.status.updated`](https://docs.didit.me/hi/transaction-monitoring/travel-rule#वेबहुक) भी भेजते हैं।

## अगले कदम

> [card] [लेन-देन सबमिट करना](https://docs.didit.me/hi/transaction-monitoring/transactions.md)
>
> सर्वर-साइड Create Transaction API और payload का पूरा संदर्भ।

> [card] [Travel Rule](https://docs.didit.me/hi/transaction-monitoring/travel-rule.md)
>
> प्रबंधित प्रेषक-लाभार्थी आदान-प्रदान, सेटिंग्स और जीवनचक्र।

> [card] [वॉलेट स्वामित्व विजेट](https://docs.didit.me/hi/transaction-monitoring/wallet-ownership-widget.md)
>
> wallet\_ownership कार्रवाइयों के पीछे का होस्टेड नियंत्रण-प्रमाण फ़्लो।

> [card] [Webhooks](https://docs.didit.me/hi/transaction-monitoring/webhooks.md)
>
> transaction.created, transaction.status.updated और हस्ताक्षर सत्यापन।

> [card] [नियम](https://docs.didit.me/hi/transaction-monitoring/rules.md)
>
> नियम कार्रवाइयाँ, जिनमें सत्यापन सत्र बनाने वाली कार्रवाइयाँ भी शामिल हैं।

> [card] [स्टेटस](https://docs.didit.me/hi/transaction-monitoring/statuses.md)
>
> लेन-देन जीवनचक्र में AWAITING\_USER का अर्थ।


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.