Python client for the Solvex FunCaptcha solving API.
Project description
solvex-sdk
Python client for the Solvex FunCaptcha solving API.
Install
pip install solvex-sdk
# or, from this repo:
pip install .
The distribution is published as solvex-sdk; the import name is solvex.
Requires Python 3.10+. Depends on httpx.
Quickstart
from solvex import SolvexClient, FunCaptchaTask, Proxy
with SolvexClient("sk_live_...") as sx:
result = sx.solve(FunCaptchaTask(
website_url="https://roblox.com",
website_public_key="476068BF-9607-4799-B53D-966BE98E2B81",
proxy=Proxy.from_url("http://user:pass@184.82.39.210:8080"),
))
print(result.token)
print(f"cost=${result.cost_usd} solved in {result.solve_seconds}s")
A proxy is required — Solvex does not run proxyless solves.
Supported site keys
Solvex rejects websitePublicKey values it doesn't know, rather than silently
forwarding bad context (wrong surl, wrong location.href, wrong referrer)
that Arkose would quietly suppress a token for. The currently-registered keys:
| Label | websitePublicKey |
|---|---|
| Roblox Login | 476068BF-9607-4799-B53D-966BE98E2B81 |
| Roblox Signup | A2A14B1D-1AF3-C791-9BBC-EE33CC7A0A6F |
Passing anything else raises UnsupportedSiteKeyError (errorId: 23) — contact
support to add the site you need.
Logged-in sessions (blob + cookies)
When the challenge is tied to a logged-in Roblox session (e.g. authenticated
actions that hand you a dataExchangeBlob), pass the blob in data and the
matching session cookie string in cookies. Without the cookie Arkose will
treat the session as mismatched and suppress the token:
result = sx.solve(FunCaptchaTask(
website_url="https://www.roblox.com",
website_public_key="476068BF-9607-4799-B53D-966BE98E2B81",
proxy=Proxy.from_url("http://user:pass@1.2.3.4:8080"),
data=roblox_data_exchange_blob,
cookies=".ROBLOSECURITY=...; RBXEventTrackerV2=...;",
))
PoW-flagged sessions
When Arkose returns pow=true, the server can solve the PoW challenge and
still hand you a token instead of failing. Opt in with solve_pow=True —
it trades 1–3s (C++ fast path) or 15–30s (Node fallback) of latency for a
higher success rate on flagged sessions. Billed as a normal solve.
task = FunCaptchaTask(..., solve_pow=True)
Async
import asyncio
from solvex import AsyncSolvexClient, FunCaptchaTask, Proxy
async def main():
async with AsyncSolvexClient("sk_live_...") as sx:
result = await sx.solve(FunCaptchaTask(
website_url="https://roblox.com",
website_public_key="476068BF-9607-4799-B53D-966BE98E2B81",
proxy=Proxy.from_url("socks5://184.82.39.210:1080"),
use_http3=True, # None = server default (enabled)
))
print(result.token)
asyncio.run(main())
Low-level
If you want to manage polling yourself:
task_id = sx.create_task(task)
while True:
r = sx.get_task_result(task_id)
if r["status"] == "ready":
print(r["solution"]["token"])
break
Balance
print(f"${sx.get_balance():.4f} remaining")
Errors
Every non-zero errorId raises a typed exception:
| Exception | errorId | Meaning |
|---|---|---|
InvalidKeyError |
1 | clientKey missing / bad / revoked |
UnsupportedTaskError |
2, 22 | task type not enabled |
UnsupportedSiteKeyError |
23 | websitePublicKey not registered — contact support |
InsufficientCreditsError |
10 | account balance too low |
TaskFailedError |
12 | solver couldn't produce a token (credits refunded) |
TaskNotFoundError |
16 | unknown taskId |
RateLimitedError |
31 | per-key or per-user rate limit |
TaskTimeoutError |
40 | task exceeded server timeout / client wait |
Catch SolvexError to catch everything.
from solvex import SolvexClient, TaskFailedError, RateLimitedError
try:
result = sx.solve(task, timeout=90)
except TaskFailedError:
# server already refunded — retry with fresh proxy
...
except RateLimitedError:
time.sleep(5)
Idempotency
Pass idempotency_key= to guard against double-billing on retries. Replays
within 24h return the same taskId without a second charge.
sx.solve(task, idempotency_key=f"user-42-{run_id}")
HTTP/3
Set use_http3=False on the task to force HTTP/2 (useful when debugging
proxies that mangle h3). Default is server-side (h3 enabled).
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file solvex_sdk-0.1.0.tar.gz.
File metadata
- Download URL: solvex_sdk-0.1.0.tar.gz
- Upload date:
- Size: 8.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.12.1.2 readme-renderer/44.0 requests/2.32.5 requests-toolbelt/1.0.0 urllib3/2.6.3 tqdm/4.67.1 importlib-metadata/8.7.0 keyring/25.7.0 rfc3986/1.5.0 colorama/0.4.6 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66836102ce6104f2114b1596ec4c537905249916db9aa76720c8403ce8149f38
|
|
| MD5 |
766af7e33619a51f3314288740c5cc22
|
|
| BLAKE2b-256 |
9084f29328e98815e0ee79ae92f0409d1d25ef6fc325510a4babce73c4b27c7a
|
File details
Details for the file solvex_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: solvex_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.12.1.2 readme-renderer/44.0 requests/2.32.5 requests-toolbelt/1.0.0 urllib3/2.6.3 tqdm/4.67.1 importlib-metadata/8.7.0 keyring/25.7.0 rfc3986/1.5.0 colorama/0.4.6 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98f811d6e199ff7528d6ba5fd3712a2a8bedbce63fcb25f9c3079f56562882af
|
|
| MD5 |
7bd099a794c98822128ff1bb136af1ce
|
|
| BLAKE2b-256 |
2db51217e33020338f92c3a1ee61d34b0efe3ca51a6b62f8abb9f943494ff57c
|