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

# التحقق بالتحويل: صفحة التحقق المستضافة

> التحقق من الهوية المستضاف عبر التحويل: التحقق عبر الأجهزة، روابط الاستدعاء ونتائج webhook كاملة. من $0.33 لكل فحص KYC كامل، و$10 مجاناً شهرياً مع Didit.



مطالبة تكامل إعادة التوجيه
        نسخ الموجّه إلى الحافظة



      
      

\<pre>

\`Integrate Didit identity verification into my web app using the redirect flow.

\## How It Works
1\. Backend creates a session via POST /v3/session/ → response includes "url"
2\. Frontend redirects user to that URL: window.location.href = url
3\. User completes verification on Didit's hosted page (https://verify.didit.me/...)
4\. Didit redirects user back to your callback URL with query params:
 ?verificationSessionId=<session_id>&status=<session status, for example Approved, Declined, In Review or Expired>
5\. Your backend receives the full, signed decision via webhook (status.updated)

\## Backend: Create Session
POST https://verification.didit.me/v3/session/
Headers: { "x-api-key": DIDIT_API_KEY, "Content-Type": "application/json" }
Body: {
"workflow_id": DIDIT_WORKFLOW_ID,
"callback": "https://myapp.com/verification-complete",
"callback_method": "both",      // "initiator" | "completer" | "both"
"vendor_data": "user-id-123"
}
201 response (all 10 fields, per OpenAPI):
\{
"session_id": "uuid",
"session_number": 43762,
"session_token": "3FaJ9wLqX2Mz",   // 12-char URL-safe token; valid until the session expires
"url": "https://verify.didit.me/session/3FaJ9wLqX2Mz",
"vendor_data": "user-id-123",
"metadata": null,
"status": "Not Started",
"workflow_id": "uuid",
"workflow_version": 3,
"callback": "https://myapp.com/verification-complete"
}
The field is named "url" — redirect the user there. Never build the URL from session_token
by hand (with "language" set, the URL gains a language segment: /es/session/...).

\## Frontend: Redirect User
window.location.href = session.url; // value of "url" from the API response

\## Callback Page: Handle Return
const params = new URLSearchParams(window.location.search);
const sessionId = params.get('verificationSessionId');
const status    = params.get('status'); // the session status, e.g. "Approved", "Declined", "In Review" or "Expired"
// IMPORTANT: Treat these query params as untrusted UI hints.
// Always confirm the final result on your backend via webhook OR by calling
// GET /v3/session/{session_id}/decision/

\## Callback Methods
\- "initiator": redirect only the device that started the flow
\- "completer": redirect the device that finished verification (e.g. mobile after QR hand-off)
\- "both": redirect whichever device is active (recommended for reliability)

\## Webhook: Receive Full Results
POST to your webhook URL with full decision data.
Verify HMAC-SHA256 signature with X-Signature-V2 header — see /integration/webhooks.

\## Rate Limits
600 session-create requests per minute per API key (falls back to bearer token, then client IP), plus a shared 300 write-requests/minute budget across all endpoints. HTTP 429 with Retry-After when exceeded.

\## Environment Variables
\- DIDIT_API_KEY — backend only (Didit Console > API & Webhooks)
\- DIDIT_WEBHOOK_SECRET — backend only (per-destination, Didit Console > API & Webhooks)
\- DIDIT_WORKFLOW_ID — backend only (Didit Console > Workflows)

\## Docs
\- Redirect flow: https://docs.didit.me/integration/web-sdks/web-redirect
\- Create Session: https://docs.didit.me/sessions-api/create-session
\- Retrieve Decision: https://docs.didit.me/sessions-api/retrieve-session
\- Webhooks: https://docs.didit.me/integration/webhooks`

\</pre>



      
      

الصق في

