Basics
- Base URL
https://unlock-api.com- API key
- 32 characters, on your account page. Send it as clientKey (JSON) or key (in.php, res.php).
- Format
- JSON methods: POST with a JSON body. in.php and res.php: GET or POST form fields; add json=1 for JSON replies.
- Limits
- 1,200 requests per minute per account, result checks included. Wait about 5 seconds after creating a task, then check every 5 seconds.
- Time limit
- A task not solved within 5 minutes fails with ERROR_CAPTCHA_UNSOLVABLE and its charge returns to the balance.
- Billing
- The task price is taken when the task is created. Failed tasks are refunded automatically.
Quick start
Solve a reCAPTCHA v2 with the JSON methods. Replace YOUR_API_KEY with your key.
import time, requests
API = "https://unlock-api.com"
KEY = "YOUR_API_KEY"
task = requests.post(f"{API}/createTask", json={
"clientKey": KEY,
"task": {
"type": "RecaptchaV2TaskProxyless",
"websiteURL": "https://example.com/login",
"websiteKey": "6LcR_RsTAAAAAFJR_5ZdbQd0SMxL7yIDmSXH1-lo"
}
}).json()
if task["errorId"]:
raise SystemExit(task["errorCode"])
while True:
time.sleep(5)
r = requests.post(f"{API}/getTaskResult", json={"clientKey": KEY, "taskId": task["taskId"]}).json()
if r["errorId"]:
raise SystemExit(r["errorCode"]) # failed tasks are refunded
if r["status"] == "ready":
print(r["solution"]["gRecaptchaResponse"])
breakJSON methods
POST /createTask Create a task
Body: clientKey and a task object. The task type decides the other fields; see Task types. Answer: errorId 0 and taskId, or errorId 1 with errorCode.
POST https://unlock-api.com/createTask
{"clientKey":"YOUR_API_KEY","task":{"type":"TurnstileTaskProxyless","websiteURL":"https://example.com","websiteKey":"0x4AAAAAAAC3DHQFLr1GavRN"}}
{"errorId":0,"taskId":1001}
{"errorId":1,"errorCode":"ERROR_ZERO_BALANCE","errorDescription":"..."}POST /getTaskResult Get the result
Body: clientKey and taskId. While the task runs: status processing. When it is done: status ready with the solution and the cost. A failed task answers errorId 1 with its errorCode.
POST https://unlock-api.com/getTaskResult
{"clientKey":"YOUR_API_KEY","taskId":1001}
{"errorId":0,"status":"processing"}
{"errorId":0,"status":"ready","solution":{"token":"0.zrSnRHO7h0..."},"cost":"0.0012","createTime":1791640000,"endTime":1791640011,"solveCount":1}POST /getBalance Get the balance
Body: clientKey. Answer: balance in US dollars.
{"clientKey":"YOUR_API_KEY"}
{"errorId":0,"balance":42.5}Report a wrong answer
reportIncorrectRecaptcha and reportIncorrectImageCaptcha accept clientKey and taskId and answer success. They are accepted for compatibility with existing libraries; a report does not change the charge.
Form methods (in.php, res.php)
Send a task: in.php
Fields: key, method and the fields of the CAPTCHA type. Answer: OK|ID, or with json=1 {"status":1,"request":"ID"}. Errors come back as their names, such as ERROR_ZERO_BALANCE.
POST https://unlock-api.com/in.php
key=YOUR_API_KEY&method=hcaptcha&sitekey=SITE_KEY&pageurl=https://example.com&json=1
OK|1001
{"status":1,"request":"1001"}Get the answer: res.php
action=get&id=ID returns OK|ANSWER when solved and CAPCHA_NOT_READY while working. action=get2 adds the cost. ids=ID1,ID2 checks up to 100 tasks at once. action=getbalance returns the balance. action=reportbad and reportgood are accepted.
GET https://unlock-api.com/res.php?key=YOUR_API_KEY&action=get&id=1001 CAPCHA_NOT_READY OK|P1_eyJ0eXAiOiJKV1Qi... GET https://unlock-api.com/res.php?key=YOUR_API_KEY&action=getbalance 42.5
More methods
POST /getToken Create and wait: getToken
Same body as createTask. The call waits up to 50 seconds and returns the same reply as getTaskResult. If the task is still running, the reply is status processing with its taskId; keep polling getTaskResult.
POST https://unlock-api.com/getToken
{"clientKey":"YOUR_API_KEY","task":{"type":"TurnstileTaskProxyless","websiteURL":"https://example.com","websiteKey":"0x4AAAA..."}}
{"errorId":0,"taskId":1001,"status":"ready","solution":{"token":"0.zrSnRHO7h0..."},"cost":"0.000725"}Result callbacks
Add callbackUrl to createTask (or pingback to in.php) and the result is sent there when the task finishes: a JSON body like getTaskResult with taskId, or for in.php a form body id=…&code=…. Only public addresses are called, once, with a 5 second timeout; the result also stays available through polling.
{"clientKey":"YOUR_API_KEY","callbackUrl":"https://your.server/captcha-result","task":{...}}
POST https://your.server/captcha-result
{"errorId":0,"taskId":1001,"status":"ready","solution":{...},"cost":"0.0005"}Statistics
getQueueStats returns tasks waiting and being solved now and the average solve time in the last hour. getSpendingStats returns your volume and money per hour for one UTC day (date as unix time). test echoes the body it receives.
POST https://unlock-api.com/getQueueStats {"clientKey":"..."} -> {"errorId":0,"waiting":3,"solving":12,"speed":6.4,"total":15}
POST https://unlock-api.com/getSpendingStats {"clientKey":"...","date":1791590400} -> {"errorId":0,"data":[{"dateFrom":...,"volume":120,"money":0.06},...]}
POST https://unlock-api.com/test {"anything":1} -> {"errorId":0,"received":{"anything":1}}IP allow list
If you set an IP allow list on the account page, requests from other IPs get ERROR_IP_NOT_ALLOWED.
Task types
Every type has a proxyless name and a proxy name (with Proxyless removed). Names are matched in any case and with the spellings other solver APIs use. Proxy tasks also need proxyType (http, socks4, socks5), proxyAddress and proxyPort, or one proxy string like http://user:[email protected]:8080. Optional fields not listed here are passed to the solver as sent.
reCAPTCHA v2
DetailsRecaptchaV2TaskProxylessRecaptchaV2Task
Fields
websiteURL (required)websiteKey (required)
reCAPTCHA v2 Enterprise
DetailsRecaptchaV2EnterpriseTaskProxylessRecaptchaV2EnterpriseTask
Fields
websiteURL (required)websiteKey (required)
reCAPTCHA v3
DetailsRecaptchaV3TaskProxylessRecaptchaV3Task
Fields
websiteURL (required)websiteKey (required)
Cloudflare Turnstile
DetailsTurnstileTaskProxylessTurnstileTask
Fields
websiteURL (required)websiteKey (required)
FunCaptcha (Arkose Labs)
DetailsFunCaptchaTaskProxylessFunCaptchaTask
Fields
websiteURL (required)websitePublicKey (required)
Friendly Captcha
DetailsFriendlyCaptchaTaskProxylessFriendlyCaptchaTask
Fields
websiteURL (required)websiteKey (required)
Lemin Cropped Captcha
DetailsLeminTaskProxylessLeminTask
Fields
websiteURL (required)captchaId (required)divId (required)
DataDome
DetailsDataDomeSliderTask
Fields
websiteURL (required)captchaUrl (required)userAgent (required)
KeyCaptcha
DetailsKeyCaptchaTaskProxylessKeyCaptchaTask
Fields
websiteURL (required)s_s_c_user_id (required)s_s_c_session_id (required)s_s_c_web_server_sign (required)s_s_c_web_server_sign2 (required)
Prosopo Procaptcha
DetailsProsopoTaskProxylessProsopoTask
Fields
websiteURL (required)websiteKey (required)
CaptchaFox
DetailsCaptchaFoxTaskProxylessCaptchaFoxTask
Fields
websiteURL (required)websiteKey (required)
Yandex SmartCaptcha
DetailsYandexSmartCaptchaTaskProxylessYandexSmartCaptchaTask
Fields
websiteURL (required)websiteKey (required)
Binance Captcha
DetailsBinanceTaskProxylessBinanceTask
Fields
websiteURL (required)websiteKey (required)
Errors
The same names in both formats. Requests refused with an error are not charged.
| Error | What it means and what to do |
|---|---|
ERROR_KEY_DOES_NOT_EXIST | The key is wrong. Copy it again from the account page. (in.php and res.php: ERROR_WRONG_USER_KEY) |
ERROR_ZERO_BALANCE | The balance does not cover the task. Add funds; nothing was charged. |
ERROR_NO_SLOT_AVAILABLE | Too many requests right now, so the task could not be accepted. Try again in a few seconds; nothing was charged. |
ERROR_TASK_NOT_SUPPORTED | The task type is unknown or turned off. Check the type name. |
ERROR_BAD_PARAMETERS | A required field is missing or has the wrong format. |
ERROR_PAGEURL | websiteURL or pageurl is missing or is not a full http(s) address. |
ERROR_GOOGLEKEY | googlekey is missing on an in.php reCAPTCHA request. |
ERROR_BAD_PROXY | A proxy task needs proxyAddress and proxyPort. |
ERROR_ZERO_CAPTCHA_FILESIZE | The image is missing or too small. |
ERROR_TOO_BIG_CAPTCHA_FILESIZE | The image is larger than 100 KB. |
ERROR_IMAGE_TYPE_NOT_SUPPORTED | The image is not valid base64. |
ERROR_WRONG_CAPTCHA_ID | There is no task with this id on your account. |
CAPCHA_NOT_READY | in.php and res.php only: the task is still running. Check again in 5 seconds. |
ERROR_CAPTCHA_UNSOLVABLE | The task could not be solved in time. Its charge is back on your balance. |
ERROR_TOO_MANY_REQUESTS | Too many requests. Slow down result checks to every 5 seconds. |
ERROR_IP_NOT_ALLOWED | The request came from an IP that is not on the account's allow list. Add the IP on the account page. |