← Tài liệu

Webhook

Nextfarm gửi POST tới hệ thống của bạn khi có sự kiện ở trại. Chủ trại thêm địa chỉ nhận (https://) và chọn sự kiện ở Quản lý › Webhook.

Sự kiện

Sự kiệnNhómKhi nào
iot.alert.raisedIoTCảm biến vượt ngưỡng: thiết bị, chỉ số, giá trị, ngưỡng, mức độ.
iot.device.offlineIoTThiết bị ngừng báo về quá thời gian cho phép.
harvest.batch.createdThu hoạchLô thu hoạch được khai báo và xác nhận: thửa, loại cây, sản lượng (kg).

Tin gửi đi

Lệnh mẫu
POST https://erp.htx-cua-ban.vn/hooks/nextfarm
Content-Type: application/json
X-Nextfarm-Event: iot.alert.raised
X-Nextfarm-Delivery: 0199...          (mã lượt giao — dùng để bỏ trùng)
X-Nextfarm-Timestamp: 1790467200      (giây Unix)
X-Nextfarm-Signature: sha256=9c1e...

{
  "id": "0199...", "type": "iot.alert.raised",
  "workspace_id": "...", "occurred_at": "2026-09-27T03:10:00Z",
  "data": { "alert_id": "...", "device_id": "...", "device_code": "NK2", "zone_id": "...",
            "parcel_ids": [], "metric": "temperature", "value": 41.2, "threshold": 38,
            "severity": "high", "message": "..." }
}
Sự kiệnTrường trong data
iot.alert.raisedalert_id, device_id, device_code, zone_id, parcel_ids, metric, value, threshold, severity, message
iot.device.offlinedevice_id, device_code, device_name, zone_id, parcel_ids, last_heartbeat
harvest.batch.createdharvest_record_id, parcel_id, crop_type_id, quantity_kg, confirmed_at

Kiểm chữ ký

X-Nextfarm-Signature = sha256= + hex của HMAC-SHA256(bí_mật, timestamp + "." + thân_tin). Bí mật (whsec_…) hiện một lần lúc tạo địa chỉ hoặc lúc xoay. Từ chối tin có timestamp lệch quá 5 phút.

Node.js (Express)
import crypto from "node:crypto";
// cần thân tin NGUYÊN BẢN — express.raw, không express.json
app.post("/hooks/nextfarm", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.header("X-Nextfarm-Timestamp");
  const expected = "sha256=" + crypto.createHmac("sha256", process.env.NEXTFARM_WEBHOOK_SECRET)
    .update(ts + "." + req.body).digest("hex");
  const got = req.header("X-Nextfarm-Signature") ?? "";
  const ok = got.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got));
  if (!ok || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
  const event = JSON.parse(req.body);   // bỏ trùng theo X-Nextfarm-Delivery
  res.sendStatus(200);
});
Python (Flask)
import hmac, hashlib, time
@app.post("/hooks/nextfarm")
def hook():
    ts = request.headers["X-Nextfarm-Timestamp"]
    body = request.get_data()
    expected = "sha256=" + hmac.new(SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-Nextfarm-Signature", "")) \
       or abs(time.time() - int(ts)) > 300:
        return "", 401
    return "", 200

Thử lại và tạm dừng

Địa chỉ nhận phải là https:// tới máy chủ công khai. Nextfarm từ chối địa chỉ nội bộ (localhost, 10.x, 192.168.x, 169.254.x…) cả lúc lưu lẫn lúc gửi.

Luật bảo mật đầy đủ cho đối tác: Bảo mật →