कार्य और वेबहुक
मीडिया जनरेशन (वीडियो, इमेज, संगीत) असिंक्रोनस है: आप एक कार्य (job) बनाते हैं और तैयार होने पर उसका परिणाम प्राप्त करते हैं। कार्य पूरा होने का पता लगाने के दो तरीके हैं: पोलिंग (polling) और वेबहुक (push)। नीचे कार्य की संरचना और परिणाम विश्वसनीय ढंग से प्राप्त करने का तरीका बताया गया है।
कार्य का जीवनचक्र
POST /media/generate → status: processing ──► done (result_url तैयार है)
│ └─► failed (error, राशि वापस कर दी गई)
└── (वैकल्पिक) callback_url → done/failed पर पुश-वेबहुक- बनाना। मॉडल और पैरामीटर के साथ
POST /media/generate—idऔर पोलिंग के लिए लिंक लौटाता है:
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
"poll": "https://nordrouter.com/media/job/beefb531-…" }प्रतीक्षा। कार्य
processing→done(याfailed) से गुजरता है। इमेज में कुछ सेकंड, वीडियो और संगीत में कुछ दर्जन सेकंड से लगभग दो मिनट लगते हैं।परिणाम। पूरे हुए कार्य में
result_urlभरा होता है (nordrouter.comका लिंक); फ़ाइल सीमित समय तक संग्रहीत रहती है (GET /media/modelsमेंretention_days) — इसे सहेजने के लिए डाउनलोड करें।
GET /media/job/:id के उत्तर (और वेबहुक बॉडी — नीचे देखें) का प्रारूप एक जैसा है:
{ "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 न हो जाए:
curl https://nordrouter.com/media/job/beefb531-…हर 2–3 सेकंड में पोलिंग करें। पोलिंग हमेशा काम करती है और इसके लिए सार्वजनिक पते की आवश्यकता नहीं होती — स्क्रिप्ट, नोटबुक और CI के लिए उपयुक्त है।
तरीका 2. वेबहुक (push)
पोलिंग से बचने के लिए — POST /media/generate में callback_url दें, और कार्य पूरा होने पर हम आपके पते पर POST भेजेंगे:
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 फ़ील्ड होता है:
{ "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 है, जिसकी कुंजी आपका सीक्रेट है। इसकी जाँच करके सुनिश्चित करें कि अनुरोध हमारी ओर से है और जाली नहीं है:
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) # स्थिर समय में तुलना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:
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:
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, लैपटॉप | सर्वर, प्रोडक्शन बैकएंड |
सुझाव: बैकएंड पर — वेबहुक + बैकअप के लिए पोलिंग; स्क्रिप्ट/लैपटॉप पर — केवल पोलिंग।