ویب ہُکس
پولنگ کے بجائے، ایک رَن کو webhook_url دیں۔ جب درخواست حتمی حیثیت (succeeded، failed یا
canceled) تک پہنچتی ہے، ہم اس URL پر دستخط شدہ POST بھیجتے ہیں۔
curl -X POST "https://api.doitong.com/v1/run/{model_id}?webhook_url=https://example.com/hooks/doitong" \
-H "Authorization: Bearer $DOITONG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "..."}'
ایونٹ
POST /hooks/doitong HTTP/1.1
Content-Type: application/json
User-Agent: Doitong-Webhooks/1
Doitong-Request-Id: req_8k2m4q7x1z9c3v5b6n0p2r4t
Doitong-Signature: t=1760961609,v1=5f1c0d6e2b…
{
"id": "evt_8k2m4q7x1z9c3v5b6n0p2r4t_succeeded",
"object": "event",
"type": "request.succeeded",
"created_at": "2026-10-20T12:00:09Z",
"data": {
"id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
"object": "request",
"status": "succeeded",
"outputs": [ { "type": "video", "url": "https://content.doitong.com/dev-api/…/0-output.mp4" } ]
}
}
type،request.succeeded،request.failedیاrequest.canceledہوتا ہے۔dataمکمل درخواست آبجیکٹ ہے، بالکل وہی جوGET /requests/{id}واپس کرتا ہے۔idدرخواست اور اس کی حتمی حیثیت کے لیے مستقل ہوتا ہے۔ اسے پہلے سے پروسیس شدہ ڈیلیوری نظرانداز کرنے کے لیے استعمال کریں۔
ڈیلیوریز اور دوبارہ کوششیں
10 سیکنڈ کے اندر کسی بھی 2xx حیثیت کے ساتھ جواب دیں۔ اس کے علاوہ کوئی بھی جواب (یا ٹائم آؤٹ) دوبارہ کوشش کرواتا ہے: کل زیادہ سے زیادہ 6 کوششیں،
30 سیکنڈ، 2 منٹ، 10 منٹ، 1 گھنٹے اور 6 گھنٹے کے بعد۔ جواب دینے سے پہلے سست کام نہ کریں؛ جواب کے بعد کریں۔
دستخط کی تصدیق کریں
ہر کلید کا اپنا دستخطی راز ہوتا ہے۔ اسے ایک بار GET https://api.doitong.com/v1/account (webhook_signing_secret،
یہ whsec_ سے شروع ہوتا ہے) سے پڑھیں اور کلید کے ساتھ محفوظ کریں۔
Doitong-Signature ہیڈر t=<unix time>,v1=<signature> ہوتا ہے، جہاں دستخط آپ کے راز کو کلید کے طور پر استعمال کرتے ہوئے
"<t>.<raw request body>" کا hex HMAC-SHA256 ہوتا ہے۔ تصدیق کے لیے:
- موصول شدہ raw body بائٹس کو بالکل اسی طرح لیں (کسی بھی JSON parsing سے پہلے)۔
- اپنے راز کے ساتھ
t + "." + bodyکا HMAC-SHA256، lowercase hex میں، حساب کریں۔ - اس کا مستقل وقت میں
v1سے موازنہ کریں۔ - جب
tآپ کی گھڑی سے 5 منٹ سے زیادہ دور ہو تو ایونٹ مسترد کریں (replay protection)۔
Node.js (Express) اور Python (Flask) میں مکمل وصول کنندہ:
import crypto from "node:crypto";
import express from "express";
const SECRET = process.env.DOITONG_WEBHOOK_SECRET; // whsec_...
const app = express();
app.post("/hooks/doitong", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("Doitong-Signature") || "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
const expected = crypto.createHmac("sha256", SECRET).update(t + "." + req.body).digest("hex");
const given = Buffer.from(parts.v1 || "", "utf8");
const valid =
given.length === expected.length &&
crypto.timingSafeEqual(given, Buffer.from(expected, "utf8")) &&
Math.abs(Date.now() / 1000 - t) < 300;
if (!valid) return res.status(400).send("bad signature");
const event = JSON.parse(req.body);
if (event.type === "request.succeeded") {
console.log(event.data.id, event.data.outputs.map((o) => o.url));
}
res.sendStatus(204);
});
import hashlib
import hmac
import json
import os
import time
from flask import Flask, abort, request
SECRET = os.environ["DOITONG_WEBHOOK_SECRET"].encode() # whsec_...
app = Flask(__name__)
@app.post("/hooks/doitong")
def doitong_hook():
body = request.get_data() # raw bytes
parts = dict(p.split("=", 1) for p in request.headers.get("Doitong-Signature", "").split(",") if "=" in p)
t = parts.get("t", "0")
expected = hmac.new(SECRET, t.encode() + b"." + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, parts.get("v1", "")) or abs(time.time() - int(t)) > 300:
abort(400)
event = json.loads(body)
if event["type"] == "request.succeeded":
print(event["data"]["id"], [o["url"] for o in event["data"]["outputs"]])
return "", 204
تجاویز
- فوراً جواب دیں اور اپنی پروسیسنگ قطار میں شامل کریں۔
- راز اس API کلید کا ہوتا ہے جس نے رَن شروع کیا۔ مختلف سروسز کی کلیدوں کے راز مختلف ہوتے ہیں۔