حدود معدل الطلبات

يمر كل طلب FourA API بثلاثة فحوصات قبل أن يصل إلى المحرك: حدود خطتك الخاصة، ثم الحصة المشتركة للمنصة الخاصة بنقطة النهاية (endpoint) التي طلبتها، ثم الحصة المشتركة للمنصة لجميع حركات المرور. يمكن لكل فحص رفض الطلب بشكل مستقل، ويستجيب كل منها بجسم استجابة (body) مختلف.

الفحوصات الثلاثة، بالترتيب

  1. حدود الخطة. ما تسمح به خطتك الخاصة: نقاط النهاية والمعلمات المضمنة، وعدد الطلبات التي يمكن تشغيلها في الوقت نفسه لكل endpoint، والعدد المسموح به في الدقيقة، وعدد طلبات المتصفح يوميا، والأرصدة والنطاق الترددي المتاحان في فترة الفوترة.
  2. حد المنصة العام. كل ما يتعامل معه مضيف API الذي استدعيته في تلك اللحظة، بغض النظر عن endpoint التي توجهت إليها حركة المرور. الرفض هنا يبلغ عن "service": "api".
  3. حد المنصة لكل endpoint. حركة المرور على خدمة single أو proxy أو browser التي طلبتها.

يتم تقييم خطتك أولا، وهذا الترتيب هو العقد المعتمد وليس مجرد تفصيل تنفيذي. الحصص المشتركة هي ملكية عامة، لذا فإن الطلب الذي كانت المنصة سترفضه حتما يجب ألا يستهلكها أثناء عملية رفضه. الحساب الذي يرسل أكثر بكثير مما تسمح به خطته يتم إيقافه قبل أن يمس أي مورد يعتمد عليه الآخرون.

الفحصان 2 و3 يحسبان إجمالي حركة مرور FourA، وليس حركة مرورك أنت. اعتبر الرفض من أي منهما بمثابة "FourA مشغولة"، وليس "أرسلت طلبات كثيرة جدا". الفحص 1 يخص حسابك وحده، ولا يتأثر بأي شيء آخر على المنصة.

الرفض من أي من الفحصين المشتركين يعيد لحسابك كل ما احتسبه قبوله، سواء حصة الدقيقة أو حصة المتصفح اليومية، لأن الطلب لم يصل أبدا إلى الواجهة الخلفية (backend). كما أنه لا يُحسب ضمن فترة إيقاف إعادة المحاولة الموضحة في الطلبات في الدقيقة أيضا: قدرة FourA الاستيعابية هي التي رفضته، وليست خطتك.

لا تحتجز POST /api/auto/ أي حصة خاصة بها. تمر الاستدعاءات الفرعية لخدمات Single وProxy وBrowser التي تجريها نيابة عنك عبر الفحوصات الثلاثة كأي طلب آخر، لذا فإن مجموعة متوازية من الاستدعاءات التلقائية تُحسب ضمن خطتك من خلال استدعاءاتها الفرعية. (تعتمد إحصاءات طلباتك ومعدل النجاح على الاستدعاء التلقائي نفسه مرة واحدة، وتظهر الاستدعاءات الفرعية كمحاولات تابعة له).

حدود الخطة

تستجيب حدود الخطة مع ترويسة X-FourA-Limit تحدد الحد الذي رفض الطلب. يوجد نفس الرمز في جسم الاستجابة تحت reason، حتى تتمكن من التعامل معه برمجيا دون قراءة الترويسات. يحمل كل جسم استجابة لحدود الخطة الحقول error وreason وdocumentation، بينما تعتمد بقية الحقول على نوع الحد.

X-FourA-Limit الحالة ما الذي تم استنفاذه
plan_limit_feature 403 الـ endpoint الذي تم استدعاؤه، أو المعامل exitCountries، غير مشمول في خطتك
plan_limit_premium 403 exitClass: premium غير مشمول في خطتك
plan_limit_concurrency 429 الطلبات المتزامنة على هذا الـ endpoint
plan_limit_rate 429 عدد الطلبات في الدقيقة على هذا الـ endpoint
plan_limit_browser_daily 429 طلبات المتصفح لليوم
plan_limit_credits 429 الأرصدة المفوترة لفترة الفاتورة
plan_limit_bandwidth 429 سعة النطاق الترددي لفترة الفاتورة

الأرقام الخاصة بكل حد تابعة لخطتك، وتسردها علامة التبويب Limits & Features في Usage & Limits بجانب استهلاكك المباشر. لا تقم بتضمينها برمجيا بشكل ثابت: كل طلب مرفوض يتضمن الحد الأقصى الذي تسبب في رفضه.

