ตั้งค่า Webhook

PUT/api/v1/webhook
สิทธิ์ที่ต้องใช้:orders:write

ตั้ง เปลี่ยน หรือปิด URL ที่จะให้เราแจ้งเมื่อออเดอร์เดินมาถึงสถานะสุดท้าย · หน้านี้ว่าด้วยการลงทะเบียนปลายทางอย่างเดียว ส่วนหน้าตาของคำขอที่เรายิงไปหาคุณ วิธีตรวจลายเซ็น และนโยบายการยิงซ้ำ อยู่ที่หน้า Callback ที่เราส่งไปหาคุณ (/developers/webhooks/callback) · ปลายทางผูกกับ คีย์ API หนึ่งใบ ไม่ใช่กับบัญชี ถ้าคุณใช้หลายคีย์ต้องตั้งแยกทีละใบ

กุญแจถูกแสดงครั้งเดียว และหมุนใหม่ทุกครั้งที่ตั้งสำเร็จ

secret ถูกแสดงครั้งเดียวตรงคำตอบของการตั้งค่าเท่านั้น ไม่มีเอนด์พอยต์ไหนอ่านมันกลับได้เลย เก็บลงที่เก็บความลับของคุณทันทีที่ได้รับ ทำหายแล้วทางเดียวคือตั้งใหม่แล้วรับกุญแจใบใหม่ · ทุกครั้งที่ตั้งสำเร็จ กุญแจจะถูกหมุนใหม่เสมอ แม้จะส่ง URL เดิมเป๊ะ ๆ ก็ตาม กุญแจใบเก่าใช้ไม่ได้ทันทีตั้งแต่วินาทีนั้น — อย่ายิงคำขอนี้ซ้ำ ๆ เพียงเพื่อยืนยันว่าค่าที่ตั้งไว้ยังอยู่ เพราะมันจะทำให้ตัวตรวจฝั่งคุณที่ยังถือกุญแจใบเก่าปฏิเสธทุก payload · การปิด webhook ล้างกุญแจทิ้งไปด้วยในจังหวะเดียวกัน เปิดใหม่ทีหลัง = ได้กุญแจใบใหม่เสมอ

ตั้งปลายทางให้เสร็จก่อนเริ่มสั่งซื้อ

ตั้ง webhook หลังจากสั่งซื้อไปแล้ว จะไม่ได้รับแจ้งของออเดอร์ที่ค้างอยู่ตอนนั้น — event ที่เข้าคิวไว้ตอนที่ยังไม่มีปลายทางจะถูกทิ้งภายในรอบถัดไป และไม่ถูกส่งย้อนหลังให้เมื่อคุณตั้งปลายทางทีหลัง ไม่มีทางขอให้ส่งใหม่ได้เลย · การปิด webhook ระหว่างที่ยังมีออเดอร์ค้างอยู่ก็ให้ผลเดียวกัน · ตั้งปลายทางให้เรียบร้อยก่อนเริ่มสั่งซื้อเสมอ และถ้าเพิ่งมาตั้งทีหลัง ให้ไล่อ่านออเดอร์ที่ยังไม่ปิดของคุณเองหนึ่งรอบ

การปฏิเสธที่ด่านยืนยันตัวตนเกิดกับเอนด์พอยต์นี้ด้วย

ห้ารหัสของด่านยืนยันตัวตน — invalid_key (401) · key_revoked (401) · insufficient_scope (403) · quota_exceeded (429) · too_many_inflight (429) — เกิดได้กับทุกเอนด์พอยต์ รวมทั้งเอนด์พอยต์นี้ เพราะถูกโยนตั้งแต่ก่อนคำขอจะเดินไปถึงตรรกะของหน้านี้เลยสักบรรทัด (scope ที่ต้องมีคือค่าที่ประกาศไว้หัวหน้านี้) · แท็บคำตอบด้านบนจึงไล่เฉพาะสิ่งที่เอนด์พอยต์นี้เองตอบ ไม่ได้แปลว่าห้ารหัสนั้นเกิดที่นี่ไม่ได้ · รายละเอียดครบทุกตัวอยู่ที่ หน้าเอนด์พอยต์ตัวตน ที่เดียว ทั้ง HTTP status ของแต่ละตัว · ตัวไหนกินโควตารายวันบ้าง · header อะไรกลับมาบ้าง · และทำไม 429 สองตัวต้องรับมือคนละแบบ — จงใจไม่คัดลอกมาไว้ทุกหน้า เพราะสำเนาที่สองคือที่ที่ลืมแก้ตามในวันที่กติกาเปลี่ยน

