WebHooks

หัวข้อทั้งหมดในหน้านี้

Webhooks

Webhook คืออะไร

Webhook เป็นการแจ้งเตือนจากเซิร์ฟเวอร์ของเราไปยัง HTTPS endpoint ที่คุณกำหนด เมื่อเกิดเหตุการณ์ (Event) บางอย่างในบัญชีของคุณ โดยแต่ละการแจ้งเตือนจะส่งออบเจ็กต์ event ที่มีข้อมูลของเหตุการณ์นั้นไปยัง Endpoint URL

Webhook ช่วยให้ร้านค้าได้รับการแจ้งเตือนแบบเรียลไทม์ เมื่อเกิดเหตุการณ์สำคัญในบัญชี โดยไม่ต้องเรียก API ซ้ำๆ เพื่อตรวจสอบสถานะ เพราะ Webhook จะส่งการแจ้งเตือนไปยังเซิร์ฟเวอร์ทันทีเมื่อมีเหตุการณ์เกิดขึ้น

ประโยชน์ของ Webhook

  • ระบบทำงานมีประสิทธิภาพมากขึ้น: ร้านค้าไม่จำเป็นต้องเรียก API ซ้ำๆ ช่วยลดภาระของเซิร์ฟเวอร์และคำขอที่ไม่จำเป็น
  • อัปเดตแบบเรียลไทม์: รับการแจ้งเตือนทันทีเมื่อเกิดเหตุการณ์ เช่น การชำระเงินสำเร็จ การคืนเงิน หรือข้อโต้แย้ง
  • รองรับระบบ Automation: Webhook สามารถทริกเกอร์เวิร์กโฟลว์อัตโนมัติในแอปพลิเคชันของร้านค้าทันที เช่น อัปเดตสถานะคำสั่งซื้อ ส่งอีเมลให้ลูกค้า หรือปรับยอดบัญชี
  • ความน่าเชื่อถือสูง: ช่วยให้ร้านค้าไม่พลาดเหตุการณ์สำคัญ แม้ในช่วงที่แอปพลิเคชันของร้านค้าไม่ได้ตรวจสอบสถานะอย่างต่อเนื่อง

การกำหนดค่า

ร้านค้าสามารถกำหนดค่า Webhook endpoints แยกสำหรับโหมดทดสอบและโหมดใช้งานจริงได้

ดูข้อมูล Event ทั้งหมด

ร้านค้าสามารถเข้าถึงข้อมูล Event ทั้งหมดได้ผ่าน:

  • หน้า Events บนแดชบอร์ด (คลิกไอคอนบัญชีที่แถบด้านขวา แล้วเลือก Events)
  • The Events API

การประมวลผลเป็นลำดับ (Serialization)

ออบเจ็กต์ Event ในคำขอ POST (หรือการตอบกลับผ่าน Events API) จะประมวลผลตามลำดับตาม API Version เริ่มต้นของ Event เสมอ และไม่ขึ้นกับค่า Omise-Version ที่ส่งไปกับคำขอที่ทริกเกอร์ Event

ตัวอย่าง

สำหรับบัญชีตั้งค่าเวอร์ชันไว้ที่ 2017-11-02:

  1. รายการรับชำระเงิน (Charge) ถูกสร้างโดยใช้ curl ที่ข้อมูลเวอร์ชัน -H "Omise-Version: 2019-05-29"
  2. คำขอนี้จะสร้าง Event charge.create ซึ่งฝังออบเจ็กต์ Charge ไว้ภายใน
  3. ออบเจ็กต์ดังกล่าวจะเรียงลำดับตาม Charge API เวอร์ชัน 2017-11-02 ไม่ใช่เวอร์ชัน 2019-05-29
  4. แม้จะอัปเดตบัญชีเป็นเวอร์ชัน 2019-05-29 ในภายหลัง ออบเจ็กต์ Charge สำหรับ Event นี้จะยังคงเรียงลำดับตามเวอร์ชัน 2017-11-02

ข้อกำหนดและแนวทางปฏิบัติ

ข้อกำหนด

  • URL ต้องเป็น HTTPS
  • URL ต้องมีใบรับรอง SSL ที่ถูกต้อง (ไม่รองรับใบรับรองที่สร้างขึ้นเอง)
  • สามารถตรวจสอบใบรับรอง SSL ของคุณได้โดยใช้ SSL Labs
  • สำหรับใบรับรอง SSL แบบไม่มีค่าใช้จ่าย สามารถดูรายละเอียดเพิ่มเติมได้ที่ Let's Encrypt

