# Migrate From 2Captcha: Cloudflare Turnstile in.php and createTask

> Move Cloudflare Turnstile solving from 2Captcha to ZeroCaptcha: keep in.php and res.php or createTask, change the host and key, and check what differs.

- Source: https://zerocaptcha.io/guides/migrate-from-2captcha
- Published: 2026-09-30
- Updated: 2026-10-01
- Author: ZeroCaptcha Engineering

If your code solves Cloudflare Turnstile through 2Captcha, you can move it to ZeroCaptcha without
rewriting it. ZeroCaptcha speaks both of the request formats 2Captcha documents for Turnstile:
the classic `in.php` and `res.php`, and the `createTask` JSON format. In most cases the change is
the base URL and the key. This guide shows both paths, the differences to check, and how to roll
the change out safely.

ZeroCaptcha is not affiliated with 2Captcha. Facts about 2Captcha below come from its public pages,
checked 1 October 2026.

## Path 1: in.php and res.php

2Captcha's first API creates a task with `in.php` and reads it with `res.php`. ZeroCaptcha serves
both on its API host, for `method=turnstile`:

```sh
# Before: https://2captcha.com/in.php?key=OLD_KEY&method=turnstile&...
# action and data are the widget's data-action and data-cdata (or turnstile.render()'s action and
# cData options): keep sending them, and leave out any the widget does not set. The
# Idempotency-Key makes a retried submit return the same task.
curl -H "Idempotency-Key: $(uuidgen)" \
  "$ZEROCAPTCHA_API/in.php?key=$ZEROCAPTCHA_KEY&method=turnstile&sitekey=0x4AAAAAAAB1cD2eF3gH4iJ5&pageurl=https%3A%2F%2Fshop.example.com%2Flogin&action=login&data=session-7f3a9c2e&json=1"
```

```json
{ "status": 1, "request": "10000004821" }
```

Then poll `res.php` every second or two:

```sh
curl "$ZEROCAPTCHA_API/res.php?key=$ZEROCAPTCHA_KEY&action=get&id=10000004821&json=1"
```

The replies are the ones 2Captcha clients already handle: `CAPCHA_NOT_READY` while the task runs,
`OK|<token>` (or `{"status": 1, "request": "<token>"}` with `json=1`) when it is solved, and an
error code such as `ERROR_CAPTCHA_UNSOLVABLE` when it is not. `action=get2` adds the price, and
`action=getbalance` returns your balance. Every parameter is in
[the 2Captcha format](https://zerocaptcha.io/docs/2captcha).

## Path 2: createTask

2Captcha also documents a JSON format for Turnstile, with `createTask` at
`https://api.2captcha.com/createTask` and the task types `TurnstileTaskProxyless` and
`TurnstileTask` ([2Captcha's Cloudflare Turnstile docs](https://2captcha.com/api-docs/cloudflare-turnstile)).
ZeroCaptcha accepts the same types and the same fields, so a 2Captcha client's body works
unchanged, with the widget's action in `action` and its cData in `data`, as 2Captcha documents
them. Written fresh, send the two in the task's `metadata`, as most createTask clients do:

```json
{
  "clientKey": "zc_live_…",
  "task": {
    "type": "TurnstileTaskProxyless",
    "websiteURL": "https://shop.example.com/login",
    "websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5",
    "metadata": { "action": "login", "cdata": "session-7f3a9c2e" }
  }
}
```

Either way, copy them from the widget's `data-action` and `data-cdata` (or the `action` and
`cData` options of `turnstile.render()`), and leave out any it does not set: many sites check both
when they verify the token. Post the body to `/createTask` on the ZeroCaptcha API host, with an
`Idempotency-Key` header so a retried create returns the same task, then poll `/getTaskResult`
with the `taskId`. `userAgent` and `pagedata` are
accepted and ignored. [createTask and getTaskResult explained](https://zerocaptcha.io/guides/createtask-gettaskresult-explained)
walks through the replies.

## What to check before you switch

- **Task IDs.** `in.php` answers numbers, as 2Captcha does, such as `10000004821`, so a client
  that parses them as numbers works unchanged. The JSON `createTask` format answers UUIDs, such as
  `0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b`: code that uses it must keep the ID as text.
- **Cloudflare only.** `method=turnstile` in `in.php`, and the Cloudflare Turnstile and challenge
  page task types in the JSON format. Other methods are answered with `ERROR_BAD_PARAMETERS` (or
  `ERROR_TASK_NOT_SUPPORTED` in the JSON format), at no charge.
- **Proxies are HTTP or HTTPS.** SOCKS proxies are not supported yet and are refused with
  `ERROR_PROXY_FORMAT`. See [Solve Cloudflare Turnstile with a proxy](https://zerocaptcha.io/guides/solve-cloudflare-turnstile-with-a-proxy).
- **Several tasks at once:** `action=get` with `ids` reads up to 100, as 2Captcha documents it.
- **Reports are recorded, not refunded.** `reportbad` and `reportgood` answer `OK_REPORT_RECORDED`
  and our staff read them, but every charge is final.
- **Cloudflare challenge pages** (the `pagedata` case) are not served in the 2Captcha format, whose replies have no place for the user agent a clearance needs. Use the createTask format or REST for them.
  See the [Cloudflare WAF and 5-second challenge solver](https://zerocaptcha.io/cloudflare-challenge-solver) page.

## pingback works without registration

On ZeroCaptcha, any public http or https URL works as `pingback`, with nothing to register first,
and each call carries a `ZeroCaptcha-Signature` header you can check with
HMAC-SHA256. The call is a form post of `id=<task id>&code=<token>`, or the error code. See
[Captcha solver callbacks](https://zerocaptcha.io/guides/captcha-solver-callbacks).

## Prices

2Captcha lists Cloudflare Turnstile at $1.45 per 1,000 on its
[pricing page](https://2captcha.com/pricing) (checked 1 October 2026). ZeroCaptcha's current
price per 1,000 solved tasks is on its [pricing page](https://zerocaptcha.io/pricing). On ZeroCaptcha you are charged
only when a token is ready; a task that fails or expires costs nothing.

## Rolling it out

1. [Sign up](https://zerocaptcha.io/docs/quickstart) with an email and a password, create a key and add funds.
2. Make the base URL and key configuration, not code, if they are not already.
3. Point a share of your traffic, such as one worker, at ZeroCaptcha.
4. Compare solve times and success on your pages, and on the [status page](https://zerocaptcha.io/status).
5. Move the rest once you are satisfied.

For a side-by-side view of the two services, see the
[2Captcha alternative](https://zerocaptcha.io/compare/2captcha-alternative) comparison. The
[Cloudflare Turnstile solver](https://zerocaptcha.io/cloudflare-turnstile-solver) page has complete samples in every supported language.

## Questions

### Do I have to rewrite my 2Captcha client?

Usually not. A client for 2Captcha's in.php and res.php, or for its createTask format, needs its base URL and key changed. in.php answers numeric task IDs, as 2Captcha does; a createTask client must keep its UUID task IDs as text.

### Does pingback need to be registered first?

No. Any public http or https URL works as pingback, and each call is signed so you can check it came from ZeroCaptcha.

### Can I move my 2Captcha balance?

No. The two services are separate. ZeroCaptcha is prepaid in US dollars; you add funds in crypto from $10.
