Skip to content
voidcaptcha

Task type

Hunt Captcha solver API

Hunt is the anti-bot behind the hd-api and captcha-api endpoints on a number of sportsbook and betting sites. It works in two layers, and a protected request can need either or both. The first is a fingerprint: every sensitive request has to carry an X-HD header, minted by an obfuscated script the site serves. The second is a challenge, shown when a request still looks automated — the site answers with error 113 and a meta.token, and expects an x-captcha-token back. This task does both. Send apiGetLib on its own and you get an X-HD; add the site’s meta.token as data and you get the captcha solution. Both are tied to the IP address that produced them, which is why a proxy is required here rather than optional.

Tip

Send task.type as HuntCaptcha and the solution arrives in solution.token, with solution.data beside it.

What it looks like#

Hunt chooses the challenge per site and per session — you do not. These are raw captures of the two image challenges exactly as the solver receives them. The checkbox and the silent check have no image at all and are handled the same way. Whichever one is served, the call is identical.

Hunt Captcha: Score a goal
swipe_goalScore a goalA slider moves the ball along a curve. It has to stop on the ring.
Hunt Captcha: Click in order
happy_puzzleClick in orderFind the four shapes in the picture and click them in the order shown above it.
Hunt Captcha: Click in order, with decoys
happy_puzzleClick in order, with decoysThe same challenge with overlapping shapes and letters scattered over it.

Before you integrate

  1. A full solve is two calls. Send apiGetLib on its own to get an X-HD and put it in the x-hd header of your request to the site. If the site still answers with error 113 it returns meta.token beside it: send that back to us as data and the result is the captcha token, which goes in x-captcha-token when you repeat the request. Each call is billed as one solve. Only this meta.token flow is supported — the widgetUrl scenario is not, and a task carrying one is refused rather than guessed at.
  2. Both tokens only work from the address that produced them. Give us the same sticky proxy you send the site’s own requests through, and reuse the userAgent we return. A rotating exit, or a different User-Agent on your side, is the usual reason a good token is refused.

A site that will not solve is worth telling us about — coverage is per target as much as per type. The quickest route is Telegram (@VoidCaptchaSupport), where someone usually answers within minutes. You can also open a ticket from your dashboard or email [email protected]. Send the URL and the site key either way.

task.type
HuntCaptcha
Median
7.8s
over 299 solves, 30d
Success
97.3%
Price / 1k
$1.50
$0.0015 each
Proxy
Required

Solve request#

Solving Hunt Captcha is a single synchronous call. You post one task object and the response carries the finished solution — no task id to store, nothing to poll for.

POSThttps://api.voidcaptcha.com/v1/getResult

The connection is held open for the whole solve, which for this type runs a median of 7.8s. Set a client timeout that covers it — the default socket timeout in most HTTP libraries is shorter than the work. If holding a connection that long does not suit your worker fleet, the same task goes to /v1/createTask and you collect it from /v1/checkTask instead.

When to use it#

  • Registration and login flows on sportsbook sites
  • Requesting an SMS or email code behind an X-HD check
  • Keeping a session alive when a request is escalated to a challenge

Task object structure#

These fields go inside task. The envelope around it — clientKey and the optional softId — is the same for every type and is described in the API reference.

PropertyTypeRequiredDescription
typestringRequiredLiteral "HuntCaptcha". Matching is case-insensitive.
urlstringRequiredThe page Hunt runs on — usually the registration or login page. websiteURL is accepted as another name for it.e.g. https://example.com/en/registration
apiGetLibstringRequiredFull URL of the site’s Hunt api.js, including its 40-character app hash. Search the Network tab in DevTools for hd-api to find it.e.g. https://example.com/hd-api/external/apps/0123456789abcdef0123456789abcdef01234567/api.js
datastringOptionalThe meta.token the site returns with its captcha error (code 113). Send it to get a captcha solution; leave it out to get an X-HD. It changes on every response, so use it immediately.e.g. SITE_META_TOKEN
proxystringRequiredRequired, and it must be the exit you use for the site itself — the tokens are bound to it. Accepts host:port, host:port:user:pass, or a full http:// or socks5:// URL. Use a sticky session.e.g. proxy.example.com:9090:user:pass
user_agentstringOptionalPin the User-Agent used for the solve. Omit it and a coherent one is chosen for you and returned in the response — match whatever you send downstream.e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 …

Example payload#

The whole body, assembled from the table above — copy it formatted to read, or on one line to paste straight into a terminal or a REST client. The values are placeholders: swap the key for your own and the URL and site key for the page you are solving.

