APIエラー
FourA APIからのエラーの処理方法。
エラーレスポンスの形式
APIはすべてのエラーに対してフラットなJSONオブジェクトを返します。ネストされたerrorオブジェクトやエラーコードはありません。
{
"error": "Invalid API key"
}
一部のエラーには、トップレベルにstatus、service、retryAfter、current、limitsなどの追加フィールドが含まれます。
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
リクエストの追跡
すべてのAPI response(成功またはエラー)には、その呼び出しのUUIDを含むX-Foura-Request-Id headerが含まれています。これを開発者側でログに記録してください。特定のリクエストに何が起こったかをサポートに問い合わせる際、このIDがあれば弊社で調査できます。
curl -i -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://example.com"}'
# HTTP/1.1 200 OK
# X-Foura-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
# Content-Type: application/json
# ...
エラータイプ
400: Bad Request
request bodyに必要なフィールドが不足しているか、無効な値が含まれているか、またはAPIが取得を拒否するターゲットを指定しています。
{
"error": "Invalid request body format"
}
同じ400はSSRF保護も対象としています。urlがプライベート、ループバック、またはその他の予約済みIP範囲(RFC 5735、RFC 6598、IPv6予約済みブロック)に解決される場合、requestはFourAのネットワークから送信される前に拒否されます。
{
"error": "Target <ip> resolves to a private/reserved IP"
}
解決策: requestに必要なすべてのフィールドが含まれていること、URLがhttp://またはhttps://を使用していること、およびホストがパブリックアドレスに解決されることを確認してください。
401: Unauthorized
API keyが不足しているか、無効です。
キーが不足している場合:
{
"error": "Missing API key. Include X-API-Key header."
}
キーが無効な場合:
{
"error": "Invalid API key"
}
解決策: X-API-Key headerに有効なキーが含まれていることを確認してください。必要に応じて、Dashboardから新しいキーを生成してください。
429: Rate Limited
短時間に送信されたrequestが多すぎます。
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
解決策: さらにrequestを送信する前に、retryAfterに示された秒数だけ待機してください。詳細はRate Limitsを参照してください。
500: Server Error
弊社側で問題が発生しました。
解決策: 少し時間を置いてからrequestを再試行してください。エラーが解消されない場合は、status pageを確認するか、失敗したresponseのX-Foura-Request-Idを添えてサポートにお問い合わせください。
503: Service Disabled or At Capacity
503は、メンテナンスのためにサービスが一時的に利用できないか、同時実行制限に達したことを意味します。どちらのresponseにもretryAfterフィールドが含まれています。同時実行制限によるエラーの場合は、currentとlimitsも含まれます。
{
"error": "Service disabled",
"status": 503,
"retryAfter": 60
}
解決策: retryAfter秒待ってから再試行してください。ステータスページにアクティブなメンテナンス期間が記載されています。
200 OK内のターゲット側のエラー
すべてのエラーが2xx以外のHTTPステータスとして表示されるわけではありません。ターゲットサイトがエラーペイロードを含むHTTP 200を返した場合、FourAはbodyをそのまま渡しますが、requestをapplication_errorとして分類します。ターゲットが、設定したvalidateルールで許容されない2xx以外のステータスを返した場合、結果はapplication_failとなり、bodyは変更されずに渡されます。
どちらの場合も、通信レベルでrequestが成功したかのように課金対象となります。Outcomesのリファレンスで詳細な分類を説明しています。
レスポンスのエンコーディング
FourAはresponse bodyをUTF-8に自動デコードします。ターゲットがwindows-1251、gbk、shift_jis、iso-8859-*、またはContent-Type headerやHTMLの<meta charset>タグで宣言されたその他の文字セットを提供している場合、data(single、proxy)またはbody(browser)フィールドでクリーンなUTF-8文字列を受け取ります。
バイナリペイロード(画像、protobuf、生の音声など)の場合は、requestでreturnBuffer: trueを設定してください。bodyは、文字セットの変換が適用されないbase64バッファとして返されます。
リトライ戦略
実用的なリトライポリシーの例:
import time
import requests
def make_request(url, payload, api_key, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
url,
headers={"X-API-Key": api_key, "Content-Type": "application/json"},
json=payload,
)
if resp.status_code == 200:
return resp.json()
body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
retry_after = body.get("retryAfter", 2 ** attempt)
request_id = resp.headers.get("X-Foura-Request-Id", "?")
if resp.status_code in (429, 503):
time.sleep(retry_after)
continue
if resp.status_code >= 500:
time.sleep(2 ** attempt)
continue
# 400/401/404 won't fix themselves
raise RuntimeError(f"{resp.status_code} (request {request_id}): {body.get('error')}")
raise RuntimeError(f"Exhausted {max_retries} retries")
関連情報
- Rate Limits: 同時実行数とRPMの詳細
- Request Outcomes: 7つの結果(outcome)値の解説
- Common Issues: 現象、原因、解決策