Skip to content

कार्य और वेबहुक ​

मीडिया जनरेशन (वीडियो, इमेज, संगीत) असिंक्रोनस है: आप एक कार्य (job) बनाते हैं और तैयार होने पर उसका परिणाम प्राप्त करते हैं। कार्य पूरा होने का पता लगाने के दो तरीके हैं: पोलिंग (polling) और वेबहुक (push)। नीचे कार्य की संरचना और परिणाम विश्वसनीय ढंग से प्राप्त करने का तरीका बताया गया है।

कार्य का जीवनचक्र ​

POST /media/generate  →  status: processing  ──►  done   (result_url तैयार है)
        │                                     └─►  failed (error, राशि वापस कर दी गई)
        └── (वैकल्पिक) callback_url → done/failed पर पुश-वेबहुक
  1. बनाना। मॉडल और पैरामीटर के साथ POST /media/generate — id और पोलिंग के लिए लिंक लौटाता है:
json
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
  "poll": "https://nordrouter.com/media/job/beefb531-…" }
  1. प्रतीक्षा। कार्य processing → done (या failed) से गुजरता है। इमेज में कुछ सेकंड, वीडियो और संगीत में कुछ दर्जन सेकंड से लगभग दो मिनट लगते हैं।

  2. परिणाम। पूरे हुए कार्य में result_url भरा होता है (nordrouter.com का लिंक); फ़ाइल सीमित समय तक संग्रहीत रहती है (GET /media/models में retention_days) — इसे सहेजने के लिए डाउनलोड करें।

GET /media/job/:id के उत्तर (और वेबहुक बॉडी — नीचे देखें) का प्रारूप एक जैसा है:

json
{ "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }
  • status — processing | done | failed।
  • result_url — केवल done होने पर भरा होता है, अन्यथा null।
  • result_url_2 — संगीत मॉडल (Suno) का दूसरा ट्रैक, अन्यथा null।
  • results — कार्य की सभी फ़ाइलें: [{ "index": 1, "name": "Результат 1", "ext": "png", "url": "…" }] (3D के लिए — मॉडल और प्रीव्यू, ट्रैक अलग करने के लिए — «वोकल», «इंस्ट्रुमेंटल»… ट्रैक)।
  • cost_usd — वास्तविक लागत (वास्तविक उपयोग के अनुसार राशि काटी जाती है; असफल जनरेशन के लिए शुल्क नहीं लिया जाता — आरक्षित राशि वापस कर दी जाती है)।
  • error — failed होने पर त्रुटि का टेक्स्ट, अन्यथा null।

तरीका 1. पोलिंग (polling) ​

सबसे आसान तरीका — समय-समय पर GET /media/job/:id का अनुरोध करें, जब तक status का मान done/failed न हो जाए:

bash
curl https://nordrouter.com/media/job/beefb531-…

हर 2–3 सेकंड में पोलिंग करें। पोलिंग हमेशा काम करती है और इसके लिए सार्वजनिक पते की आवश्यकता नहीं होती — स्क्रिप्ट, नोटबुक और CI के लिए उपयुक्त है।

तरीका 2. वेबहुक (push) ​

पोलिंग से बचने के लिए — POST /media/generate में callback_url दें, और कार्य पूरा होने पर हम आपके पते पर POST भेजेंगे:

bash
curl https://nordrouter.com/media/generate \
  -H "Authorization: Bearer sk-nr-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "image/nano-banana-2",
    "input": { "prompt": "…" },
    "callback_url": "https://your-server.com/webhooks/nordrouter",
    "callback_secret": "आपकी-कोई-भी-स्ट्रिंग"
  }'

यदि callback_url स्वीकार हो जाता है, तो कार्य बनाने के उत्तर में "webhook": "registered" शामिल होता है। कार्य बनाते समय callback_url की जाँच तुरंत होती है: यदि यह उपयुक्त नहीं है (https नहीं है या निजी/स्थानीय पता है), तो अनुरोध कारण सहित 400 लौटाएगा ({ "error": "callback_url отклонён: …", "code": "invalid_callback" }), और कार्य नहीं बनेगा।

वेबहुक का बॉडी ​

जब कार्य की स्थिति done/failed हो जाती है, तो आपके callback_url पर POST आता है। इसका बॉडी GET /media/job/:id जैसा ही होता है, साथ में event फ़ील्ड होता है:

json
{ "event": "media.completed", "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }
  • event — media.completed (सफलता) या media.failed (त्रुटि)।

हस्ताक्षर की जाँच ​

यदि आपने callback_secret दिया है, तो X-NR-Signature हेडर में sha256=<hmac> होता है — यह अनुरोध के रॉ बॉडी का HMAC-SHA256 है, जिसकी कुंजी आपका सीक्रेट है। इसकी जाँच करके सुनिश्चित करें कि अनुरोध हमारी ओर से है और जाली नहीं है:

python
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)  # स्थिर समय में तुलना
javascript
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

