Handle CAPTCHA task polling and timeouts
Create one task, keep its ID, and poll that task until it’s ready, failed, or your deadline expires. A client timeout is not a failed task, and reaching the end of a long-poll wait doesn’t mean solving has stopped.
On this page
Choose the server wait and client timeout separately
waitMs controls how long an API request waits for a result before responding. It’s a URL query parameter, not a field in the task JSON. Creation defaults differ by product; GET polling has its own limit.
| Request | Server wait |
|---|---|
| Create reCAPTCHA v3 Enterprise task | Waits up to 15000 ms by default. |
| Create Kasada task | Waits up to 75000 ms by default. |
| Create Ticketmaster TMPT task | Asynchronous by default: waitMs=0. An explicit waitMs can be up to 75000. |
| GET an existing task | No wait by default. An explicit waitMs can be up to 15000. |
Give the HTTP client enough time for the requested server wait plus network overhead. A client timeout shorter than the server wait can interrupt the response before you receive the task’s current state.
Create once and keep polling finite
The official SDKs’ solve method creates once and polls until a ready result or an error. Python exposes timeout in seconds and poll_interval in seconds; Node.js exposes timeoutMs and pollIntervalMs in milliseconds. The documented settings use a three-minute solve deadline and a one-second polling interval.
For direct control, Python provides create_task and get_task; Node.js provides createTask and getTask. Use this sequence:
- 1.
Set a deadline and create one task
Choose an overall deadline before creation. Keep a requestId with the exact task inputs so an interrupted creation can be recovered. To avoid waiting during creation, explicitly select a zero wait.
- 2.
Save the returned task ID and inspect its status
Creation may already return a terminal result. Return the solution on ready. On failed, inspect errorCode and error and stop; failed solves are refunded. Only pending and solving need more polling.
- 3.
Retrieve the same task while time remains
Use GET /v1/tasks/:id, optionally with a long-poll wait of up to 15000 ms. Handle non-success HTTP responses before reading a success payload. If the response still says pending or solving, repeat against the same ID—not by creating another task.
- 4.
Stop at the deadline
Bound each request by the time left, allowing for network overhead. When your deadline expires, stop the local loop and retain the task ID for recovery. Don’t relabel the task as failed just because your client stopped waiting.
This request retrieves an existing task, allowing a 15-second server wait and a 30-second client timeout. Set TASK_ID to the saved ID and keep SOLVETHREE_API_KEY on the server. Neither timeout is an overall deadline for a repeated polling loop.
curl --fail-with-body --max-time 30 \
"https://api.solvethree.com/v1/tasks/$TASK_ID?waitMs=15000" \
-H "Authorization: Bearer $SOLVETHREE_API_KEY"Read the task status, not just the HTTP status
An HTTP success response can contain a task that still needs polling. pending and solving are nonterminal; only ready contains a usable solution. failed is terminal and includes errorCode and error.
{
"nonterminal": [
{
"id": "example-task",
"status": "pending"
},
{
"id": "example-task",
"status": "solving"
}
],
"ready": {
"id": "example-task",
"status": "ready",
"solution": {
"token": "EXAMPLE_TOKEN",
"userAgent": "EXAMPLE_USER_AGENT",
"secChUa": "EXAMPLE_CLIENT_HINTS"
}
},
"failed": {
"id": "example-task",
"status": "failed",
"errorCode": "site-unreachable",
"error": "target page did not respond"
}
}The ready response shown here contains a reCAPTCHA token. Kasada returns headers and TMPT returns a raw cookie value instead. A ready result means a solution was generated—not that the downstream target accepted it. If a ready reCAPTCHA token is rejected, switch from polling diagnosis to checking the submitted token.
Recover the existing task after a timeout
A connection timeout tells you that the client didn’t receive a complete response. It doesn’t prove creation failed. Before paying for another solve, recover the task you may already have created.
- 1.
If you have a task ID, resume GET polling
Retrieve that ID with a fresh, finite local deadline. A timed-out GET is not a reason to submit another create request.
- 2.
If creation was interrupted, reuse its requestId
Replay the identical task request with the same requestId to recover the existing task. Changing the task inputs while reusing that ID conflicts. See request ID recovery for the full contract.
Both SDKs generate a requestId when omitted and never automatically retry creation. Their SolvethreeError exposes recovery IDs: request_id and task_id in Python, or requestId and taskId in JavaScript. Check those fields before deciding to create a new logical task.
- A polling request returns an HTTP error
Inspect the HTTP status separately from task status. SDK ApiError exposes that status and any retry delay.
Try this: For temporary polling failures, honor Retry-After within the overall solve deadline. The SDK fields are retry_after in Python seconds and retryAfterMs in JavaScript milliseconds.
- The task returns failed
Read errorCode and error; the SDK represents this as TaskFailedError.
Try this: Stop polling that task. Diagnose the reported cause before creating another one; don’t blindly retry unchanged invalid inputs or assume the problem is credit.
- Retrieval returns HTTP 410
The stored result has expired.
Try this: Stop retrying retrieval as though this were a temporary polling error. Completed results have bounded retention and aren’t a permanent solution cache.
Saving a ready response doesn’t extend the target’s token or cookie lifetime.
Sources and API reference
Still stuck?
Send support your task ID and the error you received.