الطلب المرفوض لا يستهلك أي شيء. النتيجة هي rate_limit، وتتم فوترة success فقط.

Endpoint أو معامل غير مشمول في الخطة

الحالة 403 مع plan_limit_feature تعني أن الاستدعاء طلب شيئا غير مشمول في الخطة. يتم إجراء هذا التحقق قبل احتساب أي شيء، وبالتالي فإن الاستدعاء المرفوض لا يؤثر على معدل الطلبات أو العدادات اليومية.

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

تُرجع الشيفرة والحالة السابقتان نفسيهما استجابةً لطلب POST /api/proxy/ الذي يُحدد exitCountries ضمن خطة لا تتضمن الاستهداف الجغرافي. تُحدد سلسلة 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 له نفس الهيكل بالنسبة لـ exitClass: premium في خطة لا تتضمن premium exits. قد تقوم FourA بدلا من ذلك بخدمة مثل هذا الـ request من المجموعة القياسية (standard pool) والإبلاغ عن exitClass: standard في الـ response، لذا تعامل مع كلتا الإجابتين. لا يستهلك أي منهما premium exit. راجع exitClass.

لا يقوم أي من خطأي 403 بتعيين Retry-After. لن يؤدي الانتظار إلى تغيير النتيجة.

Simultaneous requests

يتم احتساب التزامن (Concurrency) لكل endpoint: تتضمن خطتك حدا أقصى واحدا لـ Single، وواحدا لـ Proxy، وواحدا لـ Browser. يتم إرجاع الـ request الذي يتجاوز الحد كرمز 429 مع 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 يحسب الـ request المرفوض أيضاً، لذا يقرأ قيمة تزيد بواحد على الأقل مقارنة بـ limit.

الحل هو تقييد التوازي (parallelism) لديك بدلاً من زيادة وتيرة المحاولة. الرد على 429 بإعادة إرسال نفس الحزمة فوراً يؤدي إلى إنتاج 429 أخرى لكل استدعاء فيها. راجع تشغيل Requests بالتوازي للاطلاع على نمط عمل تطبيقي.

Requests لكل دقيقة

يتضمن كل من Single و Proxy حداً مسموحاً به في الدقيقة، يُحسب على مدار دقيقة منزلقة (sliding minute). فقط الـ requests المقبولة هي التي تُحسب ضمنه: يتم استبعاد الـ request المرفوض، بحيث إذا أرسل الحساب بانتظام معدلاً يتجاوز حده المسموح به بقليل، فسيتم تلبية الحد المسموح به له بدلاً من رفض كل شيء تقريباً.

{
  "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 هي المدة المتبقية حتى يتم قبول request إضافي واحد، إذا لم تقم بإرسال أي شيء آخر في هذه الأثناء: ثانية واحدة على الأقل و120 ثانية كحد أقصى. يحمل الـ header‏ Retry-After نفس القيمة.

إعادة محاولة الـ requests المرفوضة بسرعة أكبر من ذلك تخضع لقاعدة خاصة بها. عندما تتجاوز الـ requests التي رفضها هذا المخصص خلال الدقيقة المتحركة ضعف المخصص، يتم رفض الاستدعاء مع فترة توقف مؤقت مدتها 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
}

لا تُحتسب عمليات الرفض أثناء فترة الإيقاف المؤقت، لذا ينتهي الإيقاف تلقائيًا مع مرور الدقيقة، حتى بالنسبة للعميل الذي يواصل إعادة المحاولة. للتمييز بين فترة الإيقاف المؤقت والحصة العادية، اقرأ cooldown بدلاً من نص error.

طلبات المتصفح يوميًا

لا يملك Browser حصة لكل دقيقة. حد الخطة الخاص به هو عدد طلبات المتصفح يوميًا، محسوبة بدءًا من منتصف الليل بتوقيت UTC، ويحسب العداد كل طلب متصفح مقبول، وليس الطلبات الناجحة فقط.

