ไทย
ไทย
Appearance
ไทย
ไทย
Appearance
Webhook แจ้งเตือนแอปพลิเคชันของคุณแบบเรียลไทม์เมื่อมีเหตุการณ์เกิดขึ้นกับข้อมูลรับรองของคุณ — เมื่อมีการออก การนำส่ง การเพิกถอน หรือการเข้าชม แทนที่จะต้องคอยเรียก API (polling) คุณเพียงลงทะเบียนปลายทาง HTTPS แล้ว badges.ninja จะส่งคำขอ POST ที่ลงลายเซ็นไปยังปลายทางนั้นสำหรับทุกเหตุการณ์ที่คุณสมัครรับ
ปลายทางสำหรับการจัดการทั้งหมดต้องมีการยืนยันตัวตนผ่านส่วนหัว X-Api-Key ดูที่ การยืนยันตัวตน การสร้างหรือลบปลายทางต้องใช้คีย์ที่มีสิทธิ์ write ส่วนการแสดงรายการต้องใช้สิทธิ์ read ดูที่ คีย์ API
POST /webhooks| พารามิเตอร์ | ชนิด | จำเป็น | คำอธิบาย |
|---|---|---|---|
url | string | ใช่ | ปลายทาง HTTPS ของคุณ ต้องขึ้นต้นด้วย https:// |
events | string[] | ไม่ | ชนิดเหตุการณ์ที่จะสมัครรับ หากละไว้หรือส่ง ["*"] จะได้รับทุกเหตุการณ์ |
curl -X POST https://api.badges.ninja/webhooks \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"]
}'201 Created ความลับสำหรับลงลายเซ็น (signing secret) จะถูกส่งกลับเพียงครั้งเดียวเท่านั้น — จัดเก็บไว้ตอนนี้ เพราะคุณไม่สามารถเรียกดูได้อีก
{
"id": "e4b19ff5-063d-4799-bd75-d03641be624f",
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"],
"secret": "2be6d335682c1658242fde3a523fd8a2493bab8c"
}GET /webhooksส่งกลับปลายทางที่คุณลงทะเบียนไว้ ความลับสำหรับลงลายเซ็นจะไม่รวมอยู่ในผลลัพธ์เลย
{
"webhooks": [
{
"id": "e4b19ff5-063d-4799-bd75-d03641be624f",
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"],
"active": true,
"failureCount": 0,
"createdAt": 1787685415083,
"lastStatus": 200,
"lastDeliveryAt": 1787685480777
}
]
}DELETE /webhooks/{id}curl -X DELETE https://api.badges.ninja/webhooks/e4b19ff5-063d-4799-bd75-d03641be624f \
-H "X-Api-Key: bws_your_api_key_here"การนำส่งไปยังปลายทางจะหยุดทันที
| เหตุการณ์ | เกิดขึ้นเมื่อ… |
|---|---|
credential.issued | มีการออกข้อมูลรับรองให้แก่ผู้รับ |
credential.delivered | อีเมลแจ้งเตือนของข้อมูลรับรองถูกส่งไปยังผู้รับ (แบบเดี่ยวหรือแบบกลุ่ม) |
credential.revoked | ข้อมูลรับรองถูกเพิกถอน |
credential.viewed | หน้าข้อมูลรับรองสาธารณะของผู้รับถูกเข้าชมเป็นครั้งแรก |
การนำส่งทุกครั้งเป็นคำขอ POST ที่มีเนื้อความ JSON รูปแบบดังนี้:
{
"id": "b1c2d3e4-...",
"type": "credential.issued",
"createdAt": 1787685415083,
"data": { }
}| ฟิลด์ | คำอธิบาย |
|---|---|
id | รหัสการนำส่งที่ไม่ซ้ำกัน (ใช้เพื่อขจัดรายการซ้ำ) |
type | ชนิดเหตุการณ์ |
createdAt | เวลาประทับของเหตุการณ์ (epoch มิลลิวินาที) |
data | เพย์โหลดเฉพาะของแต่ละเหตุการณ์ (ดูด้านล่าง) |
data แยกตามชนิดเหตุการณ์ credential.issued
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"badgeId": "https://api.badges.ninja/certify-badge/badge/<guid>",
"badgeName": "Advanced Certification",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" },
"issuedOn": "2026-08-25",
"expires": null
}credential.delivered
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" },
"badgeName": "Advanced Certification"
}credential.revoked
{ "awardId": "https://api.badges.ninja/certify-badge/award/<guid>", "reason": "Issued in error" }credential.viewed
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" }
}การนำส่งแต่ละครั้งจะมีส่วนหัวเหล่านี้:
| ส่วนหัว | คำอธิบาย |
|---|---|
X-Bws-Event | ชนิดเหตุการณ์ (เหมือนกับ type ในเนื้อความ) |
X-Bws-Delivery | รหัสการนำส่ง (เหมือนกับ id ในเนื้อความ) |
X-Bws-Signature | sha256= ตามด้วยค่า HMAC-SHA256 ของเนื้อความคำขอดิบ โดยใช้ความลับของปลายทางเป็นคีย์ |
User-Agent | badges.ninja-webhooks/1 |
ตรวจสอบลายเซ็นทุกครั้งก่อนที่จะเชื่อถือการนำส่ง คำนวณค่า HMAC-SHA256 ของเนื้อความคำขอดิบโดยใช้ความลับสำหรับลงลายเซ็นของปลายทางคุณ แล้วเปรียบเทียบ (แบบใช้เวลาคงที่) กับส่วนหัว X-Bws-Signature
import crypto from "node:crypto";
function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(signatureHeader);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}ใช้ไบต์ตรงตามที่คุณได้รับมา — การแยกวิเคราะห์ (parse) แล้วแปลง JSON กลับเป็นสตริงใหม่จะเปลี่ยนไบต์และทำให้ลายเซ็นใช้ไม่ได้
2xxfailureCount และหลังจากล้มเหลวติดต่อกัน 20 ครั้ง ปลายทางจะถูกปิดใช้งานโดยอัตโนมัติ (active: false) และหยุดรับการนำส่งจนกว่าคุณจะแก้ไขและลงทะเบียนปลายทางใหม่X-Bws-Delivery (หรือ id ในเนื้อความ) เพื่อทำให้ตัวจัดการของคุณเป็น idempotentคุณยังสามารถจัดการปลายทางได้โดยไม่ต้องใช้ API — เปิด Webhooks ในแถบด้านข้างของแดชบอร์ดเพื่อเพิ่ม แสดงรายการ และลบปลายทาง รวมถึงเลือกว่าปลายทางแต่ละรายการจะรับเหตุการณ์ใดบ้าง