ข้อมูลที่ต้องส่ง

Request body

ชื่อชนิดวิธีใช้
urlบังคับสตริง หรือ null
URL ปลายทางที่จะให้เรายิงไปหา หรือส่ง null เพื่อปิด webhook
รายละเอียดและข้อควรระวัง
  • ⚠️ **ต้องมีคีย์ url อยู่ใน body เสมอ
  • ไม่ส่งมาเลยถือว่าคำขอเขียนผิด ไม่ใช่คำสั่งปิด** (ดูคำเตือนเรื่องการปิดข้างล่าง)
  • ข้อกำหนดของ URL: ต้องเป็น https เท่านั้น
  • ใช้พอร์ต 443 เท่านั้น (จะละไว้หรือเขียน :443 ก็ได้)
  • ชื่อโฮสต์ต้องเป็นชื่อโดเมน ห้ามใส่เป็นหมายเลข IP ไม่ว่าจะเขียนรูปแบบไหน
  • โดเมนนั้นต้องชี้ไปที่อยู่สาธารณะเท่านั้น (ที่อยู่ในวงเครือข่ายภายในถูกปฏิเสธ)
  • ชี้กลับมาที่โดเมนของร้านไม่ได้
  • ยาวไม่เกิน 2048 ตัวอักษร
  • ใส่พาธและ query string ได้ตามปกติ
  • เราไม่ตาม redirect ปลายทางที่ตอบ 3xx นับเป็นการส่งที่ล้มเหลว ให้ใส่ URL ตัวจริงมาเลย
  • ⚠️ กฎชุดนี้ถูกตรวจซ้ำทุกครั้งก่อนยิงจริง ไม่ใช่แค่ตอนตั้งค่า ปลายทางที่ผ่านวันนี้ แต่วันหลังโดเมนไปชี้ที่อยู่ต้องห้าม จะถูกทิ้งทั้ง event โดยไม่มีการลองใหม่
  • ถ้าจู่ ๆ webhook เงียบไปหลังคุณย้ายผู้ให้บริการ ให้เช็คก่อนว่าโดเมนยังชี้ไปที่อยู่สาธารณะอยู่จริง

Header

ชื่อชนิดวิธีใช้
Authorizationบังคับstring
คีย์ของคุณในรูป Bearer <คีย์> — ต้องส่งมาทุกคำขอ · ปลายทางที่ตั้งจะผูกกับคีย์ใบนี้เท่านั้น ไม่มีผลกับคีย์ใบอื่นของคุณ
Content-Typeบังคับstring
ต้องเป็น application/json เพราะคำขอนี้มี body
รายละเอียดและข้อควรระวัง
  • ประกาศเป็นชนิดอื่นแล้วเนื้อคำขอจะถูกอ่านเป็นข้อความล้วนหรือเป็นฟอร์ม ไม่ใช่ JSON แล้วตกเป็น 400 bad_request ทั้งที่ตัว JSON เขียนถูกทุกตัวอักษร
  • ระวัง curl -d เป็นพิเศษ มันประกาศชนิดเป็นฟอร์มให้เองเมื่อไม่ได้สั่งเป็นอย่างอื่น

ข้อมูลที่ได้รับ

