Webhook
Αντί για polling, δώστε σε μια εκτέλεση ένα webhook_url. Όταν το αίτημα φτάσει σε τελική κατάσταση (succeeded, failed ή canceled), στέλνουμε υπογεγραμμένο 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παραμένει σταθερό για ένα αίτημα και την τελική του κατάσταση. Χρησιμοποιήστε το για να αγνοείτε μια παράδοση που έχετε ήδη επεξεργαστεί.
Παραδόσεις και επαναλήψεις
Απαντήστε με οποιαδήποτε κατάσταση 2xx εντός 10 δευτερολέπτων. Οτιδήποτε άλλο (ή ένα timeout) επαναλαμβάνεται: έως 6 προσπάθειες συνολικά, μετά από 30 δευτερόλεπτα, 2 λεπτά, 10 λεπτά, 1 ώρα και 6 ώρες. Εκτελέστε τις αργές εργασίες μετά την απάντηση, όχι πριν.
Επαλήθευση υπογραφής
Κάθε κλειδί έχει το δικό του μυστικό υπογραφής. Διαβάστε το μία φορά από το GET https://api.doitong.com/v1/account (webhook_signing_secret, ξεκινά με whsec_) και αποθηκεύστε το μαζί με το κλειδί.
Η κεφαλίδα Doitong-Signature είναι t=<unix time>,v1=<signature>, όπου η υπογραφή είναι το hex HMAC-SHA256 του "<t>.<raw request body>", με το μυστικό σας ως κλειδί. Για επαλήθευση:
- Πάρτε τα byte του αρχικού σώματος ακριβώς όπως παραλήφθηκαν (πριν από οποιαδήποτε ανάλυση JSON).
- Υπολογίστε HMAC-SHA256 του
t + "." + bodyμε το μυστικό σας, ως πεζά δεκαεξαδικά. - Συγκρίνετέ το με το
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
Συμβουλές
- Απαντήστε γρήγορα και τοποθετήστε την επεξεργασία στη δική σας ουρά.
- Το μυστικό ανήκει στο κλειδί API που ξεκίνησε την εκτέλεση. Τα κλειδιά σε διαφορετικές υπηρεσίες έχουν διαφορετικά μυστικά.