Metadata-Version: 2.4
Name: easycaptcha-sdk
Version: 0.1.0
Summary: Easycaptcha API SDK with interchangeable sync and async transports
License-Expression: MIT
Project-URL: Homepage, https://www.easycaptcha.to
Project-URL: Documentation, https://www.easycaptcha.to/docs/api
Project-URL: Support, https://dashboard.easycaptcha.to/tickets
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typing_extensions<5,>=4.6
Provides-Extra: requests
Requires-Dist: requests<3,>=2.31; extra == "requests"
Provides-Extra: httpx
Requires-Dist: httpx<1,>=0.27; extra == "httpx"
Provides-Extra: curl-cffi
Requires-Dist: curl_cffi<1,>=0.11; extra == "curl-cffi"
Provides-Extra: all
Requires-Dist: requests<3,>=2.31; extra == "all"
Requires-Dist: httpx<1,>=0.27; extra == "all"
Requires-Dist: curl_cffi<1,>=0.11; extra == "all"
Dynamic: license-file

# Easycaptcha Python SDK

Solve hCaptcha challenges with Easycaptcha from Python 3.10+. Includes synchronous and asynchronous clients.

## Install

```sh
python -m pip install easycaptcha-sdk
```

Get an API key from the [dashboard](https://dashboard.easycaptcha.to) and set `EASYCAPTCHA_API_KEY` in your environment.

## Solve a captcha

This example creates a token job, waits for it to finish, and prints the token:

```python
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": "your-sitekey",
        "url": "https://example.com",
        "hold": 30,
    })

    while job["status"] in ("queued", "running"):
        time.sleep(1)
        job = client.get_job(job["task_id"])

    if job["status"] == "failed":
        raise RuntimeError(job["error"]["code"])
    print(job["result"]["token"])
```

`hold: 30` lets creation wait up to 30 seconds for a result. If the job is still pending, keep checking with `get_job`. Ending an HTTP request does not cancel the job.

For enterprise tokens, use `"type": "hcaptcha_enterprise_token"` and include `rqdata`. For image recognition, use `"type": "hcaptcha_recognition"` and pass the challenge object as `task`; challenge media must be base64 data URIs. See the [API documentation](https://www.easycaptcha.to/docs/api) for request fields and result formats.

## Async usage

Install the async HTTP dependency:

```sh
python -m pip install 'easycaptcha-sdk[httpx]'
```

```python
import asyncio
import os
from easycaptcha.backends.httpx import AsyncHttpxClient

async def main():
    async with AsyncHttpxClient(os.environ["EASYCAPTCHA_API_KEY"]) as client:
        job = await client.create_job({
            "type": "hcaptcha_token",
            "sitekey": "your-sitekey",
            "url": "https://example.com",
            "hold": 30,
        })
        while job["status"] in ("queued", "running"):
            await asyncio.sleep(1)
            job = await client.get_job(job["task_id"])
        if job["status"] == "failed":
            raise RuntimeError(job["error"]["code"])
        print(job["result"]["token"])

asyncio.run(main())
```

## Balance and feedback

Inside your client context:

```python
balance = client.get_balance()
print(balance["balance_microcents"])

# After checking whether the result worked:
client.send_feedback(job["task_id"], success=True)
```

Async clients use the same methods with `await`. Balance values are integer strings: 100,000,000 microcents = USD 1. Use `int` for exact arithmetic.

## Client options

```python
with UrllibClient(os.environ["EASYCAPTCHA_API_KEY"], timeout=60) as client:
    balance = client.get_balance()
```

`timeout` is in seconds and defaults to 45. You can also set `base_url` or `developer_tag`.

If you already use another HTTP library, choose its client instead:

| Install extra | Module                           | Sync client      | Async client          |
| ------------- | -------------------------------- | ---------------- | --------------------- |
| None          | `easycaptcha.backends.urllib`    | `UrllibClient`   | `AsyncUrllibClient`   |
| `requests`    | `easycaptcha.backends.requests`  | `RequestsClient` | `AsyncRequestsClient` |
| `httpx`       | `easycaptcha.backends.httpx`     | `HttpxClient`    | `AsyncHttpxClient`    |
| `curl-cffi`   | `easycaptcha.backends.curl_cffi` | `CurlCffiClient` | `AsyncCurlCffiClient` |

Install extras with `python -m pip install 'easycaptcha-sdk[requests]'`, for example. The urllib and requests async clients run HTTP in a thread; httpx and curl_cffi support native async requests.

The optional-library clients accept a `session` for custom proxy or TLS settings. Use `with` or `async with` to close client-owned sessions; supplied sessions stay open.

## Handle errors

```python
from easycaptcha import APIError

try:
    with UrllibClient(os.environ["EASYCAPTCHA_API_KEY"]) as client:
        balance = client.get_balance()
except APIError as error:
    print(error.problem.get("code"), error.request_id)
```

HTTP errors raise `APIError`; network failures raise `TransportError`; invalid responses or extension downloads raise `ProtocolError`. A failed job is returned with `status: "failed"` and `error`.

The SDK does not retry requests automatically. A job submission may succeed even if its response is lost, so check its outcome before submitting again.

## Download the browser extension

```python
with UrllibClient() as client:  # No API key needed to download.
    extension = client.download_extension()

configured = extension.configure_settings({
    "apikey": os.environ["EASYCAPTCHA_API_KEY"],
    "enabled": True,
})
configured.save("extension.zip")
```

Downloads select the latest Chromium release and verify its checksum. Pass `version_id="your-extension-version-id"` to select a release, or use `get_extension()` for metadata only.

Extract the ZIP and load it as an unpacked extension. Settings support `apikey`, `enabled`, `burst`, and `fast`; saved popup preferences override these defaults. Keep configured ZIPs private because they contain your API key. See the [extension setup guide](https://www.easycaptcha.to/docs/extension#configure-defaults-in-the-manifest).

## Support

[Open a support ticket](https://dashboard.easycaptcha.to/tickets) with your SDK/runtime version, a minimal example, and the error code or request ID. Remove credentials. Development and release instructions are in [CONTRIBUTING.md](CONTRIBUTING.md).

[MIT license](LICENSE).
