WebHooks
หัวข้อทั้งหมดในหน้านี้
Webhooks
ภาพรวม
Webhook คือ HTTP POST request ที่ส่งจากเซิร์ฟเวอร์ของเราไปยัง HTTPS endpoint ที่คุณกำหนด เมื่อเกิดเหตุการณ์เฉพาะขึ้นบนบัญชีของคุณ แต่ละ request จะมีอ็อบเจกต์ event ที่มีข้อมูล payload สำหรับการดำเนินการที่เป็นตัวกระตุ้น
Webhook ช่วยให้สามารถรับการแจ้งเตือนแบบอะซิงโครนัสและเรียลไทม์เมื่อเกิดเหตุการณ์สำคัญบนบัญชีของคุณ แทนที่จะต้องส่ง request ซ้ำๆ ไปยัง API เพื่อตรวจสอบการเปลี่ยนแปลงสถานะ Webhook จะพุชการแจ้งเตือนไปยังเซิร์ฟเวอร์ของคุณโดยตรงในทันทีที่เหตุการณ์เกิดขึ้น
ประโยชน์หลัก:
- ประสิทธิภาพ: ขจัดความจำเป็นในการ polling อย่างต่อเนื่อง ลด API call และภาระเซิร์ฟเวอร์ที่ไม่จำเป็น
- การอัปเดตแบบเรียลไทม์: รับการแจ้งเตือนทันทีเมื่อเกิดเหตุการณ์ เช่น การชำระเงินสำเร็จ การคืนเงิน หรือการโต้แย้ง
- การทำงานอัตโนมัติ: เรียกใช้เวิร์กโฟลว์อัตโนมัติในแอปพลิเคชันของคุณทันทีเมื่อได้รับเหตุการณ์ เช่น การอัปเดตสถานะคำสั่งซื้อ การส่งอีเมลให้ลูกค้า หรือการกระทบยอดบัญชี
- ความน่าเชื่อถือ: รับประกันว่าคุณจะไม่พลาดเหตุการณ์สำคัญ แม้ในช่วงที่แอปพลิเคชันของคุณไม่ได้ตรวจสอบการอัปเดตอยู่
การตั้งค่า
ตั้งค่า Webhook endpoint แยกต่างหากสำหรับโหมดทดสอบและโหมดจริง:
- โหมดทดสอบ: https://dashboard.omise.co/test/webhooks
- โหมดจริง: https://dashboard.omise.co/live/webhooks
การดูข้อมูล Event
เข้าถึงข้อมูล event ของ Webhook ทั้งหมดได้ผ่าน:
- แดชบอร์ดในหัวข้อ
Events
คลิกไอคอน Account ที่แผงด้านขวาและเลือก Events - Events API
การ Serialize ข้อมูล
อ็อบเจกต์ event ใน POST request (หรือที่ส่งคืนผ่าน Events API) จะถูก serialize ตามค่าเริ่มต้นเวอร์ชัน API ณ เวลาที่เกิดเหตุการณ์เสมอ โดยไม่คำนึงถึงค่าของ header Omise-Version ที่ส่งมาใน request ที่เป็นตัวกระตุ้น
ตัวอย่าง
สำหรับบัญชีที่ตั้งค่าเวอร์ชันเป็น 2017-11-02:
- สร้าง charge โดยใช้
curlพร้อม-H "Omise-Version: 2019-05-29" - Request ดังกล่าวสร้าง event
charge.createที่มีอ็อบเจกต์chargeฝังอยู่ - อ็อบเจกต์จะถูก serialize ตามเวอร์ชัน
2017-11-02ของCharge API ไม่ใช่ เวอร์ชัน2019-05-29 - แม้หลังจากอัปเดตบัญชีเป็นเวอร์ชัน
2019-05-29แล้ว event ก็ยังคง serialize ตามเวอร์ชัน2017-11-02อยู่
ข้อกำหนดและแนวปฏิบัติที่ดี
ข้อกำหนดทางเทคนิค
- URL ต้อง ใช้ HTTPS
- URL ต้อง ใช้ SSL certificate ที่ถูกต้อง (ไม่รองรับ self-signed certificate)
- ตรวจสอบ SSL certificate ด้วย SSL Labs
- สำหรับ SSL certificate ฟรี ไปที่ Let's Encrypt
แนวปฏิบัติด้านความปลอดภัย
แนะนำ: การตรวจสอบลายเซ็น
เราแนะนำอย่างยิ่งให้นำการตรวจสอบลายเซ็นมาใช้เป็นมาตรการรักษาความปลอดภัยหลักเพื่อรับรองความถูกต้องของ Webhook การตรวจสอบลายเซ็นยืนยันทางการเข้ารหัสว่า request มาจาก Omise และไม่ได้ถูกดัดแปลง ซึ่งให้การป้องกันที่แข็งแกร่งที่สุดจากผู้ไม่ประสงค์ดีที่พยายามส่ง Webhook ปลอมไปยัง endpoint ของคุณ ดูรายละเอียดการนำไปใช้งานได้ที่หัวข้อการปกป้อง Endpoint
ทางเลือก: การตรวจสอบ Event
หากการตรวจสอบลายเซ็นไม่สามารถนำไปใช้ได้ในการติดตั้งของคุณ ให้ใช้การตรวจสอบ event เป็นทางเลือก เมื่อได้รับ Webhook event (เช่น charge.complete) ให้ใช้ resource ID เพื่อส่ง GET request อิสระเพื่อยืนยันสถานะ โปรดทราบว่าวิธีนี้ไม่ได้ป้องกัน endpoint ของคุณจากการรับ request ปลอม แต่ช่วยให้คุณตรวจสอบความถูกต้องของข้อมูล event ได้หลังจากได้รับแล้วเท่านั้น
ตัวอย่างเวิร์กโฟลว์การตรวจสอบ event:
1. รับ Webhook `charge.complete`
2. ดึง Charge ID จาก Webhook payload
3. ส่ง GET request ไปที่ `/charges/{CHARGE_ID}`
4. ตรวจสอบสถานะ charge อย่างอิสระ
Event ที่รองรับ
Event บัตร
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
card.destroy |
บัตรถูกลบแล้ว |
card.update |
บัตรถูกอัปเดตแล้ว |
Event Charge
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
charge.capture |
Charge ถูก capture แล้ว (เฉพาะการ capture ด้วยตนเอง) |
charge.complete |
Charge เสร็จสมบูรณ์แล้ว (หมายเหตุ: การทำ charge บัตรที่ไม่ใช่ 3DS ให้สำเร็จจะไม่ทริกเกอร์ Webhook นี้) |
charge.create |
Charge ถูกสร้างแล้ว |
charge.expire |
Charge หมดอายุแล้ว (เฉพาะ Barcode Alipay) |
charge.reverse |
Charge ถูกยกเลิกแล้ว (เฉพาะการยกเลิกด้วยตนเอง) |
charge.update |
Charge ถูกอัปเดตแล้ว |
Event ลูกค้า
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
customer.create |
ลูกค้าถูกสร้างแล้ว |
customer.destroy |
ลูกค้าถูกลบแล้ว |
customer.update |
ลูกค้าถูกอัปเดตแล้ว |
customer.update.card |
บัตรถูกอัปเดตโดยอัตโนมัติผ่านลูกค้า |
Event การโต้แย้ง
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
dispute.accept |
การโต้แย้งได้รับการยอมรับแล้ว |
dispute.close |
การโต้แย้งถูกปิดแล้ว |
dispute.create |
การโต้แย้งถูกเปิดแล้ว |
dispute.update |
การโต้แย้งถูกอัปเดตแล้ว |
Event ผู้รับเงิน
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
recipient.activate |
ผู้รับเงินถูกเปิดใช้งานแล้ว |
recipient.create |
ผู้รับเงินถูกสร้างแล้ว |
recipient.deactivate |
ผู้รับเงินถูกปิดใช้งานแล้ว |
recipient.destroy |
ผู้รับเงินถูกลบแล้ว |
recipient.update |
ผู้รับเงินถูกอัปเดตแล้ว |
recipient.verify |
ผู้รับเงินได้รับการยืนยันแล้ว |
Event การคืนเงิน
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
refund.create |
การคืนเงินถูกสร้างแล้ว |
Event กำหนดการ
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
schedule.create |
กำหนดการถูกสร้างแล้ว |
schedule.destroy |
กำหนดการถูกลบแล้ว |
schedule.expire |
กำหนดการหมดอายุแล้ว |
schedule.expiring |
กำหนดการใกล้หมดอายุแล้ว |
schedule.suspend |
กำหนดการถูกระงับแล้ว |
Event การโอนเงิน
| ชื่อ Event | ตัวกระตุ้น |
|---|---|
transfer.create |
การโอนเงินถูกสร้างแล้ว |
transfer.destroy |
การโอนเงินถูกลบแล้ว |
transfer.fail |
การโอนเงินถูกทำเครื่องหมายว่าล้มเหลว |
transfer.pay |
การโอนเงินถูกทำเครื่องหมายว่าชำระแล้ว |
transfer.send |
การโอนเงินถูกทำเครื่องหมายว่าส่งแล้ว |
transfer.update |
การโอนเงินถูกอัปเดตแล้ว |
Dynamic Webhook
บัญชี Omise ทุกบัญชีมี endpoint Webhook แบบ static ที่ตั้งค่าได้หนึ่งรายการ โดยค่าเริ่มต้น การแจ้งเตือน event ทั้งหมดจะถูกส่งไปยัง endpoint นี้
ฟีเจอร์ Dynamic Webhook ช่วยให้คุณระบุ endpoint Webhook แบบกำหนดเองในแต่ละ charge ได้ โดยส่งพารามิเตอร์ webhook_endpoints เมื่อสร้าง charge
การทำงาน
เมื่อระบุ webhook_endpoints:
- Event ทั้งหมดสำหรับ charge นั้นจะถูกส่งไปยัง
webhook_endpointsที่ระบุ - Event จะไม่ถูกส่งไปยัง Webhook แบบ static
เมื่อไม่ได้ระบุ webhook_endpoints:
- การแจ้งเตือน event จะถูกส่งไปยัง Webhook แบบ static ของบัญชี
การปกป้อง Endpoint
Omise ใช้อัลกอริทึม HMAC-SHA256 ในการลงนาม Webhook payload ทางการเข้ารหัส เมื่อมีการตั้งค่า Webhook secret ในบัญชีของคุณ ลายเซ็นดิจิทัลจะถูกรวมอยู่ใน Webhook header ตรวจสอบลายเซ็นเพื่อรับรองความถูกต้องและความครบถ้วนของ Webhook request
Header ลายเซ็น Webhook
| Header | คำอธิบาย |
|---|---|
Omise-Signature |
ลายเซ็น HMAC ที่เข้ารหัสเป็น Hex ที่สร้างโดย Omise ระหว่างการหมุนเวียน secret header จะมีลายเซ็นสองรายการคั่นด้วยเครื่องหมายจุลภาค โดยแต่ละรายการสอดคล้องกับ secret แต่ละรายการ |
Omise-Signature-Timestamp |
Unix timestamp เมื่อสร้างลายเซ็น |
ตัวอย่าง header:
Omise-Signature: 072cc0d8b49d49ce7119857279b1e36a9efa25fadb468d0126628064d4062c83
Omise-Signature-Timestamp: 1758696391
// ระหว่างการหมุนเวียน
Omise-Signature: 072cc0d8b49d49ce7119857279b1e36a9efa25fadb468d0126628064d4062c83,4bb1e14023f53d076e598245e5e16fd96a94d46072149c483815718eecf2a38d
วิธีตรวจสอบลายเซ็น Webhook
ขั้นตอนที่ 1: ดึงลายเซ็น
ดึง header Omise-Signature และ Omise-Signature-Timestamp จาก Webhook request
ขั้นตอนที่ 2: เตรียม payload สำหรับลงนาม
สร้าง payload สำหรับการสร้างลายเซ็น HMAC โดยการต่อข้อมูลต่อไปนี้:
- ค่าของ header
Omise-Signature-Timestamp - จุด (
.) - raw body ของ Webhook request ที่เข้ารหัสเป็น UTF-8
รูปแบบ:
<TIMESTAMP>.<RAW_BODY>
ขั้นตอนที่ 3: ถอดรหัส Webhook Secret
Webhook secret คือ HMAC secret key ที่เข้ารหัสเป็น Base64 ถอดรหัสก่อนดำเนินการขั้นตอนถัดไป
ขั้นตอนที่ 4: คำนวณลายเซ็นที่คาดหวัง
คำนวณ HMAC-SHA256 digest ของ payload สำหรับลงนามโดยใช้ secret ที่ถอดรหัสแล้ว จากนั้นเข้ารหัสผลลัพธ์เป็นสตริง hexadecimal
ขั้นตอนที่ 5: เปรียบเทียบลายเซ็น
- วนซ้ำลายเซ็นทั้งหมดใน header
Omise-Signature - เปรียบเทียบลายเซ็นแต่ละรายการกับลายเซ็นที่คาดหวัง
- ปฏิเสธ Webhook request หากไม่มีลายเซ็นใดตรงกัน
- หากลายเซ็นตรงกัน คุณสามารถดำเนินการประมวลผล Webhook ได้ทันที หรือเลือกตรวจสอบ timestamp ก่อนเพื่อความปลอดภัยเพิ่มเติมจากการโจมตีแบบ replay
ข้อควรพิจารณาด้านความปลอดภัยที่สำคัญ:
- การป้องกัน timing attack: ใช้อัลกอริทึมการเปรียบเทียบสตริงแบบ constant-time เมื่อเปรียบเทียบลายเซ็นเพื่อป้องกันการโจมตีแบบ timing
- การป้องกัน replay attack (ไม่บังคับ): เพื่อความปลอดภัยที่เพิ่มขึ้น ให้ตรวจสอบ timestamp โดยคำนวณความแตกต่างระหว่างเวลาระบบปัจจุบันกับ timestamp ที่ได้รับ ปฏิเสธ Webhook หากความแตกต่างเกินกว่าที่ยอมรับได้ (เช่น 5 นาที) เพื่อป้องกันการโจมตีแบบ replay การตรวจสอบ timestamp เป็นตัวเลือกเสริม การที่ลายเซ็นตรงกันเพียงอย่างเดียวก็ยืนยันความถูกต้องของ Webhook ได้แล้ว
ตัวอย่างการนำไปใช้งาน
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf;
}
}));
function verifySignature({ req }) {
// ขั้นตอนที่ 1: ดึงลายเซ็น
const signatureHeader = req.headers['omise-signature'];
const timestampHeader = req.headers['omise-signature-timestamp'];
// ขั้นตอนที่ 2: เตรียม payload สำหรับลงนาม
const rawBody = req.rawBody.toString('utf8');
const signedPayload = `${timestampHeader}.${rawBody}`;
// ขั้นตอนที่ 3: ถอดรหัส Webhook secret
const secret = Buffer.from('<YOUR_WEBHOOK_SECRET>', 'base64');
// ขั้นตอนที่ 4: คำนวณลายเซ็นที่คาดหวัง
const expectedBuffer = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest();
// ขั้นตอนที่ 5: เปรียบเทียบกับลายเซ็นทั้งหมดใน header
const signatures = signatureHeader.split(',');
for (const sig of signatures) {
const sigBuffer = Buffer.from(sig, 'hex');
if (crypto.timingSafeEqual(sigBuffer, expectedBuffer)) {
// ไม่บังคับ: เพิ่มการตรวจสอบ timestamp ได้ที่นี่
return true;
}
}
return false;
}
app.post('/webhook', (req, res) => {
if (!verifySignature({ req })) {
return res.status(401).send('Invalid signature');
}
// หากตรวจสอบแล้ว ส่ง 200 หลังจากประมวลผล Webhook
res.status(200).send('OK');
});
การจัดการ Webhook Secret
คุณสามารถดู สร้าง และจัดการ Webhook secret ได้ในส่วนการตั้งค่า Webhook ของแดชบอร์ด Omise Secret เป็นแบบเฉพาะสภาพแวดล้อม โดย secret ของโหมดทดสอบแยกจาก secret ของโหมดจริง
⚠ ข้อควรระวัง: Webhook secret เป็นข้อมูลที่ต้องรักษาเป็นความลับ ให้จัดการเหมือนข้อมูลประจำตัวที่ละเอียดอ่อน อย่าเปิดเผยใน client-side code, repository สาธารณะ หรือแชร์ในสภาพแวดล้อมที่ไม่ปลอดภัยเป็นอันขาด
การหมุนเวียน Secret
หากคุณต้องการอัปเดต secret (เช่น เพื่อปฏิบัติตามข้อกำหนดด้านความปลอดภัย หรือเนื่องจาก secret ถูกเปิดเผย) Omise มีขั้นตอนการหมุนเวียนที่ไม่ต้องหยุดให้บริการ:
- การหมุนเวียน Secret: เมื่อคุณ
Roll
secret ใหม่จะถูกสร้างขึ้นทันที เพื่อป้องกันการหยุดชะงักของบริการ secret เดิมจะยังคงใช้งานได้อีก24 ชั่วโมง - ลายเซ็นคู่: ในช่วงเปลี่ยนผ่าน 24 ชั่วโมงนี้ Omise จะลงนาม Webhook ทุกรายการด้วยทั้ง secret ใหม่และเก่า header
Omise-Signatureจะมีลายเซ็นสองรายการคั่นด้วยเครื่องหมายจุลภาค - การเพิกถอนด้วยตนเอง: คุณไม่สามารถลบ secret ที่ใช้งานอยู่หลักได้ อย่างไรก็ตาม คุณสามารถเพิกถอน secret ที่กำลังจะหมดอายุด้วยตนเองได้ตลอดเวลาในช่วง 24 ชั่วโมงเพื่อสิ้นสุดช่วงเปลี่ยนผ่านทันที
- จำนวนสูงสุด: คุณสามารถมี secret ที่ใช้งานอยู่พร้อมกันได้สูงสุดสองรายการ (รายการปัจจุบันและรายการที่กำลังจะหมดอายุ) หาก secret ที่กำลังจะหมดอายุยังใช้งานอยู่ คุณต้องรอให้หมดอายุหรือเพิกถอนด้วยตนเองก่อนจึงจะ Roll secret ได้อีกครั้ง
การทดสอบ
เราแนะนำให้ใช้โหมดทดสอบเพื่อตรวจสอบตรรกะการตรวจสอบลายเซ็นก่อนเปลี่ยนไปใช้โหมดจริง
- การจำลองที่ปลอดภัย: การหมุนเวียนหรือเพิกถอน secret ในโหมดทดสอบไม่มีผลกระทบต่อสภาพแวดล้อมการใช้งานจริงของโหมดจริง
- การตรวจสอบตรรกะการหมุนเวียน: เราแนะนำอย่างยิ่งให้ทดสอบขั้นตอน
การหมุนเวียน Secret
ในโหมดทดสอบ เพื่อให้แน่ใจว่าโค้ดของคุณจัดการกับพฤติกรรมลายเซ็นคู่ได้อย่างถูกต้องก่อนที่จะหมุนเวียนในสภาพแวดล้อมการใช้งานจริง
การแก้ไขปัญหา
ปัญหาที่พบบ่อย
ไม่ได้รับ Webhook:
- ตรวจสอบว่า URL ของ endpoint เป็น HTTPS พร้อม SSL certificate ที่ถูกต้อง
- ตรวจสอบว่า firewall อนุญาต request ขาเข้าจาก IP ของเซิร์ฟเวอร์ Webhook Omise ต่อไปนี้:
54.169.118.22752.74.199.17518.139.13.19
- ยืนยันว่า endpoint เข้าถึงได้และตอบสนองต่อ request
การตรวจสอบลายเซ็นล้มเหลว:
- ยืนยันว่าคุณใช้ Webhook secret ที่ถูกต้องสำหรับสภาพแวดล้อมของคุณ (ทดสอบ vs จริง)
- ตรวจสอบว่าคุณใช้ raw request body โดยไม่มีการแก้ไขใดๆ
- ตรวจสอบให้แน่ใจว่าถอดรหัส Base64 ของ Webhook secret อย่างถูกต้อง
Event ถูกส่งไปยัง endpoint ผิด:
- ตรวจสอบว่ามีการระบุพารามิเตอร์
webhook_endpointsระหว่างการสร้าง charge หรือไม่ - ตรวจสอบการตั้งค่า Webhook แบบ static ในแดชบอร์ด
คำถามที่พบบ่อย
สามารถตั้งค่า endpoint Webhook แบบ static หลายรายการได้หรือไม่?
ไม่ได้ แต่ละบัญชี Omise รองรับ endpoint Webhook แบบ static เพียงหนึ่งรายการ หากต้องการส่ง event ไปยังหลายปลายทางในแต่ละ charge ให้ใช้ฟีเจอร์Dynamic Webhook และส่ง URL หลายรายการในพารามิเตอร์ webhook_endpoints เมื่อสร้าง charge
จะได้รับ Webhook สำหรับทุก event type โดยอัตโนมัติหรือไม่?
ใช่ โดยค่าเริ่มต้น endpoint Webhook แบบ static จะรับการแจ้งเตือนสำหรับ event type ที่รองรับทั้งหมด ปัจจุบันยังไม่มีตัวเลือกในการกรอง event type เฉพาะในระดับบัญชีสำหรับ endpoint แบบ static
endpoint ควรส่งคืน HTTP response code อะไร?
endpoint ควรส่งคืน response 200 OK หลังจากรับและประมวลผล Webhook สำเร็จ การส่งคืน status code ที่ไม่ใช่ 2xx อาจทำให้ Omise ถือว่าการส่งล้มเหลว
Omise จะลองส่ง Webhook ซ้ำเมื่อล้มเหลวหรือไม่?
Omise ไม่รับประกันการลองส่งซ้ำอัตโนมัติสำหรับการส่งที่ล้มเหลวในปัจจุบัน เพื่อให้แน่ใจว่าคุณไม่พลาด event ให้นำเวิร์กโฟลว์การตรวจสอบ event มาใช้เป็น fallback หรือ poll Events API สำหรับ event ที่คุณอาจพลาดไป
ทำไมจึงไม่ได้รับ Webhook สำหรับ charge บัตรที่ไม่ใช่ 3DS ที่เสร็จสมบูรณ์?
event charge.complete จะไม่ถูกทริกเกอร์สำหรับ charge บัตรที่ไม่ใช่ 3DS เฉพาะ charge ที่ผ่านกระบวนการยืนยันตัวตน 3DS หรือวิธีการชำระเงินแบบอะซิงโครนัสอื่นๆ เท่านั้นที่จะสร้าง Webhook charge.complete
สามารถใช้ endpoint Webhook เดียวกันสำหรับทั้งโหมดทดสอบและโหมดจริงได้หรือไม่?
ได้ แต่ไม่แนะนำ โหมดทดสอบและโหมดจริงใช้ Webhook secret ที่แตกต่างกัน ดังนั้น endpoint ของคุณจะต้องจัดการทั้งสองอย่าง การรักษา endpoint แยกต่างหากสำหรับแต่ละสภาพแวดล้อมจะปลอดภัยและจัดการได้ง่ายกว่า
จะจัดการการหมุนเวียน Webhook secret โดยไม่มี downtime ได้อย่างไร?
ใช้ตัวเลือก Roll
ในการตั้งค่า Webhook ในช่วงเปลี่ยนผ่าน 24 ชั่วโมง Omise จะส่งทั้งลายเซ็นเก่าและใหม่ใน header Omise-Signature อัปเดตตรรกะการตรวจสอบของคุณให้ยอมรับลายเซ็นใดลายเซ็นหนึ่งก่อนเพิกถอน secret เก่า ดูรายละเอียดที่การหมุนเวียน Secret
ควรทำอย่างไรหาก Webhook secret ถูกเปิดเผย?
Roll secret ทันทีในการตั้งค่า Webhook เพื่อสร้าง secret ใหม่ จากนั้นเพิกถอน secret ที่กำลังจะหมดอายุด้วยตนเองเพื่อสิ้นสุดช่วงเปลี่ยนผ่านทันที อัปเดตแอปพลิเคชันของคุณด้วย secret ใหม่โดยเร็วที่สุด