---
type: how-to
title: Integração no lado do servidor
summary: Pegue o caputchin-token de um envio e confirme-o com /siteverify antes de confiar na requisição.
---

O widget entrega ao navegador um token de uso único. Esse token não prova nada até que seu servidor o confirme com o Caputchin. Este é o passo que transforma um desafio visível em proteção de verdade, e é uma única chamada HTTPS.

Você precisa de um backend que consiga fazer uma requisição de saída, e do segredo da sua chave de site (`cpt_sec_...`) disponível ali, nunca no navegador.

## 1. Leia o token

Quando o formulário posta, seu handler recebe um campo extra ao lado dos seus: `caputchin-token`. O widget o injetou no formulário quando o visitante resolveu o desafio.

## 2. Confirme-o com /siteverify

Faça POST do token e do seu segredo. A requisição e a resposta têm o mesmo formato do `siteverify` do reCAPTCHA, então uma integração existente migra com pouca mudança:

```http
POST https://verify.caputchin.com/v1/siteverify
Content-Type: application/json

{ "secret": "cpt_sec_...", "response": "<caputchin-token>" }
```

```js
// Node 18+
const verdict = await fetch("https://verify.caputchin.com/v1/siteverify", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    secret: process.env.CAPUTCHIN_SECRET,
    response: token,
  }),
}).then((r) => r.json());

if (!verdict.success) {
  // reject the submission
}
```

A mesma chamada em outras linguagens está em [exemplos de integração de backend](/docs/integration-guides/backend-examples).

## 3. Leia a resposta

```json
{
  "success": true,
  "error-codes": [],
  "platform": { "game_id": "caputchin/games/leaf-memory", "score": 847, "duration_ms": 4200 }
}
```

- **`success`** é a única coisa em que ramificar. `true` significa que um visitante real resolveu o desafio; confie na requisição. `false` significa descartá-la.
- **`error-codes`** aparece quando `success` é `false`, nomeando o que deu errado (um token ausente, expirado ou já usado, e assim por diante).
- **`platform`** são metadados alegados pelo cliente (qual jogo, a pontuação, a duração). É anulável e **não é um sinal de segurança**. Registre-o para análises se quiser, mas nunca condicione a confiança à pontuação.

## As regras que protegem você

- **Uso único.** Um token verifica uma vez. Enviar o mesmo de novo retorna `success: false`, então você não precisa rastrear replays por conta própria.
- **Vida curta.** Um token expira dez minutos depois de emitido, então verifique-o enquanto trata o envio, não em um job atrasado.
- **O segredo fica no servidor.** Ele nunca vai ao navegador, e é o que autentica a chamada.

## Erros comuns

- **Verificar no cliente.** O evento `pass` e a presença do token são só de UX. Toda decisão de confiança acontece aqui, no servidor, com seu segredo.
- **Condicionar ao `score`.** É metadado, não um valor de confiança.

## Perguntas comuns

### Por quanto tempo um token é válido?

Dez minutos depois de emitido. Verifique-o enquanto você trata o envio, não a partir de um job atrasado ou uma fila que pode rodar mais tarde.

### Posso verificar o mesmo token duas vezes?

Não. Um token é de uso único. Enviar o mesmo de novo retorna `success: false`, então você não precisa rastrear replays por conta própria.

### Devo confiar no `score` ou no `game_id`?

Não. O bloco `platform` (jogo, pontuação, duração) são metadados alegados pelo cliente e é anulável. Ramifique só no `success`, e nunca condicione a confiança à pontuação.

### Preciso de um SDK para isto?

Não. A conferência é um único POST HTTPS para `/v1/siteverify`. A mesma chamada em Node, Python, PHP, Go, Ruby, .NET e curl está em [exemplos de integração de backend](/docs/integration-guides/backend-examples).

## Veja também

- [Exemplos de integração de backend](/docs/integration-guides/backend-examples) para esta chamada na sua linguagem.
- [Verificação hospedada](/docs/hosted-verification/overview) para pular o backend por completo.