แนวทางปฏิบัติด้านความปลอดภัย

แนะนำ: การตรวจสอบลายเซ็น (Signature Verification)

เราขอแนะนำให้ใช้การตรวจสอบลายเซ็นเป็นมาตรการรักษาความปลอดภัยหลักเพื่อยืนยันความถูกต้องของ Webhook การตรวจสอบลายเซ็นจะยืนยันว่าคำขอมาจาก Omise จริง และไม่ได้ถูกดัดแปลง ช่วยป้องกันผู้ไม่หวังดีที่พยายามส่ง Webhook ปลอมมายัง Endpoint ของคุณได้อย่างมีประสิทธิภาพ ดูรายละเอียดการใช้งานได้ที่หัวข้อ แนวทางการป้องกัน Endpoint

ทางเลือก: การตรวจสอบ Event (Event Verification)

หากการตรวจสอบลายเซ็นไม่สามารถใช้งานได้ในระบบของคุณ สามารถใช้การตรวจสอบ Event เป็นมาตรการรักษาความปลอดภัยสำรองได้ เมื่อได้รับ Webhook (เช่น charge.complete) ให้ใช้ Resource ID เพื่อสร้างคำขอ GET สำหรับตรวจสอบสถานะ อย่างไรก็ตาม วิธีนี้จะไม่ป้องกัน Webhook ปลอมที่ส่งมายัง Endpoint ของคุณ แต่ช่วยให้สามารถยืนยันความถูกต้องของข้อมูล Event หลังจากได้รับแล้ว

ตัวอย่างการยืนยันความถูกต้องของ Event:

1. Receive `charge.complete` webhook
2. Extract Charge ID from the webhook payload
3. Perform GET request to `/charges/chrg_test_no1t4tnemucod0e51mo`
4. Verify the charge status independently

Event ต่างๆ ที่มีการแจ้งเตือน

Event เกี่ยวกับบัตร

ชื่อ Event ทริกเกอร์
card.destroy ทำลายบัตรแล้ว
card.update อัปเดตบัตรแล้ว

Event เกี่ยวกับรายการรับชำระเงิน

ชื่อ Event ทริกเกอร์
charge.capture ตัดวงเงินแล้ว (สำหรับการตัดวงเงินด้วยตัวเอง (Manual Capture) เท่านั้น)
charge.complete รับชำระเงินสำเร็จ (หมายเหตุ: รายการรับชำระเงินผ่านบัตรที่ไม่ผ่าน 3DS จะไม่ทริกเกอร์ Event นี้)
charge.create สร้างรายการรับชำระเงินแล้ว
charge.expire รายการรับชำระเงินหมดอายุ (สำหรับ อาลีเพย์ (บาร์โค้ด) เท่านั้น)
charge.reverse ยกเลิกการกันวงเงิน (สำหรับการยกเลิกการกันวงเงินด้วยตนเองเท่านั้น)
charge.update อัปเดตรายการรับชำระเงินแล้ว

Event เกี่ยวกับลูกค้า

ชื่อ Event ทริกเกอร์
customer.create สร้างลูกค้าแล้ว
customer.destroy ลบลูกค้าแล้ว
customer.update อัปเดตลูกค้าแล้ว
customer.update.card อัปเดตบัตรแล้ว (การอัปเดตผ่านทางลูกค้า)

Event เกี่ยวกับการปฏิเสธรายการ

ชื่อ Event ทริกเกอร์
dispute.accept รับการปฏิเสธรายการแล้ว
dispute.close ยุติการปฏิเสธรายการแล้ว
dispute.create สร้างการปฏิเสธรายการแล้ว
dispute.update อัปเดตการปฏิเสธรายการแล้ว

Event เกี่ยวกับลิงก์

ชื่อ Event ทริกเกอร์
link.create สร้างลิงก์แล้ว

Event เกี่ยวกับบัญชีที่ผูกไว้

ชื่อ Event ทริกเกอร์
linked_account.create สร้างบัญชีที่ผูกไว้แล้ว
linked_account.complete บัญชีที่ผูกไว้ถูกลงทะเบียนสำเร็จโดยลูกค้า

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 อัปเดตรายการโอนเงินแล้ว

