Bỏ qua để đến nội dung

Webhook

Bona Fide gửi một yêu cầu HTTPS POST đến endpoint của bạn cho mọi sự kiện phong bì mà bạn đăng ký nhận. Các lần gửi tuân theo đặc tả Standard Webhooks, nên bất kỳ thư viện nào của đặc tả này cũng có thể xác minh chúng.

Tại Settings › Webhooks, hoặc bằng một khóa API có phạm vi quyền org:manage:

Terminal window
curl https://api.bonafidesign.com/v1/webhook-endpoints \
-H "Authorization: Bearer $BONA_FIDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/hooks/bona-fide",
"description": "Production",
"events": ["envelope.completed", "envelope.sealed", "envelope.declined"]
}'

Phản hồi chứa secret (whsec_…), chỉ duy nhất lần này. Danh sách events rỗng nghĩa là đăng ký nhận mọi sự kiện. URL phải là https:// công khai. Một endpoint thuộc về một chế độ: endpoint tạo bằng khóa thử nghiệm chỉ nhận sự kiện của phong bì ở chế độ thử nghiệm, endpoint trực tiếp chỉ nhận sự kiện trực tiếp.

PATCH /v1/webhook-endpoints/{id} thay đổi URL, sự kiện hoặc mô tả, và tạm dừng hoặc tiếp tục endpoint (enabled). POST /v1/webhook-endpoints/{id}/test gửi một ping webhook.test.

Loại Khi nào
envelope.created Phong bì đã được tạo
envelope.ready Tài liệu đã được kết xuất và phong bì sẵn sàng cho người nhận
recipient.sent Đã đến lượt một người nhận (và, với phương thức gửi qua email, liên kết của họ đã được gửi)
recipient.viewed Một người nhận mở trang ký lần đầu tiên
recipient.signed Một người nhận đã gửi (hoặc được ký đối ứng tự động)
recipient.declined Một người nhận đã từ chối
envelope.completed Mọi người nhận đã xong. data.values chứa các biến và mọi giá trị đã nhập
envelope.sealed Tệp PDF đã niêm phong sẵn sàng để tải xuống
envelope.declined Phong bì kết thúc vì một người nhận đã từ chối
envelope.voided Bạn đã hủy phong bì
envelope.expired expiresAt đã qua trước khi hoàn tất
signing_link.used Một khách truy cập đã bắt đầu phong bì từ liên kết ký luôn hoạt động

acceptance.created được dành sẵn trong schema và hiện chưa được phát.

{
"id": "evt_9sKq2Lm4Tz",
"type": "envelope.completed",
"createdAt": "2026-10-13T14:09:52.004Z",
"testMode": false,
"data": {
"envelope": {
"id": "env_8Gm2kQ4rT1",
"status": "completed",
"seal": "pending",
"recipients": [{ "id": "rcp_5Jw0pLs9Xe", "role": "client", "status": "completed", "…": "…" }],
"externalId": "user_8841",
"metadata": {},
"…": "…"
},
"values": {
"variables": { "client": { "name": "Acme Robotics, Inc." }, "effective_date": "2026-10-13" },
"recipients": {
"client": { "client_title": "CEO", "start_date": "2026-11-01" }
}
}
}
}

data.envelope là toàn bộ phong bì tại thời điểm xảy ra sự kiện. data.values chỉ có trên envelope.completed: các biến bạn đã gửi, và giá trị các trường của từng vai trò theo id trường.

Mỗi lần gửi đều mang:

Header Giá trị
webhook-id Id sự kiện (evt_…); giống nhau ở mọi lần thử lại. Dùng để chống trùng lặp
webhook-timestamp Số giây Unix khi lần thử này được ký
webhook-signature v1,<base64 HMAC-SHA256>, phân tách bằng dấu cách khi có nhiều secret cùng ký
user-agent BonaFide-Webhooks/1

Chữ ký là HMAC-SHA256 trên {webhook-id}.{webhook-timestamp}.{raw body}, với khóa là phần đã giải mã base64 của secret sau whsec_. Hãy xác minh nội dung thô (trước khi phân tích JSON), so sánh trong thời gian hằng định, và từ chối dấu thời gian lệch quá năm phút so với đồng hồ của bạn.

import express from 'express';
import { Webhook } from 'standardwebhooks'; // npm i standardwebhooks
const wh = new Webhook(process.env.BONA_FIDE_WEBHOOK_SECRET!); // whsec_…
const app = express();
app.post('/hooks/bona-fide', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = wh.verify(req.body, req.headers as Record<string, string>); // throws if forged or too old
} catch {
return res.sendStatus(400);
}
queue.add(event); // do the work asynchronously and answer quickly
res.sendStatus(204);
});

Một lần gửi thành công khi nhận được bất kỳ mã 2xx nào trong vòng 10 giây. Chuyển hướng không được theo. Mọi trường hợp khác được thử lại với thời gian chờ tăng dần, sau 5 giây, 5 phút, 30 phút, 2 giờ, 5 giờ, 10 giờ, 14 giờ, 20 giờ và 24 giờ, tối đa ba ngày sau sự kiện. Sau đó lần gửi được đánh dấu là thất bại.

  • Phản hồi nhanh và xử lý bất đồng bộ; chống trùng lặp dựa trên webhook-id.
  • Các lần gửi có thể đến không theo thứ tự: hãy kiểm tra data.envelope.status thay vì giả định một trình tự.
  • GET /v1/webhook-endpoints/{id}/deliveries liệt kê các lần thử gần đây kèm mã trạng thái, lỗi và thời gian, và mỗi endpoint hiển thị tỷ lệ thành công trong 24 giờ (health).
  • POST /v1/events/{id}/redeliver gửi lại một sự kiện đến một endpoint, chẳng hạn sau một sự cố gián đoạn.

POST /v1/webhook-endpoints/{id}/secret/rotate trả về secret mới ngay lập tức. Trong 24 giờ tiếp theo, mọi lần gửi được ký bằng cả secret mới và secret cũ (hai mục trong webhook-signature), nhờ đó bạn có thể triển khai secret mới mà không bỏ lỡ sự kiện nào.