Verify a Caputchin token on your backend
When a user submits the form, your backend receives a caputchin-token field. Pass it to /siteverify along with your secret. Reference for the endpoint shape is api.
1. Read the token from the form
caputchin-token=<wrappedToken>
The widget injects this hidden field. See widget.
2. POST to /siteverify
POST https://api.caputchin.com/siteverify
Content-Type: application/json
{
"secret": "cpt_sec_...",
"response": "<wrappedToken>"
}
Top level is reCAPTCHA-shape-compatible — if you've integrated reCAPTCHA before, the request shape is familiar.
3. Read the response
{
"success": true,
"...other cap_siteverify fields": "...",
"platform": {
"game_id": "bubble-pop",
"score": 0.847,
"duration_ms": 4200
}
}
The platform.score and platform.duration_ms are client-claimed metadata, not security signals — see ADR-0002. Treat verification as binary on success. If you want to record score for a leaderboard or analytics, that's fine; just don't gate trust decisions on it.
4. Handle replay protection
The platform verifies the wrapped token's HMAC and rejects replays automatically. You don't need to track tokens client-side. A token is single-use; submitting the same one twice returns success: false.
5. Use any HTTP client
There is no first-party server SDK in any language — see ADR-0011. The endpoint is a plain JSON POST, so fetch in Node, requests in Python, Net::HTTP in Ruby, or whatever HTTP client your backend already uses works directly. Copy-paste examples for the most common languages live in snippets. For a typed client, run your preferred generator against the OpenAPI spec — the contract is three endpoints, so the generated output is short.
What about the customer's risk model?
If you want risk scoring (block / challenge / allow tiers), build it on top of verified PoW with your own signals. The platform deliberately does not provide a confidence score — see ADR-0002 and principles.
Common mistakes
- Verifying client-side. Don't. The widget's
completeevent is UX-gating only. All trust decisions happen server-side with your secret. - Sending the secret to the browser. Don't. The secret never leaves your backend.
- Forgetting to add your domain to the allowlist. Tokens issued from non-allowed origins fail verification. Configure in the dashboard.
- Using
scoreto make trust decisions. It's metadata, not security. See above.