Webhook แบบ Dynamic

Webhook แบบ Dynamic เป็นฟีเจอร์ที่ช่วยให้ร้านค้าสามารถกำหนด Endpoint ของแต่ละ Charge ได้เอง โดยระบุพารามิเตอร์ webhook_endpoints ขณะสร้าง Charge

หากไม่ได้ระบุค่า การแจ้งเตือนของ Event ทั้งหมดจะถูกส่งไปยัง Webhook แบบ static ซึ่งเป็นค่าเริ่มต้นสำหรับทุกบัญชีผู้ใช้ของ Omise

ลักษณะการทำงาน

เมื่อมีการระบุ webhook_endpoints:

  • การแจ้งเตือน Event ทั้งหมดที่เกี่ยวข้องกับ Charge ที่ระบุจะถูกส่งไปที่ webhook_endpoints
  • การแจ้งเตือนจะไม่ส่งไปที่ Webhook แบบ static

เมื่อไม่ได้ระบุ webhook_endpoints:

  • การแจ้งเตือน Event จะถูกส่งไปยัง static webhook ของบัญชีแทน

แนวทางการป้องกัน Endpoint

Omise ใช้อัลกอริทึม HMAC-SHA256 เพื่อสร้างลายเซ็นดิจิทัลให้กับข้อมูลของ Webhook
เมื่อมีการตั้งค่า webhook secret สำหรับบัญชีของคุณ ระบบจะเพิ่มลายเซ็นนี้ไว้ใน Webhook headers ของแต่ละคำขอที่ส่งจาก Omise การตรวจสอบลายเซ็นช่วยให้คุณสามารถยืนยันได้ว่าข้อความ Webhook นั้นถูกส่งมาจาก Omise จริงและข้อมูลภายในไม่ถูกดัดแปลงระหว่างทาง

ลายเซ็นดิจิทัลบน Webhook Headers

Header Description
Omise-Signature Omise จะสร้างลายเซ็น HMAC ที่เข้ารหัสแบบ Hex ในระหว่างที่มีการหมุนเปลี่ยน webhook secret เพื่อความปลอดภัย โดย Webhook ที่ส่งออกจาก Omise จะมีลายเซ็นสองค่าใน Header คั่นด้วยเครื่องหมายจุลภาค ลายเซ็นแต่ละค่าจะสอดคล้องกับ Secret ที่แตกต่างกัน
Omise-Signature-Timestamp Unix timestamp ที่ Omise ระบุไว้ใน Webhook header เพื่อบอกเวลาที่สร้างลายเซ็นขึ้นมา

ตัวอย่าง Header:

Omise-Signature: 072cc0d8b49d49ce7119857279b1e36a9efa25fadb468d0126628064d4062c83
Omise-Signature-Timestamp: 1758696391

// During rotation
Omise-Signature: 072cc0d8b49d49ce7119857279b1e36a9efa25fadb468d0126628064d4062c83,4bb1e14023f53d076e598245e5e16fd96a94d46072149c483815718eecf2a38d

วิธีตรวจสอบลายเซ็นของ Webhook

ขั้นตอนที่ 1: ดึงค่าลายเซ็น

ดึงค่า Omise-Signature และ Omise-Signature-Timestamp จาก Webhook header

ขั้นตอนที่ 2: เตรียมข้อมูลสำหรับสร้างลายเซ็น

สร้างสตริง Signed Payload เพื่อใช้ตรวจสอบลายเซ็น โดยนำค่าต่อไปนี้มาต่อกัน:

  1. ค่า Omise-Signature-Timestamp
  2. เครื่องหมายจุด (.)
  3. เนื้อหา raw body ของ Webhook (เข้ารหัสแบบ UTF-8)

รูปแบบ:

<TIMESTAMP>.<RAW_BODY>

ขั้นตอนที่ 3: ถอดรหัส Webhook Secret

webhook secret ที่ได้จาก Omise จะถูกเก็บในรูปแบบ Base64 ซึ่งต้องถอดรหัสก่อนนำมาใช้

ขั้นตอนที่ 4: คำนวณลายเซ็นที่ระบบคาดว่าจะได้ (Expected Signature)

