Webhook คืออะไร? แอปแจ้งกันและกันอย่างไร
Webhook คือข้อความอัตโนมัติที่บริการหนึ่งส่งมายังแอปของคุณทันทีที่มีบางอย่างเกิดขึ้น เมื่อการชำระเงินของลูกค้าสำเร็จ Stripe จะส่ง webhook ไปยังที่อยู่ในแอปของคุณ บอกว่า "ชำระเงินสำเร็จ นี่คือรายละเอียด" แล้วแอปของคุณก็ตอบสนอง เช่น ทำเครื่องหมายคำสั่งซื้อว่าจ่ายแล้ว ส่งใบเสร็จ หรือปลดล็อกบัญชี สรุปสั้นๆ คือ API คือแอปของคุณถามบริการอื่นว่าอะไร ส่วน webhook คือบริการอื่นเรียกแอปของคุณเพื่อบอกบางอย่าง
ทำไมมันจึงสำคัญเมื่อคุณสร้างด้วย AI
เมื่อแอปของคุณรับการชำระเงิน รับข้อมูลแบบฟอร์มจากเครื่องมืออื่น หรือเชื่อมต่อกับบริการอย่าง GitHub, Shopify หรือปฏิทิน คุณจะเจอ webhook แน่นอน มันมักเป็นวิธีที่ ถูกต้อง ในการรู้ว่ามีบางอย่างเกิดขึ้น แต่ก็เป็นจุดที่แอปที่สร้างด้วย AI มักผิดพลาดอย่างแนบเนียน:
- จุดรับ (endpoint) ยอมรับทุกคำขอ ใครก็สามารถปลอมเหตุการณ์ "ชำระเงินสำเร็จ" ได้
- แอปให้สิทธิ์เข้าถึงในหน้าที่ redirect หลังชำระเงิน แทนที่จะให้ใน webhook ทำให้คนที่ปิดแท็บก่อนกำหนดไม่ได้สิ่งที่จ่ายไป และคนที่พบ URL หน้าสำเร็จได้ของฟรี
- เหตุการณ์เดียวกันมาถึงสองครั้ง และลูกค้าได้รับสองคำสั่งซื้อหรือสองอีเมล
การรู้ว่า webhook ทำงานอย่างไรช่วยให้คุณขอการป้องกันเหล่านี้ได้ตั้งแต่ต้น
ตัวอย่างในชีวิตประจำวัน: ข้อความแจ้งการส่งพัสดุ
คุณรู้ว่าพัสดุมาถึงหรือยังได้สองวิธี วิธีแรกคือเดินไปหน้าบ้านทุกสิบนาทีเพื่อเช็ก (นั่นคือ polling เมื่อแอปของคุณเรียก API ซ้ำๆ เพื่อถามว่า "มีอะไรใหม่ไหม") วิธีที่สองคือให้คนส่งพัสดุส่งข้อความหาคุณเมื่อส่งถึงแล้ว (นั่นคือ webhook)
ข้อความนั้นดีกว่าชัดเจน ตราบใดที่คุณเชื่อถือได้ หากใครก็ส่งข้อความ "พัสดุส่งถึงแล้ว" มาได้ คุณจะอยากรู้ว่ามันมาจากคนส่งจริงๆ และถ้าโทรศัพท์คุณปิดอยู่ตอนข้อความมาถึง คุณจะอยากให้คนส่งลองใหม่ในภายหลัง สองเรื่องนี้ คือ การยืนยัน และ การลองใหม่ คือส่วนสำคัญที่ทำให้ webhook ยุ่งยาก
webhook ทำงานอย่างไร ทีละขั้น
- คุณสร้างจุดรับ ในแบ็กเอนด์ของแอป คือ URL เช่น
https://yourapp.com/webhooks/stripeที่รับคำขอPOST - คุณลงทะเบียน URL นั้นกับผู้ให้บริการ และเลือกเหตุการณ์ที่ต้องการ (เช่น "checkout เสร็จสมบูรณ์" และ "ยกเลิกการสมัครสมาชิก")
- ผู้ให้บริการให้ signing secret แก่คุณ คุณเก็บมันเป็น secret บนเซิร์ฟเวอร์ — ดู environment variables และ secrets
- เหตุการณ์เกิดขึ้น ผู้ให้บริการส่งคำขอ HTTP ไปยัง URL ของคุณ พร้อมเนื้อหา JSON ที่อธิบายเหตุการณ์ และ header ลายเซ็น
- แอปของคุณตรวจสอบลายเซ็น บันทึก event ID ตอบกลับด้วยรหัสสำเร็จ (
200) อย่างรวดเร็ว แล้วจึงทำงาน - หากแอปของคุณไม่ตอบกลับด้วยความสำเร็จ ผู้ให้บริการหลายรายจะลองส่งใหม่ในภายหลัง
ลายเซ็น
ลายเซ็นพิสูจน์ว่าคำขอมาจากผู้ให้บริการจริงและไม่ได้ถูกแก้ไข เช่น Stripe คำนวณ HMAC (ลายนิ้วมือที่ใช้คีย์) ด้วย SHA-256 จากเนื้อหาของคำขอและ timestamp โดยใช้ signing secret แล้วส่งผลลัพธ์ใน header Stripe-Signature แอปของคุณทำการคำนวณเดียวกันด้วยสำเนาของ secret ที่มี หากผลตรงกัน คำขอนั้นเป็นของแท้ เนื่องจาก timestamp ก็ถูกลงลายเซ็นด้วย คุณจึงปฏิเสธคำขอเก่าที่ใครบันทึกไว้แล้วส่งซ้ำในภายหลังได้ ไลบรารีของ Stripe ตั้งค่าความคลาดเคลื่อนที่ยอมรับได้ไว้ห้านาทีเป็นค่าเริ่มต้น ตามเอกสารของ Stripe ณ เดือนกันยายน 2026
รายละเอียดเชิงปฏิบัติอย่างหนึ่ง: ลายเซ็นคำนวณจากเนื้อหาดิบ (raw) ของคำขอ หากเฟรมเวิร์กของคุณแปลงและจัดรูปแบบ JSON ใหม่ก่อนตรวจสอบ การตรวจจะล้มเหลว นี่เป็นบั๊กที่พบบ่อยมาก
การลองใหม่ การซ้ำ และลำดับ
ผู้ให้บริการแต่ละรายต่างกัน ให้ตรวจสอบเอกสารของแต่ละราย ณ เดือนกันยายน 2026:
| พฤติกรรม | Stripe | GitHub |
|---|---|---|
| ลองใหม่อัตโนมัติ | มี สูงสุดสามวัน โดยเว้นระยะห่างที่เพิ่มขึ้นในโหมดใช้งานจริง | ไม่มี คุณต้องส่งใหม่เองด้วยตนเองหรือด้วยสคริปต์ |
| เวลาตอบกลับ | ตอบ 2xx อย่างรวดเร็ว ก่อนงานที่ช้าใดๆ | การส่งที่ใช้เวลาตอบเกิน 10 วินาทีถือว่าล้มเหลว |
เอกสารของ Stripe ยังระบุว่าเหตุการณ์ไม่ได้รับประกันว่าจะมาถึงตามลำดับที่เกิดขึ้น และเหตุการณ์เดียวกันอาจมาถึงมากกว่าหนึ่งครั้งได้นานๆ ครั้ง จึงแนะนำให้ติดตาม event ID
บทเรียนทั่วไปใช้ได้กับผู้ให้บริการทุกราย เหตุการณ์อาจมาถึงช้า มาถึงมากกว่าหนึ่งครั้ง และมาถึงไม่ตามลำดับ ตัวจัดการของคุณควรเป็น idempotent คือการประมวลผลเหตุการณ์เดียวกันสองครั้งให้ผลเท่ากับการประมวลผลหนึ่งครั้ง
ตัวอย่างประกอบ: ปลดล็อกคอร์สที่ต้องจ่ายเงิน
คุณขายคอร์สออนไลน์ นักเรียนคลิก ซื้อ ชำระเงินบนหน้า checkout ของ Stripe แล้วถูกส่งกลับมายังเว็บไซต์ของคุณ
วิธีที่เปราะบาง: หน้า "ขอบคุณ" ปลดล็อกคอร์ส หากนักเรียนปิดเบราว์เซอร์ระหว่าง redirect เขาจ่ายเงินแล้วแต่ไม่มีสิทธิ์เข้าถึง และหากใครเดา URL หน้าขอบคุณได้ เขาจะได้สิทธิ์เข้าถึงโดยไม่ต้องจ่าย
วิธีที่ใช้ webhook:
- เมื่อ Stripe ยืนยันการชำระเงิน มันจะส่งเหตุการณ์
checkout.session.completedไปยัง/webhooks/stripe - แบ็กเอนด์ของคุณตรวจสอบลายเซ็นด้วย signing secret หากไม่ผ่าน ตอบ
400และไม่ทำอะไรเลย - ตรวจว่า event ID นั้นเคยประมวลผลแล้วหรือไม่ ถ้าใช่ ตอบ
200และหยุด - บันทึก event ID ตอบ
200แล้วจึงให้สิทธิ์เข้าถึงแก่นักเรียนและส่งอีเมลต้อนรับ - หน้าขอบคุณเพียงแสดงข้อความ "ได้รับการชำระเงินแล้ว คอร์สของคุณจะปรากฏในไม่ช้า" และตรวจสถานะสิทธิ์เข้าถึงของนักเรียน
ต่อมา หากการสมัครสมาชิกถูกยกเลิกหรือบัตรถูกปฏิเสธ เหตุการณ์ webhook อื่นจะบอกแอปของคุณให้ลบหรือระงับสิทธิ์เข้าถึง นี่คือวิธีที่ผลิตภัณฑ์แบบสมัครสมาชิกทำให้ข้อมูลตรงกับระบบการเรียกเก็บเงิน ดู SaaS คืออะไร และ วิธีเพิ่มระบบชำระเงินในแอปของคุณ
คำศัพท์สำคัญ
- Endpoint: URL ในแอปของคุณที่รับ webhook
- Event / payload: สิ่งที่เกิดขึ้น และข้อมูลที่อธิบายมัน (มักเป็น JSON)
- Signing secret: secret ที่ใช้ร่วมกันเพื่อตรวจสอบลายเซ็น
- Idempotent: การทำซ้ำได้อย่างปลอดภัยด้วยผลลัพธ์เดิม
- Polling: การเรียก API ซ้ำๆ เพื่อถามหาการเปลี่ยนแปลงแทนที่จะรอ webhook
- Tunnel: เครื่องมือที่ให้แล็ปท็อปมี URL สาธารณะชั่วคราว เพื่อให้ webhook เข้าถึงได้ระหว่างการพัฒนา
ความผิดพลาดและความเข้าใจผิดที่พบบ่อย
- ไม่ตรวจลายเซ็น URL ของจุดรับไม่ใช่ความลับ การตรวจลายเซ็นคือสิ่งที่ทำให้คำขอเชื่อถือได้
- ทำงานช้าก่อนตอบกลับ การส่งอีเมลหรือสร้าง PDF ก่อนตอบอาจทำให้หมดเวลา ซึ่งกระตุ้นการลองใหม่ ซึ่งทำให้เกิดข้อมูลซ้ำ
- สมมติว่าส่งครั้งเดียวและตามลำดับเสมอ บันทึก event ID และอย่าพึ่งลำดับที่มาถึง
- ใช้ URL ของ preview webhook ต้องใช้ที่อยู่สาธารณะที่คงที่ Preview ส่วนตัวและ
localhostเข้าถึงจากอินเทอร์เน็ตไม่ได้ ให้ใช้ URL ที่เผยแพร่แล้ว (หรือ tunnel ขณะทดสอบ) - ปนกันระหว่าง secret โหมดทดสอบและโหมดจริง ผู้ให้บริการมักออก signing secret ต่างกันสำหรับโหมดทดสอบและโหมดจริง เก็บทั้งสองไว้และใช้ให้ถูกต้อง
- เชื่อ payload อย่างไม่ไตร่ตรองสำหรับการตัดสินใจสำคัญ สำหรับการกระทำที่มีความเสี่ยงสูง เป็นเรื่องสมเหตุสมผลที่จะดึงสถานะล่าสุดจาก API ของผู้ให้บริการหลังได้รับเหตุการณ์
สิ่งที่ควรขอจาก AI builder ของคุณ
เพิ่มจุดรับ
POST /webhooks/stripeบนเซิร์ฟเวอร์ ตรวจลายเซ็น Stripe โดยใช้เนื้อหาดิบของคำขอและ secretSTRIPE_WEBHOOK_SECRETปฏิเสธลายเซ็นที่ไม่ถูกต้องด้วย 400 บันทึก event ID ของแต่ละเหตุการณ์และข้ามเหตุการณ์ที่เคยประมวลผลแล้ว ตอบ 200 อย่างรวดเร็ว จากนั้นจัดการcheckout.session.completedโดยทำเครื่องหมายคำสั่งซื้อว่าจ่ายแล้วและส่งใบเสร็จ บันทึกประเภทเหตุการณ์ ห้ามให้สิทธิ์เข้าถึงจากหน้า success ของ checkout
จากนั้นทดสอบ: ส่งเหตุการณ์ทดสอบจากแดชบอร์ดของผู้ให้บริการ ส่งเหตุการณ์เดิมอีกครั้ง และส่งคำขอที่ลายเซ็นผิด มีเพียงครั้งแรกเท่านั้นที่ควรเปลี่ยนแปลงอะไร
Webhook ใน Mythex
Mythex ไม่มีบริการ webhook แยกต่างหาก คุณขอให้เอเจนต์เพิ่มจุดรับ webhook ในแบ็กเอนด์ของแอปคุณเอง แล้วชี้ผู้ให้บริการไปยัง URL ที่เผยแพร่แล้วของคุณ เพราะ webhook ต้องใช้ที่อยู่สาธารณะ signing secret ใส่ในความลับของโปรเจกต์ และหากคุณเปลี่ยนมันในแอปที่ใช้งานจริง ให้เผยแพร่ใหม่ สูตร การจัดการ webhook ในเอกสารมี starter prompt และ เทมเพลตร้านค้า เป็นจุดเริ่มต้นที่ดีสำหรับแอปที่รับการชำระเงิน
คำถาม
Webhook คืออะไรแบบง่ายๆ?
Webhook คือข้อความอัตโนมัติที่บริการหนึ่งส่งไปยังที่อยู่เว็บในแอปของคุณ เมื่อมีเหตุการณ์เกิดขึ้น เช่นการชำระเงินสำเร็จหรือมีการส่งแบบฟอร์ม แทนที่แอปของคุณจะถามซ้ำๆ ว่ามีอะไรเปลี่ยนไปหรือไม่ บริการอื่นจะเป็นฝ่ายแจ้งให้ทราบเอง
ความต่างระหว่าง webhook กับ API คืออะไร?
เมื่อเรียก API แอปของคุณขอบางสิ่งจากบริการอื่นแล้วได้รับคำตอบ ส่วน webhook คือบริการอื่นเรียกแอปของคุณเมื่อเหตุการณ์เกิดขึ้น หลายการเชื่อมต่อใช้ทั้งสองอย่าง คือ webhook เพื่อรับรู้เหตุการณ์ และการเรียก API เพื่อดึงรายละเอียดหรือดำเนินการ
Webhook ปลอดภัยหรือไม่?
ปลอดภัยได้ หากคุณตรวจสอบมัน ผู้ให้บริการที่ออกแบบดีจะลงลายเซ็นทุก webhook ด้วยความลับที่แชร์กับคุณเท่านั้น และแอปของคุณควรปฏิเสธคำขอใดก็ตามที่ลายเซ็นไม่ตรงกัน หากไม่มีการตรวจสอบนี้ ใครก็ตามที่พบ URL อาจส่งเหตุการณ์ปลอมมาได้
จะเกิดอะไรขึ้นถ้าแอปของฉันล่มตอนที่ส่ง webhook?
ขึ้นอยู่กับผู้ให้บริการ เช่น Stripe จะลองส่งซ้ำที่ล้มเหลวได้สูงสุดสามวันในโหมดใช้งานจริง ขณะที่ GitHub ไม่ลองส่งซ้ำอัตโนมัติและให้คุณส่งใหม่เอง ตรวจสอบเอกสารของผู้ให้บริการแต่ละราย และออกแบบตัวจัดการ (handler) ของคุณให้รับมือกับเหตุการณ์ที่มาช้าหรือซ้ำได้