POSThttps://api.voidcaptcha.com/v1/getResult
{
  "clientKey": "void_a1b2c3d4e5f60718293a4b5c6d7e8f90",
  "task": {
    "type": "HuntCaptcha",
    "url": "https://example.com/en/registration",
    "apiGetLib": "https://example.com/hd-api/external/apps/0123456789abcdef0123456789abcdef01234567/api.js",
    "proxy": "proxy.example.com:9090:user:pass"
  }
}

Example request#

The smallest thing that gets a token back, in your language. Python and Node.js use the official client (pip install voidcaptcha, npm install voidcaptcha); every other language makes the HTTP call its standard library already has. The complete version, with the key read from the environment and the error envelope checked, is in Sample code at the bottom of this page.

Language choice is remembered across the whole site, so switching here carries to every other sample in the docs.

# pip install voidcaptcha
from voidcaptcha import VoidCaptcha

client = VoidCaptcha("void_a1b2c3d4e5f60718293a4b5c6d7e8f90")

result = client.hunt(
    url="https://example.com/en/registration",
    api_get_lib="https://example.com/hd-api/external/apps/0123456789abcdef0123456789abcdef01234567/api.js",
    proxy="proxy.example.com:9090:user:pass",
)

print(result.value)

Example response#

A successful solve returns errorId: 0 and a solution object. The result is in solution.token; alongside it is the userAgent the solve ran under.

solution carries those and nothing else — the gateway copies the result field, anything extra this type returns, and userAgent across, and drops the rest of whatever the solver sent. Timing arrives at the top level as elapsedMs, present only when the duration is known, beside cost and your remaining balance. The figures below are illustrative: nothing here is a published median.

This type also returns solution.data. The same token again, at data.token — the shape CapMonster returns it in, so code written against their response reads ours unchanged. Use whichever you prefer.

JSON
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "03AGdBq25V6…",
    "data": { "token": "6IyDCCpDdSK…YGs1Wug/z/kLNSpjewI=" },
    "userAgent": "Mozilla/5.0 …"
  },
  "cost": "$0.0015",
  "balance": "$411.24",
  "elapsedMs": 4820
}

Send that userAgent on your downstream request as well — for the cookie-based types the result is bound to it and will be rejected under a different one.

Errors for this type#

The codes Hunt Captcha can return, on top of the shared authentication and billing set. Branch on errorCode, not on the HTTP status.

CodeHTTPMeaningRetry
ERROR_KEY_MISSING401No clientKey was supplied.Do not retry
ERROR_KEY_INVALID401The key does not exist or has been revoked.Do not retry
ERROR_KEY_SUSPENDED403The account attached to this key is suspended.Do not retry
ERROR_TYPE_NOT_ENABLED403This account is not enabled for the requested task type.Do not retry
ERROR_BAD_REQUEST400The body was not valid JSON, or task was missing.Do not retry
ERROR_PROXY_FORMAT400The proxy string could not be parsed.Do not retry
ERROR_CAPTCHA_UNSOLVABLE200The challenge was served but could not be completed.Retry
ERROR_TIMEOUT200The solve exceeded the maximum time for this type.Retry with backoff
ERROR_INSUFFICIENT_BALANCE402Your balance will not cover this solve.Do not retry
ERROR_THREAD_LIMIT429You have more solves in flight than your key permits.Retry with backoff
ERROR_RATE_LIMITED429Too many requests in a short window.Retry with backoff

Every code, with the fix for each, is on the error reference. A failed solve is never charged.

Sample code#

A complete file: key from the environment, task built, error envelope checked, result used. It calls the endpoint directly rather than through an SDK, so it works as a starting point in any language.

import os
import sys

import requests

API = "https://api.voidcaptcha.com/v1/getResult"

payload = {
    "clientKey": os.environ["VOIDCAPTCHA_KEY"],
    "task": {
        "type": "HuntCaptcha",
        "url": "https://example.com/en/registration",
        "apiGetLib": "https://example.com/hd-api/external/apps/0123456789abcdef0123456789abcdef01234567/api.js",
        "proxy": "proxy.example.com:9090:user:pass"
    },
}

# The endpoint is synchronous: it holds the connection open for the whole
# solve, so the read timeout has to cover it, not just the handshake.
res = requests.post(API, json=payload, timeout=180).json()

if res["errorId"] != 0:
    sys.exit(f"{res['errorCode']}: {res['errorDescription']}")

solution = res["solution"]

# Carry the User-Agent downstream — the result was earned under it.
print(solution["token"])
print(solution["userAgent"])

Last updated on 2 August 2026