Metadata-Version: 2.4
Name: solvegate
Version: 1.0.0
Summary: Official Python SDK for the SolveGate API (Cloudflare Turnstile + WAF solving).
License: MIT
Project-URL: Homepage, https://solvegate.io
Keywords: solvegate,captcha,turnstile,cloudflare,waf
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# solvegate — Python SDK

Official client for the [SolveGate API](https://solvegate.io) — clear Cloudflare
Turnstile + WAF challenges and get a token back. **Zero dependencies** (stdlib only);
wraps auth, the error envelope, `429` backoff, and async polling.

```bash
pip install solvegate
```

```python
import os
from solvegate import SolveGate

sg = SolveGate(os.environ["SOLVEGATE_KEY"])  # sg_live_… or a free sg_test_… sandbox key

# Synchronous — blocks until solved (or raises on timeout):
res = sg.solve(gate="turnstile", sitekey="0x4AAAAAAAAA_target", url="https://app.example.com")
print(res.token, res.solve_ms)

# Asynchronous — return immediately, then poll:
pending = sg.solve(gate="turnstile", sitekey=sitekey, url=url, async_=True)
solved = sg.wait(pending.id)
if solved.status == "solved":
    use(solved.token)

# Retrieve any solve by id:
s = sg.retrieve("slv_8Kd2aF9")
```

## API

| Method | Description |
|---|---|
| `SolveGate(api_key, base_url=…, timeout=60, max_retries=3)` | construct a client |
| `sg.solve(gate, sitekey, url, action=None, async_=False, proxy=None, idempotency_key=None)` | → `Solve` |
| `sg.retrieve(id)` | → `Solve` (never billed) |
| `sg.wait(id, interval=1.0, timeout=60.0)` | poll an async solve until it leaves `pending` |

`Solve` has `.id .status .gate .token .solve_ms .expires_at .billed`. Errors raise
`SolveGateError` with `.code` / `.status` / `.billed` (e.g. `balance_empty`,
`rate_limited`, `solve_timeout`). Note `async_` (trailing underscore) maps to the
API's `async` field. You're only billed for a successful solve.
