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

# Backend em Express

> A rota que emite a credencial e o receptor de webhook, num servidor Express.

Quando o seu front não é Next.js, a rota é a mesma, só muda o framework.

```ts title="server.ts" theme={null}
import express from "express";

const app = express();

app.post("/api/verificacoes", express.json(), async (req, res) => {
  const usuario = await autenticar(req);
  if (!usuario) return res.status(401).json({ erro: "nao_autenticado" });

  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!,
    }),
  });

  const { verification, entry } = await resposta.json();
  await db.cadastro.vincular(cadastro.id, verification.public_id);

  res.json({ entry });
});

// `raw`, não `json`: a conferência da assinatura precisa dos bytes originais.
app.post(
  "/api/webhooks/legitimuz",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    const corpoCru = req.body.toString("utf8");
    const assinatura = req.get("X-Legitimuz-Signature") ?? "";

    if (!assinaturaValida(corpoCru, assinatura, process.env.LEGITIMUZ_WEBHOOK_SECRET!)) {
      return res.sendStatus(401);
    }

    const inedita = await db.entregas.registrarSeInedita(req.get("X-Legitimuz-Delivery")!);
    if (inedita) await fila.publicar(JSON.parse(corpoCru));

    res.sendStatus(200);
  }
);

app.listen(3000);
```

<Warning>
  A ordem dos middlewares importa. Um `express.json()` global antes da rota de webhook consome o
  corpo e a conferência da assinatura passa a falhar sempre.
</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>
