---
type: how-to
title: Серверная интеграция
summary: Возьми caputchin-token из отправки и подтверди его через /siteverify, прежде чем довериться запросу.
---

Виджет вручает браузеру одноразовый токен. Этот токен ничего не доказывает, пока твой сервер не подтвердит его через Caputchin. Это шаг, который превращает видимое испытание в настоящую защиту, и это единственный HTTPS-вызов.

Тебе нужен бэкенд, способный сделать исходящий запрос, и секрет твоего ключа сайта (`cpt_sec_...`), доступный там, никогда в браузере.

## 1. Прочитай токен

Когда форма отправляется, твой обработчик получает одно дополнительное поле рядом с твоими собственными: `caputchin-token`. Виджет вставил его в форму, когда посетитель прошёл испытание.

## 2. Подтверди через /siteverify

Отправь POST с токеном и своим секретом. Запрос и ответ по форме как `siteverify` у reCAPTCHA, так что существующая интеграция переносится с малыми изменениями:

```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
}
```

Тот же вызов на других языках смотри в [примерах бэкенд-интеграции](/docs/integration-guides/backend-examples).

## 3. Прочитай ответ

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

- **`success`** это единственное, на чём ты ветвишься. `true` означает, что настоящий посетитель прошёл испытание; доверяй запросу. `false` означает, отбрось его.
- **`error-codes`** появляется, когда `success` равно `false`, и называет, что пошло не так (отсутствующий, просроченный или уже использованный токен и так далее).
- **`platform`** это заявленные клиентом метаданные (какая игра, счёт, длительность). Поле nullable и **не является сигналом безопасности**. Записывай его для аналитики, если хочешь, но никогда не привязывай доверие к счёту.

## Правила, которые тебя защищают

- **Одноразовость.** Токен проверяется один раз. Отправка того же снова возвращает `success: false`, так что тебе не нужно самому отслеживать реплеи.
- **Короткоживущий.** Токен истекает через десять минут после выдачи, так что проверяй его во время обработки отправки, а не в отложенном задании.
- **Секрет остаётся на сервере.** Он никогда не идёт в браузер, и именно он аутентифицирует вызов.

## Частые ошибки

- **Проверка на клиенте.** Событие `pass` и наличие токена это только UX. Каждое решение о доверии происходит здесь, на сервере, с твоим секретом.
- **Привязка к `score`.** Это метаданные, а не значение доверия.

## Частые вопросы

### Сколько времени токен действителен?

Десять минут после выдачи. Проверяй его, пока обрабатываешь отправку, а не из отложенного задания или очереди, которая может сработать позже.

### Можно ли проверить один и тот же токен дважды?

Нет. Токен одноразовый. Отправка того же снова возвращает `success: false`, так что тебе не нужно самому отслеживать реплеи.

### Стоит ли доверять `score` или `game_id`?

Нет. Блок `platform` (игра, счёт, длительность) это заявленные клиентом метаданные, и он nullable. Ветвись только по `success` и никогда не привязывай доверие к счёту.

### Нужен ли мне для этого SDK?

Нет. Проверка это один HTTPS-запрос POST к `/v1/siteverify`. Тот же вызов на Node, Python, PHP, Go, Ruby, .NET и curl смотри в [примерах бэкенд-интеграции](/docs/integration-guides/backend-examples).

## См. также

- [Примеры бэкенд-интеграции](/docs/integration-guides/backend-examples) для этого вызова на твоём языке.
- [Размещённая проверка](/docs/hosted-verification/overview), чтобы пропустить бэкенд целиком.