ชื่อชนิดวิธีใช้
urlสตริง หรือ null
URL ที่เราบันทึกไว้จริงและจะยิงไปหา
รายละเอียดและข้อควรระวัง
  • อาจไม่เหมือนที่คุณพิมพ์มาเป๊ะ ๆ เพราะเราจัดรูปให้เป็นมาตรฐานก่อน (ชื่อโฮสต์ตัวใหญ่ถูกแปลงเป็นตัวเล็ก
  • พาธว่างถูกเติม / ให้)
  • ให้ยึดค่าที่คืนมานี้เป็นค่าจริง
  • เป็น null ในคำตอบของคำสั่งปิด
secretสตริง
กุญแจลับสำหรับตรวจลายเซ็นของคำขอที่เราจะยิงไปหาคุณ (วิธีใช้อยู่ที่หน้า Callback)
รายละเอียดและข้อควรระวัง
  • ⚠️ ค่านี้แสดงครั้งเดียวตรงนี้เท่านั้น อ่านกลับทีหลังไม่ได้ ให้เก็บลงที่เก็บความลับฝั่งคุณทันที
  • มีเฉพาะในคำตอบของการตั้งหรือเปลี่ยนปลายทาง คำตอบของคำสั่งปิดไม่มีฟิลด์นี้
rotated_atสตริง ISO 8601 (UTC)
เวลาที่กุญแจใบนี้ถูกออกให้ · มีเฉพาะในคำตอบของการตั้งหรือเปลี่ยนปลายทางเหมือนกัน
data.reasonสตริง
ฟิลด์เดียวที่บอกได้ว่าปลายทางตกด่านไหน
รายละเอียดและข้อควรระวัง
  • ทั้งเจ็ดกรณีที่ URL ถูกปฏิเสธใช้สถานะ 400 กับรหัส webhook_url_rejected ร่วมกันหมด สิ่งเดียวที่ต่างกันคือค่านี้
  • ค่าที่เป็นไปได้: malformed อ่านเป็น URL ไม่ได้ หรือส่งค่าที่ไม่ใช่สตริงมา
  • not_https ไม่ได้ขึ้นต้นด้วย https://
  • bad_port ระบุพอร์ตอื่นที่ไม่ใช่ 443
  • ip_literal ชื่อโฮสต์เป็นหมายเลข IP ไม่ใช่ชื่อโดเมน
  • own_domain ชี้กลับมาที่โดเมนของร้าน หรืออยู่ใต้ vercel.app/localhost (ดูแท็บของรหัสนี้
  • สามชุดนี้ใช้รหัสเดียวกัน)
  • private_host ชื่อนั้นชี้ไปที่อยู่ในเครือข่ายภายในหรือช่วงที่สงวนไว้
  • unresolvable หาที่อยู่ของชื่อนั้นไม่ได้ หรือได้ค่าที่อ่านไม่ออกกลับมา
  • ให้แตกสาขาด้วยค่านี้ ห้ามไปแมตช์ข้อความใน message ถ้อยคำเปลี่ยนได้ตลอดโดยที่ค่านี้ยังเหมือนเดิม
  • ค่าที่ยังไม่รู้จักเป็นไปได้เสมอในอนาคตเหมือนทุกคำศัพท์ของ API นี้ ให้ปฏิบัติกับมันแบบเดียวกับ malformed คือถือว่า URL นั้นใช้ไม่ได้แล้วให้คนดู
  • **นี่เป็นแถวเดียวในตารางนี้ที่อธิบายฟิลด์ของคำตอบที่ *ล้มเหลว* ไม่ใช่คำตอบที่สำเร็จ** ที่ต้องมาอยู่ตรงนี้เพราะมันเป็นฟิลด์เดียวของทั้ง API ที่โครงคำตอบตอนล้มเหลวแบบมาตรฐานไม่มี ไม่เขียนไว้ที่นี่ก็ไม่มีที่ไหนอธิบายมันเลย

สถานะที่อาจได้รับ