تنقل طريقة إعادة التوجيه المستخدمين إلى صفحة تحقق تستضيفها Didit، ثم تعيدهم إلى تطبيقك عبر رابط الاستدعاء.| الميزة | الوصف |
| - | - |
| وقت الإعداد | 5 دقائق |
| يتطلب خادمًا خلفيًا | ✅ نعم (لإنشاء الجلسات) |
| يبقى على نطاقك | ❌ لا (يتم التحويل إلى verify.didit.me أو إلى نطاقك المخصص بالعلامة البيضاء) |
| دعم الأجهزة المتعددة | ✅ نعم |
| توافق المتصفحات | ✅ جميع المتصفحات |***## متى تستخدم إعادة التوجيه- **التحقق عبر الأجهزة المتعددة**: ابدأ على سطح المكتب وأكمل على الجهاز المحمول
- **أقصى درجات التوافق**: يعمل في جميع المتصفحات، بما فيها الإصدارات القديمة
- **تكامل بسيط**: لا حاجة إلى إعداد iframe
- **مشكلات الكاميرا**: عندما يكون الوصول إلى الكاميرا داخل iframe مشكلة***## التنفيذ### الخطوة 1: إنشاء جلسة (الخادم الخلفي)تستخدم استجابة إنشاء الجلسة حقلًا اسمه **`url`**، مرّر هذه القيمة إلى المتصفح.```javascript theme={null}
// Node.js / Express
app.post('/api/create-verification', async (req, res) => {
  const { userId } = req.body;

  const response = await fetch('https://verification.didit.me/v3/session/', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.DIDIT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      workflow_id: process.env.DIDIT_WORKFLOW_ID,
      vendor_data: userId,
      callback: 'https://yourapp.com/verification-complete',
      callback_method: 'both', // most reliable across desktop ↔ mobile handoffs
    }),
  });

  if (!response.ok) {
    return res.status(response.status).send(await response.text());
  }

  const session = await response.json();
  // 201 per OpenAPI: { session_id, session_number, session_token, url, vendor_data,
  //                    metadata, status, workflow_id, workflow_version, callback }
  res.json({ sessionId: session.session_id, verificationUrl: session.url });
});
```### الخطوة 2: توجيه المستخدم (الواجهة الأمامية)**HTML:**```html theme={null}
<button onclick="startVerification()">Verify Identity</button>

<script>
  async function startVerification() {
    const response = await fetch('/api/create-verification', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ userId: 'user-123' })
    });
    
    const { verificationUrl } = await response.json();
    window.location.href = verificationUrl;
  }
</script>
```**React:**```tsx theme={null}
function VerifyButton() {
  const [loading, setLoading] = useState(false);

  const startVerification = async () => {
    setLoading(true);
    
    const response = await fetch('/api/create-verification', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ userId: 'user-123' })
    });
    
    const { verificationUrl } = await response.json();
    window.location.assign(verificationUrl);
  };

  return (
    <button onClick={startVerification} disabled={loading}>
      {loading ? 'Loading...' : 'Verify Identity'}
    </button>
  );
}
```**Vue:**```vue theme={null}
<template>
  <button @click="startVerification" :disabled="loading">
    {{ loading ? 'Loading...' : 'Verify Identity' }}
  </button>
</template>

<script setup>
import { ref } from 'vue';

const loading = ref(false);

async function startVerification() {
  loading.value = true;
  
  const response = await fetch('/api/create-verification', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userId: 'user-123' })
  });
  
  const { verificationUrl } = await response.json();
  window.location.href = verificationUrl;
}
</script>
```***## معالجة الاستدعاءعند اكتمال التحقق، تعيد Didit توجيه المستخدم إلى رابط الاستدعاء الخاص بك مع معاملات الاستعلام:```
https://yourapp.com/verification-complete?verificationSessionId=abc123&status=Approved
```| المعامل | الوصف |
| - | - |
| `verificationSessionId` | المعرّف الفريد للجلسة |
| `status` | الحالة الحالية للجلسة، مثل `Approved` أو `Declined` أو `In Review` أو `Expired`. راجع [حالات التحقق](https://docs.didit.me/ar/integration/verification-statuses.md) |### مثال Next.js```tsx theme={null}
// pages/verification-complete.tsx
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

export default function VerificationComplete() {
  const router = useRouter();
  const { verificationSessionId, status } = router.query;
  const [message, setMessage] = useState('Processing...');

  useEffect(() => {
    if (!router.isReady) return;

    async function handleResult() {
      // Optionally verify the result with your backend
      await fetch('/api/verify-session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          sessionId: verificationSessionId, 
          status 
        })
      });

      // Redirect based on status
      switch (status) {
        case 'Approved':
          setMessage('Verification successful! Redirecting...');
          setTimeout(() => router.push('/dashboard'), 2000);
          break;
        case 'Declined':
          setMessage('Verification was not successful.');
          setTimeout(() => router.push('/verification-failed'), 2000);
          break;
        case 'In Review':
          setMessage('Your verification is under review.');
          setTimeout(() => router.push('/verification-pending'), 2000);
          break;
        default:
          setMessage('Unknown status. Please contact support.');
      }
    }

    handleResult();
  }, [router.isReady, verificationSessionId, status]);

  return (
    <div className="flex flex-col items-center justify-center min-h-screen">
      <div className="animate-spin w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full mb-4" />
      <p className="text-lg">{message}</p>
    </div>
  );
}
```### مثال Express.js```javascript theme={null}
// routes/verification.js
app.get('/verification-complete', async (req, res) => {
  const { verificationSessionId, status } = req.query;
  
  // Optionally verify with Didit API
  // const session = await diditApi.getSession(verificationSessionId);
  
  // Update your database
  await db.users.update({
    where: { verificationSessionId },
    data: { verificationStatus: status }
  });
  
  // Redirect based on status
  switch (status) {
    case 'Approved':
      res.redirect('/dashboard?verified=true');
      break;
    case 'Declined':
      res.redirect('/verification-failed');
      break;
    case 'In Review':
      res.redirect('/verification-pending');
      break;
    default:
      res.redirect('/error');
  }
});
```### مثال Vue Router```typescript theme={null}
// router/index.ts
{
  path: '/verification-complete',
  component: () => import('@/views/VerificationComplete.vue'),
  beforeEnter: async (to, from, next) => {
    const { verificationSessionId, status } = to.query;
    
    // Store result and redirect
    await store.dispatch('verification/handleResult', { 
      sessionId: verificationSessionId, 
      status 
    });
    
    if (status === 'Approved') {
      next('/dashboard');
    } else if (status === 'Declined') {
      next('/verification-failed');
    } else {
      next('/verification-pending');
    }
  }
}
```***## الفتح في تبويب جديدإذا كنت تفضّل إبقاء تطبيقك مفتوحًا أثناء قيام المستخدم بالتحقق:```javascript theme={null}
// Open in new tab
window.open(verificationUrl, '_blank');

