Call the CAPTCHA API from Laravel
Use Laravel’s HTTP client to create a solvethree task, then retrieve that task by its ID. Keep the API key and proxy credentials on the server. A successful HTTP response isn’t enough: read the task status before using its solution.
On this page
Configure the site and server credentials
- 1.
Activate the site profile
Set up the target hostname in the console so your workspace has an active reCAPTCHA profile. Sending a hostname in a task doesn’t create one. See site profile setup.
- 2.
Add the server configuration
Add the example’s
solvethreeentry to the existing array inconfig/services.php. SetSOLVETHREE_API_KEY,CAPTCHA_SITE, andSOLVETHREE_PROXYin your server environment. Keep these values out of browser code;CAPTCHA_SITEis the hostname, not a full URL. - 3.
Match the target action
The example sends
login. Change it to the action used by your intended target request. It supplies oneproxy; don’t also sendproxyCandidates.
Create a service with separate create and retrieve methods
<?php
// app/Services/CaptchaApi.php — configure services.solvethree in config/services.php.
namespace App\Services;
use Illuminate\Support\Facades\Http;
use InvalidArgumentException;
final class CaptchaApi
{
private function client()
{
return Http::baseUrl('https://api.solvethree.com/v1')
->withToken(config('services.solvethree.key'))
->acceptJson()->asJson()->connectTimeout(10)->timeout(25);
}
public function create(string $requestId): array
{
if (!preg_match('/^[A-Za-z0-9_-]{1,64}$/', $requestId)) {
throw new InvalidArgumentException('Invalid logical request ID');
}
// The caller keeps this requestId; do not generate another on a timeout.
return $this->client()->post('/tasks?waitMs=0', [
'site' => config('services.solvethree.site'),
'action' => 'login',
'proxy' => config('services.solvethree.proxy'),
'requestId' => $requestId,
])->throw()->json();
}
public function retrieve(string $taskId): array
{
if (!preg_match('/^[A-Za-z0-9_-]{1,128}$/', $taskId)) {
throw new InvalidArgumentException('Invalid task ID');
}
return $this->client()->get('/tasks/'.rawurlencode($taskId), ['waitMs' => 15000])
->throw()->json();
}
}
// config/services.php entry:
// 'solvethree' => ['key' => env('SOLVETHREE_API_KEY'),
// 'site' => env('CAPTCHA_SITE'), 'proxy' => env('SOLVETHREE_PROXY')],
// Invoke from your authenticated controller/job. Poll retrieve only while pending
// or solving; ready contains the solution, failed is terminal. Never use retry()
// on create without preserving both this ID and the exact original inputs.withToken sends the workspace key as Bearer authentication. The POST body is flat: site, action, proxy, and requestId are top-level fields. Don’t add a type or url field for reCAPTCHA. Omitting recaptchaType selects the documented enterprise-v3 default.
Both methods call throw() before json(). Laravel’s HTTP client doesn’t throw for unsuccessful HTTP responses by default, so this prevents the caller from treating an HTTP error payload as a successful task response. The service sets connection and request timeouts and deliberately has no automatic POST retry.
Keep the task ID and check its status
- 1.
Create once for each logical solve
From your authenticated controller or job, retain a caller-generated
requestIdbefore callingcreate. It must contain 1–64 ASCII letters, numbers, underscores, or hyphens. Save the returned task ID separately: the logical request ID is for creation recovery; the task ID is whatretrieveaccepts. - 2.
Retrieve the existing task
Call
retrievewith the saved task ID. If the status ispendingorsolving, arrange a later retrieval rather than running a tight loop in the controller. Give the caller an overall waiting deadline; the service’s HTTP timeout limits each request, not the lifetime of the solve. Reaching that deadline isn’t a reason to create another task. - 3.
Handle the terminal result
For
failed, stop retrieving and inspecterrorCodeanderror; failed solves are refunded. Forready, use the returned solution token. Submit it with the returneduserAgentandsecChUaidentity and the same proxy used for solving. A ready solution still has to be accepted by the target.
Keep HTTP errors separate from task failures. An unsuccessful HTTP response is handled by throw(); a successful response containing failed needs task-level handling. Don’t retry unchanged invalid inputs or assume every failure means insufficient credit. See API error handling.
Recover a timed-out creation without buying another solve
A connection timeout doesn’t tell you whether solvethree created the task. If you already have its task ID, retrieve it. Otherwise, repeat creation with the same requestId and exactly the same task inputs to recover the existing task.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.