Caputchin
Hosted verification

Webhook payload reference

When a submission clears verification, the forwarder sends one POST to your configured webhook URL. This page is the exact contract for that request. For the setup walkthrough, see set up hosted verification; for the concept, see verify without a backend.

Request line and headers

The forwarder sends a POST with a JSON body and these headers:

HeaderValue
content-typeapplication/json
acceptapplication/json
user-agentCaputchin-Forwarder/0.1
x-caputchin-test1, present only on a dashboard Test delivery; absent on real submissions

The call is sent with redirects disabled and a timeout of a few seconds. The request is not signed; the secrecy of the webhook URL is what authenticates it.

Body

The body is a JSON object with two top-level keys, caputchin (verification metadata Caputchin adds) and form (your submitted fields):

{
  "caputchin": {
    "site_key": "cpt_pub_...",
    "session_id": "...",
    "game_id": "caputchin/games/leaf-memory",
    "score": 847,
    "duration_ms": 4200,
    "verified_at": 1748640000000
  },
  "form": {
    "email": "visitor@example.com",
    "message": "Hello!"
  }
}

The caputchin object

FieldTypeMeaning
site_keystringThe public cpt_pub_... key the submission came from.
session_idstringAn opaque verification-session id, useful for correlation or deduplication. On a test delivery it is prefixed test_.
game_idstring or nullThe game the visitor played. Null when the verification ran without a game.
scorenumber or nullThe game score. Client-claimed metadata for analytics, never a trust signal. Null when not applicable.
duration_msnumber or nullHow long the visitor spent playing the game, in milliseconds. Client-claimed, not a trust signal. Null when not applicable (for example a verification with no game).
verified_atnumberWhen Caputchin verified the token, as a Unix epoch in milliseconds.
testboolean (optional)Present and true only on a dashboard test delivery. Absent on real submissions.

game_id, score, and duration_ms are each nullable on a real submission, so guard for null before reading them. None of the caputchin fields are a trust decision: the trust is that the request arrived at all, because a submission that fails verification is never forwarded.

The form object

form is a flat object of your submitted fields as string keys and string values, exactly as posted, with one change: the caputchin-token field is stripped before delivery, so it never appears here. The forwarder accepts text fields only; a submission carrying a file upload is rejected before any delivery.

What your handler should return

Return any 2xx status to acknowledge receipt. The forwarder treats a non-2xx response, a timeout, or a connection failure as a failed delivery, and a failed delivery is not retried. Track delivery health on the statistics page.

See also

On this page