BILSOLVER API

A private captcha-solving API for Cloudflare Turnstile and Aliyun captcha. If you have used 2Captcha or CapMonster, the flow is identical — only the base URL changes.

Introduction

Every request is JSON over HTTPS. The base URL is:

https://bilsolver.com

You solve a captcha in two calls: createTask submits the job and returns a taskId; getTaskResult polls that id until the token is ready. You are charged only for solves that land — failed tasks are refunded automatically.

Authentication

Every request carries your clientKey in the JSON body. There are no headers to sign.

Get a key: sign in with email or Google at bilsolver.com/login. Your key (bil_u_…) and a starting balance appear on your account page instantly.

The solve flow

# 1 — create a task
curl -X POST https://bilsolver.com/createTask \
  -H "Content-Type: application/json" \
  -d '{
    "clientKey": "YOUR_API_KEY",
    "task": {
      "type": "TurnstileTaskProxyless",
      "websiteURL": "https://example.com",
      "websiteKey": "0xAAA..."
    }
  }'
# → { "errorId": 0, "taskId": 84123901 }

# 2 — poll for the result
curl -X POST https://bilsolver.com/getTaskResult \
  -H "Content-Type: application/json" \
  -d '{ "clientKey": "YOUR_API_KEY", "taskId": 84123901 }'
# → { "errorId": 0, "status": "ready", "solution": { "token": "0.AB..." } }
import requests, time

BASE = "https://bilsolver.com"
KEY  = "YOUR_API_KEY"

r = requests.post(BASE + "/createTask", json={
    "clientKey": KEY,
    "task": {
        "type": "TurnstileTaskProxyless",
        "websiteURL": "https://example.com",
        "websiteKey": "0xAAA...",
    },
})
task_id = r.json()["taskId"]

while True:
    time.sleep(3)
    res = requests.post(BASE + "/getTaskResult", json={
        "clientKey": KEY, "taskId": task_id,
    }).json()
    if res["status"] == "ready":
        print(res["solution"]["token"])
        break
const BASE = "https://bilsolver.com";
const KEY  = "YOUR_API_KEY";

const post = (path, body) =>
  fetch(BASE + path, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  }).then(r => r.json());

const { taskId } = await post("/createTask", {
  clientKey: KEY,
  task: { type: "TurnstileTaskProxyless", websiteURL: "https://example.com", websiteKey: "0xAAA..." },
});

let res;
do {
  await new Promise(r => setTimeout(r, 3000));
  res = await post("/getTaskResult", { clientKey: KEY, taskId });
} while (res.status === "processing");

console.log(res.solution.token);

createTask

POST/createTask

Submits a captcha job. Returns a taskId immediately; solving happens on the cluster in the background.

FieldTypeDescription
clientKeyrequiredstringYour API key.
taskrequiredobjectThe task object — see task types. Its type field selects the captcha.
callbackUrloptionalstringAn https URL — the result is POSTed here when ready. See callbacks.

Response — { "errorId": 0, "taskId": <number> }. On error, errorId: 1 with an errorCode and errorDescription.

getTaskResult

POST/getTaskResult

Polls a task. Poll every 2–3 seconds. A typical solve takes 1–5 seconds.

FieldTypeDescription
clientKeyrequiredstringYour API key.
taskIdrequirednumberThe id returned by createTask.

While solving: { "errorId": 0, "status": "processing" }

When ready: { "errorId": 0, "status": "ready", "solution": { "token": "…" } }

getBalance

POST/getBalance

Returns your remaining balance in USD.

curl -X POST https://bilsolver.com/getBalance \
  -d '{ "clientKey": "YOUR_API_KEY" }'
# → { "errorId": 0, "balance": 9.87 }

health & stats

GET/health
GET/stats

/health returns service status. /stats returns live cluster metrics — solved count, success rate, workers online and uptime. Both are public and unauthenticated.

Cloudflare Turnstile

Type TurnstileTask (with proxy) or TurnstileTaskProxyless. Price $0.002 / solve.

FieldTypeDescription
typerequiredstringTurnstileTask or TurnstileTaskProxyless.
websiteURLrequiredstringThe page URL where the widget appears.
websiteKeyrequiredstringThe Turnstile sitekey (0x…).
actionoptionalstringThe widget action, if set.
cDataoptionalstringThe widget cData, if set.
proxyURLproxy onlystringSee proxy format.

Solution: { "token": "…", "userAgent": "…" } — resubmit the token under the returned userAgent.

Aliyun Captcha V2

Type AliyunV2Task / AliyunV2TaskProxyless. Price $0.003 / solve.

FieldTypeDescription
typerequiredstringAliyunV2Task or AliyunV2TaskProxyless.
websiteURLrequiredstringThe page URL hosting the captcha.
websiteKeyrequiredstringThe Aliyun sceneId.
prefixrequiredstringThe Aliyun prefix for the scene.
proxyURLproxy onlystringSee proxy format.

Aliyun Captcha V3

Type AliyunV3Task / AliyunV3TaskProxyless. Price $0.004 / solve. Same fields as V2 (websiteURL, websiteKey=sceneId, prefix).

Proxy format

For the non-proxyless task types, pass proxyURL as a full URL:

http://user:pass@host:port
http://host:port
socks5://user:pass@host:port

Proxyless task types run through the cluster's own egress — no proxy needed.

Callbacks (webhooks)

Add callbackUrl to createTask and skip polling. When the task finishes, BILSOLVER POSTs the result to your URL:

# ready
{ "taskId": 84123901, "status": "ready", "errorId": 0, "solution": { "token": "…" } }
# failed (refunded)
{ "taskId": 84123901, "status": "failed", "errorId": 1, "errorCode": "ERROR_CAPTCHA_UNSOLVABLE" }

Callbacks are retried up to 3 times (0s, 2s, 5s) on non-2xx responses.

Error codes

CodeMeaning
ERROR_KEY_DOES_NOT_EXISTThe clientKey is not recognised.
ERROR_ZERO_BALANCEAccount balance is zero — top up to continue.
ERROR_NO_SUCH_TASKTask not found or expired (tasks live ~15 min).
ERROR_WRONG_TASK_TYPEUnknown task type, or not allowed for this key.
ERROR_WRONG_WEBSITEURLMissing or invalid websiteURL.
ERROR_WRONG_WEBSITEKEYMissing sitekey / sceneId.
ERROR_WRONG_PREFIXMissing prefix (Aliyun).
ERROR_NO_SLOT_AVAILABLECluster busy — retry in a few seconds.
ERROR_CAPTCHA_UNSOLVABLEThe captcha could not be solved after retries — refunded.
Ready? Get your API key and send your first task. Watch the cluster live on the dashboard.