Official Python SDK for the Thronic Solver hCaptcha solving API.
Project description
thronic-solver
Official Python SDK for the Thronic Solver hCaptcha solving API.
Sub-second solves, transparent pay-per-solve pricing, typed responses, sync and async clients, automatic retries, and a CLI.
pip install thronic-solver
Quickstart
from thronic_solver import Thronic
client = Thronic(api_key="tsk_live_...")
token = client.solve(
url="https://example.com",
sitekey="a1b2c3",
type="hcaptcha", # required: hcaptcha | hcaptcha_enterprise
proxy="user:pass@host:port", # required
)
print(token)
solve() blocks until the challenge is solved and returns a Solution.
str(solution) is the token, so print(token) prints it directly — or use
token.token, token.cost, token.elapsed, token.balance.
Set the key via the environment instead of in code:
export THRONIC_API_KEY=tsk_live_...
client = Thronic() # picks up THRONIC_API_KEY
Async
pip install "thronic-solver[async]"
import asyncio
from thronic_solver import AsyncThronic
async def main():
async with AsyncThronic() as client:
token = await client.solve(url="https://example.com", sitekey="a1b2c3",
type="hcaptcha", proxy="user:pass@host:port")
print(token)
asyncio.run(main())
Solve many concurrently:
results = await client.solve_many([
{"url": "https://a.com", "sitekey": "k1", "type": "hcaptcha", "proxy": "u:p@h:1"},
{"url": "https://b.com", "sitekey": "k2", "type": "hcaptcha", "proxy": "u:p@h:2"},
])
for r in results:
print(r if not isinstance(r, Exception) else f"failed: {r}")
Fire-and-poll (non-blocking)
task = client.create_task(url="https://example.com", sitekey="a1b2c3",
type="hcaptcha", proxy="user:pass@host:port")
print(task.task_id)
result = client.get_result(task.task_id)
if result.is_success:
print(result.token)
elif result.is_pending:
print("still solving…")
Batch solves with the sync client:
for outcome in client.solve_many([
{"url": u, "sitekey": k, "type": "hcaptcha", "proxy": p} for u, k, p in targets
]):
if isinstance(outcome, Exception):
print("failed:", outcome)
else:
print("token:", outcome.token)
Account
bal = client.balance()
print(bal.balance, bal.currency, bal.remaining_solves)
acc = client.account()
print(acc.username, acc.email)
for row in client.history(limit=10):
print(row.task_id, row.status, row.cost, row.solve_ms)
s = client.stats()
print(s.success_rate, s.avg_solve_ms)
client.validate() # -> True / False
Options
client = Thronic(
api_key="tsk_live_...",
base_url="https://solver.thronic.cc", # or http://localhost:5002
timeout=30, # per-request timeout (seconds)
max_retries=3, # retries on 429/5xx/network errors
backoff_factor=0.5, # exponential backoff with jitter
)
Required fields
Every solve needs four things:
| Field | Why |
|---|---|
url |
The page hosting the captcha |
sitekey |
The hCaptcha sitekey |
type |
hcaptcha or hcaptcha_enterprise. No default — the two are priced differently, so guessing would mis-bill you |
proxy |
Solving from the server's own IP gets it scored and blocked, degrading everyone's success rate |
Accepted proxy formats — host:port, user:pass@host:port, or with a scheme
(http, https, socks4, socks5, socks5h). A host without a port is rejected.
Both are validated client-side, so a mistake raises ValidationError locally
instead of costing a round trip.
Discord runs hCaptcha Enterprise and additionally requires rqdata.
Enterprise challenges, proxies and custom user agents:
token = client.solve(
url="https://example.com",
sitekey="a1b2c3",
type="hcaptcha_enterprise",
rqdata="...",
proxy="user:pass@host:port",
user_agent="Mozilla/5.0 ...",
timeout=180,
poll_interval=3,
)
Error handling
Every error inherits from ThronicError:
from thronic_solver import (
Thronic, ThronicError, InsufficientBalanceError,
RateLimitError, SolveFailedError, SolveTimeoutError,
)
try:
token = client.solve(url=url, sitekey=key, type="hcaptcha", proxy=proxy)
except InsufficientBalanceError as e:
print(f"Top up! balance={e.balance} cost={e.cost}")
except RateLimitError as e:
print(f"Slow down, retry in {e.retry_after}s")
except SolveFailedError as e:
print(f"Engine could not solve task {e.task_id}")
except SolveTimeoutError:
print("Took too long")
except ThronicError as e:
print(f"API error: {e} (http={e.status_code}, code={e.code})")
| Exception | HTTP | Meaning |
|---|---|---|
ValidationError |
400 | Missing/invalid url, sitekey, type, or proxy |
AuthenticationError |
401 | Missing or invalid API key |
InsufficientBalanceError |
402 | Balance too low — top up |
PermissionDeniedError |
403 | Key disabled or account inactive |
RateLimitError |
429 | Rate limit exceeded (retry_after) |
ServiceUnavailableError |
503 | Engine/API temporarily down |
NetworkError |
– | Connection/DNS/timeout before reaching the API |
APIError |
5xx | Unexpected server response |
SolveFailedError |
– | Engine finished but produced no token |
SolveTimeoutError |
– | No result within your timeout |
Transient failures (429, 500, 502, 503, 504, network errors) are retried
automatically with exponential backoff + jitter, honouring Retry-After.
CLI
export THRONIC_API_KEY=tsk_live_...
thronic balance
thronic account
thronic solve --url https://example.com --sitekey a1b2c3 \n --type hcaptcha --proxy user:pass@host:port
thronic history --limit 10
thronic stats
thronic validate
# machine-readable
thronic --json balance
Requirements
- Python 3.8+
requests(installed automatically);httpxonly for the async client
Links
- Website: https://solver.thronic.cc
- API docs: https://solver.thronic.cc/docs
- Source: https://github.com/imlittledoo/thronic-solver
- Issues: https://github.com/imlittledoo/thronic-solver/issues
- Contact: hello@thronic.cc
License
MIT © Thronic
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 thronic_solver-1.1.0.tar.gz.
File metadata
- Download URL: thronic_solver-1.1.0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58f41d6f5ecfe8d4a1b1a3e09bfde5c0b9523697d1751849aa20cc1d7bed3431
|
|
| MD5 |
b5405f2b58675a6c0ba02be68307993a
|
|
| BLAKE2b-256 |
b69f500ab6706eedeed2c273b732053bc1064b2dbba26dbc9d9ddde5209e2dbb
|
Provenance
The following attestation bundles were made for thronic_solver-1.1.0.tar.gz:
Publisher:
publish.yml on imlittledoo/thronic-solver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thronic_solver-1.1.0.tar.gz -
Subject digest:
58f41d6f5ecfe8d4a1b1a3e09bfde5c0b9523697d1751849aa20cc1d7bed3431 - Sigstore transparency entry: 2207608058
- Sigstore integration time:
-
Permalink:
imlittledoo/thronic-solver@dbc0e1a9347fd60593a0fc0e76cb49279d550620 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/imlittledoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dbc0e1a9347fd60593a0fc0e76cb49279d550620 -
Trigger Event:
release
-
Statement type:
File details
Details for the file thronic_solver-1.1.0-py3-none-any.whl.
File metadata
- Download URL: thronic_solver-1.1.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
775b444e7bdc84cf10bf8eef0ba707ca7f52f78d6abba63ca22ab34ed9153fa4
|
|
| MD5 |
b8e9d8f3b688145ce2ec5bfe731a1404
|
|
| BLAKE2b-256 |
3dc851a4283b986fd6272b0fdc27eb0d730887bc39fd49ae3cdb3cc5666c2498
|
Provenance
The following attestation bundles were made for thronic_solver-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on imlittledoo/thronic-solver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thronic_solver-1.1.0-py3-none-any.whl -
Subject digest:
775b444e7bdc84cf10bf8eef0ba707ca7f52f78d6abba63ca22ab34ed9153fa4 - Sigstore transparency entry: 2207608079
- Sigstore integration time:
-
Permalink:
imlittledoo/thronic-solver@dbc0e1a9347fd60593a0fc0e76cb49279d550620 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/imlittledoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dbc0e1a9347fd60593a0fc0e76cb49279d550620 -
Trigger Event:
release
-
Statement type: