レート制限
すべてのFourA API requestは、エンジンに到達する前に3つのチェックを通過します。まずご利用プランの制限、次に呼び出したendpointに対するプラットフォームの共有枠、最後にすべてのトラフィックに対するプラットフォームの共有枠です。各チェックは個別にrequestを拒否でき、それぞれ異なるbodyで応答します。
3つのチェック(順序通り)
- プラン制限。 ご利用のプランで許可されている内容です。含まれるendpointとパラメータ、endpointごとに同時に実行可能なrequest数、1分あたりの件数、1日あたりのブラウザrequest数、および請求期間内に利用可能なクレジットと帯域幅が含まれます。
- グローバルプラットフォーム制限。 トラフィックの送信先endpointに関わらず、呼び出したAPIホストがその時点で処理しているすべてのトラフィックです。ここでの拒否は
"service": "api"を報告します。 - endpointごとのプラットフォーム制限。 呼び出したsingle、proxy、またはbrowserサービス上のトラフィックです。
ご利用のプランが最初に判定されます。この順序は実装上の詳細ではなく契約仕様です。共有枠は全ユーザーの共有リソースであるため、プラットフォームが拒否することになるrequestが、拒否される過程でその枠を消費してはなりません。プランの許可枠を大幅に超えて送信しているアカウントは、他のユーザーが利用するリソースに触れる前に遮断されます。
チェック2と3は、ユーザー自身ではなくFourA全体のトラフィックをカウントします。いずれかによる拒否は、「送信量が多すぎる」ではなく「FourAが混雑している」と解釈してください。チェック1はお客様のアカウントのみを対象としており、プラットフォーム上の他の要素によって変動することはありません。
共有チェックのいずれかで拒否された場合、requestはバックエンドに到達しなかったため、分単位のバケットやブラウザの日次スロットなど、受付時にカウントされたすべてのリソースがアカウントに返還されます。また、Requests per minuteに記載されているリトライ待機時間にもカウントされません。プランではなくFourAのキャパシティによって拒否されたためです。
POST /api/auto/自体はスロットを保持しません。代理で実行されるSingle、Proxy、Browserのサブコールは、他のrequestと同様に3つのチェックをすべて通過します。そのため、autoコールの並列バッチはサブコールを通じてプランにカウントされます。(request数と成功率はautoコール自体を1回としてカウントし、サブコールはその試行として表示されます。)
プラン制限
プラン制限による拒否は、呼び出しを拒否した制限の名前を示すX-FourA-Limitヘッダーで応答します。同じコードはbody内のreasonにも含まれているため、headerを読み取らずに条件分岐できます。すべてのプラン制限bodyにはerror、reason、documentationが含まれ、残りのフィールドは制限の種類によって異なります。
X-FourA-Limit |
ステータス | 枯渇した項目 |
|---|---|---|
plan_limit_feature |
403 | 呼び出した endpoint または exitCountries パラメータがプランに含まれていません |
plan_limit_premium |
403 | exitClass: premium はプランに含まれていません |
plan_limit_concurrency |
429 | その endpoint における同時 request 数 |
plan_limit_rate |
429 | その endpoint における 1 分あたりの request 数 |
plan_limit_browser_daily |
429 | 1 日あたりのブラウザ request 数 |
plan_limit_credits |
429 | 請求期間の請求対象クレジット |
plan_limit_bandwidth |
429 | 請求期間の帯域幅 |
各制限値はプランによって異なり、Usage & Limits の Limits & Features タブで現在の使用状況と並んで表示されます。これらをハードコードしないでください。すべての拒否レスポンスには、拒否理由となった上限値が含まれます。
拒否された request はクレジットを消費しません。結果は rate_limit となり、請求対象となるのは success のみです。
プランに含まれていない Endpoint またはパラメータ
plan_limit_feature を伴う 403 は、プランに含まれていない機能を呼び出しが要求したことを意味します。このチェックはいかなるカウントよりも前に実行されるため、拒否された呼び出しが rate limit や日次カウンターに影響することはありません。
{
"error": "The browser endpoint is not included in your plan (Free). Upgrade to use it.",
"reason": "plan_limit_feature",
"documentation": "https://foura.ai/prices"
}
ジオターゲティングのないプランで exitCountries を設定した POST /api/proxy/ 呼び出しに対しても、同じコードとステータスが返されます。error 文字列に対象のパラメータ名が含まれます:
{
"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 は、Premium 出口のないプランにおける exitClass: premium に対しても同じ形式になります。FourA は代わりに標準プールからこのようなリクエストを処理し、レスポンスで exitClass: standard を報告する場合があるため、両方の応答を処理できるようにしてください。どちらの場合も Premium 出口は消費されません。exitClass を参照してください。
どちらの 403 も Retry-After を設定しません。待機しても結果は変わりません。
同時リクエスト
同時実行数はエンドポイントごとにカウントされます。プランには Single 用、Proxy 用、Browser 用の各上限が個別に設定されています。上限を超えたリクエストは Retry-After: 1 を含む 429 として返されます。
{
"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 は拒否されたリクエストもカウントするため、limit より少なくとも1つ多く読み取られます。
解決策は、無作為にリトライするのではなく、並行数を制限することです。429に対して同じバッチを即座に再送信すると、バッチ内のすべての呼び出しで再び429が発生します。実際の実装パターンについては リクエストを並行して実行 を参照してください。
Requests per minute
Single と Proxy には、スライディングウィンドウ(1分間)で測定される1分あたりの許容量があります。許可されたリクエストのみがカウント対象となります。拒否されたリクエストは差し引かれるため、許容量をわずかに超えて安定してリクエストを送信するアカウントでも、ほぼすべてが拒否されるのではなく、許容量の上限まで処理されます。
{
"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 は、その間に追加の送信を行わなかった場合に次の1件の request が許可されるまでの待機時間(最短1秒、最長120秒)を示します。Retry-After header にも同じ値が設定されます。
拒否された request をこれより早く再試行する場合のルールも存在します。直近1分間のスライディングウィンドウ内でこの割り当てによって拒否された request 数が割り当て制限の2倍を超えると、呼び出しは代わりに30秒の待機を伴って拒否されます。
{
"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
}
一時停止中の拒否はカウントされないため、クライアントがリトライを続けても、時間が経過すれば一時停止は自動的に終了します。通常のリクエスト枠と一時停止を区別するには、errorのテキストではなくcooldownを確認してください。
1日あたりのBrowser requests
Browserには分単位の枠はありません。プラン制限はUTC午前0時からカウントされる1日あたりのBrowser requests数であり、メーターは成功したものだけでなく、受け入れられたすべてのBrowser requestをカウントします。
{
"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
}
この拒否レスポンスには retry_after_seconds および Retry-After header は含まれません。待機時間が秒単位ではなく数時間におよぶためです。処理を停止し、次回の実行を UTC 午前0時にスケジュールしてください。
請求期間のクレジット
請求対象のクレジットのみがカウントされます。つまり、成功した request のみが対象です。請求合計が今期利用可能なクレジットに達すると、期間がリセットされるか追加購入するまで、以降の request は拒否されます。
{
"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 は、今期の request が停止する請求対象クレジット数です。自身で計算せず body から読み取ってください。プランに追加で購入したクレジットが既に含まれています。
請求期間の帯域幅
帯域幅の上限があるプランでは、今期の標準トラフィックが上限に達すると request を拒否します。プレミアムトラフィックには独自の使用枠があり、この上限にはカウントされません。追加購入した帯域幅はプラン付属の帯域幅と同様にカウントされ、error 文字列にはプラン単体の上限ではなく実際に利用可能な値が提示されます。
{
"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"
}
両方の期間制限において、retry_after_secondsの上限は24時間です。resets_atは期間が更新される正確な日時です。
Plan limit fields
| Field | Type | Present on | Description |
|---|---|---|---|
error |
string | all | 適用されている制限値を含む、人間が読める形式のメッセージ |
reason |
string | all | plan_limit_と制限名。X-FourA-Limitヘッダーと同じ値。 |
documentation |
string | all | プランページへのリンク |
retry_after_seconds |
number | concurrency, rate, credits, bandwidth | 待機時間。Retry-Afterヘッダーと同じ値。 |
limit |
number | concurrency | そのendpointでプランが許可する同時実行request数 |
in_flight |
number | concurrency | アカウント内でそのendpoint上を実行中のrequest数(拒否されたrequestを含む) |
limit_per_minute |
number | rate | そのendpointでプランが許可する1分間あたりのrequest数 |
current_rate |
number | rate | スライディング1分間でカウントされたrequest数(拒否されたrequestを含む) |
refused_last_minute |
number | rate pause | スライディング1分間で1分間あたりの許容量により拒否されたrequest数。30秒間の一時停止時のみ。 |
cooldown |
boolean | rate pause | リトライが早すぎることによる30秒間の一時停止時はtrue。通常の1分制限拒否時は存在しません。 |
limit_per_day |
number | browser daily | プランで許可されている1日あたりのブラウザrequest数 |
used_today |
number | browser daily | 本日カウントされたブラウザrequest数(拒否されたrequestを含む) |
used |
number | credits | 今期間のこれまでの請求対象クレジット |
hard_stop |
number | credits | 今期間でrequestが停止する請求対象クレジット数 |
used_bytes |
number | bandwidth | 今期間のこれまでの標準トラフィック(バイト単位)。プレミアムトラフィックは含まれません。 |
limit_bytes |
number | bandwidth | 今期間で利用可能なバイト数 |
resets_at |
string | credits, bandwidth | 期間終了日時のISO 8601タイムスタンプ |
プラン制限はretry_after_secondsを使用します。以下のプラットフォーム制限はretryAfterを使用します。リトライヘルパーは両方を読み取るか、プラン制限のみが設定するRetry-Afterヘッダーを読み取る必要があります。
Platform Limits
プラットフォームチェックは、サービスごとに2つの項目を追跡し、全サービス全体でさらに1つを追跡します。
- Concurrency: FourAが同時に実行しているrequest数。
- RPM: FourAが過去60秒間に受信したrequest数。
両方のカウンターは、そのサービスを使用する全員で共有されます。以下のresponseに含まれるcurrentおよびlimitsは、お客様のアカウントではなくプラットフォームの状態を示します。独自の値を確認したい場合は、プラン制限responseからin_flightを読み取るか、dashboardのUsage & Limitsを開いてください。
429: RPM Exceeded
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": {
"concurrency": 12,
"rpm": 3000
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
直近1分間のリクエスト上限に達しました。retryAfter秒待機してください。
503: Concurrency Exceeded
{
"error": "Service at capacity",
"status": 503,
"service": "proxy",
"retryAfter": 2,
"current": {
"concurrency": 500,
"rpm": 1200
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
サービスは同時に実行できる最大数のrequestを実行しています。これは数秒で解消されます。
Service Disabled
メンテナンスのためにサービスが一時的にオフラインになっている場合、APIは別のエラーメッセージとともに503を返します:
{
"error": "Service disabled",
"status": 503,
"service": "single",
"retryAfter": 60,
"current": { "concurrency": 0, "rpm": 0 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
これはレート制限ではありません。サービスが一時的に利用不可になっています。retryAfter の値を確認し、指定された秒数待機してから再試行してください。通常は数分以内に解決します。
どちらの 503 形式も同じキーを持つため、存在するフィールドではなく error 文字列で分岐してください。Service disabled はメンテナンス、Service at capacity は同時実行数によるものです。
メンテナンス形式では、current.concurrency と current.rpm は常に 0 になります。測定が行われる前にリクエストが拒否されたことを示します。
プラットフォーム制限フィールド
| フィールド | タイプ | 説明 |
|---|---|---|
error |
string | 人間が読める形式のエラーメッセージ |
status |
number | HTTP ステータスコード (429 または 503) |
service |
string | 呼び出しを拒否したサービス: single, proxy, browser, または api |
retryAfter |
number | 再試行までの推奨待機時間 (秒) |
current.concurrency |
number | 拒否時にサービスがプラットフォーム全体で実行していたリクエスト数 |
current.rpm |
number | 過去60秒間にサービスがプラットフォーム全体で受け付けたリクエスト数 |
limits.maxConcurrency |
number | プラットフォーム全体におけるサービスの同時実行許容量 |
limits.maxRpm |
number | プラットフォーム全体におけるサービスの1分あたりの許容量 |
1つのヘルパーですべての拒否を処理する
待機する価値のあるプラン制限では Retry-After が設定され、そのボディには retry_after_seconds が含まれ、プラットフォームのボディには retryAfter が含まれます。この順序で3つすべてを読み取り、待機しても解消されないプラン制限で停止します。
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")
日次クォータの回復には数時間、期間クォータの回復には数日かかるため、待機ではなく処理停止として扱ってください。次回の実行をスケジュールする場合は、bodyからresets_atを読み取ります。
Tips
- 拒否されたバッチを再試行するのではなく、インフライトのrequest数を制限してください。再試行ストームは1つの429を大量の429へと悪化させます。
- まず
X-FourA-Limitを確認してください。その制限が自身のアカウント起因かプラットフォーム起因かを1つの文字列で判別でき、プラットフォーム側の拒否でこれが設定されることはありません。 - 数値をハードコードしないでください。プラン制限の各responseには拒否理由となった上限値が含まれており、Usage & Limitsですべて確認できます。
- プラットフォーム制限時の
retryAfterは種別ごとに固定です: 同時実行数は2秒、RPMは5秒、メンテナンスは60秒です。 - 2種類の503を区別するには
errorでマッチングしてください。どちらの形式にもcurrentとlimitsが含まれるため、「これらのフィールドが存在するか」だけのチェックではメンテナンスが同時実行数の問題として判定されてしまいます。 X-FourA-Limitを含む403はプランに関するものであり、ターゲットサイトに関するものではありません。ターゲットは応答していません。
The Proxy Port Has Its Own Numbers
上記はすべてJSON APIに関する内容です。proxy.foura.ai経由で送信されるトラフィックには、異なる単位(同時オープントンネル数、毎分のトンネルオープン数、請求期間の標準トラフィック)の個別のプラン数値が適用されます。CONNECTには格納するbodyが存在しないため、これらの拒否はJSON bodyではなくX-Foura-Error headerを伴うHTTPステータスとして返されます。ステータス表についてはProxy Portを、ポートのギガバイトがどのプールから消費されるかについてはHow Your Plan Is Meteredを参照してください。
Related
- Run Requests in Parallel: 同時実行数制限の実装パターン
- Usage & Limits: すべてのプラン制限と現在の使用状況
- API Endpoints: パラメータリファレンス完全版
- Error Handling: すべてのエラータイプとresponse
- Response Headers:
X-FourA-Limit、Retry-After、その他 - Troubleshooting: 一般的な問題と解決策