คำนวณค่า HMAC-SHA256 digest ของ signed payload จากขั้นตอนก่อนหน้า โดยใช้ค่า webhook secret ที่ถอดรหัสแล้ว จากนั้นแปลงผลลัพธ์ให้อยู่ในรูปแบบ hexadecimal string

ขั้นตอนที่ 5: เปรียบเทียบลายเซ็น

  1. ตรวจสอบลายเซ็นทั้งหมดใน Omise-Signature header
  2. เปรียบเทียบลายเซ็นแต่ละตัวกับลายเซ็นที่ระบบคาดว่าจะได้ (Expected signature)
  3. หากไม่มีค่าใดตรงกัน ให้ปฏิเสธคำขอ
  4. หากมีลายเซ็นใดตรงกัน ถือว่า Webhook นั้นถูกต้องและสามารถประมวลผลต่อได้ทันที นอกจากนี้ คุณสามารถตรวจสอบ Timestamp เพิ่มเติม เพื่อป้องกันการโจมตีแบบ replay attack

ข้อควรระวังด้านความปลอดภัย:

  • ป้องกันการโจมตีแบบ Timing Attack: ใช้อัลกอริทึมเปรียบเทียบสตริงแบบใช้เวลาเท่ากัน (constant-time) เมื่อตรวจสอบลายเซ็น
  • ป้องกันการโจมตีแบบ Replay Attack (ไม่บังคับ): สำหรับความปลอดภัยเพิ่มเติม สามารถตรวจสอบ timestamp โดยคำนวณความต่างระหว่างเวลาระบบปัจจุบันกับ Timestamp ที่ได้รับ
    • หากความต่างเกินกว่าช่วงเวลาที่กำหนด (เช่น 5 นาที) ให้ปฏิเสธ Webhook
    • การตรวจสอบ Timestamp เป็นตัวเลือกเสริม แม้ไม่ตรวจสอบ ก็สามารถยืนยันได้ว่า Webhook มาจาก Omise จริง หากลายเซ็นตรงกัน

ตัวอย่างการใช้งาน

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 }) {
  // Step 1: Retrieve the signature(s)
  const signatureHeader = req.headers['omise-signature'];
  const timestampHeader = req.headers['omise-signature-timestamp'];

  // Step 2: Prepare the signed payload
  const rawBody = req.rawBody.toString('utf8');
  const signedPayload = `${timestampHeader}.${rawBody}`;

  // Step 3: Decode the webhook secret
  const secret = Buffer.from('<YOUR_WEBHOOK_SECRET>', 'base64');

  // Step 4: Compute the expected signature
  const expectedBuffer = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest();

  // Step 5: Compare against all signatures in the header
  const signatures = signatureHeader.split(',');
  for (const sig of signatures) {
    const sigBuffer = Buffer.from(sig, 'hex');
    if (crypto.timingSafeEqual(sigBuffer, expectedBuffer)) {
      // Optional: Add timestamp validation here
      return true;
    }
  }
  return false;
}

app.post('/webhook', (req, res) => {
  if (!verifySignature(req)) {
     res.status(401).send('Invalid signature')
  }

  // If verified, return 200 after processing webhook
  res.status(200).send('OK');
});

การจัดการ Webhook Secret

ร้านค้าสามารถ ดู สร้าง และจัดการ webhook secret ได้จากส่วนตั้งค่า Webhook ในแดชบอร์ดของ Omise โดย Secret ของแต่ละโหมดการใช้งานจะแยกจากกัน Secret ในโหมดทดสอบไม่สามารถใช้งานในโหมดใช้งานจริงได้
[คำเตือน] Webhook Secret เป็นข้อมูลลับ เช่นเดียวกับรหัสผ่านหรือข้อมูลอ่อนไหวอื่นๆ ห้ามเปิดเผยให้กับโค้ดฝั่งไคลเอนต์ Repositories สาธารณะ หรือแชร์ในสภาพแวดล้อมที่ไม่ปลอดภัยโดยเด็ดขาด

การหมุนเปลี่ยน Webhook Secret เพื่อความปลอดภัย

