Webhook
ᡳᠨᡝᠩᡤᡳ ᠪᠠᠶᠠᠨ ᠰᡳᠯᡤᠠᠯᠠᠮᡝ ᠪᠠᡳᡨᠠᠯᠠᡵᠠ ᡠᠨᡩᡝᡵᡝᠩᡤᡝ᠂ ᡝᡵᡝ ᠪᠠᠶᠠᠨ ᡳ webhook_url ᡳ ᠪᡝᠶᡝ ᠪᡝ ᡝᠨᡩᡝᡵᡝᠮᡝ ᡠᠯᡥᡳᠮᡝ ᠪᠠᠨᠵᡳᠨᠠᠮᡝ᠂ ᠪᠠᠶᠠᠨ ᡳ ᡩᠠᠯᡵᠠᠮᡝ ᠪᠠᡳᡨᠠᠯᠠᡵᠠ ᠪᠠᠶᠠᠨ ᡳ ᠮᡠᠩᡤᠠᠨ ᠪᠠᠶᠠᠨ ᡳ ᠮᡠᠶᠠᠨ ᡳ ᠪᠠᡳᡨᠠᠯᠠᠩᡤᡝ (succeeded, failed ᠵᡠᠯᡝ ᠪᠠᠨᡳ canceled) ᠪᠣᠯᠣᠮᡝ᠂ ᠮᡳᠨᡳ ᡝᠨᡩᡝᡵᡝᠮᡝ ᡤᠠᠰᡥᠠᠨ ᠵᠠᠯᠠᠨ ᡳ POST ᡝᠨᡩᡝᡵᡝᠮᡝ ᠪᡝᠶᡝ ᠵᠠᠯᠠᠨ ᡩᡝ ᡝᠨᡩᡝᡵᡝᠮᡝ.
curl -X POST "https://api.doitong.ru/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 ᠪᠠᡳᡨᠠᠯᠠᠩᡤᡝ ᡩᡝ ᡩᠠᡵᠠᠨᠠᠮᡝ. ᡠᠮᡝ ᡩᡝᠯᡤᡳ (2xx ᠪᠠᠨᡳ ᠰᡳᠯᡤᠠᠯᠠᠮᡝ) ᠵᡠᠯᡝ ᠪᠠᠨᡳ ᠮᡠᠶᠠᠨᠠᠮᡝ: ᠵᡠᠯᡝ ᠪᠠᠶᠠᠨ 6 ᠵᠠᠯᠠᠨ᠂ 30 ᠰᡝᠺᡠᠨᡩᡝ᠂ 2 ᠮᡳᠨᡠᡨᡝ᠂ 10 ᠮᡳᠨᡠᡨᡝ᠂ 1 ᠴᡳᠣᠸᠠᠨ ᠪᠠᠨᡳ 6 ᠴᡳᠣᠸᠠᠨ. ᠵᡠᠯᡝ ᠵᡝᠪᡝ ᡩᠠᡵᠠᠨᠠᠮᡝ ᠣᠴᡳᠨᡳ ᡝᡵᡝ ᠪᠠᠶᠠᠨ ᠪᠠᠨᡳ ᡝᠨᡩᡝᡵᡝᠮᡝ.
ᠵᠠᠯᠠᠨ ᡳ ᠵᡠᠯᡝ ᠪᠠᠨᡳᠮᡝ
ᠵᡠᠯᡝ ᠵᠠᠯᠠᠨ ᡩᡝ ᠪᡳᠶᠠ ᠵᡠᠯᡝᠨ ᡳ ᡤᠠᠰᡥᠠᠨ ᠪᠠᠨᡳᠨᠠᠮᡝ. GET https://api.doitong.ru/v1/account ᡳ ᠵᡠᠯᡝ ᠮᡠᠶᠠᠨ ᠮᠠᠨᡳ (webhook_signing_secret᠂ ᡝᠯᡝ whsec_ ᡩᡝ ᡝᠵᡝᠨ) ᡠᠯᡥᡳᠮᡝ ᠪᠠᠨᡳᠮᡝ ᠵᡠᠯᡝ ᠵᠠᠯᠠᠨ ᡩᡝ ᠵᡠᠯᡝ ᠪᠠᠨᡳᠮᡝ.
Doitong-Signature ᡳ ᠵᠠᠯᠠᠨ ᠣᠴᡳ t=<unix time>,v1=<signature>᠂ ᡝᡵᡝ ᠵᡠᠯᡝ ᠣᠴᡳ "<t>.<raw request body>" ᡳ ᠮᡠᠶᠠᠨ ᡳ HMAC-SHA256 ᡳ ᡠᡵᠰᡝ ᠮᡠᠶᠠᠨᠠᠮᡝ᠂ ᠰᡳᠨᡳ ᠪᠠᠨᡳᠨ ᠣᠴᡳ ᠵᡠᠯᡝᠨ. ᠵᡠᠯᡝᠯᡝᠮᡝ:
- ᡝᠨᡩᡝᡵᡝᠮᡝ ᠣᠯᡥᠣ ᠪᠠᠶᠠᠨ ᡳ ᠮᡠᠶᠠᠨ ᠪᡝ ᠵᡠᠯᡝ ᠪᠠᠨᡳᠮᡝ ᠠᠪᡠᠰᡥᠠᠮᡝ᠂ JSON ᠵᡠᠯᡝᠯᡝᠮᡝ ᠪᠠᠨᡳᠮᠪᡝ ᠣᠴᡳᠨᡳ.
- ᠰᡳᠨᡳ ᠪᠠᠨᡳᠨ ᡩᡝ
t + "." + bodyᡳ HMAC-SHA256 ᠪᡝ ᡠᡵᠰᡝ ᠮᡠᠶᠠᠨᠠᠮᡝ ᠪᠠᠨᡳᠮᡝ ᠮᡠᠶᠠᠨ ᠪᡝ ᠪᠠᠷᠠ ᠦᠰᡳᡥᡝᠮᡝ ᠪᡝᠶᡝᠯᡝᠮᡝ. v1ᡳ ᠵᡠᠯᡝ ᡩᡝ ᠮᡠᠶᠠᠨ ᠪᡝ ᠠᠮᠪᠠ ᠵᡠᠯᡝᠨ ᠪᠠᠨᡳᠮᡝ ᠰᡳᠯᡤᠠᠯᠠᠮᡝ.tᠰᡳᠨᡳ ᠴᡳᠣᠸᠠᠨ ᡩᡝ 5 ᠮᡳᠨᡠᡨᡝ ᡩᡝ ᡩᠠᠯᡵᠠᠨ ᠣᠴᡳ ᠵᡠᠯᡝ ᠪᡝ ᡠᠯᡥᡳᠮᡝ᠂ ᠵᡠᠯᡝ ᠪᠠᠨᡳᠨ ᠪᡝ ᠪᠠᠨᡳᠮᡝ.
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
ᡤᡠᠯᡤᠠᠨ ᠵᡠᠯᡝ
- ᠵᠠᠯᠠᠨ ᠪᡝ ᠮᡠᠶᠠᠨᠠᠮᡝ ᡝᠨᡩᡝᡵᡝᠮᡝ ᠰᡳᠨᡳ ᠵᡝᠪᡝ ᠵᠠᠯᠠᠨ ᡩᡝ ᠪᠠᠨᡳᠮᡝ.
- ᠪᠠᠨᡳᠨ ᠣᠴᡳ ᠪᠠᠶᠠᠨ ᠪᠠᠨᡳᠮᡝ ᠪᡝᠶᡝ ᠪᠠᠨᡳᠮᡝ ᠵᡠᠯᡝᠨ ᡳ ᠪᠠᠨᡳᠨ ᠣᠴᡳ ᠵᡠᠯᡝᠨ ᠵᡠᠯᡝᠨ ᠣᠴᡳᠨᡳ.