API — Captcha solving
A separate listener speaking the anti-captcha.com protocol: point third-party software at it and solve images, access cookies and reCAPTCHA v2 through your own proxies.
What this is
BlankTrail Proxy can accept captcha-solving tasks over the anti-captcha.com protocol. It is a separate listener on its own port: software that already speaks that protocol only needs to be pointed at your address instead of the solving service's.
The listener is separate rather than a set of routes on the dashboard port, for two reasons. Official protocol clients hit the host root, so they take the root paths entirely. And the captcha API may well be needed on the LAN where the dashboard must not be visible to anyone.
Turning it on
Three fields in the captcha_api section of the configuration file. The switch and the address can also be changed in the dashboard: Settings → the Captcha API card.
captcha_api:
enabled: true
addr: ":8892"
allow_lan: false
max_concurrent: 10
task_ttl: "5m"
port_idle_timeout: "10m"
| Field | What it does |
|---|---|
| enabled | Whether to start the listener. Off by default. |
| addr | Listener address. An empty host means loopback until allow_lan is on. |
| allow_lan | Whether to accept requests from other machines. A setting of its own, separate from the dashboard's; on in the Docker image. |
| max_concurrent | Cap on concurrent tasks. Zero means no cap at all. |
| task_ttl | How long a finished task's answer is kept. |
| port_idle_timeout | How long an idle port opened for a task's proxy is kept before closing. |
In a container
Everything but the switch is already set up in the image: port 8892 is declared, the compose files shipped with it publish the port on 127.0.0.1, and the image configuration lets the listener bind beyond the loopback. All that is left is turning it on — with a variable or right in the dashboard. The override is one-way: variables turn things on and set values, but cannot switch off what the configuration has enabled.
docker run -d \
-e BT_CAPTCHA_API_ENABLED=1 \
-p 127.0.0.1:8892:8892 \
... blanktrail-proxy
Key and access
clientKey is your dashboard's API key — the very same one. There is no separate key for the captcha API: a second secret with its own storage and rotation is not worth introducing for a single surface.
- The key travels in the request BODY, as the protocol requires, not in a header.
- Key guessing is rate-limited: after a run of failures an address is refused regardless of whether the next key is correct.
- Requests from other machines are refused until allow_lan is on — including getQueueStats and test.
Supported task types
| Type | What it does |
|---|---|
| ImageToTextTask | Reads the text on an image with a local model. |
| AntiGateTask | Passes the site's protection and returns the access cookies. |
| RecaptchaV2Task | Solves reCAPTCHA v2 from the page address and site key, through your proxy. |
| RecaptchaV2TaskProxyless | The same, but without your proxy — a direct exit. |
Other protocol types answer ERROR_TASK_NOT_SUPPORTED. That is a normal answer, not a failure: the client sees it right at task creation and can go to another service without waiting.
How it works
- Create a task with createTask and get a numeric taskId.
- Poll getTaskResult while the answer says processing.
- Receive ready and the solution object — its contents depend on the task type.
Reading an image
The image is passed as base64. The answer carries the recognised text in the text field.
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "ImageToTextTask",
"body": "iVBORw0KGgoAAAANSUhEUg..."
}
}
Access cookies
AntiGateTask passes the site's protection and returns the cookies. Alongside them the answer carries the address of the port through which those cookies must be presented.
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "AntiGateTask",
"websiteURL": "https://example.com/",
"proxyType": "http",
"proxyAddress": "203.0.113.7",
"proxyPort": 8080,
"proxyLogin": "user",
"proxyPassword": "pass"
}
}
reCAPTCHA v2
The task needs the page address and the site's public key. The variant without your proxy is called RecaptchaV2TaskProxyless and requires no proxy fields.
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "RecaptchaV2Task",
"websiteURL": "https://example.com/login",
"websiteKey": "6Lc_aCMTAAAAA...",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
"proxyType": "http",
"proxyAddress": "203.0.113.7",
"proxyPort": 8080
}
}
What happens to the userAgent you send
The userAgent you send does not go on the wire. It SELECTS the nearest profile by browser family, major version and operating system, and what goes on the wire is that profile's user-agent — together with the TLS and HTTP/2 fingerprints that match it.
Methods
/createTaskclientKey requiredCreates a task and returns a numeric taskId.
{
"errorId": 0,
"taskId": 12
}/getTaskResultclientKey requiredReturns the task's state, and the solution object once it is ready.
{
"clientKey": "YOUR_API_KEY",
"taskId": 12
}{
"errorId": 0,
"status": "ready",
"solution": {
"gRecaptchaResponse": "03AGdBq26...",
"userAgent": "Mozilla/5.0 ..."
}
}/getBalanceclientKey requiredReturns the balance. The product has no billing, so the value is constant; zero means the licence is inactive.
/getQueueStatsno key requiredLoad: how many tasks are running and how busy the solver pool is.
/reportIncorrectImageCaptchaclientKey requiredAccepted for compatibility: the product cannot learn from reports.
/reportIncorrectRecaptchaclientKey requiredThe same for reCAPTCHA.
/reportCorrectRecaptchaclientKey requiredThe same, for confirming a correct solution.
/testno key requiredReturns the parsed request body. Useful when a third-party client sends the wrong thing.
Error codes
The codes and their names are the protocol's: client libraries compare the errorCode string itself. Below are the ones this service returns.
| errorId | errorCode | When |
|---|---|---|
| 1 | ERROR_KEY_DOES_NOT_EXIST | The key is wrong, or the address is temporarily blocked for guessing. |
| 2 | ERROR_NO_SLOT_AVAILABLE | No free solvers right now, or the max_concurrent cap is reached. |
| 10 | ERROR_ZERO_BALANCE | The licence is inactive: renew it, tasks are not accepted. |
| 11 | ERROR_IP_NOT_ALLOWED | The request came from another machine while allow_lan is off. |
| 12 | ERROR_CAPTCHA_UNSOLVABLE | Solving failed. You may retry, but the profile stays the same until the port closes on idle; if the failure repeats, check the page address and the site key. |
| 16 | ERROR_NO_SUCH_CAPCHA_ID | No task with that taskId: it finished and was dropped once task_ttl elapsed, or it belongs to another key. |
| 23 | ERROR_TASK_NOT_SUPPORTED | The task type is not supported, or the required model is not installed. |
| 25 | ERROR_PROXY_CONNECT_REFUSED | Your proxy refused the connection. Fix the proxy; retrying the task is pointless. |
| 26 | ERROR_PROXY_CONNECT_TIMEOUT | Your proxy could not be reached within the allotted time. |
| 27 | ERROR_PROXY_READ_TIMEOUT | Your proxy accepted the connection and went silent. |
| 49 | ERROR_PROXY_NOT_AUTHORISED | Your proxy rejected the login or the password. |
Limits
- Tasks live in memory and do not survive a restart: afterwards the old taskId answers ERROR_NO_SUCH_CAPCHA_ID.
- A task that does not finish within its budget is declared failed and frees its place in the cap.
- There is no callback: the callbackUrl field is accepted and ignored, the result is fetched by polling.
- Tasks for the same site through the same proxy run one after another — a property of the anti-replay design, not a configuration cap.