Solve reCAPTCHA Enterprise with PHP
You can call solvethree directly from PHP. The example below requests a reCAPTCHA v3 Enterprise token, follows the task until it finishes, and stops on a failed solve.
On this page
Before you run it
Use PHP 8+ with the cURL extension. Run it on your server, with the cURL extension enabled.
- Create an active site profile for your target hostname in the console. See site profile setup.
- Set
SOLVETHREE_API_KEYto your workspace API key andSOLVETHREE_PROXYto your HTTP(S) proxy URL. - Replace
accounts.example.comandloginwith your hostname and the action used by the page. Use a hostname forsite, without a scheme or path.
Create the task and wait for the result
Save the code as solve.php and run php solve.php.
<?php
// Requires PHP 8+ with the cURL extension.
$apiKey = getenv('SOLVETHREE_API_KEY');
$proxy = getenv('SOLVETHREE_PROXY');
if (!$apiKey || !$proxy) throw new RuntimeException('Set the API key and proxy');
function api(string $path, ?array $body = null): array {
global $apiKey, $deadline;
$remaining = $deadline - microtime(true);
if ($remaining <= 0) throw new RuntimeException("Keep the task ID and resume polling");
$curl = curl_init('https://api.solvethree.com/v1' . $path);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT_MS => min(30000, max(1, (int) ceil($remaining * 1000))),
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey, 'Content-Type: application/json'],
]);
if ($body !== null) {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body, JSON_THROW_ON_ERROR));
}
$raw = curl_exec($curl);
$error = curl_error($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($raw === false) throw new RuntimeException('Connection failed: ' . $error);
if ($status < 200 || $status >= 300) throw new RuntimeException('API HTTP ' . $status);
return json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
}
$requestId = bin2hex(random_bytes(16)); // Save this with the task inputs for recovery.
$deadline = microtime(true) + 180;
$task = api('/tasks?waitMs=0', [
'site' => 'accounts.example.com', 'action' => 'login',
'proxy' => $proxy, 'requestId' => $requestId,
]);
while (in_array($task['status'], ['pending', 'solving'], true)) {
if (microtime(true) >= $deadline) throw new RuntimeException('Keep the task ID and resume polling');
$task = api('/tasks/' . rawurlencode($task['id']) . '?waitMs=15000');
if (in_array($task['status'], ['pending', 'solving'], true)) usleep(1000000);
}
if ($task['status'] !== 'ready') throw new RuntimeException(
($task['errorCode'] ?? 'Unexpected task state') . ': ' . ($task['error'] ?? '')
);
$solution = $task['solution'];
// Use $solution['token'], ['userAgent'] and ['secChUa'] with the same proxy.
echo 'Ready task: ' . $task['id'] . PHP_EOL;The POST uses waitMs=0 to return a task immediately. Each GET then waits up to 15 seconds for an update. The loop continues for pending or solving, and stops at ready or failed.
The request defaults to Enterprise v3. For standard v3, add recaptchaType: v3. Keep type and url out of a reCAPTCHA task body.
Use the token in your application
The token is $solution['token']. The task ID printed by the program is for retrieving the task; use the token value in your application's CAPTCHA field.
Use $solution['userAgent'] as User-Agent and $solution['secChUa'] as sec-ch-ua in the target request.
Send that request through the same proxy used for the solve. Then check the application response: a generated token does not establish that the target accepted the request.
If the request fails
A failed task includes errorCode and error; the example stops and reports them. Failed solves are refunded. An HTTP error such as 401 or 402 is a separate request problem—check the API error reference before retrying.
Keep the requestId and exact task inputs if you need recovery after a timeout or process restart. If you have the task ID, poll it. Otherwise, resend the original inputs with the same requestId. Simply restarting the program generates another ID and can create another billable solve.
The caller stops waiting after its deadline; that does not cancel a task already created. See polling and timeout recovery for the full sequence.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.