Skip to content
voidcaptcha

Reference

API reference

One envelope for every challenge type. The only part that varies is the contents of the task object — and whether you wait on the call or collect it later.

Tip

Every challenge type goes through the same envelope. Learn it once and adding a type later is a change to task.type and its fields, nothing more. Post it to /v1/getResult and wait, or to /v1/createTask and pick it up from /v1/checkTask.

Endpoint#

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

The call is synchronous: it holds open until the challenge is solved or fails, then returns the finished result. Nothing to poll, no job id to store — for most integrations this is the whole API.

Note

Because the connection stays open for the length of the solve, set a client timeout that covers the slowest type you use rather than leaving the library default in place. If holding a connection is the wrong shape for your workers, the same task can be handed to the asynchronous pair below instead.

Request#

PropertyTypeRequiredDescription
clientKeystringRequiredYour API key. May also be sent as an Authorization: Bearer header instead of in the body.
taskobjectRequiredThe challenge to solve. Its fields depend on task.type — see the switcher below.
task.typestringRequiredSelects which challenge is being solved and therefore which other fields apply. Case-insensitive.
softIdstringOptionalOptional label echoed back in the response. Useful for correlating your own logs.

The task object#

task.type decides which fields the rest of the object takes. Pick a type below and both the field table and the code sample update — the URL fragment changes too, so you can link someone straight to the variant they need.

reCAPTCHA v3 — Score-based, invisible. Returns a token carrying a passing score for your action.

median —proxy requiredreturns solution.tokenfull page →

PropertyTypeRequiredDescription
typestringRequiredLiteral "ReCaptchaV3". Also accepts: ReCaptchaV3Enterprise, ReCaptchaV3Fast, ReCaptchaV3FastEnterprise, ReCaptchaV3Max, ReCaptchaV3EnterpriseMax. Matching is case-insensitive.
urlstringRequiredThe page the challenge is served on.e.g. https://example.com/login
site_keystringRequiredThe site key from the reCAPTCHA script tag.e.g. 6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696
actionstringOptionalThe action name the page passes to grecaptcha.execute. Must match exactly or verification fails.e.g. login
proxystringRequiredUpstream proxy. Accepts host:port, host:port:user:pass, or a full http:// URL. Use a sticky session — a rotating exit IP mid-solve looks like a hijacked session and will fail.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 …
Request · POST /v1/getResult
# pip install voidcaptcha
from voidcaptcha import VoidCaptcha

client = VoidCaptcha("void_a1b2c3d4e5f60718293a4b5c6d7e8f90")

result = client.recaptcha_v3(
    url="https://example.com/login",
    site_key="6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696",
    action="login",
    proxy="proxy.example.com:9090:user:pass",
)

print(result.value)
Response
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "03AGdBq25V6…",
    "userAgent": "Mozilla/5.0 …"
  },
  "cost": "$0.0008",
  "balance": "$411.24",
  "elapsedMs": 4820
}

Response#

PropertyTypeRequiredDescription
errorIdnumberRequiredZero on success, non-zero on failure. Check this first.
statusstringRequiredready on success, failed otherwise.
solutionobjectOptionalPresent on success. The field carrying the result varies by type.
solution.userAgentstringOptionalThe User-Agent the solve ran under. Send this downstream — cookie-based types are bound to it.
solution.elapsed_timestringOptionalSeconds the solve took, as a string.
coststringOptionalWhat this solve charged. "$0.0000" for test keys and refunded failures.
balancestringOptionalYour remaining balance after the call.
errorCodestringOptionalPresent on failure. A stable string such as ERROR_IP_BLOCKED.
errorDescriptionstringOptionalPresent on failure. A human-readable explanation, safe to log.

Check errorId rather than the HTTP status. A solve that fails for a reason on the target’s side — a blocked IP, an unsolvable challenge, a timeout — answers 200 with a non-zero errorId: it is a well-formed response describing a failure, not a transport error, and nothing is charged for it. A status outside 2xx means the call did not go through at all — a bad key, a malformed request, an empty balance or a thread limit.

The asynchronous pair#

Some fleets cannot hold a connection open for the length of a solve — a serverless function with a short ceiling, or a worker that must not block on one task. Those hand the task over and collect it later. Same envelope, same task object, same error codes; only the shape of the wait changes.

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

The body is exactly what you would have posted to /v1/getResult. The response returns as soon as the task is accepted, not when it is finished.

PropertyTypeRequiredDescription
errorIdnumberRequiredZero once the task is accepted. A rejected task fails here rather than later.
statusstringRequiredprocessing once the task is accepted and running.
taskIdstringOptionalPresent on success. The handle you pass to checkTask.
POSThttps://api.voidcaptcha.com/v1/checkTask
PropertyTypeRequiredDescription
clientKeystringRequiredThe same key the task was created with. A task is only visible to its own key.
taskIdstringRequiredThe handle createTask returned.

/v1/checkTask answers with status: "processing" while the solve is still running, and with the same finished envelope the synchronous call returns — solution, cost, balance — once it is not. Poll no faster than every two seconds; a tighter loop earns ERROR_RATE_LIMITED and does not make the solve arrive sooner.

JSON
// POST /v1/createTask
{ "clientKey": "void_a1b2c3d4e5f60718293a4b5c6d7e8f90", "task": { "type": "ReCaptchaV3", "...": "..." } }
→ { "errorId": 0, "status": "processing", "taskId": "vt_8f3c1d92a4b7" }

// POST /v1/checkTask
{ "clientKey": "void_a1b2c3d4e5f60718293a4b5c6d7e8f90", "taskId": "vt_8f3c1d92a4b7" }
→ { "errorId": 0, "status": "processing" }
→ { "errorId": 0, "status": "ready", "solution": { "token": "03AGdBq25V6…" } }

Warning

A result is not durable. The task id itself is — it is a row in our database, and it stays yours — but the solution it points at is held for ten minutes and then dropped, because we do not retain the tokens we hand back. Once it has aged out, /v1/checkTask answers ERROR_TASK_NOT_FOUND and no amount of further polling will produce it. Collect a result in the session that created it, and treat a lost one as a solve to repeat rather than one to recover.

Note

/v1/checkTask is deliberately not called getTaskResult. Next to a synchronous /v1/getResult, a polling endpoint one word away from it is a name people misread under pressure. A task is billed once, on the solve, no matter how many times you check it. Clients written for Anti-Captcha or CapSolver, which do call it getTaskResult, use the separate compatibility endpoints.

Rate limits#

Accounts are limited by concurrent solves in flight rather than by requests per second, which suits a synchronous API better. The default is ten; exceeding it returns ERROR_THREAD_LIMIT with HTTP 429. Ask support to raise it and mention the throughput you need.

Idempotency#

Solves are not idempotent — each call performs real work against the target and is charged on success. Do not blind-retry a request that timed out client-side without checking whether it actually completed; use softId to correlate.

Errors#

Failures carry a numeric errorId, a stable errorCode string and a description. The error reference lists every code together with whether retrying is worth attempting.

Last updated on 2 August 2026