Omise มีระบบหมุนเปลี่ยน Secret โดยไม่ส่งผลกระทบต่อการให้บริการ สำหรับกรณีที่ร้านค้าจำเป็นต้องอัปเดต Secret เพื่อให้เป็นไปตามข้อกำหนดด้านความปลอดภัย หรือในกรณีที่ Secret รั่วไหล โดยมีรายละเอียดดังนี้

  • Rotating a Secret: เมื่อเลือกหมุนเปลี่ยน Secret ระบบจะสร้าง Secret ใหม่ทันที เพื่อป้องกันไม่ให้บริการหยุดทำงาน Secret เดิมจะยังคงใช้งานได้ต่ออีก 24 ชั่วโมง
  • Dual-Signatures: ในช่วงเปลี่ยนผ่าน 24 ชั่วโมงนี้ Webhook ที่ส่งออกจาก Omise จะมีลายเซ็นสองค่าใน Header ทั้ง Secret ใหม่และ Secret เดิม โดยแต่ละค่าจะคั่นด้วยเครื่องหมายจุลภาค (,)
  • Manual Revocation: ร้านค้าจะไม่สามารถลบ Secret หลักที่กำลังใช้งานอยู่ได้ แต่สามารถเพิกถอน Secret ที่จะหมดอายุได้ในช่วงเปลี่ยนผ่าน 24 ชั่วโมง หากต้องการยุติช่วงเปลี่ยนผ่านทันที
  • Capacity: ร้านค้าสามารถมี Secret ที่ใช้งานพร้อมกันได้สูงสุด 2 ค่า ได้แก่ Secret ปัจจุบัน และ Secret ที่กำลังจะหมดอายุ หาก Secret ที่กำลังจะหมดอายุยังคงใช้งานอยู่ ต้องรอให้หมดอายุหรือเพิกถอนด้วยตนเองก่อน จึงจะสามารถ Roll Secret ใหม่ได้อีกครั้ง

ทดสอบการใช้งาน

ก่อนสลับไปใช้งานในโหมดใช้งานจริง เราแนะนำให้ตรวจสอบความถูกต้องของกระบวนการตรวจสอบลายเซ็นในโหมดทดสอบก่อน

  • Safe Simulation: การหมุนเปลี่ยนหรือเพิกถอน Secret ในโหมดทดสอบจะไม่ส่งผลกระทบต่อระบบที่ใช้งานจริง
  • Verify Rotation Logic: เราขอแนะนำให้ทดสอบขั้นตอนการหมุนเปลี่ยน Secret ในโหมดทดสอบ เพื่อให้มั่นใจว่าโค้ดของคุณสามารถรองรับพฤติกรรม ลายเซ็นคู่ (Dual-Signature) ได้อย่างถูกต้อง ก่อนดำเนินการหมุนเปลี่ยน Secret ในระบบใช้งานจริง

การแก้ไขปัญหา

ปัญหาที่พบบ่อย

ไม่ได้รับ Webhook:

  • ตรวจสอบว่า URL ของ Endpoint เป็น HTTPS และมี SSL certificate ที่ถูกต้อง
  • ตรวจสอบว่า Firewall ของคุณอนุญาตให้รับคำขอจากเซิร์ฟเวอร์ Omise
  • ยืนยันว่า Endpoint ของคุณสามารถเข้าถึงได้ และตอบสนองคำขออย่างถูกต้อง

ตรวจสอบลายเซ็นไม่สำเร็จ:

  • ตรวจสอบว่าคุณกำลังใช้ webhook secret ที่ถูกต้อง สำหรับการใช้งานของคุณ (โหมดทดสอบหรือโหมดใช้งานจริง)
  • ยืนยันว่าคุณใช้ raw request body โดยไม่ถูกแก้ไขใดๆ
  • ตรวจสอบการถอดรหัส Base64 ของ webhook secret ให้ถูกต้อง

ส่ง Events ไปยัง Endpoint ผิด:

  • ตรวจสอบว่าได้ระบุพารามิเตอร์ webhook_endpoints ระหว่างสร้าง charge หรือไม่
  • ตรวจสอบการตั้งค่า static webhook ในแดชบอร์ด

แหล่งข้อมูลเพิ่มเติม

เว็ปไซต์นี้มีการใช้คุกกี้เพื่อวิเคราะห์การใช้และปรับการใช้งานให้เหมาะกับท่าน เมื่อกดยอมรับหรือยังคงเข้าชมเว็บไซต์ต่อ เราถือว่าท่านยินยอมในการใช้งานคุกกี้ของเว็บไซต์ อ่านนโยบายความเป็นส่วนตัว