Token API examples
Submit an hCaptcha token task and retrieve its result in Python or JavaScript.
Before you start
Create a paid API key in the dashboard and set the EASYCAPTCHA_API_KEY environment variable. Set HCAPTCHA_SITEKEY and HCAPTCHA_PAGE_URL to the site key and page URL for your integration. Keep your API key on the server; do not put it in browser JavaScript.
Submit POST https://api.easycaptcha.to/v1/task with type: "hcaptcha_token", sitekey, and url. The examples use hold: 30 to wait up to 30 seconds for completion. If the task is still queued or running, they poll GET /v1/task/{task_id}?hold=30 using the same API key.
A completed task has status: "completed" and its token in result.token. A failed task has status: "failed" and an embedded error, even when the lookup itself returns HTTP 200. HTTP errors use Problem Details.
Python
Install the HTTP client with python -m pip install requests. Save the following as token.py and run python token.py.
import os
import time
import requests
BASE_URL = "https://api.easycaptcha.to"
def read_response(response):
body = response.json()
if not response.ok:
raise RuntimeError(
f"HTTP {response.status_code}: {body.get('detail', body)} "
f"(request_id={body.get('request_id', 'unknown')})"
)
return body
with requests.Session() as client:
client.headers["Authorization"] = f"Bearer {os.environ['EASYCAPTCHA_API_KEY']}"
# Submit once. Do not retry this POST after a timeout or connection failure.
task = read_response(client.post(
f"{BASE_URL}/v1/task",
json={
"type": "hcaptcha_token",
"sitekey": os.environ["HCAPTCHA_SITEKEY"],
"url": os.environ["HCAPTCHA_PAGE_URL"],
"hold": 30,
},
timeout=45,
))
task_id = task["task_id"]
print(f"Task ID: {task_id}")
deadline = time.monotonic() + 300
while task["status"] in ("queued", "running"):
if time.monotonic() >= deadline:
raise TimeoutError(f"Still waiting for {task_id}; retrieve this task again")
time.sleep(1)
task = read_response(client.get(
f"{BASE_URL}/v1/task/{task_id}",
params={"hold": 30},
timeout=45,
))
if task["status"] == "failed":
problem = task["error"]
raise RuntimeError(
f"Task {task_id} failed: {problem['detail']} "
f"(request_id={problem['request_id']})"
)
token = task["result"]["token"]
# Pass token to your integration immediately.
print(token)
JavaScript
This example uses Node.js 22 or newer and its built-in fetch. Save it as token.mjs and run node token.mjs.
import { setTimeout as sleep } from "node:timers/promises";
const baseUrl = "https://api.easycaptcha.to";
const authorization = `Bearer ${process.env.EASYCAPTCHA_API_KEY}`;
async function api(path, options = {}) {
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
Authorization: authorization,
...(options.body ? { "Content-Type": "application/json" } : {}),
},
signal: AbortSignal.timeout(45_000),
});
const body = await response.json();
if (!response.ok) {
throw new Error(
`HTTP ${response.status}: ${body.detail ?? body.title} ` +
`(request_id=${body.request_id ?? "unknown"})`,
);
}
return body;
}
// Submit once. Do not retry this POST after a timeout or connection failure.
let task = await api("/v1/task", {
method: "POST",
body: JSON.stringify({
type: "hcaptcha_token",
sitekey: process.env.HCAPTCHA_SITEKEY,
url: process.env.HCAPTCHA_PAGE_URL,
hold: 30,
}),
});
const taskId = task.task_id;
console.log(`Task ID: ${taskId}`);
const deadline = performance.now() + 300_000;
while (task.status === "queued" || task.status === "running") {
if (performance.now() >= deadline) {
throw new Error(`Still waiting for ${taskId}; retrieve this task again`);
}
await sleep(1000);
task = await api(`/v1/task/${encodeURIComponent(taskId)}?hold=30`);
}
if (task.status === "failed") {
throw new Error(
`Task ${taskId} failed: ${task.error.detail} ` +
`(request_id=${task.error.request_id})`,
);
}
const token = task.result.token;
// Pass token to your integration immediately.
console.log(token);
Enterprise tokens
Enterprise token tasks require account whitelisting. Use the sales contact form to request access. Once enabled, use type: "hcaptcha_enterprise_token" and add the integration’s rqdata string to the request. The polling flow and result.token field are the same.
{
"type": "hcaptcha_enterprise_token",
"sitekey": "YOUR_SITEKEY",
"url": "https://your-site.test/login",
"rqdata": "YOUR_RQDATA",
"hold": 30
}
Timeouts and modes
A local timeout does not cancel the task. Save the returned task_id so you can retrieve that task again. If the initial POST times out before returning an ID, its outcome is unknown; automatically resubmitting may create another charged task.
Both examples submit standard tasks. Add the optional burst and fast booleans if you want extra concurrency or higher queue priority. See the API reference for the complete request and response schemas.
Optional worker proxy
You can include a proxy object in a token task request. It contains scheme
(http, https, or socks5), host, port (1–65535), and optional username
and password. The proxy is passed to the token worker for challenge traffic.
"proxy": {
"scheme": "http",
"host": "proxy.example",
"port": 8080,
"username": "proxy-user",
"password": "proxy-password"
}
Developer revenue sharing
Activate the developer program in the dashboard to get your tag. Your software
can send X-Developer-Tag: dev_... or add "developer_tag": "dev_..." to the
JSON task request. Tags apply only to that request and cannot be set on API
keys. Header and body tags must match if both are supplied.
The developer earns 5% of credit spent on attributed paid requests, credited to service balance daily. Refunded requests, free-plan tasks, and the developer’s own requests do not generate revenue. Developer tags provide attribution; requests still require a valid customer API key.
Read the affiliate and developer program guide for activation, daily credits, eligibility, and payout approval.