Rate Limits

Cada request à API FourA passa por três verificações antes de alcançar uma engine: os limites do seu próprio plano, depois a cota compartilhada da plataforma para o endpoint chamado e, por fim, a cota compartilhada da plataforma para todo o tráfego. Cada verificação pode recusar uma request por si só, e cada uma responde com um body diferente.

As três verificações, em ordem

  1. Limites do plano. O que o seu próprio plano permite: quais endpoints e parâmetros ele inclui, quantas requests podem ser executadas simultaneamente por endpoint, quantas por minuto, quantas requests de browser por dia e os créditos e largura de banda disponíveis no período de faturamento.
  2. Limite global da plataforma. Tudo o que o host da API chamado está processando naquele momento, independentemente do endpoint de destino do tráfego. Uma recusa aqui retorna "service": "api".
  3. Limite da plataforma por endpoint. Tráfego no serviço single, proxy ou browser chamado.

O seu próprio plano é avaliado primeiro, e essa ordem é um contrato, não um detalhe de implementação. As cotas compartilhadas são um recurso comum; portanto, uma request que a plataforma já iria recusar não deve consumi-las no caminho até ser rejeitada. Uma conta enviando muito mais do que seu plano permite é interrompida antes de interferir nos recursos utilizados por outras pessoas.

As verificações 2 e 3 contabilizam o tráfego total da FourA, não o seu. Interprete uma recusa de qualquer uma delas como "A FourA está ocupada", e não como "você enviou requisições demais". A verificação 1 diz respeito apenas à sua conta, e nada mais na plataforma a altera.

Uma recusa de qualquer uma das verificações compartilhadas devolve à sua conta tudo o que a admissão contabilizou, tanto o bucket por minuto quanto o slot diário de browser, porque a request nunca alcançou um backend. Ela também não conta para a pausa de retry descrita em Requests por minuto: a capacidade da FourA a recusou, não o seu plano.

O POST /api/auto/ não ocupa um slot próprio. As subchamadas de Single, Proxy e Browser feitas por ele para você passam por todas as três verificações como qualquer outra request, portanto, um lote paralelo de chamadas auto consome o limite do seu plano por meio de suas subchamadas. (A contagem de requests e a taxa de sucesso contabilizam a chamada auto em si, uma vez; as subchamadas são exibidas como tentativas dela.)

Limites do plano

Um limite de plano responde com um header X-FourA-Limit indicando qual limite recusou a chamada. O mesmo código está no body sob reason, para que você possa criar condicionais sem ler os headers. Todo body de limite de plano inclui error, reason e documentation; o restante dos campos depende do limite.

X-FourA-Limit Status O que se esgotou
plan_limit_feature 403 O endpoint chamado ou o parâmetro exitCountries não está no seu plano
plan_limit_premium 403 exitClass: premium não está no seu plano
plan_limit_concurrency 429 Requests simultâneos nesse endpoint
plan_limit_rate 429 Requests por minuto nesse endpoint
plan_limit_browser_daily 429 Requests de browser no dia
plan_limit_credits 429 Créditos cobrados no período de faturamento
plan_limit_bandwidth 429 Largura de banda no período de faturamento

Os números por trás de cada limite são do seu plano, e a aba Limits & Features de Usage & Limits lista todos eles ao lado do seu consumo em tempo real. Não defina esses valores no código: cada recusa traz o limite máximo que a originou.

Um request recusado não consome nada. O resultado é rate_limit, e apenas success é faturado.

Endpoint ou parâmetro não incluído no plano

Um 403 com plan_limit_feature indica que a chamada solicitou algo não incluído no plano. A verificação ocorre antes de qualquer contagem, portanto a chamada recusada não afeta seu rate limit nem seus contadores diários.

{
  "error": "The browser endpoint is not included in your plan (Free). Upgrade to use it.",
  "reason": "plan_limit_feature",
  "documentation": "https://foura.ai/prices"
}

O mesmo código e status respondem a uma chamada POST /api/proxy/ que define exitCountries em um plano sem geo targeting. A string error nomeia o parâmetro:

{
  "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"
}

plan_limit_premium tem o mesmo formato para exitClass: premium em um plano sem saídas premium. O FourA pode, em vez disso, atender a essa request usando o pool padrão e retornar exitClass: standard na response, portanto trate ambas as respostas. Nenhuma delas consome uma saída premium. Consulte exitClass.

