Skip to content
easycaptcha.to
Documentation

hCaptcha solver API for Python

Create hCaptcha token tasks in Python with the easycaptcha SDK. Choose sync or async clients, poll results, and handle failures without duplicate submissions.

Choose the result your application needs

A token task returns a token for your integration. A recognition task returns answers to an existing image challenge. These are different operations: sending a sitekey to the token API does not return tile coordinates, and classifying an image does not return a verification token.

Use hcaptcha_token when your application needs a token. Use hcaptcha_recognition when you already have the challenge object and need recognition results. The API reference documents both schemas. Enterprise token tasks use a separate type and require account approval.

Install the Python SDK

python -m pip install easycaptcha-sdk

The standard-library backend needs no extra HTTP package. For native async HTTP, install easycaptcha-sdk[httpx] and import AsyncHttpxClient from easycaptcha.backends.httpx. Other backends include requests and curl_cffi; importing the core package does not require all of them.

Keep your customer API key in EASYCAPTCHA_API_KEY. Set HCAPTCHA_SITEKEY and HCAPTCHA_PAGE_URL to the values for your integration. A sitekey is public configuration, while the easycaptcha API key authorizes paid work.

Submit once and poll the same job

import os
import time
from easycaptcha.backends.urllib import UrllibClient

with UrllibClient(os.environ["EASYCAPTCHA_API_KEY"]) as client:
    job = client.create_job({
        "type": "hcaptcha_token",
        "sitekey": os.environ["HCAPTCHA_SITEKEY"],
        "url": os.environ["HCAPTCHA_PAGE_URL"],
        "hold": 30,
    })
    job_id = job["task_id"]
    print(f"Task ID: {job_id}")
    deadline = time.monotonic() + 180
    while job["status"] in ("queued", "running"):
        if time.monotonic() >= deadline:
            raise TimeoutError(f"Retrieve {job_id} again later")
        time.sleep(1)
        job = client.get_job(job_id)
    if job["status"] == "failed":
        raise RuntimeError(job["error"]["detail"])
    token = job["result"]["token"]
    # Pass token to your application's completion handler.

hold lets creation wait for up to 30 seconds. It does not guarantee completion. The SDK’s get_job performs one lookup; this example supplies the polling loop. The local deadline bounds how long the script waits, rather than canceling server-side work.

Handle uncertainty explicitly

Save the task ID as soon as creation returns. A network timeout during the initial POST can leave the outcome unknown. Automatically submitting again may create another paid task. If you have an ID, retrieve it; if you do not, report the ambiguous submission instead of silently retrying it.

HTTP failures raise SDK errors. A job can also have a failed status in a successful HTTP response, so always check the job status before reading result. Send feedback with client.send_feedback(job_id, success) after observing the integration’s actual outcome, rather than treating a returned token as proof of success.

For async applications, keep the same lifecycle but await create_job, get_job, and feedback, and use asyncio.sleep between lookups. Avoid blocking an event loop with the synchronous client. See token API examples for plain HTTP alternatives and pricing for billing units.

Get started with easycaptcha

Build your next integration with easycaptcha.

Create an account, get your API key, and start submitting hCaptcha jobs. Use typed Python and JavaScript SDKs or integrate directly over HTTP.

Create an accountExplore the API

Prepaid credit. Check pricing before submitting paid tasks.