← 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ện | Nhóm | Khi nào |
|---|---|---|
iot.alert.raised | IoT | Cảm biến vượt ngưỡng: thiết bị, chỉ số, giá trị, ngưỡng, mức độ. |
iot.device.offline | IoT | Thiết bị ngừng báo về quá thời gian cho phép. |
harvest.batch.created | Thu hoạch | Lô 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ện | Trường trong data |
|---|---|
iot.alert.raised | alert_id, device_id, device_code, zone_id, parcel_ids, metric, value, threshold, severity, message |
iot.device.offline | device_id, device_code, device_name, zone_id, parcel_ids, last_heartbeat |
harvest.batch.created | harvest_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 "", 200Thử lại và tạm dừng
- Trả
2xxtrong 10 giây là thành công. Mã khác, quá giờ hoặc chuyển hướng (3xx) là hỏng. - Hỏng thì thử lại sau 1 phút, 5 phút, 30 phút, 2 giờ, 6 giờ, 24 giờ (tổng 7 lần gửi).
- 5 lượt giao hỏng hết mọi lần thử, liên tiếp ⇒ địa chỉ tự tạm dừng; bật lại ở màn Webhook.
- Màn Webhook có Gửi thử (tin
webhook.test), nhật ký giao 50 lượt gần nhất, Giao lại, Xoay bí mật.
Đị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 →