NSLSolver

Quickstart

From zero to a solved captcha in under a minute. Authenticate, check your balance, send a solve request, and use the result.

Grab your API key

API keys are provisioned from the dashboard or by an admin. A key encodes:

  • A balance (or unlimited flag)
  • A list of allowed captcha types
  • A maximum captchas-per-minute (CPM) ceiling
  • An optional IP allowlist

Treat the key like a password. Don't ship it in client-side bundles or commit it to source control.

The key is sent in the X-API-Key header on every request. There is no query-parameter fallback — passing the key in the URL will return 401.

Confirm you're set up

Hit GET /balance to verify the key works and read the limits it carries:

curl https://api.nslsolver.com/balance \
  -H "X-API-Key: $NSL_API_KEY"

A healthy response looks like this:

{
  "success": true,
  "balance": 14.50,
  "unlimited": false,
  "allowed_types": ["turnstile", "challenge", "kasada", "akamai"],
  "max_cpm": 600,
  "current_cpm": 0,
  "cpm_limit": 600
}

The fields that matter for sizing your workers:

  • max_cpm — your absolute ceiling, in captchas per minute.
  • current_cpm — how many you've already used in the rolling window.
  • cpm_limit — same as max_cpm, included for symmetry.

Send your first solve

Pick the captcha type you're up against. The request shape changes per type — see the solve reference for the full schema.

turnstile.py
import requests

r = requests.post(
    "https://api.nslsolver.com/solve",
    headers={"X-API-Key": "YOUR_KEY"},
    json={
        "type": "turnstile",
        "site_key": "0x4AAAAAAAB...",
        "url": "https://example.com",
    },
    timeout=120,
)
data = r.json()
print(data["token"])

Needed fields: type, site_key, url. Everything else is optional — see the Turnstile page for the full list.

challenge.py
import requests

r = requests.post(
    "https://api.nslsolver.com/solve",
    headers={"X-API-Key": "YOUR_KEY"},
    json={
        "type": "challenge",
        "url": "https://example.com/protected",
        "proxy": "http://user:[email protected]:8080",
    },
    timeout=120,
)
data = r.json()
print(data["cookies"]["cf_clearance"])

A proxy is required for Challenge — the solver uses it as the egress so the resulting cf_clearance is valid for your traffic.

kasada.py
import requests

r = requests.post(
    "https://api.nslsolver.com/solve",
    headers={"X-API-Key": "YOUR_KEY"},
    json={
        "type": "kasada",
        "url": "https://passport.twitch.tv",
        "user_agent": "Mozilla/5.0 ... Chrome/145.0.0.0 Safari/537.36",
        "ua_version": 145,
        "kasada_config": {
            "p_js_path": "/149e9513-.../2d206a39-.../p.js",
            "fp_host": "passport.twitch.tv",
            "tl_host": "gql.twitch.tv"
        }
    },
    timeout=180,
)
print(r.json()["headers"])

Kasada needs the p.js path and the FP/TL hosts you can find in DevTools. The response contains the x-kpsdk-* headers to forward on your next request.

Use the result

Each captcha type returns a slightly different payload. Replay it back at the protected site exactly as you would if a real browser had solved it.

{
  "success": true,
  "type": "turnstile",
  "token": "0.AkBr7...",
  "cost": 0.0008
}

Submit token in the form field the site expects (commonly cf-turnstile-response).

{
  "success": true,
  "type": "challenge",
  "cookies": { "cf_clearance": "abc123..." },
  "user_agent": "Mozilla/5.0 ...",
  "cost": 0.001
}

Send the cookie back on subsequent requests from the same proxy IP and using the returned user_agent. The clearance is bound to both.

{
  "success": true,
  "type": "kasada",
  "headers": {
    "x-kpsdk-ct": "...",
    "x-kpsdk-cd": "...",
    "x-kpsdk-v": "j-1.2.xxx",
    "x-kpsdk-h": "..."
  },
  "cost": 0.0015
}

Forward the x-kpsdk-* headers on your next request to the protected origin, keeping the same User-Agent.

The cost field tells you what was deducted for this call — useful for instrumentation.

Common pitfalls

  • Client timeouts that are too short. Most solves finish in seconds, but the server allows up to ~120 seconds for Turnstile/Challenge and ~180 seconds for Kasada. Use 120s (180s for Kasada) as your client timeout.
  • Reusing a cf_clearance from a different IP. Cloudflare binds the cookie to the egress IP from the proxy you used during the solve. Use the same proxy when replaying.
  • Calling /balance in a hot loop. That endpoint is per-IP rate limited (30/min). Check it on startup, not per request.

Next up

On this page