Skip to content

API

createTask and getTaskResult: The Captcha API Format Explained

How the createTask, getTaskResult and getBalance format works: request bodies, replies, errorId, polling, and ZeroCaptcha's Cloudflare Turnstile tasks.

3 min readPublished Updated

createTask and getTaskResult are the most widely used request format among CAPTCHA-solving services. You create a task with one JSON call, get a task ID back at once, then ask for the result until it is ready. ZeroCaptcha implements this format for Cloudflare Turnstile and Cloudflare challenge pages, so clients written for it work after changing the host and the key. This guide explains each call, the replies, and the conventions that trip people up.

The three calls

All three are POST requests with a JSON body to the API host, and all three carry your key in the body as clientKey:

Call Body Reply
/createTask clientKey, task errorId, taskId
/getTaskResult clientKey, taskId errorId, status, and solution once ready
/getBalance clientKey errorId, balance

Creating a task

Terminal window
# metadata holds 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. The Idempotency-Key makes a retried
# create return the same task.
curl -s "$ZEROCAPTCHA_API/createTask" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"clientKey": "'"$ZEROCAPTCHA_KEY"'",
"task": {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://shop.example.com/login",
"websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5",
"metadata": {"action": "login", "cdata": "session-7f3a9c2e"}
}
}'
{ "errorId": 0, "taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b" }

The task object describes the challenge. For Turnstile:

  • type: TurnstileTaskProxyless, or TurnstileTask to solve through your own proxy. The aliases AntiTurnstileTaskProxyLess and AntiTurnstileTask work too.
  • websiteURL (or websiteUrl) and websiteKey: the page and the widget’s sitekey.
  • action and cdata: when the widget sets them. See Cloudflare Turnstile action and cData.
  • Proxy fields, for TurnstileTask: see Solve Cloudflare Turnstile with a proxy.

Fields the task does not use, such as userAgent, are accepted and ignored, so a client that sends extras still works. The task’s price is held on your balance when it is created.

Polling for the result

Terminal window
curl -s "$ZEROCAPTCHA_API/getTaskResult" \
-H "Content-Type: application/json" \
-d '{"clientKey": "'"$ZEROCAPTCHA_KEY"'", "taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b"}'

While the task runs, the reply is:

{ "errorId": 0, "taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b", "status": "processing" }

When it is solved:

{
"errorId": 0,
"taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b",
"status": "ready",
"solution": { "token": "0.xT4…", "type": "turnstile" },
"cost": "0.000800",
"createTime": 1790762400,
"endTime": 1790762404,
"solveCount": 1,
"expiresAt": "2026-09-30T10:05:04Z"
}

cost is what the task cost in US dollars, as a string with six decimals. expiresAt says when the token stops working: Turnstile tokens are valid for 300 seconds and work once. If the task failed, the reply has errorId 1 and an errorCode such as ERROR_CAPTCHA_UNSOLVABLE, and nothing is charged.

The conventions

  • Every reply is HTTP 200. Success or failure is in errorId: 0 for success, 1 for an error with errorCode and errorDescription. Only failures outside the format, such as a body over the size limit, answer with an HTTP error.
  • Task IDs are strings. ZeroCaptcha’s task IDs are UUIDs. A client that keeps the ID as text passes it back unchanged; one that parses it as a number needs that changed.
  • The body is JSON whatever the Content-Type. Some clients send JSON as text/plain; that works.
  • Poll every one or two seconds. getTaskResult and getBalance share a budget; calling them far faster is answered with ERROR_RATE_LIMIT and a Retry-After header.

Retrying createTask safely

A lost reply to createTask leaves you unsure whether the task exists. Send an Idempotency-Key header with every createTask: the same key and body within 24 hours returns the first task instead of making a second. Idempotency keys for captcha tasks shows the pattern.

Callbacks instead of polling

Add callbackUrl beside task, and ZeroCaptcha posts the getTaskResult reply to that URL when the task ends, signed so you can check it. Polling still works alongside it. See Captcha solver callbacks.

The other two formats

The same tasks, prices and charges are available two other ways:

  • 2Captcha’s in.php and res.php, for clients written for that API: see the 2Captcha format.
  • REST v1, with POST /v1/tasks, a bearer key, an Idempotency-Key header and RFC 9457 problem details: see the Tasks API reference.

The compatible format reference documents every field, and the Cloudflare Turnstile solver page shows a complete program in each supported language.

Questions

Why does getTaskResult answer HTTP 200 even for errors?

That is the format's convention: the HTTP status says the call was received, and errorId says whether it worked. Check both, as the quickstart samples do.

How often should I call getTaskResult?

Every one or two seconds is enough. Polling faster only spends your read budget, and a callback removes polling altogether.

Is the createTask format the only way to use ZeroCaptcha?

No. The same tasks are available through 2Captcha's in.php and res.php, and through a REST API with bearer keys and problem details.

Read next

This guide is part of the Cloudflare Turnstile solver hub. Every task is charged only when a token is ready.

Get an API key