Webhooks

اعرف فور أن عملية التوليد تكتمل

لا حاجة إلى الاستطلاع المتكرر. يرسل Flixly طلب POST بحدث موقَّع إلى عنوانك في اللحظة التي تكتمل فيها عملية التوليد، سواء كان الطلب متزامنًا (نماذج الصور) أو غير متزامن (نماذج الفيديو وقوائم الانتظار البطيئة).

موقَّع بخوارزمية HMAC-SHA256

يحمل كل تسليم توقيعًا محسوبًا على `${timestamp}.${body}`، فتستطيع التأكد من أنه صادر عنا فعلًا وأنه لم يُعبث به.

محمي من إعادة الإرسال

يتيح لك ترويسة X-Flixly-Timestamp رفض أي توقيع أقدم من 5 دقيقة تقريبًا، وهو دفاع ضد إعادة إرسال الطلبات الملتقطة.

إعادة محاولة تلقائية

3 محاولات مع تباعد أُسّي (فوري، +2s، +6s). مهلة 5 ثانية لكل محاولة. ويبقى استطلاع /generations/{id} خيارك البديل.

سر خاص بكل مفتاح

لكل مفتاح API سرّ webhook خاص به. يمكنك تدويره في أي وقت من لوحة التحكم، وعندها تفشل التواقيع القديمة في التحقق فورًا.

تفعيل الـ webhooks

طريقتان لإخبار Flixly بالوجهة التي يرسل إليها أحداثك عبر POST:

الخيار 1 — قيمة افتراضية لكل مفتاح

اضبطه على مفتاح API الخاص بك

اضبط عنوان webhook افتراضيًا وأنشئ سرًّا للتوقيع على كل مفتاح API. عندها تُسلَّم كل عملية توليد أُرسلت بذلك المفتاح إلى ذلك العنوان.

الخيار 2 — لكل طلب على حدة

مرّره في جسم طلب التوليد

تجاوز القيمة الافتراضية للمفتاح في كل طلب بتعيين webhook_url في جسم طلب الـ POST. مفيد للوجهات العابرة أو للتوجيه حسب البيئة.

POST /api/v1/generate
{
  "model": "veo-3-fast",
  "prompt": "...",
  "webhook_url": "https://you/hook"
}

الحدث الذي تستقبله

طلب POST واحد لكل عملية توليد مكتملة (أو فاشلة). جسم بصيغة JSON وترويسات موقَّعة.

ترويسات الطلب

POST https://your-server.example.com/flixly-webhook
Content-Type: application/json
User-Agent: Flixly-Webhook/1.0
X-Flixly-Event: generation.completed
X-Flixly-Timestamp: 1781085600
X-Flixly-Signature: sha256=abc123...
X-Flixly-Delivery-Id: wh_a1b2c3d4e5f6g7h8

جسم JSON

{
  "event": "generation.completed",
  "id": "j5h2k9...",
  "status": "completed",
  "type": "TEXT_TO_IMAGE",
  "model": "flux-dev",
  "output_url": "https://cdn.flixly.ai/outputs/...",
  "credits_charged": 1,
  "error": null,
  "created_at": "2026-06-06T12:00:00Z",
  "completed_at": "2026-06-06T12:00:05Z"
}

مرجع الحقول

event
generation.completed أو generation.failed.
id
معرّف المهمة — وهو نفسه الذي أعاده لك POST /api/v1/generate وتستخدمه مع GET /api/v1/generations/{id}.
status
دائمًا completed أو failed بحلول وقت التسليم.
output_url
عنوان على cdn.flixly.ai عند النجاح، وnull عند الفشل.
credits_charged
الأرصدة المخصومة كعدد صحيح. صفر عند الفشل (تُعاد تلقائيًا).
error
رسالة خطأ موجَّهة للمستخدم عند الفشل، وnull عند النجاح. وهي منقّحة مسبقًا، فيمكن عرضها لمستخدميك بأمان.

