Truform Captcha
API reference
Truform HTTP endpoints on api.syndaq.com.
All Truform API endpoints are served from https://api.syndaq.com/v1/truform/. The widget loader and static assets are hosted at https://syndaq.com/truform/.
When you subscribe to a Truform plan, Syndaq creates a service in your client area. Each site key on that service has a public and secret key. Use the public key in your pages. Keep the secret on your server only.
An OpenAPI description is available at openapi.yaml.
Endpoints overview
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /v1/truform/challenge | Public key (sitekey query) | Fetch a new puzzle challenge |
| POST | /v1/truform/managed | Public key (body) | Managed verification with puzzle fallback |
| POST | /v1/truform/verify | Public key (body) | Verify a puzzle solution in the browser |
| POST | /v1/truform/siteverify | Secret key (body) | Server side token validation |
| GET | /v1/truform/status | Public or secret key | Key health and quota snapshot |
| GET | /v1/truform/usage | Secret key | Usage stats for the subscription |
Browser routes answer OPTIONS preflight when the Origin host matches the site key domain allowlist.
Key prefixes
| Key | Prefix | Used where |
|---|---|---|
| Public | tf_pub_ | Browser widget (data-sitekey, challenge, verify, status) |
| Secret | tf_sec_ | Server siteverify and usage only |
Both keys are tied to your plan (rate limits and monthly quota). The API checks that the key exists and is active.
Security checks
Every authenticated request passes through the following checks when applicable:
| Check | Applies to | When enforced |
|---|---|---|
| Valid key | All endpoints | Always |
| Domain allowlist | challenge, verify, managed, and successful siteverify hostname | Per site key domain configuration |
| IP allowlist | All endpoints | Only when IP restrictions are enabled for that site key |
| Rate limit | All endpoints | Per site key (per minute) |
| Monthly quota | All endpoints | Per subscription (shared across all site keys on the service) |
| Single use token | siteverify | Each response token works once |
Domain and IP rules are configured per site key in the Syndaq client area. See Site keys and security.
Response headers
Successful and error responses may include:
| Header | Description |
|---|---|
X-Request-Id | Unique ID for support and log correlation |
X-RateLimit-Limit | Plan requests per minute for this site key |
X-RateLimit-Remaining | Requests left in the current minute window |
X-RateLimit-Reset | Unix timestamp when the minute window resets |
X-Quota-Limit | Monthly quota for the subscription |
X-Quota-Remaining | Requests left this calendar month (UTC) |
X-Quota-Period | Current quota month (YYYY-MM) |
Retry-After | Seconds to wait after HTTP 429 |
Access-Control-Allow-Origin | Reflected origin when the browser Origin matches the site key allowlist |
GET /v1/truform/challenge
Used by the widget loader to fetch a puzzle. The loader calls this automatically. You rarely need to invoke it directly.
Query parameters:
| Parameter | Required | Description |
|---|---|---|
sitekey | Yes | Your tf_pub_ key |
puzzle_type | No | Puzzle style or random |
hostname | No | Page hostname (sent automatically by the widget) |
The request must come from a browser context on an allowed domain for the site key.
POST /v1/truform/managed
Used by the widget in Managed mode. Evaluates browser telemetry and IP risk signals. Returns a response token when the visitor passes without a puzzle, or interactive_required when a puzzle is needed.
Requires Managed mode to be enabled on the site key in the client area and data-mode="managed" on the widget (or mode: 'managed' in truform.render). Existing Interactive embeds do not call this endpoint.
Request body (JSON):
{
"sitekey": "tf_pub_your_public_key",
"hostname": "example.com",
"action": "login",
"telemetry": {}
}
Success response includes proof (the token for siteverify), mode (managed), plus risk_score and risk_level.
When a puzzle is required, the API returns HTTP 422 with interactive_required: true. The widget then loads the standard challenge flow.
Counts toward your monthly verification quota the same way as verify.
POST /v1/truform/verify
Called by the widget after the user completes a puzzle. Returns a response token on success.
Request body (JSON):
{
"sitekey": "tf_pub_your_public_key",
"hostname": "example.com",
"token": "…",
"action": "login",
"trace": [],
"telemetry": {}
}
Optional action labels the verification (for example login or signup). The same value can be sent to siteverify and is echoed on success.
The widget sends hostname automatically. The page must be served from a domain allowed for the site key.
On success the response includes proof (the token for siteverify), plus risk_score (0 to 100, lower is safer) and risk_level (low, medium, or high).
POST /v1/truform/siteverify
Server side validation. See Server verification for examples. Send your tf_sec_ secret in the request body.
Recommended body fields:
| Field | Required | Description |
|---|---|---|
secret | Yes | Your tf_sec_ key |
response | Yes | Value from the truform-response field |
remoteip | No | End user IP (recommended) |
action | No | Must match the action used at verify time when provided |
If IP restrictions are enabled for the site key, the request must come from an allowed IPv4 or IPv6 address.
Each response token is valid for one successful siteverify call. Reuse returns HTTP 400 with token_already_used.
GET /v1/truform/status
Lightweight health check for monitoring or CI. Pass the public site key as sitekey.
Example response:
{
"success": true,
"status": "active",
"product": "truform",
"plan": "starter",
"domains_configured": true,
"domain_count": 2,
"ip_restrictions": false,
"rate_limit_per_minute": 60,
"monthly_quota": 10000,
"quota_remaining": 8420,
"quota_period": "2026-05",
"request_id": "…"
}
GET /v1/truform/usage
Returns usage for the subscription linked to the secret key (aggregated across all site keys on the service). Authenticate with the secret key in the JSON body, query string, or Authorization: Bearer tf_sec_… header.
Widget loader globals
The script at https://syndaq.com/truform/api.js configures these defaults internally:
| Setting | Value |
|---|---|
| API base | https://api.syndaq.com |
| Challenge URL | /v1/truform/challenge |
| Verify URL | /v1/truform/verify |
| Response field | truform-response |
Errors
Failed requests return JSON with success: false, error, error_code, and request_id.
| HTTP | error_code | Typical cause |
|---|---|---|
| 400 | token_already_used | Response token was already consumed by siteverify |
| 401 | missing_credentials | No site key or secret provided |
| 401 | invalid_api_key | Unknown or inactive key |
| 401 | wrong_key_type | Public key used on siteverify or secret on browser endpoints |
| 403 | domain_not_allowed | Page hostname is not allowed for this site key |
| 403 | domain_required | Browser request missing a valid page domain |
| 403 | domain_not_configured | Site key has no domain allowlist configured |
| 403 | ip_not_allowed | Caller IP is not on the allowlist while IP restrictions are enabled |
| 429 | rate_limit_exceeded | Too many requests per minute for the site key |
| 429 | quota_exceeded | Monthly subscription quota exhausted |
| 500 | server_error | Temporary API error — retry with backoff |
Common operational causes:
- Invalid or expired response token
- Secret key mismatch on
siteverify - Widget embedded on a domain that does not match the site key
siteverifyblocked after enabling IP restrictions without adding your server egress IP
Always handle non 200 responses and failed verification gracefully in your application.
See Webhooks for quota alert notifications.