# SDKs

> The official ZeroCaptcha clients for JavaScript, Python and Go. Solve Cloudflare Turnstile and WAF challenge pages, read your balance and check callbacks.

Source: https://zerocaptcha.io/docs/sdks

Our clients for JavaScript and TypeScript, Python and Go do the same things: create a Cloudflare
Turnstile task or a Cloudflare [challenge page](https://zerocaptcha.io/docs/challenges)'s task, wait for its result, read
your balance, and check a [callback](https://zerocaptcha.io/docs/callbacks)'s signature. None has dependencies beyond its language's standard library, and each is MIT-licensed.

| Language | Package | Needs | Page |
| --- | --- | --- | --- |
| JavaScript, TypeScript | `@zerocaptcha/sdk` on npm (coming) | Node.js 20+, Deno, Bun or a browser | [Node.js](https://zerocaptcha.io/docs/sdks/node) |
| Python | `zerocaptcha` on PyPI (coming) | Python 3.9+ | [Python](https://zerocaptcha.io/docs/sdks/python) |
| Go | `github.com/zerocaptcha/zerocaptcha-go` (coming) | Go 1.22+ | [Go](https://zerocaptcha.io/docs/sdks/go) |

Each one sends an `Idempotency-Key` with every task it creates, so when it retries a request we
asked it to slow down on (429), could not serve for a moment (502, 503, 504), or whose answer never
arrived whole, it never creates a second task. A wait for a result never runs past the time you
give it. A task that fails or expires is an error with its code, such as
`ERROR_CAPTCHA_UNSOLVABLE`, and nothing is charged for it.

Give each client your API key and the API's address, from your environment, and each task the
widget's site key, and its action and cData when it sets them (see
[action and cData](https://zerocaptcha.io/docs/action-and-cdata)):

**Node**

```ts
import { ZeroCaptcha } from "@zerocaptcha/sdk";

const client = new ZeroCaptcha({
  apiKey: process.env.ZEROCAPTCHA_KEY!,
  baseUrl: process.env.ZEROCAPTCHA_API!,
});

const token = await client.solve({
  websiteURL: "https://shop.example.com/login", // the page with the widget
  websiteKey: "0x4AAAAAAAB1cD2eF3gH4iJ5", // its data-sitekey
  // The widget's data-action and data-cdata, or the action and cData options of
  // turnstile.render(). Leave out any the widget does not set.
  action: "login",
  cdata: "session-7f3a9c2e",
  // proxy: "http://user:pass@proxy.example.net:8080", // to solve through your own proxy
  // callbackUrl: "https://hooks.example.com/zerocaptcha", // to be called when it ends
});
const { available } = await client.getBalance();
```

**Python**

```python
import os

from zerocaptcha import ZeroCaptcha

client = ZeroCaptcha(api_key=os.environ["ZEROCAPTCHA_KEY"], base_url=os.environ["ZEROCAPTCHA_API"])

token = client.solve(
    website_url="https://shop.example.com/login",  # the page with the widget
    website_key="0x4AAAAAAAB1cD2eF3gH4iJ5",  # its data-sitekey
    # The widget's data-action and data-cdata, or the action and cData options of
    # turnstile.render(). Leave out any the widget does not set.
    action="login",
    cdata="session-7f3a9c2e",
    # proxy="http://user:pass@proxy.example.net:8080",  # to solve through your own proxy
    # callback_url="https://hooks.example.com/zerocaptcha",  # to be called when it ends
)
available = client.get_balance()["available"]
```

**Go**

```go
client, err := zerocaptcha.NewClient(os.Getenv("ZEROCAPTCHA_KEY"), os.Getenv("ZEROCAPTCHA_API"))
if err != nil {
	log.Fatal(err)
}
token, err := client.Solve(ctx, zerocaptcha.NewTask{
	WebsiteURL: "https://shop.example.com/login", // the page with the widget
	WebsiteKey: "0x4AAAAAAAB1cD2eF3gH4iJ5",       // its data-sitekey
	// The widget's data-action and data-cdata, or the action and cData options of
	// turnstile.render(). Leave out any the widget does not set.
	Action: "login",
	CData:  "session-7f3a9c2e",
	// Proxy:       "http://user:pass@proxy.example.net:8080", // to solve through your own proxy
	// CallbackURL: "https://hooks.example.com/zerocaptcha",   // to be called when it ends
})
```

For a challenge page, `solveChallenge` (`solve_challenge` in Python, `SolveChallenge` in Go) takes
the page and your proxy, and returns the `cf_clearance` cookie with the user agent to send it with.
Each language's page shows it.

The clients are not in those registries yet. Until they are, call the API over plain HTTP, as the
[quickstart](https://zerocaptcha.io/docs/quickstart) does in Python, Node, Go and curl.