สถานะรหัสความหมาย
200
ตั้งหรือเปลี่ยนปลายทางสำเร็จ — เก็บ secret ไว้ทันที
สามคีย์ในตัวอย่างคือคำตอบทั้งหมด ไม่มีอย่างอื่นอีก
รายละเอียดและข้อควรระวัง
  • secret แสดงครั้งเดียวตรงนี้ อ่านย้อนหลังไม่ได้ ให้บันทึกทันที
  • ⚠️ เราไม่ได้ยิงทดสอบไปที่ URL ของคุณตอนตั้งค่า คำขอนี้ตรวจแค่รูปแบบของ URL และที่อยู่ที่โดเมนนั้นชี้ไปเท่านั้น URL ที่พิมพ์ผิดแต่ยังผ่านกฎทุกข้อ คุณจะรู้ตัวก็ตอน webhook ใบแรกไม่ถึงปลายทาง
200
ปิด webhook แล้ว — จะไม่มีการแจ้งเตือนอีก
ปิดด้วยการส่ง url เป็น null ตรง ๆ
รายละเอียดและข้อควรระวัง
  • คีย์เดียวในตัวอย่างคือคำตอบทั้งหมด
  • กุญแจ (secret) ถูกล้างทิ้งไปพร้อมกันในจังหวะเดียวกัน ไม่ได้เก็บไว้ให้กลับมาใช้ คำตอบนี้จึงไม่มี secret กับ rotated_at
  • เปิดใหม่ทีหลังได้กุญแจใบใหม่เสมอ กุญแจใบเก่าใช้ไม่ได้อีก
400bad_request
body ไม่ใช่อ็อบเจกต์ JSON
เช่นส่งอาร์เรย์ สตริงเปล่า ๆ ตัวเลข หรือไม่ส่ง body มาเลย
รายละเอียดและข้อควรระวัง
  • หมายเหตุ: แท็บคำตอบของหน้านี้เรียงตามลำดับที่เราตรวจจริง เพราะ ด่านแรกที่ไม่ผ่านคือคำตอบที่คุณจะได้กลับไป ด่านที่เหลือไม่ถูกตรวจเลย
400bad_request
ไม่มีคีย์ url อยู่ใน body
เช่นส่ง {}
รายละเอียดและข้อควรระวัง
  • {"webhook_url": "https://hooks.example.com/naxset"}
  • หรือ {"URL": "https://hooks.example.com/naxset"}
  • ชื่อคีย์ต้องเป็น url ตัวพิมพ์เล็กเป๊ะ ๆ พิมพ์เป็นตัวใหญ่ไม่นับว่าส่งมา
  • ⚠️ เราจงใจไม่ถือว่ากรณีนี้เป็นคำสั่งปิด webhook เพราะบั๊กที่ทำให้ฟิลด์หายไปจาก body ต้องไม่ทำให้ webhook ของคุณถูกปิดเงียบ ๆ
  • จะปิดต้องส่ง null มาชัด ๆ
400bad_request
url ยาวเกิน 2048 ตัวอักษร
เราตรวจความยาวก่อนกฎเรื่องปลายทางทั้งหมด เพราะมันเป็นเรื่องรูปร่างของคำขอ ไม่ใช่เรื่องความปลอดภัยของปลายทาง — รหัสจึงเป็น bad_request ไม่ใช่ webhook_url_rejected
400webhook_url_rejected
malformed — อ่านเป็น URL ไม่ได้เลย
เช่น {"url": "not a url"}
รายละเอียดและข้อควรระวัง
  • {"url": ""}
  • หรือค่าที่ไม่ใช่สตริงอย่าง {"url": 123} (รวมถึงอ็อบเจกต์และ true)
  • สังเกตว่าค่าที่ไม่ใช่สตริงมาตกที่นี่ ไม่ได้ไปตกที่ด่านความยาวข้างบน
