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

# KYC via redirect: pagina di verifica ospitata

> Verifica dell'identità via redirect con Didit: multi-dispositivo, URL di callback e webhook. Da $0.33 per verifica KYC completa, $10 gratis al mese.



Prompt di integrazione del reindirizzamento
        Copia il prompt negli appunti



      
      

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



      
      

Incolla in

Il metodo di reindirizzamento invia gli utenti a una pagina di verifica ospitata da Didit e poi li riporta alla tua app tramite un URL di callback.| Funzionalità | Descrizione |
| - | - |
| Tempo di configurazione | 5 minuti |
| Backend richiesto | ✅ Sì (per creare le sessioni) |
| Resta sul tuo dominio | ❌ No (reindirizza a verify.didit.me o al tuo dominio personalizzato White label) |
| Supporto cross-device | ✅ Sì |
| Compatibilità browser | ✅ Tutti i browser |***## Quando usare il reindirizzamento- **Verifica cross-device**: inizia da desktop e completa da mobile
- **Massima compatibilità**: funziona in tutti i browser, inclusi quelli meno recenti
- **Integrazione semplice**: non serve alcuna configurazione di iframe
- **Problemi con la fotocamera**: quando l'accesso alla fotocamera in iframe non funziona***## Implementazione### Passaggio 1: crea una sessione (backend)La risposta di creazione della sessione contiene un campo chiamato **`url`**: passa questo valore al 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 });
});
```### Passaggio 2: reindirizza l'utente (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>
```***## Gestione della callbackQuando la verifica è completata, Didit reindirizza all'URL di callback con i seguenti parametri di query:```
https://yourapp.com/verification-complete?verificationSessionId=abc123&status=Approved
```| Parametro | Descrizione |
| - | - |
| `verificationSessionId` | Identificatore univoco della sessione |
| `status` | Lo stato attuale della sessione, ad esempio `Approved`, `Declined`, `In Review` o `Expired`. Vedi [stati della verifica](https://docs.didit.me/it/integration/verification-statuses.md) |### Esempio 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>
  );
}
```### Esempio 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');
  }
});
```### Esempio 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');
    }
  }
}
```***## Apri in una nuova schedaSe preferisci tenere aperta la tua app mentre l'utente esegue la verifica:```javascript theme={null}
// Open in new tab
window.open(verificationUrl, '_blank');

// Poll for completion or use webhooks
```> [!TIP]
>
> Quando usi le nuove schede, combinale con i [webhook](https://docs.didit.me/it/integration/webhooks.md) per sapere quando la verifica è completata.***## Buone pratiche di sicurezza### Verifica la callback lato serverConsidera i parametri di query `verificationSessionId` e `status` come semplici indicazioni dell'interfaccia non attendibili. Conferma sempre la decisione finale sul tuo backend, gestendo il [webhook](https://docs.didit.me/it/integration/webhooks.md) (opzione preferita) oppure recuperando di nuovo la decisione tramite l'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');
});
```### Usa i webhookPer l'integrazione più affidabile, usa i [webhook](https://docs.didit.me/it/integration/webhooks.md) per ricevere i risultati della verifica direttamente sul tuo backend, indipendentemente dal comportamento del browser dell'utente.***## Flusso cross-deviceIl metodo di reindirizzamento supporta in modo naturale la verifica cross-device:1) L'utente clicca su "Verifica" sul desktop
2) L'utente viene reindirizzato alla pagina di verifica
3) Se necessario, l'utente può scansionare il codice QR per continuare da mobile
4) Al termine, l'utente viene reindirizzato all'URL di callback: il dispositivo da cui viene effettuato il reindirizzamento è determinato da `callback_method` (`initiator`, `completer` o `both`)***## Risoluzione dei problemi### Callback non ricevuta1) Verifica che l'URL di callback sia impostato correttamente quando crei la sessione
2) Assicurati che il tuo URL di callback sia raggiungibile da internet
3) Controlla che l'URL non contenga errori di battitura o problemi di codifica### Lo stato è sempre "Declined"1) Controlla le impostazioni del workflow nella Didit Console
2) Verifica che i documenti di test che usi siano validi
3) Consulta i dettagli della sessione tramite API per i motivi specifici del rifiuto### Loop di reindirizzamento1) Assicurati che il gestore della callback non reindirizzi di nuovo alla verifica
2) Controlla eventuali problemi di cache nella pagina di callback
3) Svuota la cache del browser e riprova***## Repository di esempio> [card] [Repository GitHub](https://github.com/didit-protocol/didit-full-demo)
>
> Consulta il codice sorgente e gli esempi su GitHub


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