{
  "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، لأن فترة الانتظار بالساعات وليست بالثواني. تعامل معه كإيقاف وجدول التشغيل التالي عند منتصف الليل بتوقيت UTC.

Credits لفترة الفوترة

يتم احتساب الـ credits المفوترة فقط، ما يعني الطلبات الناجحة فقط. عندما يصل الإجمالي المفوتر إلى الـ credits المتاحة لك في هذه الفترة، سيتم رفض أي طلبات إضافية حتى تتم إعادة تعيين الفترة أو تقوم بشراء المزيد.

{
  "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 هو عدد الرصيد المحتسب الذي تتوقف عنده الـ requests خلال هذه الفترة. اقرأه من الـ body بدلاً من حسابه: فهو يتضمن بالفعل أي رصيد اشتريته بالإضافة إلى الخطة.

Bandwidth لفترة الفوترة

الخطط التي تتضمن حد أقصى للـ bandwidth ترفض الـ requests بمجرد وصول حركة المرور القياسية لهذه الفترة إليه. حركة مرور Premium لها حصتها الخاصة ولا تُحتسب ضمن هذا الحد الأقصى. يُحتسب الـ bandwidth المشترى تماماً مثل الـ bandwidth المضمن، ويعرض نص 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 هو اللحظة الدقيقة لبدء دورة الفترة التالية.

حقول حدود الخطة

الحقل النوع متوفر في الوصف
error string الكل رسالة مقروءة للمستخدم، تتضمن الرقم المحدد لك
reason string الكل plan_limit_ مضافا إليه اسم الحد. نفس قيمة الترويسة X-FourA-Limit.
documentation string الكل رابط إلى صفحة الخطط
retry_after_seconds number التزامن، المعدل، الرصيد، سعة النطاق مدة الانتظار. نفس قيمة الترويسة Retry-After.
limit number التزامن عدد الطلبات المتزامنة التي تسمح بها الخطة على نقطة النهاية تلك
in_flight number التزامن الطلبات قيد التشغيل على نقطة النهاية تلك لحسابك، بما فيها الطلب المرفوض
limit_per_minute number المعدل عدد الطلبات في الدقيقة التي تسمح بها الخطة على نقطة النهاية تلك
current_rate number المعدل الطلبات المحتسبة خلال الدقيقة المنزلقة، بما فيها الطلب المرفوض
refused_last_minute number إيقاف المعدل مؤقتا الطلبات التي رفضها حد الدقيقة خلال الدقيقة المنزلقة. يظهر فقط عند الإيقاف المؤقت لمدة 30 ثانية.
cooldown boolean إيقاف المعدل مؤقتا true عند الإيقاف المؤقت لمدة 30 ثانية بسبب إعادة المحاولة بسرعة كبيرة. غير موجود عند الرفض العادي لكل دقيقة.
limit_per_day number المتصفح اليومي طلبات المتصفح التي تسمح بها الخطة يوميا
used_today number المتصفح اليومي طلبات المتصفح المحتسبة اليوم، بما فيها الطلب المرفوض
used number الرصيد الرصيد المحتسب حتى الآن خلال هذه الفترة
hard_stop number الرصيد الرصيد المحتسب الذي تتوقف عنده الطلبات خلال هذه الفترة
used_bytes number سعة النطاق حركة المرور القياسية حتى الآن خلال هذه الفترة، بالبايت. لا تشمل حركة المرور المتميزة.
limit_bytes number سعة النطاق البايتات المتاحة خلال هذه الفترة
resets_at string الرصيد، سعة النطاق طابع زمني بتنسيق ISO 8601 لنهاية الفترة

تستخدم حدود الخطة retry_after_seconds. وتستخدم حدود المنصة أدناه retryAfter. يجب أن تقرأ أداة إعادة المحاولة المساعدة كلا الحقلين، أو تقرأ الترويسة Retry-After التي تحددها حدود الخطة فقط.

حدود المنصة

تتبع عمليات فحص المنصة أمرين لكل خدمة وأمرا إضافيا عبر جميع الخدمات:

  • التزامن: عدد الطلبات التي ينفذها FourA في الوقت نفسه.
  • RPM: عدد الطلبات التي استقبلها FourA في آخر 60 ثانية.

يشترك جميع مستخدمي تلك الخدمة في كلا العدادين. يصف كل من current وlimits في الاستجابات أدناه المنصة، وليس حسابك. إذا كنت تريد معرفة أرقامك الخاصة، فاقرأ in_flight من استجابة حد الخطة، أو افتح الاستخدام والحدود في لوحة التحكم.

429: تم تجاوز RPM

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

استنفدت الخدمة عدد الـ requests المسموح به خلال الدقيقة الأخيرة. انتظر retryAfter ثانية.

503: تم تجاوز حد التزامن (Concurrency Exceeded)

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

يقوم service بتشغيل أكبر عدد ممكن من requests المسموح له بتشغيلها في وقت واحد. تتم معالجة هذا خلال ثوانٍ.

Service Disabled

عند إيقاف service مؤقتًا للصيانة، يرجع API الرمز 503 مع رسالة خطأ مختلفة:

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

هذا ليس rate limit. الخدمة غير متوفرة مؤقتا. تحقق من قيمة retryAfter وأعد المحاولة بعد هذا العدد من الثواني. عادة ما يتم حل هذا الأمر في غضون دقائق.

يحمل كلا شكلي 503 نفس المفاتيح، لذا قم بالتفريع بناء على سلسلة error وليس على الحقول الموجودة. Service disabled تعني الصيانة، و Service at capacity تعني التزامن.

في شكل الصيانة، يكون current.concurrency و current.rpm دائما 0: تم رفض الـ request قبل قياس أي شيء.

حقول حدود المنصة

الحقل النوع الوصف
error string رسالة خطأ مقروءة للمستخدم
status number رمز حالة HTTP (429 أو 503)
service string الخدمة التي رفضت الاستدعاء: single، أو proxy، أو browser، أو api
retryAfter number وقت الانتظار الموصى به بالثواني قبل إعادة المحاولة
current.concurrency number عدد الـ requests التي كانت الخدمة تشغلها على مستوى المنصة عند الرفض
current.rpm number عدد الـ requests التي استقبلتها الخدمة على مستوى المنصة في آخر 60 ثانية
limits.maxConcurrency number حد التزامن المسموح به للخدمة على مستوى المنصة
limits.maxRpm number الحد المسموح به للخدمة في الدقيقة على مستوى المنصة

معالجة كل حالات الرفض باستخدام Helper واحد

يتم تعيين Retry-After على حدود الخطة التي تستحق الانتظار، ويكون retry_after_seconds في نصوصها، و retryAfter في نصوص المنصة. اقرأ الثلاثة بهذا الترتيب، وتوقف عند حدود الخطة التي لن يجدي معها أي انتظار:

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")

الحصة اليومية لا تعود إلا بعد ساعات، وحصة الفترة لا تعود إلا بعد أيام، لذا تعامل معهما كإيقاف تام وليس مجرد انتظار. اقرأ resets_at من جسم الاستجابة إذا كنت ترغب في جدولة التشغيل التالي.

نصائح

  • حدد الحد الأقصى لعدد الطلبات قيد التنفيذ بدلا من إعادة محاولة إرسال دفعة مرفوضة. عاصفة إعادات المحاولة تحول خطأ 429 واحدا إلى أخطاء كثيرة.
  • اقرأ X-FourA-Limit أولا. يخبرك في نص واحد ما إذا كان الحد خاصا بك أو بالمنصة، ولا يضبطه أي رفض صادر عن المنصة.
  • لا تدرج الأرقام في الكود بشكل ثابت. تحمل كل استجابة لحدود الخطة الحد الأقصى الذي تسبب في الرفض، وتعرض صفحة الاستخدام والحدود جميع هذه الحدود.
  • يتم تحديد قيمة retryAfter عند حدود المنصة حسب النوع: ثانيتان للتزامن، 5 لعدد الطلبات في الدقيقة (RPM)، 60 للصيانة.
  • طابق قيمة error للتمييز بين نوعي أخطاء 503. يحمل كلا النموذجين الحقلين current و limits، لذا فإن مجرد التحقق من "هل هذه الحقول موجودة؟" سيفسر الصيانة على أنها مشكلة تزامن.
  • خطأ 403 مع X-FourA-Limit يتعلق بخطتك، وليس بالموقع المستهدف. الموقع المستهدف لم يستجب من الأساس.

يحتوي منفذ Proxy على أرقامه الخاصة

كل ما سبق يختص بواجهة برمجة التطبيقات JSON API. حركة المرور التي ترسلها عبر proxy.foura.ai تخضع لمجموعة منفصلة من أرقام الخطة، وبوحدة قياس مختلفة: الأنفاق المفتوحة في وقت واحد، ومرات فتح الأنفاق في الدقيقة، وحركة المرور القياسية لفترة الفاتورة. تأتي عمليات الرفض هذه كحالة HTTP مع ترويسة X-Foura-Error بدلا من جسم JSON، لأن طلب CONNECT لا يحتوي على جسم لوضعها فيه. راجع منفذ Proxy للاطلاع على جدول الحالات و كيفية قياس استهلاك خطتك لمعرفة الحصة التي تُخصم منها غيغابايتات المنفذ.

مواضيع ذات صلة

آخر تحديث: 30 سبتمبر 2026