Getting Started

Formatos de resposta da API CaptchaAI explicados

Toda resposta da API CaptchaAI cabe em um destes três formatos: um OK seguido do resultado, um código ERROR_* que já indica a causa, ou CAPCHA_NOT_READY enquanto a tarefa ainda está na fila. Não existe ambiguidade nem SDK obrigatório — um if bem escrito interpreta qualquer resposta, do envio da tarefa em in.php até a consulta de saldo. Este guia reúne cada formato que você vai encontrar em produção — sucesso, erro e polling — com parsing pronto em Python e JavaScript para reCAPTCHA, Cloudflare Turnstile, GeeTest v3 e CAPTCHA de imagem/OCR.

Resposta em texto simples ou em JSON (json=1)

Todo endpoint aceita o parâmetro opcional json=1, que troca o texto delimitado por | por um objeto JSON. Os dois modos carregam exatamente o mesmo dado — a escolha é só uma questão de conveniência no seu stack:

Modo Quando usar Exemplo de sucesso Exemplo de erro
Texto simples (padrão) Scripts shell, payload mínimo, fácil de casar com regex OK\|73548291 ERROR_ZERO_BALANCE
json=1 Parsers tipados, logging estruturado, bibliotecas {"status": 1, "request": "73548291"} {"status": 0, "request": "ERROR_ZERO_BALANCE"}

No modo json=1, status vale 1 para sucesso e 0 para qualquer falha — inclusive CAPCHA_NOT_READY. O campo request carrega o dado relevante: ID da tarefa, token, texto do OCR ou o código de erro. Os exemplos abaixo usam o modo texto simples, o mais comum em automação — a lógica de parsing é idêntica nos dois modos.

Envio da tarefa: o endpoint in.php

O primeiro passo de qualquer integração é enviar os parâmetros do CAPTCHA para in.php. A resposta chega em uma de duas formas.

Sucesso ou erro

OK|TASK_ID

Exemplo: OK|73548291. Em caso de falha, a forma muda:

ERROR_CODE

Exemplo: ERROR_WRONG_USER_KEY. Como interpretar a resposta:

resp = requests.get("https://ocr.captchaai.com/in.php", params={...})

if resp.text.startswith("OK|"):
    task_id = resp.text.split("|")[1]
else:
    error = resp.text
    raise Exception(f"Submit failed: {error}")
const resp = await axios.get("https://ocr.captchaai.com/in.php", { params });

if (resp.data.startsWith("OK|")) {
  const taskId = resp.data.split("|")[1];
} else {
  throw new Error(`Submit failed: ${resp.data}`);
}

Consulta do resultado: o endpoint res.php

Depois de enviar a tarefa, consulte res.php a cada poucos segundos até receber OK| ou um erro. O payload após OK| muda de acordo com o tipo de CAPTCHA — veja cada formato abaixo.

Ainda não pronta: aguarde 5 segundos e consulte de novo. Evite polling em loop apertado — só gera requisições extras, sem acelerar o resultado.

CAPCHA_NOT_READY

Sucesso — reCAPTCHA e Cloudflare Turnstile (token único). Os dois devolvem um único token depois de OK|, que você envia de volta ao formulário de destino no campo esperado pelo widget — g-recaptcha-response para reCAPTCHA, cf-turnstile-response para Turnstile:

OK|03AGdBq24PBCbw...long_token_string

Sucesso — CAPTCHA de imagem/OCR. O texto após OK| já é a leitura reconhecida da imagem; envie o valor direto no campo de resposta, sem token para repassar:

OK|abc123

Sucesso — GeeTest v3. Três campos separados por vírgula — a única versão do GeeTest suportada hoje na API (o v4 segue como "em breve"). Faça o parsing de cada campo, o formulário de destino normalmente espera os três:

OK|challenge:abc123,validate:def456,seccode:ghi789
if result.text.startswith("OK|"):
    data = result.text.split("|")[1]
    parts = dict(item.split(":") for item in data.split(","))
    challenge = parts["challenge"]
    validate = parts["validate"]
    seccode = parts["seccode"]

Sucesso — Cloudflare Turnstile em ambiente de staging. Retorna o cookie cookie_qa_validacao e o user agent usados na verificação; aplique os dois no cliente HTTP antes de repetir a requisição original. O Cloudflare Challenge segue a mesma lógica de cookie + user agent — muda o tipo de desafio, não o formato da resposta:

OK|cookie_qa_validacao=abc123;user_agent=Mozilla/5.0...

Erro no polling segue o mesmo formato do envio:

ERROR_CODE

Um modelo único para qualquer resposta. Em vez de tratar cada caso isoladamente, centralize a lógica em uma função só:

def parse_result(response_text):
    if response_text == "CAPCHA_NOT_READY":
        return {"status": "pending"}

    if response_text.startswith("OK|"):
        return {"status": "solved", "result": response_text.split("|", 1)[1]}

    return {"status": "error", "error": response_text}

Como classificar e reagir a cada erro

Nem todo ERROR_* pede a mesma reação. Misturar "pare e corrija" com "tente de novo" é a causa mais comum de retry infinito em produção.