JSON पार्सिंग से पहले बाइट जैसे प्राप्त हुए हैं, ठीक वैसे ही HMAC की गणना करें — अन्यथा हस्ताक्षर मेल नहीं खाएगा।

10 पंक्तियों में तैयार रिसीवर ​

एक कार्यशील सर्वर, जो वेबहुक स्वीकार करता है, हस्ताक्षर की जाँच करता है और 2xx उत्तर देता है। सीक्रेट वही है जो आपने callback_secret में दिया था।

Node.js / Express:

javascript
import express from "express";
import crypto from "node:crypto";

const SECRET = "आपकी-कोई-भी-स्ट्रिंग";           // = आपका callback_secret
const app = express();

app.post("/webhooks/nordrouter",
  express.raw({ type: "application/json" }),   // रॉ बॉडी — हस्ताक्षर के लिए आवश्यक
  (req, res) => {
    const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
    const got = req.headers["x-nr-signature"] || "";
    if (expected.length !== got.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got)))
      return res.sendStatus(401);             // हस्ताक्षर मेल नहीं खाया — अनुरोध हमारी ओर से नहीं है
    const job = JSON.parse(req.body);
    if (job.event === "media.completed") console.log("तैयार:", job.result_url, "$" + job.cost_usd);
    res.sendStatus(200);                       // 2xx उत्तर दें, अन्यथा दोबारा प्रयास होगा
  });

app.listen(3000);

Python / FastAPI:

python
import hmac, hashlib
from fastapi import FastAPI, Request, Response

SECRET = b"आपकी-कोई-भी-स्ट्रिंग"                  # = आपका callback_secret
app = FastAPI()

@app.post("/webhooks/nordrouter")
async def hook(request: Request):
    raw = await request.body()                 # रॉ बाइट — हस्ताक्षर के लिए आवश्यक
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-NR-Signature", "")):
        return Response(status_code=401)       # हस्ताक्षर मेल नहीं खाया — अनुरोध हमारी ओर से नहीं है
    job = await request.json()
    if job["event"] == "media.completed":
        print("तैयार:", job["result_url"], "$", job["cost_usd"])
    return Response(status_code=200)           # 2xx उत्तर दें, अन्यथा दोबारा प्रयास होगा

स्थानीय रूप से जाँचें

callback_url एक सार्वजनिक https पता होना चाहिए। लैपटॉप पर विकास के लिए एक टनल शुरू करें — उदाहरण के लिए ngrok http 3000 — और उससे मिले https पते को callback_url में दें।

डिलीवरी और विश्वसनीयता ​

  • बढ़ते अंतराल (≈3 → 6 → 9 सेकंड) के साथ अधिकतम 4 प्रयास, प्रत्येक का टाइमआउट 15 सेकंड। 2xx उत्तर दें, अन्यथा दोबारा प्रयास होगा।
  • रीडायरेक्ट फ़ॉलो नहीं किए जाते — सीधे callback_url पर उत्तर दें।
  • डिलीवरी best-effort है: यदि सभी 4 प्रयास विफल हो जाते हैं (आपका सर्वर बंद था), तो वेबहुक बाद में दोबारा नहीं भेजा जाता। इसलिए:

वेबहुक पोलिंग का विकल्प नहीं हैं

वेबहुक प्रक्रिया को तेज़ करता है, गारंटी नहीं देता। बैकअप के रूप में GET /media/job/:id रखें: यदि उचित समय में पुश नहीं आता है, तो स्वयं स्थिति पूछें। आइडेम्पोटेंसी आपकी ज़िम्मेदारी है: एक ही कार्य वेबहुक के रूप में आ सकता है और पोलिंग में भी मिल सकता है — पहचान के लिए id का उपयोग करें।

callback_url की आवश्यकताएँ ​

  • केवल https://।
  • केवल सार्वजनिक पता। स्थानीय और निजी पते (localhost, *.local, 10.x, 172.16–31.x, 192.168.x, 127.x, 169.254.x, 100.64–127.x, IPv6 loopback/ULA/link-local) अस्वीकार किए जाते हैं — यह SSRF से सुरक्षा है। हर बार भेजने से पहले भी पते की दोबारा जाँच होती है (DNS-rebinding से सुरक्षा)।

क्या चुनें ​

पोलिंगवेबहुक
सार्वजनिक https पताआवश्यक नहींआवश्यक
प्राप्ति में देरीपोलिंग अंतराल तकलगभग तुरंत
गारंटीआपके नियंत्रण मेंbest-effort + बैकअप के रूप में पोलिंग
कहाँ सुविधाजनक हैस्क्रिप्ट, CI, लैपटॉपसर्वर, प्रोडक्शन बैकएंड

सुझाव: बैकएंड पर — वेबहुक + बैकअप के लिए पोलिंग; स्क्रिप्ट/लैपटॉप पर — केवल पोलिंग।