منصة B2B للسلع الرقمية

استطلاع حالة الطلب وطبقة الإشعارات للسلع الرقمية

لا ترسل FoxReload أي webhooks. للحصول على نتائج الطلب، استطلع GET /api/orders/{order_id} حتى تصل الحالة إلى completed أو cancelled أو failed. للمتاجر عالية الحجم التي تريد تسليمًا قائمًا على الأحداث، يوضّح هذا الدليل كيفية بناء طبقة إشعارات خفيفة أمام الاستطلاع.

استطلاع حالة الطلب وطبقة الإشعارات للسلع الرقمية


الإجابة المختصرة

لا ترسل FoxReload أي webhooks. لمعرفة متى يكتمل الطلب، استطلع GET /api/orders/{order_id} حتى تكون status إما "completed" أو "cancelled" أو "failed". عند الاكتمال، يحتوي items[].externalData على الأكواد المُسلّمة. للمتاجر عالية الحجم التي تريد سلوكًا قائمًا على الأحداث، ابنِ عامل استطلاع في الخلفية يحوّل تغيّرات الحالة إلى أحداث داخلية.


مهم — لا تدعم FoxReload الـ webhooks، ولا ترويسة X-FoxReload-Signature، ولا أحداث استدعاء order.*. لا يوجد بيئة اختبار (sandbox) — استخدم isMock: true عند إنشاء الطلب للطلبات التجريبية. لا توجد مفاتيح idempotency — إذا ترك خطأ شبكي حالة طلب غير مؤكّدة، فتحقق من GET /api/orders/{id} قبل إنشاء طلب جديد لتجنّب الشراء المزدوج.


الخلاصة الأساسية — الاستطلاع هو النمط الصحيح لـ FoxReload. معظم الطلبات تكتمل بشكل متزامن خلال ثوانٍ. أما الحالات الأبطأ، فإن حلقة استطلاع في الخلفية مع تراجع أُسّي تمنحك معالجة غير متزامنة موثوقة دون webhooks.


لمن هذا الدليل

  • المطورون الذين يدمجون FoxReload API ويحتاجون إلى التعامل مع تنفيذ الطلبات غير المتزامن
  • مشغّلو المتاجر الذين يبنون خطوط تسليم أكواد مؤتمتة
  • المهندسون الذين يريدون تسليمًا قائمًا على الأحداث لكنهم يعملون مع API قائم على الاستطلاع

كيف يعمل تنفيذ الطلبات في FoxReload

1. POST /api/orders/
   Body: {"items": [{"itemId": "product_01k...", "quantity": 1}]}
   → Response: {"id": "order_01k...", "status": "processing", ...}

2. Poll GET /api/orders/{order_id}
   → {"id": "order_01k...", "status": "processing", ...}   (not yet)
   → {"id": "order_01k...", "status": "completed",
      "items": [{"externalData": ["XXXXX-YYYYY-ZZZZZ"]}]}   (done)

عندما يكون status == "completed"، اقرأ items[i].externalData — وهي مصفوفة من الأكواد المُسلّمة أو تأكيدات الشحن. إذا واجه عنصر خطأً، فتحقق من items[i].error.


الاستطلاع مقابل الـ Webhooks

العامل الاستطلاع (FoxReload) الـ Webhooks (غير متاح)
مدعوم من FoxReload نعم لا
زمن الاستجابة يعتمد على فترة الاستطلاع (عادة <3 ثوانٍ) غير متاح
التنفيذ حلقة بسيطة غير قابل للتطبيق
معالجة الحجم العالي يُوصى بعامل في الخلفية غير متاح

حالات الطلب النهائية

الحالة المعنى الإجراء
completed تم تنفيذ الطلب؛ الأكواد في items[].externalData سلّم الأكواد للعميل
cancelled أُلغي الطلب قبل التنفيذ استرد للعميل؛ لا تُسلّم
failed فشل التنفيذ نبّه فريق العمليات؛ استرد إن تم أخذ الدفعة
processing / paid / active لا يزال قيد التقدم واصل الاستطلاع

تنفيذ استطلاع أساسي

import time
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://public-api.foxreload.com"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

def poll_order(order_id: str, max_attempts: int = 30) -> dict:
    terminal = {"completed", "cancelled", "failed"}
    delay = 1.0
    for attempt in range(max_attempts):
        resp = requests.get(f"{BASE_URL}/api/orders/{order_id}", headers=HEADERS)
        resp.raise_for_status()
        order = resp.json()
        if order["status"] in terminal:
            return order
        time.sleep(delay)
        delay = min(delay * 1.5, 15)  # exponential backoff, cap at 15s
    raise TimeoutError(f"Order {order_id} did not reach terminal status")

def get_codes(order: dict) -> list[str]:
    codes = []
    for item in order.get("items", []):
        codes.extend(item.get("externalData", []))
    return codes

# Usage
order = poll_order("order_01k...")
if order["status"] == "completed":
    codes = get_codes(order)
    deliver_to_customer(codes)
elif order["status"] == "failed":
    alert_ops(order)

الحجم العالي — عامل استطلاع في الخلفية

للمتاجر التي تعالج طلبات كثيرة في الدقيقة، شغّل عاملًا مخصصًا في الخلفية بدلًا من الاستطلاع المعطِّل داخل الطلب:

Order creation API call
  → Store order_id in DB with status = 'pending'
  → Return response to customer ("Order placed, processing")

Background worker (runs every 2–5 seconds):
  → Query DB: SELECT * FROM orders WHERE status = 'pending'
  → For each: GET /api/orders/{order_id}
  → If status changed:
      - Update DB
      - If completed: deliver codes to customer (email / bot / order page)
      - If failed: alert ops

