CapSolutio — Documentação da API
API de resolução de CAPTCHA. O fluxo é o padrão da categoria: você cria uma tarefa, recebe um taskId, e consulta o resultado até ele ficar pronto. Quem já integra um serviço de resolução encontra aqui o mesmo formato de envelope.
- URL base:
https://api.capsolutio - Formato: JSON em todas as requisições e respostas
- Autenticação: campo
clientKeyno corpo - CAPTCHA suportado: hCaptcha
Índice
- Início rápido
- Autenticação
- Criar tarefa — POST /v1/tasks
- Consultar resultado — POST /v1/tasks/result
- Usando seu próprio proxy
- Idempotência
- Códigos de erro
- Limites e cabeçalhos
- Exemplos completos
- Boas práticas
1. Início rápido
Duas chamadas resolvem um hCaptcha.
Passo 1 — criar a tarefa:
curl -X POST https://api.capsolutio/v1/tasks \
-H "Content-Type: application/json" \
-d '{
"clientKey": "sua_chave_aqui",
"task": {
"type": "HCaptchaTaskProxyless",
"websiteURL": "https://exemplo.com.br/login",
"websiteKey": "10000000-ffff-ffff-ffff-000000000001"
}
}'
{ "errorId": 0, "taskId": "mrf_9f3c1a8b7d2e4f60" }
Passo 2 — buscar o resultado (a cada 3–5 s):
curl -X POST https://api.capsolutio/v1/tasks/result \
-H "Content-Type: application/json" \
-d '{
"clientKey": "sua_chave_aqui",
"taskId": "mrf_9f3c1a8b7d2e4f60"
}'
{
"errorId": 0,
"taskId": "mrf_9f3c1a8b7d2e4f60",
"status": "ready",
"solution": {
"token": "P1_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
}
}
Use solution.token como o valor de h-captcha-response (e de g-recaptcha-response, quando o alvo espera os dois) no formulário do site.
2. Autenticação
A chave vai no corpo, no campo clientKey, em todas as chamadas:
{ "clientKey": "sua_chave_aqui", "...": "..." }
Chave ausente, desconhecida ou inativa devolve HTTP 401 com ERROR_KEY_DOES_NOT_EXIST.
3. Criar tarefa — POST /v1/tasks
Cria e enfileira uma resolução. Responde 201 para uma tarefa nova.
Corpo
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
clientKey |
string | sim | Sua chave de API. |
task |
objeto | sim | Descrição do que resolver. Ver abaixo. |
Objeto task
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
type |
string | sim | HCaptchaTask. |
websiteURL |
string | sim | URL absoluta da página real onde o widget existe. |
websiteKey |
string | sim | Sitekey do hCaptcha publicada na página. |
proxyType |
string | não | http, https, socks4 ou socks5. Ver seção 5. |
proxyAddress |
string | não | Host ou IP do seu proxy. |
proxyPort |
inteiro | não | Porta do seu proxy. |
proxyLogin |
string | não | Usuário do proxy, se houver. |
proxyPassword |
string | não | Senha do proxy, se houver. |
websiteURL e websiteKey devem ser obtidos no site correspondente que hospeda o CAPTCHA que será solucionado.
Respostas
| HTTP | Significado |
|---|---|
201 |
Tarefa criada e enfileirada. |
200 |
Repetição de uma Idempotency-Key já usada com o mesmo corpo — devolve a tarefa original, sem criar nem cobrar de novo. |
400 |
ERROR_MISSING_PARAMETER, ERROR_INVALID_WEBSITE_URL, ERROR_INVALID_SITEKEY, ERROR_INVALID_PROXY. |
401 |
ERROR_KEY_DOES_NOT_EXIST. |
402 |
ERROR_NO_QUOTA_AVAILABLE — cota total esgotada. |
409 |
ERROR_IDEMPOTENCY_CONFLICT. |
422 |
ERROR_NO_SUCH_METHOD (tipo inexistente) ou ERROR_UNSUPPORTED_CAPTCHA_TYPE (tipo conhecido, ainda não resolvido). |
429 |
ERROR_RATE_LIMIT_EXCEEDED ou ERROR_NO_DAILY_QUOTA_AVAILABLE. |
503 |
ERROR_NO_SLOT_AVAILABLE ou ERROR_TEMPORARILY_UNAVAILABLE. |
{ "errorId": 0, "taskId": "mrf_9f3c1a8b7d2e4f60" }
4. Consultar resultado — POST /v1/tasks/result
Corpo
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
clientKey |
string | sim | Sua chave de API. |
taskId |
string | sim | O taskId devolvido na criação. |
Estados
status |
Final? | O que fazer |
|---|---|---|
queued |
não | Na fila. Consulte de novo em 3–5 s. |
running |
não | Está sendo resolvido. Consulte de novo em 3–5 s. |
ready |
sim | Sucesso. solution.token está preenchido. |
failed |
sim | Não resolvido. Veja errorCode e errorDescription. |
Resposta pronta
{
"errorId": 0,
"taskId": "mrf_9f3c1a8b7d2e4f60",
"status": "ready",
"solution": {
"token": "P1_eyJ0eXAiOiJKV1Qi...",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
}
}
Resposta com falha
{
"errorId": 1,
"taskId": "mrf_9f3c1a8b7d2e4f60",
"status": "failed",
"errorCode": "ERROR_SOLVE_TIMEOUT",
"errorDescription": "o solve não completou dentro do prazo"
}
Ritmo e prazo do polling
- Consulte a cada 3–5 s. Um solve típico leva dezenas de segundos; consultar mais rápido gasta ficha do seu limite de requisições sem antecipar nada.
404 com ERROR_TASK_NOT_FOUND significa taskId inexistente. Certifique-se de usar o mesmo clientKey que criou a tarefa na sua consulta também, caso contrário, não será possível consultar a tarefa.
5. Usando seu próprio proxy
Preencha os cinco campos proxy* dentro de task. proxyAddress e proxyPort andam juntos; proxyLogin e proxyPassword só quando o proxy exige autenticação.
{
"clientKey": "mrfk_sua_chave_aqui",
"task": {
"type": "HCaptchaTask",
"websiteURL": "https://exemplo.com.br/login",
"websiteKey": "10000000-ffff-ffff-ffff-000000000001",
"proxyType": "http",
"proxyAddress": "203.0.113.10",
"proxyPort": 8080,
"proxyLogin": "usuario",
"proxyPassword": "senha"
}
}
Um proxy inválido ou inalcançável devolve ERROR_INVALID_PROXY (400) na criação, ou ERROR_PROXY_AUTH_FAILED / ERROR_PROXY_NETWORK no resultado.
6. Idempotência
Envie o cabeçalho Idempotency-Key na criação para tornar o retry seguro:
curl -X POST https://api.capsolutio/v1/tasks \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f14e45f-ceea-467a-9f2c-1b2c3d4e5f60" \
-d '{ "clientKey": "...", "task": { "...": "..." } }'
- Mesma chave, mesmo corpo → HTTP 200 com a tarefa original. Nada é criado e nada é cobrado de novo.
- Mesma chave, corpo diferente → HTTP 409,
ERROR_IDEMPOTENCY_CONFLICT. - A janela é de 1 hora.
7. Códigos de erro
Do pedido — corrija e reenvie
| Código | HTTP | Significado |
|---|---|---|
ERROR_MISSING_PARAMETER |
400 | Campo obrigatório ausente. |
ERROR_INVALID_WEBSITE_URL |
400 | websiteURL não é uma URL http/https absoluta. |
ERROR_INVALID_SITEKEY |
400 | websiteKey malformada. |
ERROR_INVALID_DOMAIN |
400 | Domínio não aceito. |
ERROR_INVALID_PROXY |
400 | Campos proxy* incompletos ou inválidos. |
ERROR_NO_SUCH_METHOD |
422 | type não existe. |
ERROR_UNSUPPORTED_CAPTCHA_TYPE |
422 | type existe, mas ainda não é resolvido. |
ERROR_IDEMPOTENCY_CONFLICT |
409 | Idempotency-Key reutilizada com outro corpo. |
ERROR_TASK_NOT_FOUND |
404 | taskId inexistente ou de outra conta. |
Da conta — não adianta repetir
| Código | HTTP | Significado |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
401 | Chave ausente, desconhecida ou inativa. |
ERROR_ACCOUNT_SUSPENDED |
401 | Conta suspensa. |
ERROR_ZERO_BALANCE |
402 | Saldo zerado. |
ERROR_NO_QUOTA_AVAILABLE |
402 | Cota total esgotada. Único 4xx sem Retry-After — esperar não resolve. |
De capacidade — repita depois do Retry-After
| Código | HTTP | Significado |
|---|---|---|
ERROR_RATE_LIMIT_EXCEEDED |
429 | Requisições demais por segundo. |
ERROR_NO_DAILY_QUOTA_AVAILABLE |
429 | Cota diária esgotada. |
ERROR_NO_SLOT_AVAILABLE |
503 | Sobrecarga momentânea do servidor. |
ERROR_TEMPORARILY_UNAVAILABLE |
503 | Indisponibilidade momentânea. |
Do solve — aparecem em status: failed
Estes chegam no resultado, não na criação. Repetir a tarefa costuma resolver: cada tentativa nasce com IP e sessão novos.
| Código | Significado |
|---|---|
ERROR_CHALLENGE_TIMEOUT |
O desafio não completou no prazo. |
ERROR_UNSUPPORTED_CHALLENGE |
Tipo de desafio ainda não suportado. |
ERROR_CAPTCHA_UNSOLVABLE |
Não resolvido depois de todas as tentativas. |
ERROR_PROXY_UNAVAILABLE |
Nenhum IP de saída disponível. |
ERROR_PROXY_AUTH_FAILED |
O proxy recusou as credenciais. |
ERROR_PROXY_NETWORK |
Falha de rede no caminho de saída. |
ERROR_SOLVE_TIMEOUT |
O solve não completou no prazo. |
ERROR_INTERNAL |
Falha interna do servidor. |
8. Limites e cabeçalhos
Idempotency-Key
Opcional na criação. Ver seção 6.
9. Exemplos completos
Python
import time
import requests
BASE = "https://api.capsolutio"
CHAVE = "sua_chave_aqui"
def resolver(website_url: str, website_key: str, timeout: int = 300) -> dict:
"""Cria a tarefa e faz polling até um estado final. Devolve a solução."""
criada = requests.post(
f"{BASE}/v1/tasks",
json={
"clientKey": CHAVE,
"task": {
"type": "HCaptchaTaskProxyless",
"websiteURL": website_url,
"websiteKey": website_key,
},
},
timeout=30,
)
criada.raise_for_status()
task_id = criada.json()["taskId"]
limite = time.monotonic() + timeout
while time.monotonic() < limite:
time.sleep(4) # 3-5 s: consultar mais rápido não antecipa nada
r = requests.post(
f"{BASE}/v1/tasks/result",
json={"clientKey": CHAVE, "taskId": task_id},
timeout=30,
)
r.raise_for_status()
dados = r.json()
if dados["status"] == "ready":
return dados["solution"]
if dados["status"] == "failed":
raise RuntimeError(f"{dados['errorCode']}: {dados.get('errorDescription')}")
raise TimeoutError(f"tarefa {task_id} não concluiu em {timeout}s")
solucao = resolver(
"https://exemplo.com.br/login",
"10000000-ffff-ffff-ffff-000000000001",
)
print(solucao["token"])
# Use o MESMO User-Agent na requisição final ao alvo.
requests.post(
"https://exemplo.com.br/login",
headers={"User-Agent": solucao["userAgent"]},
data={"h-captcha-response": solucao["token"], "usuario": "...", "senha": "..."},
)
Node.js
const BASE = "https://api.capsolutio";
const CHAVE = "mrfk_sua_chave_aqui";
const dormir = (ms) => new Promise((r) => setTimeout(r, ms));
async function resolver(websiteURL, websiteKey, timeoutMs = 300_000) {
const criada = await fetch(`${BASE}/v1/tasks`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
clientKey: CHAVE,
task: { type: "HCaptchaTaskProxyless", websiteURL, websiteKey },
}),
});
const { taskId } = await criada.json();
const limite = Date.now() + timeoutMs;
while (Date.now() < limite) {
await dormir(4000);
const r = await fetch(`${BASE}/v1/tasks/result`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ clientKey: CHAVE, taskId }),
});
const dados = await r.json();
if (dados.status === "ready") return dados.solution;
if (dados.status === "failed") {
throw new Error(`${dados.errorCode}: ${dados.errorDescription ?? ""}`);
}
}
throw new Error(`tarefa ${taskId} não concluiu no prazo`);
}
const solucao = await resolver(
"https://exemplo.com.br/login",
"10000000-ffff-ffff-ffff-000000000001",
);
console.log(solucao.token);
PHP
<?php
const BASE = 'https://api.capsolutio';
const CHAVE = 'mrfk_sua_chave_aqui';
function chamar(string $rota, array $corpo): array {
$ch = curl_init(BASE . $rota);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($corpo),
CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
curl_close($ch);
return json_decode($resposta, true);
}
$criada = chamar('/v1/tasks', [
'clientKey' => CHAVE,
'task' => [
'type' => 'HCaptchaTaskProxyless',
'websiteURL' => 'https://exemplo.com.br/login',
'websiteKey' => '10000000-ffff-ffff-ffff-000000000001',
],
]);
$taskId = $criada['taskId'];
$limite = time() + 300;
while (time() < $limite) {
sleep(4);
$dados = chamar('/v1/tasks/result', ['clientKey' => CHAVE, 'taskId' => $taskId]);
if ($dados['status'] === 'ready') {
echo $dados['solution']['token'], PHP_EOL;
exit(0);
}
if ($dados['status'] === 'failed') {
fwrite(STDERR, $dados['errorCode'] . PHP_EOL);
exit(1);
}
}
fwrite(STDERR, "tarefa {$taskId} não concluiu no prazo" . PHP_EOL);
exit(1);
10. Boas práticas
Envie o userAgent de volta. O token é emitido para a sessão que o gerou. Enviar o token com outro User-Agent é a causa mais comum de "o token veio válido e o site recusou".
Use a URL real da página. websiteURL define o origin e o Referer que o hCaptcha observa. A raiz do domínio no lugar da página de login muda o que ele vê.
Faça polling a cada 3–5 s. Mais rápido não antecipa nada e consome o seu limite de requisições.
Respeite o Retry-After. Ele vem do estado real do serviço e é melhor que qualquer backoff que você calcule.
Use Idempotency-Key em toda criação. É barato e elimina a cobrança dupla quando a resposta se perde na rede.
Trate failed como retentável, com teto. Códigos de solve costumam passar na tentativa seguinte. Recrie a tarefa, duas ou três vezes, não indefinidamente.
Não faça polling eterno. Toda tarefa tem um tempo de timeout. Não faça o pooling eternamente, defina um ponto de parada.
O token do hCaptcha tem validade curta (cerca de 2 minutos a partir da emissão). Use-o assim que receber; não o guarde em fila.