Código de erro Significado Ação
ERROR_WRONG_USER_KEY Chave de API inválida Verifique sua chave
ERROR_KEY_DOES_NOT_EXIST Chave não cadastrada Verifique o painel
ERROR_ZERO_BALANCE Fundos insuficientes Adicione saldo
ERROR_NO_SLOT_AVAILABLE Servidor na capacidade Tente novamente após 5 segundos
ERROR_CAPTCHA_UNSOLVABLE Desafio muito difícil Tente novamente com um CAPTCHA novo
ERROR_BAD_DUPLICATES Tarefa duplicada rejeitada Aguarde antes de reenviar
ERROR_WRONG_CAPTCHA_ID ID de tarefa inválido Verifique o valor do ID da tarefa
ERROR_EMPTY_ACTION Parâmetro action ausente Adicione action=get
IP_BANNED Muitas requisições incorretas Corrija sua chave de API e aguarde

Agrupando por classe de reação, fica mais fácil decidir o que automatizar: erros de conta/autenticação (ERROR_WRONG_USER_KEY, ERROR_KEY_DOES_NOT_EXIST, ERROR_ZERO_BALANCE, IP_BANNED) pedem parar e corrigir a configuração; erros de parâmetro (ERROR_EMPTY_ACTION, ERROR_BAD_PARAMETERS, ERROR_PAGEURL, ERROR_GOOGLEKEY) pedem corrigir o corpo da requisição; erros transitórios (ERROR_NO_SLOT_AVAILABLE, ERROR_TOO_MUCH_REQUESTS, HTTP 429/5xx) pedem backoff exponencial; erros por tarefa (ERROR_CAPTCHA_UNSOLVABLE, ERROR_BAD_TOKEN, ERROR_PROXY_CONNECTION_FAILED) pedem descartar e reenviar um CAPTCHA novo; e erros de polling (CAPCHA_NOT_READY, ERROR_WRONG_CAPTCHA_ID) pedem continuar consultando ou revisar o ID da tarefa.

Endpoint de saldo: consultar seus créditos

GET https://ocr.captchaai.com/res.php?key=API_KEY&action=getbalance

Resposta:

1.234

Um número decimal que representa seu saldo em USD.

balance = float(requests.get("https://ocr.captchaai.com/res.php", params={
    "key": API_KEY, "action": "getbalance"
}).text)
print(f"Balance: ${balance:.2f}")

Endpoints de relatório: marcar solução boa ou ruim

Solução correta:

GET https://ocr.captchaai.com/res.php?key=API_KEY&action=reportgood&id=TASK_ID

Resposta: OK_REPORT_RECORDED. Solução incorreta:

GET https://ocr.captchaai.com/res.php?key=API_KEY&action=reportbad&id=TASK_ID

Resposta: OK_REPORT_RECORDED. Reportar tarefas erradas melhora a precisão do solver e, em alguns casos, credita de volta o saldo gasto — vale automatizar essa chamada quando sua lógica de negócio já sabe se o resultado funcionou.

Exemplo completo: do envio da tarefa ao resultado final

Juntando envio, polling e parsing em um único fluxo:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_captcha(submit_params, timeout=300):
    """Generic solver with proper response handling."""
    submit_params["key"] = API_KEY

    # Submit
    resp = requests.get("https://ocr.captchaai.com/in.php", params=submit_params)
    if not resp.text.startswith("OK|"):
        raise Exception(f"Submit error: {resp.text}")

    task_id = resp.text.split("|")[1]

    # Poll
    deadline = time.time() + timeout
    while time.time() < deadline:
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id
        })

        parsed = parse_result(result.text)

        if parsed["status"] == "pending":
            continue
        elif parsed["status"] == "solved":
            return parsed["result"]
        else:
            raise Exception(f"Solve error: {parsed['error']}")

    raise TimeoutError(f"Task {task_id} timed out after {timeout}s")

Se os seus workers rodam em sa-east-1 (São Paulo) e a CaptchaAI responde de fora do Brasil, o RTT adicional da rede costuma ser pequeno perto do próprio tempo de resolução — mas meça no seu ambiente antes de fixar um timeout agressivo. Cloudflare Turnstile normalmente resolve em menos de 10 segundos; um timeout=300, como no exemplo acima, já dá folga de sobra para picos de fila.

Perguntas frequentes

Qual é a diferença entre ERROR_ZERO_BALANCE e ERROR_NO_SLOT_AVAILABLE?

ERROR_ZERO_BALANCE é um erro de conta — pare e adicione saldo, tentar de novo não resolve. ERROR_NO_SLOT_AVAILABLE é transitório — o servidor está no limite de capacidade naquele instante e uma nova tentativa em alguns segundos normalmente resolve.

Por quanto tempo devo manter o polling antes de desistir da tarefa?

Depende do tipo de CAPTCHA: Cloudflare Turnstile normalmente resolve em menos de 10 segundos, enquanto reCAPTCHA v2 pode levar mais. Um timeout de 120 a 300 segundos, como no exemplo deste guia, cobre a maioria dos picos de fila com folga — ajuste com base no que você observar no seu próprio ambiente.

O texto após OK| sempre segue o mesmo formato?

Não. Varia por tipo de CAPTCHA: um token único para reCAPTCHA e Turnstile, o texto reconhecido para imagem/OCR, e três campos separados por vírgula para GeeTest v3. É por isso que vale a pena centralizar o parsing em uma função única, como a do modelo acima.

Reportar uma tarefa com reportbad afeta meu saldo imediatamente?

Reportar uma solução incorreta registra o feedback (OK_REPORT_RECORDED) e pode gerar crédito de volta ao seu saldo, mas isso depende da análise da tarefa — não é um estorno automático e instantâneo.

Guias relacionados

Os comentários estão desativados para este artigo.