هذا يفصل إنشاء الطلب عن الاستطلاع ويتوسّع بنظافة. عاملك هو طبقة الإشعارات — لا تشارك FoxReload في دفع الأحداث.


بناء طبقة الإشعارات الداخلية الخاصة بك

إذا أردت سلوكًا قائمًا على الأحداث داخل نظامك الخاص، فأطلق أحداثًا داخلية من عامل الاستطلاع:

# After polling detects a status change:
if new_status == "completed":
    internal_queue.publish("order.completed", {
        "order_id": order_id,
        "codes": get_codes(order),
        "customer_id": customer_id,
    })

# Separate consumer:
@queue.consumer("order.completed")
def on_order_completed(event):
    send_code_to_customer(event["customer_id"], event["codes"])

هذا بالكامل ضمن بنيتك التحتية الخاصة. لا تشارك FoxReload في تدفّق الأحداث هذا.


تجنّب الطلبات المزدوجة (لا مفاتيح Idempotency)

لا تدعم FoxReload مفاتيح idempotency. إذا جعل خطأ شبكي من غير الواضح ما إذا أُنشئ الطلب، فـ تحقق دائمًا قبل إنشاء طلب جديد:

def safe_create_order(item_id: str, qty: int, your_ref: str) -> dict:
    # 1. Check if an order with your internal reference already exists
    existing = find_order_by_reference(your_ref)  # your DB lookup
    if existing:
        return poll_order(existing["foxreload_order_id"])

    # 2. Create new order
    resp = requests.post(
        f"{BASE_URL}/api/orders/",
        headers=HEADERS,
        json={"items": [{"itemId": item_id, "quantity": qty}]}
    )
    resp.raise_for_status()
    order = resp.json()
    save_order_reference(your_ref, order["id"])  # persist before polling
    return poll_order(order["id"])

خزّن مرجعك الداخلي ومعرّف طلب FoxReload معًا قبل الاستطلاع.


التعامل مع الطلبات العالقة

إذا بقي الطلب في processing بعد اتفاقية مستوى الخدمة لديك:

  1. واصل الاستطلاع مع تراجع — بعض عمليات التنفيذ بطيئة بشكل مشروع
  2. بعد عتبة اتفاقية مستوى الخدمة لديك (مثلًا 10 دقائق)، نبّه فريق العمليات مع معرّف الطلب
  3. لا تُلغِ وتُعِد الإنشاء تلقائيًا — تحقق مع دعم FoxReload أولًا لتجنّب الشراء المزدوج

قائمة التحقق

  • POST /api/orders/ مع مصادقة X-API-Key ونوع محتوى application/json
  • خزّن معرّف الطلب فور الإنشاء
  • استطلع GET /api/orders/{order_id} مع تراجع أُسّي
  • تعامل مع كل الحالات النهائية — completed و cancelled و failed
  • استخرج الأكواد من items[].externalData عند الاكتمال
  • تحقق من items[].error بحثًا عن إخفاقات كل عنصر في الطلبات المكتملة
  • قبل إعادة الإنشاء عند خطأ شبكي، تحقق مما إذا كان الطلب موجودًا بالفعل
  • للحجم العالي — عامل استطلاع في الخلفية مع إطلاق أحداث داخلية
  • نبّه عند الطلبات العالقة في processing بعد اتفاقية مستوى الخدمة
  • اختبر بطلبات isMock: true قبل الانطلاق الفعلي

الأسئلة الشائعة

هل تدعم FoxReload الـ webhooks؟
لا. لا ترسل FoxReload استدعاءات webhook. للحصول على نتائج الطلب، استطلع GET /api/orders/{order_id} حتى تصبح الحالة 'completed' أو 'cancelled' أو 'failed'. معظم الطلبات تكتمل خلال ثوانٍ؛ الاستطلاع كل 1–3 ثوانٍ هو النهج الموصى به.
أين توجد الأكواد المُسلّمة في استجابة الـ API؟
عندما تكون الحالة 'completed'، يحتوي مصفوفة items على externalData لكل عنصر. يحمل هذا الحقل مصفوفة الأكواد المُسلّمة أو تأكيد الشحن.
ماذا لو بقي الطلب في 'processing' لفترة طويلة؟
واصل الاستطلاع مع تراجع أُسّي. إذا بقي الطلب عالقًا بعد اتفاقية مستوى الخدمة لديك (مثلًا 10 دقائق)، فنبّه فريق العمليات. لا تنشئ طلبًا مكررًا دون التحقق أولًا من الحالة — فإعادة الإنشاء دون تحقق قد تؤدي إلى شراء مزدوج.
هل أحتاج إلى webhooks أم يمكنني استطلاع حالة الطلب؟
بالنسبة إلى FoxReload، الاستطلاع هو الطريقة الوحيدة المدعومة. عند 100 طلب/يوم يكون الاستطلاع مباشرًا. عند الحجم الأعلى، شغّل عاملًا مخصصًا في الخلفية يستطلع كل الطلبات المعلّقة وفق جدول ويُطلق أحداثًا داخلية عند تغيّر الحالة.
هل يمكنني بناء إشعارات بأسلوب webhook خاصة بي فوق الاستطلاع؟
نعم. شغّل مستطلِعًا في الخلفية يستدعي GET /api/orders/{id} لكل الطلبات المعلّقة. عندما تتغيّر الحالة إلى 'completed'، ادفع رسالة إلى طابورك الداخلي (Redis أو SQS وغيرها) أو أطلق استدعاء HTTP داخليًا. هذا بالكامل ضمن بنيتك التحتية الخاصة — لا تشارك FoxReload فيه.
احصل على وصول API الخاص بـ FoxReload

مقالات ذات صلة