Tasks API
More
Create Turnstile tasks, read their results, and follow them live.
Every operation of the API reference is generated from the contract the API serves, version 0.1.0. Replace YOUR_API_KEY in the samples with your key.
List tasks
GET/v1/tasks
Newest first, with cursor pagination.
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | Status | Only tasks with this status. |
limit | query | integer | Tasks per page, 1 to 100; 50 by default. |
cursor | query | string |
|
idempotencyKey | query | string | Only the task created with this Idempotency-Key, to recover a reply that was lost. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 OK | A page of tasks. | TaskPage (application/json) |
| 429 Too Many Requests | Over a budget for reading ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
rate_limited. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl https://api.zerocaptcha.io/v1/tasks \ -H "Authorization: Bearer YOUR_API_KEY"const response = await fetch("https://api.zerocaptcha.io/v1/tasks", { headers: { Authorization: "Bearer YOUR_API_KEY", },});console.log(response.status, await response.text());import requests
response = requests.get( "https://api.zerocaptcha.io/v1/tasks", headers={"Authorization": "Bearer YOUR_API_KEY"}, timeout=30,)print(response.status_code, response.text)Create a task
POST/v1/tasks
Queues a task and holds its price on your balance; the price is charged only if the task succeeds. Send an Idempotency-Key to retry safely: for 24 hours, the same key and request return the first reply instead of a second task, and the same key with a different request is refused. Creations are bounded by your balance and your account's share of the queue, and by no rate budget unless the service sets one.
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Key | header | string | Your ID for this task, 1 to 255 visible ASCII characters. |
Request body
JSON: CreateTask.
| Field | Type | Description |
|---|
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 Created | The task, queued; or, for a retry with the same | TaskView (application/json) |
| 409 Conflict | A request with this | Problem (application/problem+json) |
| 429 Too Many Requests | The queue share is full ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
idempotency_key_in_use, queue_full, rate_limited. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl -X POST https://api.zerocaptcha.io/v1/tasks \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: order-4521-attempt-1" \ -H "Content-Type: application/json" \ -d '{ "type": "TurnstileTaskProxyless", "websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5", "websiteURL": "https://example.com/login"}'const response = await fetch("https://api.zerocaptcha.io/v1/tasks", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Idempotency-Key": "order-4521-attempt-1", "Content-Type": "application/json", }, body: JSON.stringify({ "type": "TurnstileTaskProxyless", "websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5", "websiteURL": "https://example.com/login" }),});console.log(response.status, await response.text());import requests
response = requests.post( "https://api.zerocaptcha.io/v1/tasks", headers={"Authorization": "Bearer YOUR_API_KEY", "Idempotency-Key": "order-4521-attempt-1"}, json={ "type": "TurnstileTaskProxyless", "websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5", "websiteURL": "https://example.com/login", }, timeout=30,)print(response.status_code, response.text)Live task updates
GET/v1/tasks/events
Server-sent events for the caller's tasks: task carries a task (without its token) each time it changes, reset asks the client to refetch its list because updates were missed. Start from a list's liveCursor. Opening a stream draws on the caller's budget for reads, as a list read does; keeping it open costs nothing more. The stream ends when its key or session no longer allows it, or when its client stops taking events; an account may hold only a few streams open at once.
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
since | query | string | Where to start: |
Last-Event-ID | header | string | The last event's ID, sent by a reconnecting browser. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 OK | An event stream. | text/event-stream |
| 429 Too Many Requests | Over a budget for reading, or as many streams open as the account, or this server, may hold ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
rate_limited. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl -N https://api.zerocaptcha.io/v1/tasks/events \ -H "Authorization: Bearer YOUR_API_KEY"const response = await fetch("https://api.zerocaptcha.io/v1/tasks/events", { headers: { Authorization: "Bearer YOUR_API_KEY", },});// Events arrive as they happen; stop with Ctrl+C.const decoder = new TextDecoder();for await (const chunk of response.body) { process.stdout.write(decoder.decode(chunk, { stream: true }));}import requests
# Events arrive as they happen; stop with Ctrl+C.with requests.get( "https://api.zerocaptcha.io/v1/tasks/events", headers={"Authorization": "Bearer YOUR_API_KEY"}, stream=True, timeout=(10, None),) as response: for line in response.iter_lines(decode_unicode=True): print(line)Get a task
GET/v1/tasks/{id}
The task's status, cost and, while it is valid, its token: for a challenge page, its clearance cookie and the user agent it is bound to. A task that named a callback URL shows it with where its delivery stands and each attempt: when, the HTTP status, and when the next is due.
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string (uuid) | The task's ID. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 OK | The task. | TaskView (application/json) |
| 429 Too Many Requests | Over a budget for reading ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
rate_limited. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b \ -H "Authorization: Bearer YOUR_API_KEY"const response = await fetch("https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b", { headers: { Authorization: "Bearer YOUR_API_KEY", },});console.log(response.status, await response.text());import requests
response = requests.get( "https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b", headers={"Authorization": "Bearer YOUR_API_KEY"}, timeout=30,)print(response.status_code, response.text)Send a task's callback again
POST/v1/tasks/{id}/callback/resend
Calls the task's callback URL again, as soon as the worker gets to it, with eight more attempts if it fails: once the callback was delivered or given up, or after its record was deleted. It is signed and shaped as the first call was, and carries the same ZeroCaptcha-Delivery ID while its record lasts. A key needs the tasks:write scope; a session must be an owner's (role_required), with the CSRF token. A suspended account sends none (account_suspended).
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string (uuid) | The task's ID. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 202 Accepted | Queued: the callback as it stands now. | TaskCallback (application/json) |
| 403 Forbidden | A member's session, not an owner's ( | Problem (application/problem+json) |
| 404 Not Found | No task of this account has this ID, or the task names no callback URL ( | Problem (application/problem+json) |
| 409 Conflict | The task has not ended yet, or its callback is still being delivered ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
role_required, account_suspended, insufficient_scope, not_found, state_conflict. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl -X POST https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/callback/resend \ -H "Authorization: Bearer YOUR_API_KEY"const response = await fetch("https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/callback/resend", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", },});console.log(response.status, await response.text());import requests
response = requests.post( "https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/callback/resend", headers={"Authorization": "Bearer YOUR_API_KEY"}, timeout=30,)print(response.status_code, response.text)Report a task's token
POST/v1/tasks/{id}/report
Says whether the site accepted a solved task's token: bad when it refused it, good when it worked. The report is recorded for our staff, who watch the solvers' quality with it; tasks are final, so it refunds nothing. One report per task, and only on a task that succeeded. Needs the tasks:write scope; with a session, the CSRF token.
Authentication: Your API key, as a bearer token: Authorization: Bearer YOUR_API_KEY.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string (uuid) | The task's ID. |
Request body
JSON: NewTaskReport.
| Field | Type | Description |
|---|---|---|
verdict required | Verdict |
One of: |
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 Created | Recorded. | TaskReport (application/json) |
| 404 Not Found | No task of this account has this ID ( | Problem (application/problem+json) |
| 409 Conflict | The task did not succeed, so there is no token to report on, or it has a report already ( | Problem (application/problem+json) |
| Any other status | An error, as RFC 9457 problem details. | Problem (application/problem+json) |
Error codes
not_found, state_conflict. The errors reference says what each means, whether a retry helps and what it costs.
Sample
curl -X POST https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/report \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "verdict": "bad"}'const response = await fetch("https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/report", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "verdict": "bad" }),});console.log(response.status, await response.text());import requests
response = requests.post( "https://api.zerocaptcha.io/v1/tasks/0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b/report", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={ "verdict": "bad", }, timeout=30,)print(response.status_code, response.text)