// Poll for completion or use webhooks
```> [!TIP]
>
> عند استخدام تبويبات جديدة، ادمجها مع [webhook](https://docs.didit.me/ar/integration/webhooks.md) لتعرف متى يكتمل التحقق.***## أفضل ممارسات الأمان### تحقّق من رد الاستدعاء من جهة الخادمعامل معاملي الاستعلام `verificationSessionId` و`status` على أنهما تلميحات واجهة غير موثوقة. أكّد القرار النهائي دائمًا على خادمك الخلفي، إما بمعالجة [webhook](https://docs.didit.me/ar/integration/webhooks.md) (وهذا هو الخيار المفضّل)، أو بإعادة جلب القرار عبر واجهة API:```javascript theme={null}
// Backend: re-fetch the canonical decision before granting access
app.get('/verification-complete', async (req, res) => {
  const { verificationSessionId } = req.query;

  const response = await fetch(
    `https://verification.didit.me/v3/session/${verificationSessionId}/decision/`,
    {
      headers: { 'x-api-key': process.env.DIDIT_API_KEY },
    }
  );

  if (!response.ok) {
    return res.status(response.status).send(await response.text());
  }

  const decision = await response.json();

  // decision.status uses the canonical enum:
  // Not Started | In Progress | Awaiting User | In Review | Approved |
  // Declined   | Resubmitted | Expired | Kyc Expired | Abandoned
  if (decision.status === 'Approved') {
    // Grant access. Per-feature reports are plural arrays:
    //   decision.id_verifications[], decision.face_matches[], decision.aml_screenings[], ...
  }

  res.redirect('/dashboard');
});
```### استخدم webhookللحصول على أكثر تكامل موثوقية، استخدم [webhook](https://docs.didit.me/ar/integration/webhooks.md) لاستلام نتائج التحقق مباشرة على خادمك الخلفي، بغض النظر عن سلوك متصفح المستخدم.***## تدفق التحقق عبر الأجهزة المتعددةتدعم طريقة إعادة التوجيه التحقق عبر الأجهزة المتعددة بشكل طبيعي:1) ينقر المستخدم على "تحقق" على سطح المكتب
2) يُوجَّه المستخدم إلى صفحة التحقق
3) إذا لزم الأمر، يمكن للمستخدم مسح رمز QR للمتابعة على الجهاز المحمول
4) بعد الإكمال، يُوجَّه المستخدم إلى رابط الاستدعاء الخاص بك، ويتحكم `callback_method` في الجهاز الذي ينفّذ إعادة التوجيه (`initiator` أو `completer` أو `both`)***## استكشاف الأخطاء وإصلاحها### لم يتم استلام الاستدعاء1) تحقق من أن رابط الاستدعاء مضبوط بشكل صحيح عند إنشاء الجلسة
2) تأكد من أن رابط الاستدعاء متاح من الإنترنت
3) تحقق من أن الرابط لا يحتوي على أخطاء إملائية أو مشكلات في الترميز### الحالة دائمًا "Declined"1) تحقق من إعدادات سير العمل في Didit Console
2) تأكد من أن المستندات التجريبية التي تستخدمها صالحة
3) راجع تفاصيل الجلسة عبر واجهة API للاطلاع على أسباب الرفض المحددة### حلقة إعادة التوجيه1) تأكد من أن معالج الاستدعاء لا يعيد التوجيه إلى صفحة التحقق مرة أخرى
2) تحقق من مشكلات التخزين المؤقت في صفحة رد الاستدعاء
3) امسح ذاكرة التخزين المؤقت للمتصفح وحاول مرة أخرى***## مستودع الأمثلة> [card] [مستودع GitHub](https://github.com/didit-protocol/didit-full-demo)
>
> اطلع على الكود المصدري والأمثلة على GitHub


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