Webhooks

जनरेशन पूरा होते ही जान जाइए

पोलिंग की ज़रूरत नहीं। जैसे ही कोई जनरेशन पूरा होता है, Flixly आपके URL पर एक साइन किया हुआ इवेंट POST कर देता है — चाहे रिक्वेस्ट sync रही हो (इमेज मॉडल) या async (वीडियो मॉडल, धीमी क़तारें)।

HMAC-SHA256 से साइन किया हुआ

हर डिलीवरी पर `${timestamp}.${body}` का सिग्नेचर होता है, ताकि आप पुष्टि कर सकें कि वह वाकई हमारी ओर से आया है और उससे कोई छेड़छाड़ नहीं हुई।

रीप्ले से सुरक्षित

X-Flixly-Timestamp हेडर से आप लगभग 5 मिनट से पुराने सिग्नेचर अस्वीकार कर सकते हैं — पकड़े गए रिक्वेस्ट के दोबारा भेजे जाने से बचाव।

अपने आप रीट्राई

एक्सपोनेंशियल बैकऑफ़ के साथ 3 प्रयास (तुरंत, +2s, +6s)। हर प्रयास पर 5 सेकंड का टाइमआउट। /generations/{id} को पोल करना आपका फ़ॉलबैक है।

हर key का अलग सीक्रेट

हर API key का अपना webhook सीक्रेट होता है। उसे डैशबोर्ड से कभी भी रोटेट करें — पुराने सिग्नेचर तुरंत वेरिफ़िकेशन में फ़ेल होने लगते हैं।

Webhooks चालू करें

Flixly को यह बताने के दो तरीके हैं कि आपके इवेंट कहाँ POST करने हैं:

विकल्प 1 — हर key का डिफ़ॉल्ट

अपनी API key पर सेट करें

हर API key पर एक डिफ़ॉल्ट webhook URL सेट करें और साइनिंग सीक्रेट जनरेट करें। उस key से भेजा गया हर जनरेशन उसी URL पर डिलीवर होगा।

विकल्प 2 — हर रिक्वेस्ट पर

जनरेट बॉडी में भेजें

POST बॉडी में webhook_url देकर हर रिक्वेस्ट पर key का डिफ़ॉल्ट ओवरराइड करें। एक-बार के डेस्टिनेशन या एनवायरनमेंट के हिसाब से रूटिंग के लिए उपयोगी।

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
टास्क id — वही जो आपको POST /api/v1/generate से मिला था और जिसे आप GET /api/v1/generations/{id} के साथ इस्तेमाल करते हैं।
status
डिलीवरी के समय हमेशा completed या failed
output_url
सफल होने पर cdn.flixly.ai का URL, फ़ेल होने पर null
credits_charged
काटे गए क्रेडिट, पूर्णांक में। फ़ेल होने पर 0 (अपने आप रिफ़ंड)।
error
फ़ेल होने पर यूज़र को दिखाने लायक एरर मैसेज, सफल होने पर null। यह पहले से सैनिटाइज़ है — अपने यूज़र्स को सीधे दिखाना सुरक्षित है।

सिग्नेचर वेरिफ़ाई करें

हम हर डिलीवरी को `${timestamp}.${body}` पर HMAC-SHA256 से साइन करते हैं। आप उसी सीक्रेट से, जो जनरेट करते समय हमने आपको दिखाया था, अपने सर्वर पर HMAC दोबारा निकालते हैं और कॉन्स्टेंट टाइम में तुलना करते हैं।

रॉ बॉडी ही इस्तेमाल करें।

JSON.parse → JSON.stringify से व्हाइटस्पेस और फ़ील्ड का क्रम बदल जाता है, जिससे सिग्नेचर टूट जाता है। Express में raw-body मिडलवेयर लगाएँ। Next.js App Router में await req.json() से पहले await req.text() कॉल करें।

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

डिलीवरी और रीट्राई

sync हो या async, हर डिलीवरी एक ही पैटर्न पर चलती है:

  1. 1
    प्रयास 1 — तुरंत
    जनरेशन पूरा होते ही POST किया जाता है। 5 सेकंड का टाइमआउट। कोई भी 2xx रिस्पॉन्स सफलता मानी जाती है।
  2. 2
    प्रयास 2 — 2 सेकंड बाद
    टाइमआउट वही। यह तभी चलता है जब पहला प्रयास non-2xx लौटाए या टाइमआउट हो जाए।
  3. 3
    प्रयास 3 — 6 सेकंड बाद (कुल 8s बीत चुके)
    आख़िरी कोशिश। इसके बाद हम लॉग करके रुक जाते हैं। टास्क खुद हमारे डेटाबेस में सुरक्षित रहता है — फ़ॉलबैक के तौर पर आप कभी भी /generations/{id} पोल कर सकते हैं।

सफलता किसे माना जाता है

  • कोई भी HTTP 2xx रिस्पॉन्स। कहने को कुछ न हो तो खाली बॉडी के साथ 200 OK लौटा दें।
  • हम रीडायरेक्ट फ़ॉलो नहीं करते। ध्यान रखें कि आप जो URL हमें दे रहे हैं वही अंतिम एंडपॉइंट हो।
  • हम 301, 302 और बाक़ी 3xx रिस्पॉन्स को फ़ेल्योर मानते हैं — वे अगले hop पर X-Flixly-Signature हेडर को चुपचाप हटा देंगे।

Idempotency

हर डिलीवरी के साथ एक यूनीक X-Flixly-Delivery-Id हेडर आता है। अगर रीट्राई की वजह से वही इवेंट आपको दो बार मिल जाए (जैसे हमारा रीट्राई चल पड़ा हो, पर आपका पहला रिस्पॉन्स हम तक पहुँचने में बहुत देर लगा हो), तो अपनी तरफ़ डीडुप्लिकेशन के लिए उसी हेडर का इस्तेमाल करें।

इवेंट का id फ़ील्ड जनरेशन id है — एक ही डिलीवरी के सभी रीट्राई में वही रहता है। X-Flixly-Delivery-Id हर प्रयास पर तभी बदलेगा जब हम payload दोबारा बनाएँ (फ़िलहाल हम ऐसा नहीं करते)।

जोड़ने के लिए तैयार हैं?

अपनी API key पर एक webhook URL सेट करें और साइनिंग सीक्रेट जनरेट करें — दोनों में लगभग 30 सेकंड लगते हैं।