Kasada ACTIVE
KPSDK x-kpsdk-* minter — full solve, or a request-based payload transformer.
Overview
Kasada protects sites with an ips.js bytecode runtime (a dispatcher VM). A client runs it, builds a payload, and POSTs it to /tl to mint a cleared x-kpsdk-ct token; every subsequent request to a protected endpoint then carries a fresh x-kpsdk-cd proof-of-work.
VexSolver reimplements that runtime as a pure-Go VM — fully request-based, no browser, no headless Chromium. Every request-side header is reverse-engineered and generated natively, not replayed from a template. You can use it two ways:
- › Full solve —
POST /api/solve. We do every network hop and hand back the token bundle. Simplest to integrate. - › Payload transformer —
POST /api/kasada/payload. You own the TLS session, proxy, cookie jar and header order; we only turn the ips.js into a/tlbody. It is a clean request-based contract — the token is minted from your own egress IP.
/api/kasada/payload) for production scraping: the token is minted from your egress IP, so it never has to be replayed from a different IP than it was earned on, and there is no url field for us to misroute. Use full solve (/api/solve) when you just want a token and do not want to make the fetches yourself.Payload transformer — POST /api/kasada/payload
A clean request-based transformer contract: any request-based integration repoints by changing only the base URL. You fetch the challenge yourself and send us the ips.js; we return the exact headers and the base64 body to POST to /tl.
Request fields:
- ›
script— the raw ips.js body you fetched (required) - ›
ipsLink— the ips.js URL withx-kpsdk-vandx-kpsdk-imappended as query params (required). Withoutx-kpsdk-imthe payload is not bound to your handshake and/tlrejects it. - ›
userAgent— the exact UA your TLS client sends. Desktop and mobile both supported. - ›
acceptLanguage— yourAccept-Languageheader - ›
ip— your egress IP (informational) - ›
ct— optional. Your preflightx-kpsdk-ct(from your own/fpor the block page). Supply it and we return a complete header set you can send verbatim. We will not mint one — it is bound to your session. - ›
dv— optional, mobile only. Yourx-kpsdk-dv. It is a per-app-build constant; supplied ⇒ echoed back, omitted ⇒ absent. We never fabricate it.
curl -X POST https://api.vexsolver.com/api/kasada/payload \
-H "X-API-Key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
"acceptLanguage": "en-US,en;q=0.9",
"ip": "203.0.113.7",
"ct": "0f3HMyTUeHEy8vuVEHmB...",
"ipsLink": "https://www.twitch.tv/149e9513-.../2d206a39-.../ips.js?x-kpsdk-v=j-1.2.308&x-kpsdk-im=AALP1ZtNVs0v...",
"script": "<the full ips.js body you fetched>"
}'Response — attach headers to your /tl POST and send the base64-decoded payload as the body:
{
"headers": {
"x-kpsdk-ct": "0f3HMyTUeHEy8vuVEHmB...",
"x-kpsdk-im": "AALP1ZtNVs0vAz3hL1IT...",
"x-kpsdk-v": "j-1.2.308",
"x-kpsdk-dt": "13cz64jzaez034dy49aw52cz218y79wb2zdjez8asy11jbx9jiwc1h0",
"Content-Type": "application/octet-stream"
},
"payload": "<base64 — decode to bytes before POSTing to /tl>"
}Full transformer flow (what your client does around us)
The transformer does exactly one step: ips.js → /tl body. The fetches on either side are yours, through your own proxy and TLS client, so the whole session shares one IP.
- Fetch the challenge. GET the protected page (or
/fp). The response carries a preflightx-kpsdk-ctheader, aKPSDK:MC:<im>marker in the body (that<im>is yourx-kpsdk-im), and theips.jssrc. - Fetch ips.js from that
src, appending?x-kpsdk-v=…&x-kpsdk-im=<im>. Keep both the URL and the body. - Call
/api/kasada/payloadwithscript(the ips.js body),ipsLink(that URL), yourct,userAgent,ip,acceptLanguage. - POST
/tlyourself with the returnedheadersand the base64-decodedpayloadas the body. The server responds with the clearedx-kpsdk-ct, anx-kpsdk-st, andx-kpsdk-cr: true. - For every protected request, mint a fresh
x-kpsdk-cdvia/api/kasada/cd(below) and send it alongside the clearedx-kpsdk-ct.
Per-request proof-of-work — POST /api/kasada/cd (FREE)
Kasada requires a fresh x-kpsdk-cd on every request to a protected endpoint — a single cd replayed across requests is a stale proof and starts failing. So this endpoint is a sub-millisecond local computation and is billed at 0 credits: scraping 10k pages calls it 10k times and costs nothing extra.
- ›
st— thex-kpsdk-stfrom your/tlresponse (required) - ›
ct— the clearedx-kpsdk-ctfrom your/tlresponse (required) - ›
domain— the protected host (required) - ›
rst— optional but recommended. Your local clock in ms when the/tlresponse landed. Supplying it makesdthe real round-trip; omit it and we model a plausible one. Do not derive it from wall-clock age —stis issued once,cdis per-request.
curl -X POST https://api.vexsolver.com/api/kasada/cd \
-H "X-API-Key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"st": 1777215098000,
"rst": 1777215098310,
"ct": "0dhS2BUe4yb8whd4APoV...",
"domain": "www.twitch.tv"
}'
# response
{ "payload": "{\"workTime\":...,\"id\":\"...\",\"answers\":[15,14],\"d\":310,\"st\":1777215098000}" }Send payload as the x-kpsdk-cd header on your protected request, next to x-kpsdk-ct.
Headers we generate (all reverse-engineered, pure Go)
- ›
x-kpsdk-ct— 175-char cleared token, from the VM cipher output - ›
x-kpsdk-im— integrity marker binding the payload to your handshake - ›
x-kpsdk-v— version (j-1.2.308default) - ›
x-kpsdk-dt— device timing digest: 14 duration fields differenced from a monotone timeline, base32-encoded in random order. Fully reversed — produced, not templated. Returned inside the payloadheaders. - ›
x-kpsdk-cd— per-request proof-of-work (geometric-difficulty nonce search). Minted by/api/kasada/cd.
x-kpsdk-cr, x-kpsdk-st, x-kpsdk-h and friends are responseheaders the server issues back — you read them, you do not generate them.
Replaying on every protected request
- › Send all the token headers on GET and POST:
x-kpsdk-ct, a freshx-kpsdk-cd(per request, via/api/kasada/cd),x-kpsdk-v, andx-kpsdk-h. Browsing GETs are lenient; API/POST endpoints are strict, so a POST that drops any of these is rejected. - › Kasada rotates
x-kpsdk-cton nearly every response — always carry forward the newest one and re-derive thecdfrom it. Re-using the original token from a few requests ago is a stale token and fails. - › Set the cookies from
cookie_mapunder the site's own cookie names. Many deployments do not useKP_UIDz— e.g. footlocker.co.uk stores the token inak_bmsc_fl_uk/ak_bmsc_fl_uk-ssn. Send whatever namescookie_mapreturns; never hardcodeKP_UIDz. - › For XHR/API calls, mirror a real fetch:
content-type: application/json,origin,referer, andsec-fetch-site/mode/dest: same-origin / cors / empty.
JSESSIONID), a CSRF token, a cart/session id, and a complete request body (product SKU, size, quantity…). Those come from the site's normal flow (browse → create cart → add item), not from any bot token — a valid Kasada token with an incomplete cart request still fails, at the application, not the bot wall.Full solve — POST /api/solve
Prefer to hand us the whole job? /api/solve does every hop — fetch, VM run, /tl POST, cr=true verify — and returns the token bundle in cookie_map. Pass a page url (we auto-discover the challenge) or a direct pjs_url to skip discovery.
curl -X POST https://api.vexsolver.com/api/solve \
-H "X-API-Key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"vendor": "kasada",
"url": "https://www.twitch.tv",
"pjs_url": "https://k.twitchcdn.net/149e9513-.../2d206a39-.../p.js"
}'Response:
{
"success": true,
"vendor": "kasada",
"source": "go_kasada",
"target": "https://www.twitch.tv",
"elapsed_ms": 1820,
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
"cookie_map": {
"x-kpsdk-ct": "0dlCkpczkzzZ9bVkjiBiUOZwDDfFm3Cs...",
"x-kpsdk-cd": "{\"workTime\":...,\"answers\":[15,14],\"d\":310,\"st\":...}",
"x-kpsdk-v": "j-1.2.308",
"x-kpsdk-dt": "13cz64jzaez034dy49aw52cz218y79wb2zdjez8asy11jbx9jiwc1h0",
"x-kpsdk-im": "AALTLVJfWjWK797ZyO5QFiScq8Sds...",
"KP_UIDz": "0dlCkpczkzzZ9bVkjiBiUOZwDDfFm3Cs...",
"KP_UIDz-ssn": "0dlCkpczkzzZ9bVkjiBiUOZwDDfFm3Cs..."
}
}Replay: send your protected request with the same User-Agent, the KP_UIDz cookies, and the x-kpsdk-ct + a fresh x-kpsdk-cd (mint it per-request via /api/kasada/cd).
vendor: "kasada" + pjs_url (full solve), or send us the ips.js via /api/kasada/payload, and we route them immediately.Typical performance
- › Transformer (
/api/kasada/payload): ~1–2 s in-process VM run - › Per-request cd (
/api/kasada/cd): sub-millisecond, free - › Full solve, warm (
/api/solve): ~1–2 s via the native fast-replay path - › Full solve, cold rotation: falls back to the full goja VM (~30 s). Still succeeds (
cr=true); subsequent solves of that rotation are warm. - › Verified with
x-kpsdk-cr: trueon every tested deployment
Pricing
/api/kasada/payload and /api/solve: 1 credit per success — failures are refunded automatically. /api/kasada/cd is free, so the correct per-request-PoW usage pattern is never punished.
