ترويسات الاستجابة
يتضمن كل response من FourA API مجموعة صغيرة من الـ headers المخصصة. وهي مفيدة للتتبع والدعم ومطابقة الفواتير والتحليل اللاحق.
Headers التي تضبطها FourA
| Header | يتم ضبطه في | الوصف |
|---|---|---|
X-FourA-Request-Id |
كل response لـ /api/*، بما في ذلك أخطاء 401، باستثناء الـ body الذي لا تستطيع FourA قراءته على الإطلاق (400 Invalid JSON in request body، 413)، والذي يتم رفضه قبل تعيين معرف |
UUID يحدد هذا الـ request. سجله في السجلات من جانبك. |
X-FourA-Credits |
كل response لـ /api/* وصل إلى الـ backend |
الرصيد المستهلك في هذا الاستدعاء. يتم إرجاعه في حالة النجاح وفي حالة الفشل (تم تنفيذ العمل في الحالتين). |
X-FourA-Limit |
كل 403 أو 429 ناتج عن أحد حدود خطتك |
الحد الذي رفض الاستدعاء: plan_limit_ متبوعا بـ feature، أو premium، أو concurrency، أو rate، أو browser_daily، أو credits، أو bandwidth. |
Retry-After |
حالات 429 لحدود الخطة التي تنتهي بالانتظار: التزامن، أو معدل الطلبات، أو الرصيد، أو سعة النطاق الترددي |
عدد الثواني للانتظار كعدد صحيح. يطابق retry_after_seconds في الـ body. |
X-FourA-Exit-Class |
كل استدعاء /api/proxy/ حدد exitClass وقام بتسليم صفحة، وكل استدعاء Single أو Browser تم تقديمه عبر مخرج مدفوع |
premium أو standard: فئة المخرج التي سلمت الـ body. استدعاء Proxy الفاشل لم يسلم شيئا ولا يحمل أيا منها. |
X-FourA-Check-Page |
استجابات Single وProxy Finder وBrowser التي يكون الـ body الخاص بها برمز HTTP 200 عبارة عن صفحة فحص bot تتعرف عليها FourA | اسم صفحة الفحص، على سبيل المثال amazon-captcha. لا تتم محاسبة هذا الـ request: راجع Request Outcomes. |
Content-Type |
كل response | دائما application/json للـ envelope. يتم إرجاع content-type للهدف داخل حقل headers في الـ envelope. |
X-FourA-Request-Id
يتم وضع وسم UUID على كل استدعاء لـ POST /api/auto/ أو POST /api/single/ أو POST /api/proxy/ أو POST /api/browser/. يتم تعيين الـ header حتى في حالة فشل المصادقة، حتى تتمكن من ربط الاستدعاءات التي تحتوي على أخطاء في الإعداد أيضا.
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
X-FourA-Credits: 2
Content-Type: application/json
...
حالات الاستخدام
- تذاكر الدعم: قم بتضمين request ID وسنتمكن من العثور على الاستدعاء الدقيق في سجلاتنا.
- سجلاتك الخاصة: قم بتخزينه بجانب سطر سجل تطبيقك. إذا وردت شكوى من عميل تفيد بأن "البيانات كانت غير صحيحة عند الساعة 14:32"، يمكنك إعادة تشغيل نفس الـ request بدقة.
- التتبع عبر Dashboard: يظهر نفس الـ ID في Activity feed للمفاتيح التي تديرها، ما يتيح لك فتح الصف المطابق وفحص الـ request والـ response الملتقطين.
مثال: التسجيل من جانبك
import logging
import requests
log = logging.getLogger(__name__)
def fetch(url, api_key):
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},
)
request_id = resp.headers.get("X-FourA-Request-Id", "no-id")
credits = resp.headers.get("X-FourA-Credits", "0")
log.info("foura request_id=%s url=%s status=%s credits=%s", request_id, url, resp.status_code, credits)
resp.raise_for_status()
return resp.json()
async function fetchPage(url, apiKey) {
const resp = await fetch('https://eu.api.foura.ai/api/single/', {
method: 'POST',
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({ method: 'GET', url })
});
const requestId = resp.headers.get('X-FourA-Request-Id') || 'no-id';
const credits = resp.headers.get('X-FourA-Credits') || '0';
console.log(`foura request_id=${requestId} url=${url} status=${resp.status} credits=${credits}`);
return resp.json();
}
X-FourA-Credits
يعرض X-FourA-Credits تكلفة الرصيد (credits) للطلب الذي قمت بإجرائه للتو. إنه مقياس وليس فاتورة: يعكس الـ header ما تم استهلاكه في العملية بغض النظر عن النتيجة. طبقة الفوترة في لوحة التحكم تحتسب فقط النتائج الخاضعة للفوترة ضمن خطتك (راجع Request Outcomes لمعرفة النتائج الخاضعة للفوترة).
مرجع التكلفة
| Engine | Base | مع unblocker |
|---|---|---|
| Single | 1 | 2 |
| Proxy | 2 | 4 |
| Browser | 5 | 10 (عند حل نظام حماية) |
يُعد /api/auto/ بمثابة request واحد في لوحة التحكم الخاصة بك، وتكون تكلفة الرصيد الخاصة به هي مجموع الطلبات الفرعية التي أجراها داخليًا (يمكن أن تنتهي إعادة طلب واحدة على هدف نشط بتكلفة 2، بينما قد يستهلك الحل من الصفر على موقع معقد تكلفة أكبر بكثير). تتطابق قيمة X-FourA-Credits في الـ auto response مع meta.credits في الـ body، وتتتبع تكلفة المحاولات المتدرجة بالكامل.
لماذا يوجد header وحقل body معًا؟
الـ header عملي للغاية: يمكنك قراءته قبل تحليل الـ body، أو تسجيله في السجلات بجانب سطر الـ request، أو حسابه إجماليًا عبر العديد من الطلبات دون الحاجة لمعالجة JSON. يحتوي حقل meta.credits في الـ body (في Auto) أو البيانات الوصفية الخاصة بكل engine (في لوحات تحكم Single وProxy وBrowser) على نفس الرقم، ولكنه متاح للقراءة داخل هيكل الـ response.
X-FourA-Limit
يظهر X-FourA-Limit فقط عندما يرفض أحد حدود خطتك هذا الـ call. لا يتم تعيينه أبدًا بواسطة حدود معدل الاستخدام (rate limits) المشتركة للمنصة، لذا فإن الـ header هو أسرع طريقة للتمييز بين "خطتي أوقفت هذا" و"FourA مشغول" دون الحاجة لتحليل الـ body.
HTTP/1.1 429 Too Many Requests
X-FourA-Limit: plan_limit_concurrency
Retry-After: 1
X-FourA-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
Content-Type: application/json
قيمتان من القيم السبع تأتيان مع رمز الحالة 403 بدلا من 429: plan_limit_feature (الـ endpoint أو المعلمة exitCountries غير مدرجة في خطتك) و plan_limit_premium (exitClass: premium غير مدرج في خطتك). لا يحدد أي منهما Retry-After، لأن الانتظار لن يغير النتيجة.
STOP_ON = {
"plan_limit_feature", "plan_limit_premium",
"plan_limit_browser_daily", "plan_limit_credits", "plan_limit_bandwidth",
}
resp = requests.post(url, headers=headers, json=payload)
limit = resp.headers.get("X-FourA-Limit")
if limit in STOP_ON:
stop_the_run(limit) # hours or days away, not seconds
elif limit:
time.sleep(int(resp.headers.get("Retry-After", 1)))
القيم السبع وحقول body المرفقة مع كل منها متوفرة في حدود المعدل (Rate Limits).
X-FourA-Exit-Class
يحدد X-FourA-Exit-Class فئة الخروج التي سلمت الـ body: القيمة premium عندما يقدمها مخرج premium، والقيمة standard عندما تقدمها المجموعة standard. يظهر في استجابة POST /api/proxy/ التي سلمت صفحة عندما يُحدد الطلب exitClass، حيث يحتوي الـ body على القيمة نفسها، وفي استجابة Single أو Browser عندما يكون الـ proxy الذي قمت بتثبيته مخرج premium، حيث لا يتضمن الـ body حقلا له. لا يقدم استدعاء Proxy الفاشل أي محتوى، وبالتالي لا يحمل الـ header ولا الحقل.
HTTP/1.1 200 OK
X-FourA-Exit-Class: premium
X-FourA-Credits: 2
X-FourA-Request-Id: 2c1d0f9e-4a7b-4c3e-9d2a-8b1f6e5c4d3a
Content-Type: application/json
يُحتسب معدل نقل البيانات عبر مخرج premium ضمن حركة مرور premium الخاصة بك وكذلك ضمن إجمالي النطاق الترددي. يتم قياسه على الشبكة ويشمل محاولات premium التي لم تُرجع صفحتك، وبالتالي فإن أي request تمت الإجابة عنه بـ standard قد يكون استهلك بعض حركة مرور premium، في محاولة فشلت قبل أن يستجيب التجمع القياسي. يُحدد هذا الـ header الفئة التي تولت التسليم، وليس ما إذا كان قد تم استخدام حركة مرور premium: تُظهر علامة premium في صف النشاط وصفحة الاستخدام والحدود ما تم احتسابه. ما يفعله exitClass ومتى يُستخدم مخرج premium: exitClass.
سلوك التخزين المؤقت (Cache)
لا يقوم الـ API بتعيين Cache-Control أو ETag في الـ responses. كل استدعاء يصل مباشرة إلى الـ backend. إذا كنت بحاجة إلى التخزين المؤقت (caching)، فقم بإضافته من جانبك.
Headers استجابة الهدف
إن الـ headers التي أرجعها الموقع الهدف ليست موجودة في response الخاص بـ FourA API. بل يتم إرجاعها داخل غلاف JSON في حقل headers. بالنسبة لـ Single و Proxy endpoints، يكون هذا الحقل عبارة عن مصفوفة من كائنات الـ headers لكل قفزة (إدخال واحد لكل خطوة إعادة توجيه). أما بالنسبة لـ Browser endpoint، فهو كائن مسطح يحتوي على headers الـ response النهائي.
{
"status": 200,
"headers": [
{ "Content-Type": "text/html; charset=utf-8", "Server": "..." }
],
"data": "<!doctype html>...",
"total_time": 0.42
}
إذا كنت بحاجة إلى header هدف محدد، فاقرأه من حقل headers في الـ envelope، وليس من استجابة HTTP لطلب API نفسه.
ذو صلة
- API Endpoints: هياكل مغلفات الـ request والـ response
- API Errors: كيفية هيكلة استجابات الأخطاء
- Request Outcomes: ما هي النتائج الخاضعة للفوترة
- Activity Log: سجل لكل request مفهرس حسب request ID
- Rate Limits: ما يعنيه كل قيمة
X-FourA-Limit