Nenhum 403 define Retry-After. Aguardar não altera a resposta.

Simultaneous requests

A simultaneidade é contabilizada por endpoint: seu plano possui um limite para Single, um para Proxy e um para Browser. A request que ultrapassar o limite retorna como 429 com Retry-After: 1:

{
  "error": "Concurrency limit reached: your plan allows 50 simultaneous proxy request(s). Retry when an in-flight request finishes.",
  "reason": "plan_limit_concurrency",
  "documentation": "https://foura.ai/prices",
  "limit": 50,
  "in_flight": 51,
  "retry_after_seconds": 1
}

in_flight conta a request recusada também, portanto lê pelo menos um a mais do que limit.

A solução é limitar seu próprio paralelismo em vez de tentar novamente com mais intensidade. Responder a um 429 reenviando o mesmo lote imediatamente gera outro 429 para cada chamada nele. Consulte Executar Requests em Paralelo para ver um padrão prático.

Requests por minuto

Single e Proxy possuem um limite por minuto, medido ao longo de um minuto deslizante. Apenas requests aceitas contam para esse limite: uma request recusada é removida da contagem, portanto uma conta que solicita constantemente um pouco acima do seu limite recebe o equivalente ao seu limite, em vez de ter quase tudo recusado.

{
  "error": "Rate limit reached: your plan allows 600 single requests per minute. Cool down and retry.",
  "reason": "plan_limit_rate",
  "documentation": "https://foura.ai/prices",
  "limit_per_minute": 600,
  "current_rate": 613,
  "retry_after_seconds": 17
}

retry_after_seconds indica quanto tempo levará até que mais uma request seja aceita, caso você não envie mais nada nesse intervalo: no mínimo 1 segundo e no máximo 120. O header Retry-After contém o mesmo valor.

Tentar novamente requests recusadas mais rápido do que isso segue uma regra própria. Quando as requests recusadas por este limite no minuto móvel ultrapassarem o dobro da cota permitida, a chamada será recusada com uma pausa de 30 segundos:

{
  "error": "Rate limit cooldown: 1250 requests over your plan's 600 single requests per minute were refused in the last minute and kept arriving. Pause for 30 seconds.",
  "reason": "plan_limit_rate",
  "documentation": "https://foura.ai/prices",
  "limit_per_minute": 600,
  "current_rate": 540,
  "refused_last_minute": 1250,
  "cooldown": true,
  "retry_after_seconds": 30
}

Recusas durante a pausa não são contabilizadas, portanto a pausa termina por conta própria com o avançar do minuto, mesmo para um cliente que continua tentando novamente. Para diferenciar a pausa do limite normal, leia cooldown em vez do texto de error.

Requests de browser por dia

O Browser não tem um limite por minuto. O limite do seu plano é um número de requests de browser por dia, contados a partir da meia-noite UTC, e o medidor contabiliza todos os requests de browser admitidos, não apenas os bem-sucedidos.

{
  "error": "Daily browser limit reached: your plan allows 300 browser requests per day (resets at midnight UTC).",
  "reason": "plan_limit_browser_daily",
  "documentation": "https://foura.ai/prices",
  "limit_per_day": 300,
  "used_today": 301
}

Esta recusa não contém retry_after_seconds e nenhum header Retry-After, pois a espera é de horas em vez de segundos. Trate isso como uma interrupção e agende a próxima execução para a meia-noite UTC.

Créditos para o período de faturamento

Apenas créditos faturados contam, o que significa apenas requests bem-sucedidas. Quando o total faturado atinge os créditos disponíveis para você neste período, novas requests são recusadas até que o período seja redefinido ou você compre mais.

{
  "error": "Credit limit reached: 75,000 of 75,000 credits used this billing period. Upgrade your plan or wait for the reset.",
  "reason": "plan_limit_credits",
  "documentation": "https://foura.ai/prices",
  "used": 75000,
  "hard_stop": 75000,
  "retry_after_seconds": 86400,
  "resets_at": "2026-10-01T00:00:00.000Z"
}

hard_stop é a contagem de créditos faturados na qual as requests são interrompidas neste período. Leia este valor a partir do body em vez de calculá-lo: ele já inclui os créditos que você comprou além do plano.