التحقق من التواقيع

نوقّع كل تسليم بخوارزمية HMAC-SHA256 على `${timestamp}.${body}`. وأنت تعيد حساب الـ HMAC على خادمك بالسرّ الذي عرضناه لك عند إنشائه، ثم تقارن في زمن ثابت.

استخدم الجسم الخام.

إن JSON.parse ثم JSON.stringify يغيّران المسافات وترتيب الحقول، وهو ما يُبطل التوقيع. في Express استخدم وسيطًا برمجيًا للجسم الخام، وفي App Router الخاص بـ Next.js استدعِ await req.text() قبل await req.json().

import { Flixly } from "@flixly/sdk";

// In your webhook handler — Express, Hono, Next.js, etc.
export async function POST(req) {
  const rawBody = await req.text();   // MUST be raw — re-stringifying breaks the signature
  const signature = req.headers.get("x-flixly-signature");
  const timestamp = req.headers.get("x-flixly-timestamp");

  const valid = await Flixly.verifyWebhookSignature({
    secret:    process.env.FLIXLY_WEBHOOK_SECRET,
    timestamp,
    signature,
    body:      rawBody,
    tolerance: 300,   // optional — defaults to 300s replay window
  });

  if (!valid) {
    return new Response("invalid signature", { status: 401 });
  }

  const event = JSON.parse(rawBody);
  // event.event === "generation.completed" | "generation.failed"
  // event.id, event.status, event.output_url, event.credits_charged, ...
  await handleGenerationEvent(event);
  return new Response("ok");
}

التسليم وإعادة المحاولة

يتبع كل تسليم النمط نفسه، متزامنًا كان أم غير متزامن:

  1. 1
    المحاولة 1 — فورية
    تُرسل عبر POST مباشرة بعد اكتمال عملية التوليد. مهلة 5 ثانية. وأي استجابة 2xx تُعدّ نجاحًا.
  2. 2
    المحاولة 2 — بعد 2 ثانية
    المهلة نفسها. وتنطلق إذا أعادت المحاولة الأولى استجابة غير 2xx أو انتهت مهلتها.
  3. 3
    المحاولة 3 — بعد 6 ثانية (بمجموع 8s منقضية)
    المحاولة الأخيرة. بعدها نسجّل الأمر ونتوقف. أما المهمة نفسها فتبقى سليمة في قاعدة بياناتنا، ويمكنك دائمًا استطلاع /generations/{id} كبديل.

ما الذي يُعدّ نجاحًا

  • أي استجابة HTTP من نوع 2xx. أعد 200 OK بجسم فارغ إن لم يكن لديك ما تقوله.
  • نحن لا نتبع عمليات إعادة التوجيه. تأكد من أن العنوان الذي تعطينا إياه هو نقطة النهاية الأخيرة.
  • نتعامل مع 301 و302 وسائر استجابات 3xx على أنها إخفاقات، لأنها ستُسقط ترويسة X-Flixly-Signature بصمت عند القفزة التالية.

خاصية الحياد التكراري (Idempotency)

يحمل كل تسليم ترويسة X-Flixly-Delivery-Id فريدة. فإن أدّت إعادة المحاولة إلى استقبالك الحدث نفسه مرتين (مثلًا انطلقت إعادة محاولتنا بينما تأخّرت استجابتك الأولى في الوصول إلينا)، فاستعمل تلك الترويسة لإزالة التكرار من جهتك.

حقل id في الحدث هو معرّف عملية التوليد، وهو ثابت عبر كل محاولات التسليم الواحد. أما X-Flixly-Delivery-Id فلا يتغير بين المحاولات إلا إذا أعدنا بناء الحمولة (وهو ما لا نفعله حاليًا).

جاهز للربط؟

اضبط عنوان webhook على مفتاح API الخاص بك وأنشئ سرًّا للتوقيع — كلا الأمرين يستغرق نحو 30 ثانية.