> ## Documentation Index
> Fetch the complete documentation index at: https://documentacao.legitimuz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Checkout em Next.js

> Um fluxo de cadastro de ponta a ponta: a rota que cria a verificação, a página que abre o fluxo e o handler que recebe o desfecho.

```
app/
├─ api/
│  ├─ verificacoes/route.ts      # cria a verificação
│  └─ webhooks/legitimuz/route.ts # recebe o desfecho
└─ cadastro/page.tsx              # abre o fluxo
```

### Rota que cria

```ts title="app/api/verificacoes/route.ts" theme={null}
import { NextResponse } from "next/server";

export async function POST() {
  // 1. Quem está pedindo? Sem isto, qualquer um cria verificação na sua conta.
  const usuario = await autenticar();
  if (!usuario) return NextResponse.json({ erro: "nao_autenticado" }, { status: 401 });

  // 2. O CPF vem do SEU cadastro, nunca do corpo da requisição.
  const cadastro = await db.cadastro.porUsuario(usuario.id);

  const resposta = await fetch("https://api.legitimuz.com/public/verifications", {
    method: "POST",
    headers: {
      "X-API-Key": process.env.LEGITIMUZ_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      schema_version: "1.0",
      ref_id: cadastro.id,
      document: { type: "cpf", number: cadastro.cpf },
      integration_origin_public_id: process.env.LEGITIMUZ_ORIGIN_ID!,
    }),
  });

  if (!resposta.ok) {
    const erro = await resposta.json();
    console.error("legitimuz", resposta.status, erro.message, resposta.headers.get("X-Request-Id"));
    return NextResponse.json({ erro: "falha_ao_criar" }, { status: 502 });
  }

  const { verification, entry } = await resposta.json();

  // 3. Grave o vínculo ANTES de responder. Sem ele, o webhook chega órfão.
  await db.cadastro.vincular(cadastro.id, verification.public_id);

  // 4. Devolva só a entry.
  return NextResponse.json({ entry });
}
```

### Página que abre

```tsx title="app/cadastro/page.tsx" theme={null}
"use client";

import { useEffect, useRef, useState } from "react";

export default function Cadastro() {
  const container = useRef<HTMLDivElement>(null);
  const [estado, setEstado] = useState<"inicial" | "aberto" | "aguardando">("inicial");

  useEffect(() => {
    if (estado !== "aberto" || !container.current) return;

    let handle: { destroy: () => void } | undefined;
    let cancelado = false;

    fetch("/api/verificacoes", { method: "POST" })
      .then((r) => r.json())
      .then(({ entry }) => {
        if (cancelado || !container.current) return;
        handle = window.Legitimuz.mount({
          sdkUrl: entry.url,
          target: container.current,
          onComplete: () => setEstado("aguardando"),
        });
      });

    return () => {
      cancelado = true;
      handle?.destroy();
    };
  }, [estado]);

  if (estado === "aguardando") {
    // O desfecho vem do webhook. Aqui você só espera.
    return <p>Estamos analisando seus dados. Avisamos assim que terminar.</p>;
  }

  return estado === "inicial" ? (
    <button onClick={() => setEstado("aberto")}>Verificar identidade</button>
  ) : (
    <div ref={container} style={{ minHeight: 600 }} />
  );
}
```

<Warning>
  A tela nunca libera o cadastro. Ela só muda para "aguardando", quem libera é o handler de
  webhook, no servidor.
</Warning>

## Antes de rodar

As três POCs usam as mesmas variáveis:

```bash title=".env" theme={null}
LEGITIMUZ_API_KEY=<SUA_CHAVE>
LEGITIMUZ_ORIGIN_ID=<ORIGIN_PUBLIC_ID>
LEGITIMUZ_WEBHOOK_SECRET=<SEGREDO_DO_ENDPOINT>
```

Os três valores saem do dashboard, em
[Integrações → Segurança](/platform/integrations). Use uma integração **sandbox**.

## O que esta POC não faz

Ela mostra o caminho feliz e os erros que quebram integração. Ficou de fora de propósito:

* Autenticação de verdade. `autenticar()` é um stub.
* Migrations e schema do banco.
* Observabilidade e alerta.
* Tela de retomada quando o titular abandona e volta.

## Próximo passo

<Columns cols={2}>
  <Card title="Boas práticas" icon="bulb" href="/help/best-practices">
    O que separa uma integração que funciona de uma que gera chamado.
  </Card>

  <Card title="Ir para produção" icon="rocket" href="/start/sandbox">
    O checklist antes do primeiro titular real.
  </Card>
</Columns>
