API reference
All service interactions. Base URL: http://jkcaptcha.we4.online. The public widget key (jcv4w_…) — is used on the client, the secret API key (jcv4_…) — only on your server.
Captcha lifecycle
1. POST /api/v1/challenge?k=WIDGET_KEY → { id, width, height }
2. GET /api/v1/frame/{id}?v=N → WebP | 204 (X-Solved: 0|1, X-Version)
3. POST /api/v1/input/{id} → { solved } (drag deltas)
4. GET /api/v1/status/{id} → { solved, token }
5. GET /api/v1/verify?token=… → { valid } (your server + X-Api-Key)
Only frames and boolean answers are sent to the browser: no figure shape, no orientations, no camera. The server keeps the timer.
POST /api/v1/challenge
Creates a captcha session with the widget settings. Without k the default (demo) settings are used.
| Parameter | Where | Description |
|---|---|---|
k | query | public widget key; optional |
p | query | page marker; until the captcha is solved the same page gets the same session |
f | query | 1 — create a new captcha forcibly |
Response: { "id": "…", "width": 256, "height": 256 } · rate limit: 1/sec · 404, if the widget is not found or disabled.
GET /api/v1/frame/{id}
The current scene frame in WebP. When v equals the current version, 204 is returned — the main traffic-saving mode.
| Parameter | Where | Description |
|---|---|---|
id | path | session identifier |
v | query | client frame version (from the X-Version header) |
Headers: X-Version — frame number, X-Solved — 1, if the captcha is solved. rate limit: 40/sec · 404, if the session has expired (captcha = session: 30–60 seconds) · 410, if the page wait timeout has expired (300 seconds — the sessions are closed, the connection is forcibly terminated).
POST /api/v1/input/{id}
User input: drag deltas and behavioral aggregates. The server validates the solution when done: true.
{ "part": "ball" | "figure",
"dx": 12.5, "dy": -4.0, // deltas per batch
"done": false, // true — the user released
"ts": 1760000000000, // client clock (telemetry only)
"moves": 24, "activeMs": 380, // behavior aggregates
"reversals": 3, "jitter": 88.2, "pauses": 1 }
Response: { "solved": false } · rate limit: 40/sec; solve attempt — once per second (429 + Retry-After). Machine solutions are rejected: the captcha is not counted, a red flash appears in the frame.
GET /api/v1/status/{id}
Session status and the signed token (HMAC) after solving.
Response: { "solved": true, "token": "…" } · the token is valid for 300 seconds · rate limit: 5/sec. The remaining time is not exposed.
GET /api/v1/verify
Server-side token verification. The X-Api-Key header with your account secret key is required.
Response: { "valid": true } · 401 — the key is invalid or the account is disabled.
POST /api/v1/beacon/{id} & POST /api/v1/risk
beacon — passive page signals for the session (webdriver, hardware, screen, language, visibility). risk — risk check without a captcha.
POST /api/v1/risk X-Api-Key: jcv4_…
{ "webDriver": false, "hw": 8, "tz": -180, "screenW": 1920, "screenH": 1080,
"touch": false, "lang": "ru", "vis": 0, "elapsedMs": 5200,
"moves": 140, "keys": 6, "clicks": 2, "scrolls": 1 }
→ { "score": 0, "verdict": "human", "flags": [] }
Verdicts: human (< 30), suspicious (30–59), bot (≥ 60). The session is rejected when the risk is ≥ 60.
GET /api/v1/config
Public display parameters: the text after solving. With k — the widget text.
Response: { "solvedText": "Verification complete" } · rate limit: 1/sec.
Errors
| Code | When |
|---|---|
401 | invalid X-Api-Key (verify, risk) |
404 | the session expired/was removed, the widget is not found |
410 | the page wait timeout expired (300 seconds: its sessions are closed, new frames and input are not accepted) |
429 | rate limit exceeded; Retry-After: 1 header |