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 clientKey no corpo
  • CAPTCHA suportado: hCaptcha

Índice

  1. Início rápido
  2. Autenticação
  3. Criar tarefa — POST /v1/tasks
  4. Consultar resultado — POST /v1/tasks/result
  5. Usando seu próprio proxy
  6. Idempotência
  7. Códigos de erro
  8. Limites e cabeçalhos
  9. Exemplos completos
  10. 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.