400webhook_url_rejected
not_https — โปรโตคอลผิด
เช่นส่ง http://hooks.example.com/naxset มา · ปลายทางที่ไม่ได้ขึ้นต้นด้วย https:// ถูกปฏิเสธเสมอ ไม่มีข้อยกเว้นให้เครือข่ายภายในหรือช่วงทดสอบ
400webhook_url_rejected
bad_port — พอร์ตอื่นที่ไม่ใช่ 443
เช่นส่ง https://hooks.example.com:8443/naxset มา · เขียน :443 ชัด ๆ ได้ นอกนั้นไม่ได้
400webhook_url_rejected
ip_literal — ชื่อโฮสต์เป็นหมายเลข ไม่ใช่ชื่อ
เช่นส่ง https://203.0.113.10/hook มา
รายละเอียดและข้อควรระวัง
  • นับทุกรูปแบบการเขียน ทั้งเลขฐานสิบ ฐานสิบหก ฐานแปด IPv4 แบบย่อ และ IPv6 ในวงเล็บเหลี่ยม
  • ด่านนี้ดูว่าคุณเขียนเป็นหมายเลขหรือเปล่า ไม่ได้ดูว่าเป็นหมายเลขอะไร
400webhook_url_rejected
own_domain — ชี้กลับมาที่โดเมนของร้าน หรือโดเมนที่ระบบของร้านอาศัยอยู่
ด่านนี้กัน สามโดเมน ไม่ใช่แค่โดเมนของร้าน: naxset.com
รายละเอียดและข้อควรระวัง
  • โฮสต์ใดก็ตามที่อยู่ใต้ vercel.app
  • และ localhost
  • เทียบ ทีละ label คือชื่อโฮสต์ต้องเท่ากับโดเมนนั้นพอดี หรือลงท้ายด้วยจุดตามด้วยโดเมนนั้น (hook.example.vercel.app โดนกัน ส่วน myvercel.app ไม่โดน เพราะเป็นคนละโดเมน)
  • ⚠️ vercel.app ถูกกันทั้งโดเมนเพราะ ระบบของร้านเองก็ถูกเสิร์ฟอยู่บนโดเมนนั้นด้วย ไม่ใช่เพราะเรามีปัญหากับผู้ให้บริการรายนั้น
  • ปลายทางที่อยู่บนซับโดเมนของ vercel.app (ซึ่งเป็นเรื่องปกติมาก) จึงต้องผูกโดเมนของคุณเองเข้ากับมันก่อน แล้วลงทะเบียนด้วยโดเมนนั้นแทน
  • การเติมจุดท้ายชื่อโฮสต์ก็ยังหลบด่านนี้ไม่ได้
400webhook_url_rejected
private_host — ชื่อนั้นชี้ไปที่อยู่ภายใน
ชื่อโฮสต์มีอยู่จริง แต่ที่อยู่ที่มันชี้ไปอย่างน้อยหนึ่งตัวอยู่ในช่วงเครือข่ายภายใน loopback link-local หรือช่วงที่สงวนไว้
รายละเอียดและข้อควรระวัง
  • มีที่อยู่ผิดปนมาตัวเดียวก็ถูกปฏิเสธแล้ว ต่อให้ตัวอื่นเป็นที่อยู่สาธารณะปกติก็ตาม
400webhook_url_rejected
unresolvable — หาคำตอบที่ใช้ได้ไม่ได้
ชื่อนั้นหาที่อยู่ไม่เจอ
รายละเอียดและข้อควรระวัง
  • การถาม DNS ล้มเหลว
  • หรือได้ที่อยู่ที่อ่านไม่ออกกลับมา
  • กรณีนี้เป็นเรื่องชั่วคราวได้ โดเมนที่ DNS พังอยู่ชั่วคราวให้คำตอบเดียวกับโดเมนที่ไม่มีอยู่จริง
  • คำขอที่ถูกปฏิเสธไม่เปลี่ยนอะไรเลย ปลายทางกับกุญแจที่คุณตั้งไว้ก่อนหน้ายังอยู่ครบและยังถูกใช้อยู่เหมือนเดิม
  • PUT ที่ล้มเหลวไม่เคยปิด webhook ให้ และไม่เคยหมุนกุญแจให้

ปลายทางที่ลงทะเบียนแล้วจะเริ่มได้รับคำขอจากเราทันทีที่มีออเดอร์ปิด — หน้าตาของคำขอนั้น วิธีตรวจลายเซ็น และสิ่งที่ปลายทางของคุณต้องตอบกลับ อยู่ที่ Callback ที่เราส่งไปหาคุณ

อัปเดตล่าสุด 2026-09-07