---
type: how-to
title: Integrasi sisi server
summary: Ambil caputchin-token dari sebuah kiriman dan pastikan dengan /siteverify sebelum memercayai permintaannya.
---

Widget menyerahkan token sekali pakai ke peramban. Token itu tak membuktikan apa pun sampai servermu memastikannya dengan Caputchin. Inilah langkah yang mengubah tantangan kasatmata menjadi perlindungan sungguhan, dan ia adalah satu panggilan HTTPS.

Kamu butuh sebuah backend yang bisa membuat permintaan keluar, dan secret kunci situs-mu (`cpt_sec_...`) tersedia di sana, tak pernah di peramban.

## 1. Baca token

Saat formulir memposting, handler-mu menerima satu field ekstra di samping milikmu sendiri: `caputchin-token`. Widget menyuntikkannya ke formulir saat pengunjung menuntaskan tantangan.

## 2. Pastikan dengan /siteverify

POST token dan secret-mu. Permintaan dan responsnya berbentuk seperti `siteverify` milik reCAPTCHA, jadi integrasi yang sudah ada bisa dipindahkan dengan sedikit perubahan:

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

Panggilan yang sama di bahasa lain ada di [contoh integrasi backend](/docs/integration-guides/backend-examples).

## 3. Baca respons

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

- **`success`** adalah satu-satunya hal untuk dicabangkan. `true` berarti seorang pengunjung sungguhan menuntaskan tantangan; percayai permintaannya. `false` berarti buang.
- **`error-codes`** muncul saat `success` adalah `false`, menyebutkan apa yang salah (sebuah token yang hilang, kedaluwarsa, atau sudah terpakai, dan seterusnya).
- **`platform`** adalah metadata yang diklaim klien (game mana, skornya, durasinya). Ia nullable dan **bukan sinyal keamanan**. Catat untuk analitik jika kamu mau, tapi jangan pernah menggerbang kepercayaan pada skor.

## Aturan yang melindungimu

- **Sekali pakai.** Sebuah token terverifikasi sekali. Mengirim yang sama lagi mengembalikan `success: false`, jadi kamu tak perlu melacak replay sendiri.
- **Berumur pendek.** Sebuah token kedaluwarsa sepuluh menit setelah diterbitkan, jadi verifikasi selagi menangani kiriman, bukan di job yang ditunda.
- **Secret tetap di server.** Ia tak pernah pergi ke peramban, dan itulah yang mengautentikasi panggilannya.

## Kesalahan umum

- **Memverifikasi di sisi klien.** Event `pass` dan keberadaan token hanyalah UX. Setiap keputusan kepercayaan terjadi di sini, di sisi server, dengan secret-mu.
- **Menggerbang pada `score`.** Itu metadata, bukan nilai keyakinan.

## Pertanyaan umum

### Berapa lama sebuah token berlaku?

Sepuluh menit setelah diterbitkan. Verifikasi selagi kamu menangani kiriman, bukan dari job yang ditunda atau antrean yang mungkin jalan belakangan.

### Bisakah aku memverifikasi token yang sama dua kali?

Tidak. Sebuah token sekali pakai. Mengirim yang sama lagi mengembalikan `success: false`, jadi kamu tak perlu melacak replay sendiri.

### Haruskah aku memercayai `score` atau `game_id`?

Tidak. Blok `platform` (game, skor, durasi) adalah metadata yang diklaim klien dan ia nullable. Bercabanglah hanya pada `success`, dan jangan pernah menggerbang kepercayaan pada skor.

### Apakah aku perlu SDK untuk ini?

Tidak. Pemeriksaannya adalah satu POST HTTPS ke `/v1/siteverify`. Panggilan yang sama di Node, Python, PHP, Go, Ruby, .NET, dan curl ada di [contoh integrasi backend](/docs/integration-guides/backend-examples).

## Lihat juga

- [Contoh integrasi backend](/docs/integration-guides/backend-examples) untuk panggilan ini di bahasamu.
- [Verifikasi terhosting](/docs/hosted-verification/overview) untuk melewati backend sepenuhnya.
