Introduction
Aries Solver solves reCAPTCHA v3 and returns the token over a single HTTP request. There is nothing to poll: the response either carries a token or an error explaining what to change.
Every request is JSON in and JSON out. One successfully solved token costs one credit. Failed solves cost nothing.
Base URL
Every endpoint also exists under a /v1 prefix. Both forms behave
identically, so /getRecaptchaV3 and /v1/getRecaptchaV3 are the
same endpoint.
Authentication
Pass your API key with every request. Keys look like
ar_live_ followed by 48 hexadecimal characters.
| Method | Example |
|---|---|
| Header | X-API-Key: ar_live_… |
| Bearer token | Authorization: Bearer ar_live_… |
| Request body | {"clientKey": "ar_live_…"} |
A key spends your credits. Never ship it in a browser bundle or a mobile app. If a key leaks, ask for a replacement on Telegram and the old one is revoked immediately.
Solve a captcha
Submits a target page and returns a token for it. The call blocks until the solve finishes or the time budget runs out.
{
"url": "https://example.com/login",
"sitekey": "6LfCVLAUAAAAALFwwRnnCJ12",
"proxy": "http://user:pass@host:8080",
"action": "login",
"enterprise": false
}
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Full URL of the page holding the captcha, including the scheme. For example
https://example.com/login. |
sitekey |
string | Yes | The reCAPTCHA v3 site key from the target page. Usually begins with
6L. |
proxy |
string | Yes | Proxy the solve runs through, with scheme and port:
scheme://user:pass@host:port. Supports http,
https, socks4 and socks5. |
action |
string | No | The action name the page expects, such as login or
submit. Send it when you know it - scores are often tied to it. |
enterprise |
boolean | No | Set to true for reCAPTCHA Enterprise. Leave it out for standard
v3. |
title |
string | No | Page title to present during the solve. Derived from the domain when omitted. |
Proxy format
The scheme and the port are both required. These are valid:
http://user:pass@198.51.100.10:8080
https://user:pass@198.51.100.10:8443
socks5://user:pass@198.51.100.10:1080
http://198.51.100.10:8080
A bare host:port, or a scheme with no port, is rejected with
Invalid proxy format before the solve starts.
Response
A solved request answers 200 with the token and the fingerprint of the browser that produced it.
{
"status": "success",
"data": {
"token": "03AFcWeA5_zX2...",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/145.0.0.0 Safari/537.36",
"sec_ch_ua": "\"Chromium\";v=\"145\", \"Google Chrome\";v=\"145\"",
"sec_ch_ua_platform": "\"Windows\"",
"sec_ch_ua_mobile": "?0",
"accept_lang": "en-US,en;q=0.9"
},
"credits": 998
}
| Field | Description |
|---|---|
status | success on a solve, error otherwise. |
data.token | The reCAPTCHA v3 token to submit to the target site. |
data.user_agent | User agent of the solving browser. Send this with your request. |
data.sec_ch_ua | Client hint brand list matching the solving browser. |
data.sec_ch_ua_platform | Client hint platform, for example "Windows". |
data.sec_ch_ua_mobile | Client hint mobile flag, ?0 or ?1. |
data.accept_lang | Accept-Language of the solving browser. |
credits | Credits remaining after this solve was charged. |
Errors use the same envelope with a message instead of data:
{
"status": "error",
"message": "Insufficient credits"
}
Using the token
The token is bound to the browser that produced it. Send the returned fingerprint alongside it or the target site may score the request poorly.
- Set your request's
User-Agenttodata.user_agent. - Send
Sec-CH-UA,Sec-CH-UA-PlatformandSec-CH-UA-Mobilefrom the matching fields. - Set
Accept-Languagetodata.accept_lang. - Use the same proxy you passed to the solve.
Request the solve at the moment you need it rather than building a pool in advance. A token that has expired is rejected by the target site, not by this API.
Code examples
curl -X POST __BASE__/getRecaptchaV3 \ -H "X-API-Key: ar_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/login", "sitekey": "6LfCVLAUAAAAALFwwRnnCJ12", "proxy": "http://user:pass@host:8080", "action": "login" }'import requests API = "__BASE__/getRecaptchaV3" KEY = "ar_live_YOUR_KEY" payload = { "url": "https://example.com/login", "sitekey": "6LfCVLAUAAAAALFwwRnnCJ12", "proxy": "http://user:pass@host:8080", "action": "login", } r = requests.post(API, headers={"X-API-Key": KEY}, json=payload, timeout=180) data = r.json() if data["status"] != "success": raise RuntimeError(f"{r.status_code}: {data['message']}") solution = data["data"] # Reuse the solving browser's fingerprint on the target request. headers = { "User-Agent": solution["user_agent"], "Sec-CH-UA": solution["sec_ch_ua"], "Sec-CH-UA-Platform": solution["sec_ch_ua_platform"], "Sec-CH-UA-Mobile": solution["sec_ch_ua_mobile"], "Accept-Language": solution["accept_lang"], } print(solution["token"], data["credits"])const API = "__BASE__/getRecaptchaV3"; const KEY = "ar_live_YOUR_KEY"; async function solve() { const res = await fetch(API, { method: "POST", headers: { "X-API-Key": KEY, "Content-Type": "application/json" }, body: JSON.stringify({ url: "https://example.com/login", sitekey: "6LfCVLAUAAAAALFwwRnnCJ12", proxy: "http://user:pass@host:8080", action: "login", }), }); const data = await res.json(); if (data.status !== "success") { throw new Error(`${res.status}: ${data.message}`); } return data.data; } const solution = await solve(); // Reuse the solving browser's fingerprint on the target request. const headers = { "User-Agent": solution.user_agent, "Sec-CH-UA": solution.sec_ch_ua, "Sec-CH-UA-Platform": solution.sec_ch_ua_platform, "Sec-CH-UA-Mobile": solution.sec_ch_ua_mobile, "Accept-Language": solution.accept_lang, };package main import ( "bytes" "encoding/json" "fmt" "net/http" "time" ) type solution struct { Token string `json:"token"` UserAgent string `json:"user_agent"` } type reply struct { Status string `json:"status"` Message string `json:"message"` Data solution `json:"data"` Credits int `json:"credits"` } func main() { body, _ := json.Marshal(map[string]any{ "url": "https://example.com/login", "sitekey": "6LfCVLAUAAAAALFwwRnnCJ12", "proxy": "http://user:pass@host:8080", "action": "login", }) req, _ := http.NewRequest("POST", "__BASE__/getRecaptchaV3", bytes.NewReader(body)) req.Header.Set("X-API-Key", "ar_live_YOUR_KEY") req.Header.Set("Content-Type", "application/json") res, err := (&http.Client{Timeout: 180 * time.Second}).Do(req) if err != nil { panic(err) } defer res.Body.Close() var out reply json.NewDecoder(res.Body).Decode(&out) if out.Status != "success" { panic(fmt.Sprintf("%d: %s", res.StatusCode, out.Message)) } fmt.Println(out.Data.Token, out.Credits) }<?php $payload = [ 'url' => 'https://example.com/login', 'sitekey' => '6LfCVLAUAAAAALFwwRnnCJ12', 'proxy' => 'http://user:pass@host:8080', 'action' => 'login', ]; $ch = curl_init('__BASE__/getRecaptchaV3'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 180, CURLOPT_HTTPHEADER => [ 'X-API-Key: ar_live_YOUR_KEY', 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode($payload), ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); if ($data['status'] !== 'success') { throw new RuntimeException($data['message']); } $token = $data['data']['token'];
Check your balance
Returns the credits left on your key. POST works too. This call is free and
does not count against your rate limit budget in any meaningful way.
curl __BASE__/balance -H "X-API-Key: ar_live_YOUR_KEY"
{
"status": "success",
"credits": 998
}
Service status
No authentication required. Returns "maintenance" as the status while the
service is paused, in which case solves answer
503.
{
"status": "success",
"service": "Aries Solver"
}
Common errors
Every failure returns {"status": "error", "message": "…"} with one of the
messages below. The HTTP status and the message together tell you whether to fix the
request, top up, or retry.
| Status | Message | Cause | Solution |
|---|---|---|---|
| 400 | Missing required fields | url or sitekey empty |
Provide all required fields |
| 400 | Invalid URL format | Malformed URL | Use a full URL with scheme |
| 400 | Invalid sitekey format | Site key is not a plausible key | Copy the key from the target page |
| 400 | Missing required field: proxy | No proxy provided | Provide a valid proxy |
| 400 | Invalid proxy format | Malformed proxy URL | Check the proxy format |
| 400 | Bad proxy | Proxy not working | Use a different proxy |
| 401 | Invalid API key | Authentication failed | Check your API key |
| 402 | Insufficient credits | Balance too low | Add credits |
| 429 | Service Overloaded | Concurrency or rate limit hit | Retry after a moment |
| 500 | Error fetching token | Solve failed | Retry with backoff |
| 503 | Service temporarily at capacity | All solvers busy, or maintenance | Retry shortly |
Retry 429, 500 and 503 with exponential backoff. Every 400 and 401 will fail again unchanged - fix the request instead. 402 means top up.
Rate limits
Each account has a requests-per-minute ceiling and a cap on solves running at once. Both are set per account and can be raised - ask on Telegram if you are hitting them.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute. |
X-RateLimit-Remaining | Requests left in the current minute. |
X-RateLimit-Reset | Seconds until the window resets. |
Retry-After | Sent with 429. Wait this many seconds. |
Exceeding either limit returns 429 with
Service Overloaded. Honour Retry-After rather than retrying
immediately.
Best practices
- Solve just in time. Tokens last about two minutes, so request one when you are ready to use it.
- Send the fingerprint back. The user agent, client hints and language in the response are part of the solve.
- Reuse the same proxy. Solve and submit from the same exit address.
- Pass the right action. Scores often depend on it matching the page.
- Back off on 429 and 5xx. Double the wait each attempt rather than retrying in a tight loop.
- Watch your balance. Read
creditsfrom each solve response instead of polling/balance. - Set a generous client timeout. Allow at least 180 seconds; a solve can take a while under load.
Buying credits
Credits are sold at $2 per 1,000 solves and never expire. Keys are issued by hand, so message us with the volume you expect and one will be created for you.
https://t.me/Anxioussoul