> ## 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 por redirecionamento: página de verificação hospedada

> Didit: verificação hospedada por redirecionamento, multidispositivo, com URLs de retorno e webhooks. Desde $0.33 por KYC completo, $10 grátis/mês.



Prompt de integração por redirecionamento
        Copiar o prompt para a área de transferência



      
      

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



      
      

Colar em

O método de redirecionamento envia os usuários para uma página hospedada pela Didit para a verificação e depois os redireciona de volta para a sua aplicação por meio de uma URL de retorno.| Recurso | Descrição |
| - | - |
| Tempo de configuração | 5 minutos |
| Backend necessário | ✅ Sim (para criar sessões) |
| Permanece no seu domínio | ❌ Não (redireciona para verify.didit.me ou para o seu domínio personalizado com sua marca) |
| Suporte entre dispositivos | ✅ Sim |
| Compatibilidade com navegadores | ✅ Todos os navegadores |***## Quando usar o redirecionamento- **Verificação entre dispositivos**: comece no desktop e conclua no celular
- **Compatibilidade máxima**: funciona em todos os navegadores, inclusive nos mais antigos
- **Integração simples**: não exige configuração de iframe
- **Problemas com a câmera**: quando o acesso à câmera dentro do iframe é problemático***## Implementação### Etapa 1: criar uma sessão (backend)A resposta da criação de sessão usa um campo chamado **`url`**. Repasse esse valor para o navegador.```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 });
});
```### Etapa 2: redirecionar o usuário (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>
```***## Como lidar com o retornoQuando a verificação é concluída, a Didit redireciona para a sua URL de retorno com parâmetros de consulta:```
https://yourapp.com/verification-complete?verificationSessionId=abc123&status=Approved
```| Parâmetro | Descrição |
| - | - |
| `verificationSessionId` | Identificador único da sessão |
| `status` | O status atual da sessão, por exemplo `Approved`, `Declined`, `In Review` ou `Expired`. Consulte os [status de verificação](https://docs.didit.me/pt-br/integration/verification-statuses.md) |### Exemplo com 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>
  );
}
```### Exemplo com 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');
  }
});
```### Exemplo com 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');
    }
  }
}
```***## Abrir em uma nova abaSe você preferir manter sua aplicação aberta enquanto o usuário faz a verificação:```javascript theme={null}
// Open in new tab
window.open(verificationUrl, '_blank');

// Poll for completion or use webhooks
```> [!TIP]
>
> Ao usar novas abas, use [webhooks](https://docs.didit.me/pt-br/integration/webhooks.md) em conjunto para saber quando a verificação for concluída.***## Boas práticas de segurança### Verifique o retorno no servidorTrate os parâmetros de consulta `verificationSessionId` e `status` como indicadores não confiáveis da interface. Sempre confirme a decisão final no seu backend, seja tratando o [webhook](https://docs.didit.me/pt-br/integration/webhooks.md) (preferível), seja consultando novamente a decisão pela 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');
});
```### Use webhooksPara a integração mais confiável, use [webhooks](https://docs.didit.me/pt-br/integration/webhooks.md) para receber os resultados da verificação diretamente no seu backend, independentemente de como o navegador do usuário se comporta.***## Fluxo entre dispositivosO método de redirecionamento oferece suporte nativo à verificação entre dispositivos:1) O usuário clica em "Verificar" no desktop
2) O usuário é redirecionado para a página de verificação
3) Se necessário, o usuário pode escanear um QR code para continuar no celular
4) Após a conclusão, o usuário é redirecionado para a sua URL de retorno. O dispositivo que faz o redirecionamento é determinado por `callback_method` (`initiator`, `completer` ou `both`)***## Solução de problemas### Retorno não recebido1) Verifique se a URL de retorno foi definida corretamente ao criar a sessão
2) Garanta que a sua URL de retorno esteja acessível pela internet
3) Confira se a URL não tem erros de digitação ou problemas de codificação### Status sempre "Declined"1) Verifique as configurações do seu fluxo de verificação (workflow) no Didit Console
2) Confirme que os documentos de teste que você está usando são válidos
3) Analise os detalhes da sessão pela API para ver os motivos específicos da recusa### Loop de redirecionamento1) Garanta que o seu handler de retorno não redirecione de volta para a verificação
2) Verifique se há problemas de cache na sua página de retorno
3) Limpe o cache do navegador e tente novamente***## Repositório de exemplo> [card] [Repositório no GitHub](https://github.com/didit-protocol/didit-full-demo)
>
> Veja o código-fonte e exemplos no GitHub


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