Largura de banda para o período de faturamento

Planos que possuem um limite de largura de banda recusam requests assim que o tráfego padrão atinge esse limite no período. O tráfego premium tem sua própria franquia e não conta para este limite. A largura de banda comprada conta da mesma forma que a largura de banda incluída, e a string error informa o que está disponível para você, não apenas o que o plano inclui.

{
  "error": "Bandwidth limit reached: 50 GB is available to you this billing period.",
  "reason": "plan_limit_bandwidth",
  "documentation": "https://foura.ai/prices",
  "used_bytes": 53687091200,
  "limit_bytes": 53687091200,
  "retry_after_seconds": 86400,
  "resets_at": "2026-10-01T00:00:00.000Z"
}

Em ambos os limites de período, retry_after_seconds é limitado a 24 horas; resets_at é o instante exato em que o período é renovado.

Plan limit fields

Field Type Present on Description
error string all Mensagem legível para humanos, incluindo o limite aplicado a você
reason string all plan_limit_ mais o nome do limite. Mesmo valor do header X-FourA-Limit.
documentation string all Link para a página de planos
retry_after_seconds number concurrency, rate, credits, bandwidth Quanto tempo esperar. Mesmo valor do header Retry-After.
limit number concurrency Requests simultâneos que o plano permite nesse endpoint
in_flight number concurrency Requests em execução nesse endpoint para a sua conta, incluindo o que foi recusado
limit_per_minute number rate Requests por minuto que o plano permite nesse endpoint
current_rate number rate Requests contabilizados no minuto deslizante, incluindo o que foi recusado
refused_last_minute number rate pause Requests recusados pelo limite por minuto no minuto deslizante. Apenas na pausa de 30 segundos.
cooldown boolean rate pause true na pausa de 30 segundos por tentar novamente rápido demais. Ausente em uma recusa comum por minuto.
limit_per_day number browser daily Requests de navegador que o plano permite por dia
used_today number browser daily Requests de navegador contabilizados hoje, incluindo o que foi recusado
used number credits Créditos faturados até o momento neste período
hard_stop number credits Créditos faturados em que os requests são interrompidos neste período
used_bytes number bandwidth Tráfego padrão até o momento neste período, em bytes. O tráfego premium não está incluído.
limit_bytes number bandwidth Bytes disponíveis neste período
resets_at string credits, bandwidth Timestamp ISO 8601 do fim do período

Os limites do plano usam retry_after_seconds. Os limites da plataforma abaixo usam retryAfter. Um helper de retry precisa ler ambos, ou ler o header Retry-After, que apenas os limites do plano definem.

Platform Limits

As verificações da plataforma monitoram dois itens por serviço e mais um em todos eles:

  • Concurrency: quantos requests o FourA está executando ao mesmo tempo.
  • RPM: quantos requests o FourA recebeu nos últimos 60 segundos.

Ambos os contadores são compartilhados por todos os usuários desse serviço. current e limits nas respostas abaixo descrevem a plataforma, não a sua conta. Se você quiser o seu próprio número, leia in_flight a partir de uma resposta de limite do plano, ou abra Usage & Limits no dashboard.

429: RPM Exceeded

{
  "error": "Rate limit exceeded",
  "status": 429,
  "service": "single",
  "retryAfter": 5,
  "current": {
    "concurrency": 12,
    "rpm": 3000
  },
  "limits": {
    "maxConcurrency": 500,
    "maxRpm": 3000
  }
}

O serviço atingiu o limite de requests permitidas no último minuto. Aguarde retryAfter segundos.

503: Concorrência Excedida

{
  "error": "Service at capacity",
  "status": 503,
  "service": "proxy",
  "retryAfter": 2,
  "current": {
    "concurrency": 500,
    "rpm": 1200
  },
  "limits": {
    "maxConcurrency": 500,
    "maxRpm": 3000
  }
}

O serviço está executando o número máximo permitido de requests simultâneos. Isso se normaliza em segundos.

Serviço Desativado

Quando um serviço é temporariamente colocado offline para manutenção, a API retorna 503 com uma mensagem de erro diferente:

