Truform Captcha

Server verification

Validate Truform response tokens on your backend before accepting form data.

Never trust a form submission until your server confirms the Truform token. The secret key (tf_sec_) is required for this step and must not be exposed to browsers.

Use the secret key that belongs to the same site key as the public key on the page. If you operate multiple domains on one Truform subscription, each domain has its own key pair.

siteverify request

Send a POST request to the Syndaq API:

POST https://api.syndaq.com/v1/truform/siteverify
Content-Type: application/json

Request body:

{
  "secret": "tf_sec_your_secret_key",
  "response": "token_from_truform-response_field",
  "remoteip": "203.0.113.10",
  "action": "login"
}

The remoteip field is optional but recommended. It helps Syndaq detect abuse patterns and supports hostname validation on successful responses.

Optional action should match the label you passed to the widget when you use action tagging (for example login or checkout). This applies to both Interactive and Managed verifications.

Managed and Interactive tokens are validated the same way. A successful response may include a type field (managed or a puzzle type) for logging only — treat any successful siteverify the same in your application logic.

PHP example

<?php
$secret = getenv('TRUFORM_SECRET_KEY');
$token = $_POST['truform-response'] ?? '';
$remoteIp = $_SERVER['REMOTE_ADDR'] ?? '';

$payload = json_encode([
    'secret' => $secret,
    'response' => $token,
    'remoteip' => $remoteIp,
]);

$ch = curl_init('https://api.syndaq.com/v1/truform/siteverify');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
curl_close($ch);

$result = json_decode($body, true);
if (!is_array($result) || empty($result['success'])) {
    http_response_code(400);
    exit('Verification failed.');
}

// Token is valid. Process the form.

Node.js example

const response = await fetch('https://api.syndaq.com/v1/truform/siteverify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    secret: process.env.TRUFORM_SECRET_KEY,
    response: req.body['truform-response'],
    remoteip: req.ip,
  }),
});

const result = await response.json();
if (!result.success) {
  return res.status(400).send('Verification failed.');
}

Successful response

When verification succeeds, the API returns JSON similar to:

{
  "success": true,
  "challenge_ts": "2026-05-19T12:00:00Z",
  "hostname": "example.com",
  "action": "login",
  "remoteip": "203.0.113.10",
  "risk_score": 18,
  "risk_level": "low",
  "risk_recommendation": "accept"
}
FieldMeaning
risk_score0 to 100 (lower is safer)
risk_levellow, medium, or high
risk_recommendationSuggested handling: accept, log_and_monitor, or step_up_or_review
risk_flaggedPresent when your site key risk policy is set to flag high-risk tokens

Per-key risk policies (block, flag, or allow) are configured under Manage > Settings on Developer and Enterprise plans. When policy is block, siteverify returns HTTP 403 with risk_policy_blocked.

If verification fails, success is false and an error-codes array may describe the reason. Reusing a token that was already verified returns HTTP 409 with error code timeout-or-duplicate.

When hostname is present on a successful response, it must match the domain allowlist for your site key. Otherwise the API returns a domain error even if the token itself was valid.

IP restrictions on siteverify

If you enabled IP restrictions for a site key in the client area, the siteverify call must originate from an allowed IPv4 or IPv6 address or CIDR range. Otherwise you receive HTTP 403 with error code ip_not_allowed.

Before enabling IP restrictions, confirm the outbound IP address your application uses to reach api.syndaq.com. Add that address (or range) to the allowlist on the Manage page for the site key.

See Site keys and security for full details on IP allowlist format and when to use it.

Best practices

  • Verify on every protected endpoint, including login and signup flows.
  • Reject empty or missing tokens immediately.
  • Store the secret key in environment variables or a secrets manager. Never embed it in client side code.
  • Use the secret key that matches the public site key on the same domain.
  • Combine Truform with rate limiting and other bot defenses for high value endpoints.