Problemas Comuns

Soluções para os problemas mais comuns ao usar a API FourA.

Conteúdo Vazio ou Incompleto

Sintoma: A API retorna um status 200, mas o campo data está vazio ou sem o conteúdo esperado.

Causa: A página de destino usa JavaScript para renderizar o conteúdo após o carregamento inicial da página.

Solução: Mude do endpoint único para o endpoint de navegador. Use checkText para verificar se o conteúdo foi carregado:

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/products",
    "timeout_ms": 15000,
    "checkText": "product-list"
  }'

Observação: o endpoint browser retorna conteúdo no campo body (não em data).

403 Forbidden ou Páginas de Verificação

Sintoma: A API retorna HTML contendo uma página de verificação ou uma página de acesso negado.

Causa: O site de destino detectou a request como automatizada e a bloqueou.

Solução: Use o endpoint proxy para rotação automática de IP:

curl -X POST https://eu.api.foura.ai/api/proxy/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "maxTries": 5,
    "request": {
      "method": "GET",
      "url": "https://example.com/prices",
      "unblocker": true
    }
  }'

Se o problema persistir, aumente maxTries para dar mais tentativas à rotação de proxy.

Um 403 retornado pelo destino chega como HTTP 200 com status: 403 dentro do corpo. Um 403 na própria chamada, com um header X-FourA-Limit, é algo diferente: consulte 403 Not in Your Plan.

Timeout Errors

Sintoma: As requests falham com um erro de timeout.

Causa: A página de destino demora mais para carregar do que o timeout configurado.

Solução: Aumente timeout_ms (o padrão é 15s para single, 30s para browser, 45s para proxy):

curl -X POST https://eu.api.foura.ai/api/browser/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://slow-site.com",
    "timeout_ms": 60000
  }'

Para requests de navegador, também verifique se o seu valor de checkText realmente aparece na página. Um erro de digitação faz a chamada falhar com checkText:<your text> not found.

403 Não incluso no seu plano

Sintoma: A API retorna 403 com um header X-FourA-Limit e um reason de plan_limit_feature ou plan_limit_premium.

{
  "error": "Geo targeting (the exitCountries parameter) is not included in your plan (Free). Remove the parameter or upgrade.",
  "reason": "plan_limit_feature",
  "documentation": "https://foura.ai/prices"
}

Causa: Seu plano não inclui o endpoint chamado ou o parâmetro enviado. plan_limit_feature cobre um endpoint excluído e exitCountries sem geo targeting; plan_limit_premium cobre exitClass: premium sem saídas premium. O destino nunca foi contatado e nada foi gasto.

Solução: Remova o parâmetro, chame um endpoint incluído no seu plano ou faça upgrade. A aba Limits & Features de Usage & Limits lista o que seu plano inclui. Não repita a requisição sem alterações: nenhum Retry-After é definido porque aguardar não altera a resposta.

429 Too Many Requests

Sintoma: A API retorna 429.

Causa: Uma de duas verificações recusou a chamada, e a resposta informa qual delas. Se contiver um header X-FourA-Limit, um dos limites do seu plano foi atingido: requisições simultâneas ou requisições por minuto naquele endpoint, requisições de Browser no dia, ou os créditos ou largura de banda do período de faturamento. Se não houver esse header, o limite compartilhado por minuto da plataforma para aquele serviço estava esgotado, o que diz respeito ao tráfego da FourA e não ao seu.

Solução: Leia X-FourA-Limit primeiro. Aguarde quando o limite estiver a poucos segundos e pare quando não estiver. Os limites do plano que são liberados com espera colocam os segundos no header Retry-After e em retry_after_seconds; o limite compartilhado os coloca em retryAfter:

import time
import requests

# Plan limits that come back in hours or days, not seconds.
STOP_ON = {"plan_limit_browser_daily", "plan_limit_credits", "plan_limit_bandwidth"}

def make_request(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code == 429:
            limit = resp.headers.get("X-FourA-Limit")
            if limit in STOP_ON:
                raise Exception(f"stopped by {limit}: {resp.json().get('error')}")
            header = resp.headers.get("Retry-After")
            body = resp.json()
            wait = (
                int(header) if header and header.isdigit()
                else body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** i
            )
            time.sleep(wait)
            continue
        return resp
    raise Exception("Rate limit not resolved after retries")

# Example: single request
make_request(
    "https://eu.api.foura.ai/api/single/",
    {"method": "GET", "url": "https://example.com"}
)

Se o header indicou plan_limit_concurrency ou plan_limit_rate, a solução é limitar quantas chamadas você mantém abertas e quantas inicia por minuto, em vez de tentar novamente com mais intensidade. Reenviar um lote recusado imediatamente faz com que todo o lote seja recusado de novo. Chamadas recusadas não contam para o seu limite por minuto, mas se continuarem chegando a mais que o dobro desse limite, as recusas viram um cooldown: o corpo do 429 traz cooldown: true e pede para você pausar por 30 segundos (retry_after_seconds: 30). Executar Requests em Paralelo contém o padrão, e Usage & Limits no Dashboard mostra seus contadores em tempo real ao lado dos seus limites.

503 Service Unavailable

Sintoma: a API retorna o status 503.

Causa: isso acontece em dois casos:

  1. O serviço atingiu a capacidade máxima. O FourA já está executando tantas requests nessa engine quanto é permitido simultaneamente, contabilizadas em todo o tráfego e não apenas no seu. Service at capacity no campo error. Isso geralmente se normaliza em segundos.
  2. Serviço temporariamente desativado. Uma janela de manutenção está em andamento. Service disabled no campo error.

Ambos os casos incluem um campo retryAfter na resposta. Nenhum deles é um limite do plano: os limites do seu próprio plano sempre respondem com um header X-FourA-Limit em um 403 ou 429, nunca com 503.

Solução: aguarde retryAfter segundos e tente novamente:

import time
import requests

def make_request_with_retry(endpoint_url, payload, retries=3):
    for i in range(retries):
        resp = requests.post(
            endpoint_url,
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json=payload
        )
        if resp.status_code in (429, 503):
            header = resp.headers.get("Retry-After")
            body = resp.json()
            wait = (
                int(header) if header and header.isdigit()
                else body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** i
            )
            time.sleep(wait)
            continue
        return resp
    raise Exception("Request not resolved after retries")

Um erro 503 por capacidade significa que o FourA está ocupado, portanto aguardar e tentar novamente é a solução completa. Se você estiver recebendo 429 com X-FourA-Limit, o motivo é local: reduza o número de requests paralelas no seu pipeline.

504 Upstream Timeout

Sintoma: A API retorna 504 com {"error": "Upstream timeout"}.

Causa: A execução não terminou dentro do tempo limite definido para a request. Um destino lento, uma resolução inicial de desafio ou uma página muito grande podem causar isso. Não se trata de um problema com sua chave, seus parâmetros ou seu proxy.

Solução: Conceda mais tempo para a chamada ou tente novamente. O FourA aguarda o seu timeout_ms mais uma pequena margem, portanto aumentá-lo estende o tempo de espera de forma efetiva:

{
  "url": "https://slow-site.com/report",
  "timeout_ms": 90000
}

Para /api/auto/ em um destino protegido, uma primeira chamada a frio pode levar dezenas de segundos. Seu timeout_ms cobre toda a sequência e aceita até 180000.

Quando o /api/auto/ esgota esse orçamento, a chamada ainda responde HTTP 200. O corpo traz um error que começa com time budget exhausted, e status geralmente é 504 (uma tentativa anterior com falha pode deixar seu próprio status ali). Aumente timeout_ms ou tente novamente.

502 Upstream Unavailable

Sintoma: A API retorna 502 com {"error": "Upstream unavailable"}, ou 503 com {"error": "Backend service unavailable"}.

Causa: O FourA alcançou seu próprio mecanismo, mas não conseguiu usar a resposta, geralmente porque uma instância estava reiniciando.

Solução: Tente novamente com um recuo curto. Ambos são classificados como service_error, e apenas success é faturado, portanto, uma nova tentativa não custa nada a mais. Se durar mais de um ou dois minutos, verifique a página de status.

401 Authentication Errors

Sintoma: Toda request retorna 401 Unauthorized.

Checklist:

  1. Verifique se o header é X-API-Key: YOUR_API_KEY (não Authorization: Bearer ou Api-Key)
  2. Verifique se há espaços em branco extras ou quebras de linha na sua API key
  3. Crie uma nova chave no Dashboard se a atual puder estar comprometida

400 Target Resolves to a Private or Reserved IP

Sintoma: A API retorna 400 com Refusing to fetch <target>: target resolves to a private or reserved IP range antes que a request saia do FourA.

Causa: Sua url resolve para uma faixa de IP privada, de loopback ou reservada (RFC 5735, RFC 6598 ou blocos reservados de IPv6). O FourA recusa esses destinos para que sua rede não possa ser usada para alcançar hosts internos.

Solução: Busque uma URL pública. Se você estiver testando, use um destino público como https://example.com ou https://httpbin.org/get. Se o destino pretendido for um serviço que você executa, exponha-o em um hostname público primeiro.

{ "error": "Refusing to fetch <target>: target resolves to a private or reserved IP range. The FourA scraping API only forwards requests to public internet hosts." }

Um nome de host que não pode ser resolvido não é recusado. A chamada retorna como HTTP 200 com status: 0 e o motivo (could not resolve <host>: <reason>), como qualquer destino que o FourA não consegue alcançar, e não é cobrada.

no_eligible_proxy ao usar exitCountries

Sintoma: Uma chamada /api/proxy/ com exitCountries retorna HTTP 200 com um envelope de erro JSON:

{
  "error": "No eligible proxy found for exit countries: CZ, GB",
  "code": "no_eligible_proxy",
  "details": { "exitCountries": ["CZ", "GB"] },
  "total": 0.084
}

Causa: O pool de proxies atual não possui uma saída funcional cujo país visível pelo destino corresponda à sua lista de permissões. O FourA nunca faz fallback para um país não solicitado quando você define exitCountries.

Solução: Mantenha o escopo solicitado e tente novamente mais tarde. O pool é atualizado aproximadamente a cada dez minutos, portanto, um país sem correspondência no momento geralmente ganha uma dentro de uma hora.

import time, requests

def fetch_scoped(url, countries, max_attempts=6, wait_sec=600):
    for _ in range(max_attempts):
        r = requests.post("https://eu.api.foura.ai/api/proxy/",
            headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
            json={"maxTries": 5, "exitCountries": countries,
                  "request": {"method": "GET", "url": url}}).json()
        if r.get("code") == "no_eligible_proxy":
            time.sleep(wait_sec)
            continue
        return r
    raise RuntimeError(f"no eligible exit in {countries} after {max_attempts} attempts")

Amplie a lista de países apenas se o requisito de país do seu fluxo de trabalho realmente tiver mudado. Fallbacks silenciosos para outros países podem quebrar a lógica dependente de geolocalização downstream.

O corpo da resposta retorna como texto ilegível

Sintoma: A resposta data (ou body) contém mojibake ou caracteres ilegíveis quando o destino usa um charset diferente de UTF-8.

Causa: Por padrão, o FourA decodifica automaticamente os corpos de resposta para UTF-8 com base no header Content-Type do destino ou em uma tag HTML <meta charset>. Se o destino informar um charset incorreto, você receberá texto ilegível.

Solução: Para payloads binários (imagens, protobuf, áudio bruto), defina returnBuffer: true na request. O Single e o Proxy retornarão data como um objeto contendo os bytes brutos, {"type": "Buffer", "data": [<byte values>]}, sem nenhuma transcodificação de charset aplicada.

{
  "method": "GET",
  "url": "https://example.com/image.png",
  "returnBuffer": true
}

Para alvos de texto que declaram incorretamente o charset, decodifique os bytes brutos você mesmo: faça o fetch com returnBuffer: true, leia os valores de bytes em data.data e, em seguida, decodifique-os com o charset correto.

HTML Inesperado em Vez de JSON

Sintoma: Você esperava JSON do site de destino, mas recebeu HTML.

Causa: A página de destino pode fornecer conteúdo diferente com base nos headers.

Solução: Adicione um header Accept e habilite unblocker para obter headers de navegador realistas:

curl -X POST https://eu.api.foura.ai/api/single/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "GET",
    "url": "https://api.example.com/data",
    "headers": [["Accept", "application/json"]],
    "unblocker": true
  }'

Você também pode definir tryJsonData como true para que o FourA processe automaticamente as respostas JSON.

O body é uma página de desafio, não o conteúdo

Sintoma: A chamada foi bem-sucedida, status é 200, mas data (ou body) é uma verificação de bot em vez da página desejada.

Causa: O destino executou uma verificação de bot que o FourA encontrou, mas não conseguiu superar. A resposta indica isso: Single e Proxy retornam defense com solved: false, e Browser retorna defenseSolved: false com o provedor em defenses.present.

Solução: Verifique defense.vendor primeiro e depois escale. Tente um perfil de navegador diferente no Single, mude para Proxy para uma saída diferente ou use Browser para que o JavaScript seja executado. Referência completa dos campos e lista de provedores: Site checks.

Adicione uma substring validate.data.accept que apenas a página real contenha. Uma página de verificação que o FourA reconhece nunca é um sucesso: ela retorna com um header X-FourA-Check-Page e não é cobrada. Sem validate, uma página de verificação que o FourA não reconhece, retornada com HTTP 200, conta como sucesso, e você só descobre isso em etapas posteriores em vez de na chamada.

Ainda precisa de ajuda?

Se nenhuma das soluções acima funcionar:

  1. Verifique a status page para incidentes em andamento
  2. Revise as métricas de requisição no Dashboard
  3. Entre em contato com o suporte em support@foura.ai com os detalhes da sua requisição (inclua o X-FourA-Request-Id da resposta com falha)

Próximos passos

Atualizado em: 30 de setembro de 2026