{
  "error": "Service disabled",
  "status": 503,
  "service": "single",
  "retryAfter": 60,
  "current": { "concurrency": 0, "rpm": 0 },
  "limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}

Isso não é um rate limit. O serviço está temporariamente indisponível. Verifique o valor de retryAfter e tente novamente após esse número de segundos. Isso normalmente se resolve em minutos.

Ambos os formatos de 503 trazem as mesmas chaves, portanto faça a ramificação com base na string error e nunca em quais campos estão presentes. Service disabled é manutenção, Service at capacity é concorrência.

No formato de manutenção, current.concurrency e current.rpm são sempre 0: a request foi recusada antes de qualquer medição.

Campos de Limite da Plataforma

Campo Tipo Descrição
error string Mensagem de erro legível para humanos
status number Código de status HTTP (429 ou 503)
service string Qual serviço recusou a chamada: single, proxy, browser ou api
retryAfter number Tempo de espera recomendado em segundos antes de tentar novamente
current.concurrency number Requests que o serviço estava executando em toda a plataforma quando recusou
current.rpm number Requests que o serviço recebeu em toda a plataforma nos últimos 60 segundos
limits.maxConcurrency number Limite de concorrência do serviço em toda a plataforma
limits.maxRpm number Limite por minuto do serviço em toda a plataforma

Tratando Todas as Recusas com um Único Helper

Retry-After é definido nos limites de plano pelos quais vale a pena esperar, retry_after_seconds está em seus corpos e retryAfter está nos corpos da plataforma. Leia todos os três nessa ordem e pare nos limites de plano que nenhuma espera resolverá:

import time
import requests

# Plan limits that a short wait never clears.
STOP_ON = {
    "plan_limit_feature",
    "plan_limit_premium",
    "plan_limit_browser_daily",
    "plan_limit_credits",
    "plan_limit_bandwidth",
}

def wait_seconds(resp, attempt):
    header = resp.headers.get("Retry-After")
    if header and header.isdigit():
        return int(header)
    try:
        body = resp.json()
    except ValueError:
        return 2 ** attempt
    return body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** attempt

def fetch(url, api_key, max_retries=5):
    for attempt in range(max_retries):
        resp = requests.post(
            "https://eu.api.foura.ai/api/single/",
            headers={"X-API-Key": api_key, "Content-Type": "application/json"},
            json={"method": "GET", "url": url},
        )

        limit = resp.headers.get("X-FourA-Limit")
        if limit in STOP_ON:
            raise RuntimeError(f"stopped by plan limit {limit}: {resp.json().get('error')}")

        if resp.status_code in (429, 503):
            time.sleep(wait_seconds(resp, attempt))
            continue

        return resp

    raise RuntimeError("Max retries exceeded")

Uma franquia diária não retorna por horas, e uma franquia de período não retorna por dias, portanto, trate-as como uma parada e não como uma espera. Leia resets_at do body se você quiser agendar a próxima execução.

Dicas

  • Limite o número de requests em andamento em vez de tentar novamente um lote recusado. Uma tempestade de retentativas transforma um 429 em muitos.
  • Leia X-FourA-Limit primeiro. Ele informa em uma única string se o limite é seu ou da plataforma, e nenhuma recusa da plataforma o define.
  • Não defina números fixos no código. Cada response de limite do plano informa o teto que o recusou, e Usage & Limits mostra todos eles.
  • retryAfter nos limites da plataforma é fixo por tipo: 2 segundos para simultaneidade, 5 para RPM, 60 para manutenção.
  • Faça a correspondência em error para diferenciar os dois 503s. Ambos os formatos contêm current e limits, portanto, uma verificação de "esses campos estão presentes?" interpreta manutenção como um problema de simultaneidade.
  • Um 403 com X-FourA-Limit refere-se ao seu plano, não ao site de destino. O destino nunca respondeu.

A Porta do Proxy Tem Seus Próprios Números

Tudo acima refere-se à API JSON. O tráfego enviado através de proxy.foura.ai segue um conjunto separado de números do plano, em uma unidade diferente: túneis abertos simultaneamente, aberturas de túnel por minuto e o tráfego padrão para o período de faturamento. Essas recusas chegam como um status HTTP com um header X-Foura-Error em vez de um body JSON, porque um CONNECT não tem body para incluir um. Consulte Proxy Port para a tabela de status e How Your Plan Is Metered para saber de qual pool os gigabytes da porta são consumidos.

Relacionado

Atualizado em: 30 de setembro de 2026