Official Python client for the NoneCap hCaptcha solving API.
Project description
nonecap
Official Python client for the NoneCap hCaptcha solving API.
Submit a captcha, get back a token. The client handles the polling, the timeouts, and the error cases so you don't write the request loop yourself. Sync and async, fully typed.
Install
pip install nonecap
Python 3.9+. The only dependency is httpx.
Quick start
Grab an API key from dashboard.nonecap.com, then:
from nonecap import NoneCap
nc = NoneCap(api_key="nc_live_...")
solve = nc.solve(
type="hcaptcha",
sitekey="10000000-ffff-ffff-ffff-000000000001",
url="https://example.com/login",
)
print(solve.token) # the hCaptcha token, ready to submit
solve() submits the captcha and waits until it's done, using the API's long-poll so you aren't hammering it with requests. It returns the solved solve, or raises if the solve fails or your timeout runs out.
Async
Same surface, awaited. Use it as an async context manager so the connection pool gets cleaned up:
import asyncio
from nonecap import AsyncNoneCap
async def main() -> None:
async with AsyncNoneCap(api_key="nc_live_...") as nc:
solve = await nc.solve(type="hcaptcha", sitekey="...", url="https://example.com")
print(solve.token)
asyncio.run(main())
Handling failures
Every error this library raises extends NoneCapError, so you can catch the whole family or pick out the one you care about.
from nonecap import (
NoneCap,
SolveFailedError,
InsufficientCreditsError,
RateLimitError,
)
try:
solve = nc.solve(type="hcaptcha", sitekey=sitekey, url=url)
except SolveFailedError as err:
print("Could not solve it:", err.solve.error.code if err.solve.error else "?")
except InsufficientCreditsError:
print("Out of credits. Top up at dashboard.nonecap.com")
except RateLimitError:
print("Too many solves in flight, back off and retry")
The subclasses are AuthenticationError (401), PermissionDeniedError (403), InsufficientCreditsError (402), ValidationError (422/400, with a param naming the bad field), NotFoundError (404), ConflictError (409), RateLimitError (429), APIError (5xx), APIConnectionError and APITimeoutError (the request never landed), and SolveTimeoutError (your solve() budget ran out). SolveFailedError carries the full solve so you can read the underlying error code and the timings.
Enterprise captchas
For hcaptcha_enterprise, rqdata is required. The @overload signatures enforce that in mypy and pyright, so leaving it out fails your type check, and a runtime check backs it up before any network call:
solve = nc.solve(
type="hcaptcha_enterprise",
sitekey=sitekey,
url=url,
rqdata="...", # required for enterprise
)
Proxies
Pass a proxy as a dict or a URL string. The solve runs through it, and the bytes are metered back on the solve.
nc.solve(
type="hcaptcha",
sitekey=sitekey,
url=url,
proxy={"scheme": "http", "host": "1.2.3.4", "port": 8080, "username": "u", "password": "p"},
# or: proxy="http://u:p@1.2.3.4:8080"
)
Lower-level API
solve() is the convenient path. When you want control over submission and polling, the resource methods map one to one to the REST API:
# Submit without waiting: returns immediately with a pending solve
pending = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url)
# Submit and hold the connection up to 30s for it to finish
maybe_done = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url, wait=30)
# Poll one solve, long-polling up to 30s
solve = nc.solves.retrieve(pending.id, wait=30)
# Cancel a pending or in-flight solve
nc.solves.cancel(pending.id)
# List a page of solves
page = nc.solves.list(limit=50, status="solved")
# Or iterate every solve, newest first
for s in nc.solves.list_all():
print(s.id, s.status)
# Your account and credit balance
me = nc.me()
print(me.credits_balance)
On AsyncNoneCap the same methods are coroutines, and list_all() is an async iterator (async for s in nc.solves.list_all()).
Configuration
NoneCap(
api_key="nc_live_...", # required
base_url="https://api.nonecap.com", # override if you need to
timeout=100.0, # per HTTP request, seconds
http_client=my_httpx_client, # inject your own httpx.Client
)
solve() takes its own timeout (seconds, default 180) for the overall wait.
Typing
The package ships a py.typed marker and full inline annotations. Solves come back as frozen dataclasses with the exact field names the API uses (solve.token, solve.credits_charged, solve.queue_ms), so what you read in the API reference is what you get in code.
License
MIT, see LICENSE.
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 nonecap-0.1.0.tar.gz.
File metadata
- Download URL: nonecap-0.1.0.tar.gz
- Upload date:
- Size: 14.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
410a3eab7ab2aa29187003c21e1f54a25e90ec18a060e22653cd05d5e626c45c
|
|
| MD5 |
490a54fc2e4f23c30986d3fff17840e9
|
|
| BLAKE2b-256 |
b0001f5e94a0c6e2fbd713465bd7bb7a142053c51a8ac71b64c8f98bfa3ace99
|
Provenance
The following attestation bundles were made for nonecap-0.1.0.tar.gz:
Publisher:
ci.yml on nonecap/nonecap-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nonecap-0.1.0.tar.gz -
Subject digest:
410a3eab7ab2aa29187003c21e1f54a25e90ec18a060e22653cd05d5e626c45c - Sigstore transparency entry: 1789585958
- Sigstore integration time:
-
Permalink:
nonecap/nonecap-py@9a7919fa64d1c82b7f6feeb7430d935adcddaa27 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nonecap
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9a7919fa64d1c82b7f6feeb7430d935adcddaa27 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nonecap-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nonecap-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7aa72f54845f0b096ad04d5567e85b2116640e4440f4c1270ffb88d525e5419a
|
|
| MD5 |
4d1806ac244c2d5f92234a49f7f8045f
|
|
| BLAKE2b-256 |
b05f494dc51ac6db8e8f3370cf5fb218c3cf8c8922bdd74cad15dbb0ed0b67c4
|
Provenance
The following attestation bundles were made for nonecap-0.1.0-py3-none-any.whl:
Publisher:
ci.yml on nonecap/nonecap-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nonecap-0.1.0-py3-none-any.whl -
Subject digest:
7aa72f54845f0b096ad04d5567e85b2116640e4440f4c1270ffb88d525e5419a - Sigstore transparency entry: 1789586085
- Sigstore integration time:
-
Permalink:
nonecap/nonecap-py@9a7919fa64d1c82b7f6feeb7430d935adcddaa27 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nonecap
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9a7919fa64d1c82b7f6feeb7430d935adcddaa27 -
Trigger Event:
push
-
Statement type: