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:
- 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 capacityno campoerror. Isso geralmente se normaliza em segundos. - Serviço temporariamente desativado. Uma janela de manutenção está em andamento.
Service disabledno campoerror.
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:
- Verifique se o header é
X-API-Key: YOUR_API_KEY(nãoAuthorization: BearerouApi-Key) - Verifique se há espaços em branco extras ou quebras de linha na sua API key
- 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:
- Verifique a status page para incidentes em andamento
- Revise as métricas de requisição no Dashboard
- Entre em contato com o suporte em support@foura.ai com os detalhes da sua requisição (inclua o
X-FourA-Request-Idda resposta com falha)
Próximos passos
- Error Handling: Referência de códigos de erro da API
- Rate Limits: Todos os limites de plano e da plataforma, com campos
- Request Outcomes: Como os resultados classificam o que aconteceu
- Site checks: O que o campo
defenseindica - Choosing the Right Endpoint: Escolha a melhor abordagem para o seu destino
- Dashboard Overview: Monitore suas requisições