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

# Redirect KYC Web: Halaman Verifikasi yang Di-hosting

> Verifikasi identitas yang di-hosting lewat redirect: lintas perangkat, URL callback, dan hasil webhook lengkap. Mulai $0.33 per KYC penuh, gratis $10/bulan.



Prompt Integrasi Redirect
        Salin prompt ke papan klip



      
      

\<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>



      
      

Tempel ke

Metode Redirect mengalihkan pengguna ke halaman verifikasi yang di-hosting oleh Didit, lalu mengembalikan mereka ke aplikasi Anda melalui URL callback.| Fitur | Deskripsi |
| - | - |
| Waktu Penyiapan | 5 menit |
| Memerlukan Backend | ✅ Ya (untuk membuat sesi) |
| Tetap di Domain Anda | ❌ Tidak (dialihkan ke verify.didit.me atau domain kustom White Label Anda) |
| Dukungan Lintas Perangkat | ✅ Ya |
| Kompatibilitas Browser | ✅ Semua browser |***## Kapan Menggunakan Redirect- **Verifikasi lintas perangkat**: Mulai di desktop, selesaikan di ponsel
- **Kompatibilitas maksimal**: Berfungsi di semua browser, termasuk browser yang lebih lama
- **Integrasi sederhana**: Tidak perlu konfigurasi iframe
- **Masalah kamera**: Saat akses kamera iframe bermasalah***## Implementasi### Langkah 1: Buat sesi (backend)Respons pembuatan sesi menggunakan kolom bernama **`url`**. Teruskan nilai tersebut ke browser.```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 });
});
```### Langkah 2: Alihkan Pengguna (Frontend)**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>
```***## Menangani CallbackKetika verifikasi selesai, Didit mengalihkan pengguna ke URL callback Anda dengan parameter query:```
https://yourapp.com/verification-complete?verificationSessionId=abc123&status=Approved
```| Parameter | Deskripsi |
| - | - |
| `verificationSessionId` | Pengidentifikasi unik sesi |
| `status` | Status sesi saat ini, misalnya `Approved`, `Declined`, `In Review` atau `Expired`. Lihat [status verifikasi](https://docs.didit.me/id/integration/verification-statuses.md) |### Contoh 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>
  );
}
```### Contoh 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');
  }
});
```### Contoh 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');
    }
  }
}
```***## Buka di Tab BaruJika Anda ingin aplikasi tetap terbuka selama pengguna melakukan verifikasi:```javascript theme={null}
// Open in new tab
window.open(verificationUrl, '_blank');

// Poll for completion or use webhooks
```> [!TIP]
>
> Saat menggunakan tab baru, gabungkan dengan [webhook](https://docs.didit.me/id/integration/webhooks.md) untuk mengetahui kapan verifikasi selesai.***## Praktik Keamanan Terbaik### Verifikasi callback di sisi serverPerlakukan parameter query `verificationSessionId` dan `status` sebagai petunjuk UI yang tidak tepercaya. Selalu konfirmasi keputusan akhir di backend Anda, baik dengan menangani [webhook](https://docs.didit.me/id/integration/webhooks.md) (direkomendasikan) maupun dengan mengambil ulang keputusan melalui 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');
});
```### Gunakan WebhookUntuk integrasi yang paling andal, gunakan [webhook](https://docs.didit.me/id/integration/webhooks.md) agar hasil verifikasi langsung diterima oleh backend Anda, apa pun perilaku browser pengguna.***## Alur Lintas PerangkatMetode redirect secara alami mendukung verifikasi lintas perangkat:1) Pengguna mengklik "Verify" di desktop
2) Pengguna dialihkan ke halaman verifikasi
3) Jika diperlukan, pengguna dapat memindai kode QR untuk melanjutkan di ponsel
4) Setelah selesai, pengguna dialihkan ke URL callback Anda. Perangkat yang melakukan pengalihan dikendalikan oleh `callback_method` (`initiator`, `completer`, atau `both`)***## Pemecahan Masalah### Callback Tidak Diterima1) Pastikan URL callback sudah diatur dengan benar saat membuat sesi
2) Pastikan URL callback Anda dapat diakses dari internet
3) Periksa bahwa URL tidak memiliki salah ketik atau masalah encoding### Status Selalu "Declined"1) Periksa pengaturan alur kerja Anda di Didit Console
2) Pastikan dokumen uji yang Anda gunakan valid
3) Tinjau detail sesi melalui API untuk melihat alasan penolakan yang spesifik### Perulangan Redirect1) Pastikan handler callback Anda tidak mengalihkan kembali ke verifikasi
2) Periksa masalah cache pada halaman callback Anda
3) Hapus cache browser lalu coba lagi***## Repositori Contoh> [card] [Repositori GitHub](https://github.com/didit-protocol/didit-full-demo)
>
> Lihat kode sumber dan contoh di GitHub


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