Үндсэн агуулга руу алгасах

Webhook — ирсэн эвент

Толгойнууд, HMAC-SHA256 гарын үсэг (Node · Python · Go), давтан илгээлт, эвентийн төрөл.

Таны URL руу POST, Content-Type: application/json, User-Agent: BuildryChat/1.0. 2xx буцаахад л амжилттай; бусдад 0.5с · 1с · 2с-ийн дараа дахин (нийт 4 оролдлого, тус бүр 10с timeout). 20 дараалсан алдаанд webhook paused болно — dashboard-д URL-аа дахин хадгалахад сэргэнэ (нууц шинээр гарна). Хүргэлтийн лог 14 хоног dashboard/GET /v1/webhook/deliveries-д.

Толгойнууд: X-Buildry-Event · X-Buildry-Delivery (uuid, давхардлыг үүгээр таслана) · X-Buildry-Timestamp (unix сек) · X-Buildry-Signature: sha256=<hex>.

Гарын үсэг шалгах

Гарын үсэг: HMAC-SHA256(secret, timestamp + "." + raw_body). Body-г түүхий байтаар (parse хийхээс өмнө) авна.

Node
// Node (Express: app.use(express.raw({ type: "*/*" })))
const crypto = require("crypto");
function verify(req, secret) {
  const ts = req.header("X-Buildry-Timestamp");
  const sig = (req.header("X-Buildry-Signature") || "").replace("sha256=", "");
  const mac = crypto.createHmac("sha256", secret).update(ts + "." + req.body).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300; // 5 мин replay цонх
  return fresh && sig.length === mac.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(mac));
}
Python
import hmac, hashlib, time
def verify(headers, raw_body: bytes, secret: str) -> bool:
    ts = headers["X-Buildry-Timestamp"]
    sig = headers.get("X-Buildry-Signature", "").removeprefix("sha256=")
    mac = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return abs(time.time() - int(ts)) < 300 and hmac.compare_digest(sig, mac)
Go
import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"math"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// rawBody = io.ReadAll(r.Body) — JSON задлахаас өмнө.
func verify(h http.Header, rawBody []byte, secret string) bool {
	ts := h.Get("X-Buildry-Timestamp")
	sec, err := strconv.ParseInt(ts, 10, 64)
	if err != nil || math.Abs(float64(time.Now().Unix()-sec)) >= 300 { // 5 мин replay цонх
		return false
	}
	sig, err := hex.DecodeString(strings.TrimPrefix(h.Get("X-Buildry-Signature"), "sha256="))
	if err != nil {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(ts + "."))
	mac.Write(rawBody)
	return hmac.Equal(sig, mac.Sum(nil))
}

Дугтуй ба эвентүүд

Дугтуй:

{ "id": "<delivery uuid>", "event": "message.received", "created_at": "2026-09-08T08:00:00Z", "data": { … } }
eventdata
message.receivedworkspace_id, conversation_id, platform (messenger·instagram·telegram·webchat), channel{kind, external_id}, contact{id, sender_id, name, profile_pic}, message{id, text, type, external_id, created_at, attachment?{url,type}}
postback.receivedдээрхтэй ижил + postback{payload, received_at} — таны илгээсэн товчны payload
comment.receivedworkspace_id, platform, channel, comment{id, post_id, text, from{id,name}, received_at}
testworkspace_id, sent_at — «Тест илгээх» товч / POST /v1/webhook/test

Зөвхөн ҮЙЛЧЛҮҮЛЭГЧИЙН ирсэн зүйл дамжина — таны өөрийн хариу, OpenBot-ийн inbox-оос бичсэн хариу, page-ийн өөрийн коммент ХЭЗЭЭ Ч ирэхгүй (давталт үүсгэхгүй).

Webhook-оо API-аар удирдах

Dashboard-гүйгээр:

  • GET /v1/webhook · PUT /v1/webhook {url} → {webhook, secret} (secret нэг удаа) · DELETE /v1/webhook · POST /v1/webhook/test → {delivery} · GET /v1/webhook/deliveries?limit=