ਵੈੱਬਹੁੱਕ
ਪੋਲਿੰਗ ਕਰਨ ਦੀ ਬਜਾਏ, ਕਿਸੇ ਰਨ ਨੂੰ 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" } ]
}
}
typerequest.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 ਨਾਲ ਬਣਦਾ ਹੈ। ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ:
- ਪ੍ਰਾਪਤ ਕੀਤੇ ਅਨੁਸਾਰ ਕੱਚੇ ਬਾਡੀ ਬਾਈਟ ਬਿਲਕੁਲ ਉਹੀ ਲਓ (ਕਿਸੇ ਵੀ JSON ਪਾਰਸਿੰਗ ਤੋਂ ਪਹਿਲਾਂ)।
- ਆਪਣੇ ਸੀਕ੍ਰੇਟ ਨਾਲ
t + "." + bodyਦਾ HMAC-SHA256 ਗਣਨਾ ਕਰੋ, lowercase hex ਵਜੋਂ। - constant time ਵਿੱਚ ਇਸਦੀ
v1ਨਾਲ ਤੁਲਨਾ ਕਰੋ। - ਜਦੋਂ
tਤੁਹਾਡੀ ਘੜੀ ਤੋਂ 5 ਮਿੰਟਾਂ ਤੋਂ ਵੱਧ ਦੂਰ ਹੋਵੇ ਤਾਂ ਇਵੈਂਟ ਰੱਦ ਕਰੋ (replay ਸੁਰੱਖਿਆ)।
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 ਕੁੰਜੀ ਨਾਲ ਸੰਬੰਧਿਤ ਹੁੰਦਾ ਹੈ ਜਿਸਨੇ ਰਨ ਸ਼ੁਰੂ ਕੀਤਾ ਸੀ। ਵੱਖ-ਵੱਖ ਸੇਵਾਵਾਂ ਦੀਆਂ ਕੁੰਜੀਆਂ ਦੇ ਸੀਕ੍ਰੇਟ ਵੀ ਵੱਖ ਹੁੰਦੇ ਹਨ।