[{"data":1,"prerenderedAt":1008},["ShallowReactive",2],{"docs-nav":3,"docs-\u002Fdocs\u002Fwebhooks":35,"docs-surround-\u002Fdocs\u002Fwebhooks":1004},[4,9,13,18,22,26,30],{"path":5,"title":6,"category":7,"order":8},"\u002Fdocs","Introduction","intro",1,{"path":10,"title":11,"category":7,"order":12},"\u002Fdocs\u002Fgetting-started","เริ่มต้นใช้งาน",10,{"path":14,"title":15,"category":16,"order":17},"\u002Fdocs\u002Fauthentication","Authentication","core",20,{"path":19,"title":20,"category":16,"order":21},"\u002Fdocs\u002Fapi","API Reference",25,{"path":23,"title":24,"category":16,"order":25},"\u002Fdocs\u002Fwebhooks","Webhooks",30,{"path":27,"title":28,"category":16,"order":29},"\u002Fdocs\u002Fsecurity","Security & PDPA",50,{"path":31,"title":32,"category":33,"order":34},"\u002Fdocs\u002Fchangelog","Changelog","meta",90,{"id":36,"title":24,"badge":37,"body":38,"category":16,"description":998,"extension":999,"meta":1000,"navigation":540,"order":25,"path":23,"seo":1001,"stem":1002,"updatedAt":37,"__hash__":1003},"docs\u002Fdocs\u002Fwebhooks.md",null,{"type":39,"value":40,"toc":990},"minimark",[41,50,55,63,146,153,157,168,376,392,395,456,460,479,488,512,901,907,911,945,956,960,970,973,986],[42,43,44,45,49],"p",{},"ตั้ง endpoint ของคุณที่ ",[46,47,48],"strong",{},"Settings → Webhooks"," — SlipBolt จะ POST event ทุกครั้งที่มีผลตรวจสลิปใหม่",[51,52,54],"h2",{"id":53},"event-types","Event types",[42,56,57,58,62],{},"มี 3 event · เลือก subscribe ได้ต่อ endpoint (ไม่เลือกเลย = ได้ ",[59,60,61],"code",{},"slip.verified"," อย่างเดียว)",[64,65,66,85],"table",{},[67,68,69],"thead",{},[70,71,72,76,79],"tr",{},[73,74,75],"th",{},"Event",[73,77,78],{},"เมื่อไร",[73,80,81,84],{},[59,82,83],{},"data.status"," ที่มากับ event",[86,87,88,103,118],"tbody",{},[70,89,90,95,98],{},[91,92,93],"td",{},[59,94,61],{},[91,96,97],{},"สลิปผ่านการตรวจ",[91,99,100],{},[59,101,102],{},"SUCCESS",[70,104,105,110,113],{},[91,106,107],{},[59,108,109],{},"slip.duplicate",[91,111,112],{},"สลิปใบนี้เคยส่งมาแล้ว",[91,114,115],{},[59,116,117],{},"DUPLICATE",[70,119,120,125,128],{},[91,121,122],{},[59,123,124],{},"slip.failed",[91,126,127],{},"ตรวจไม่ผ่าน",[91,129,130,133,134,133,137,133,140,133,143],{},[59,131,132],{},"INVALID"," · ",[59,135,136],{},"FRAUD",[59,138,139],{},"AMOUNT_MISMATCH",[59,141,142],{},"RECEIVER_MISMATCH",[59,144,145],{},"PROVIDER_ERROR",[147,148,150],"callout",{"type":149},"info",[42,151,152],{},"ยังไม่มี event ฝั่งบัญชี\u002Fแพ็ก (เช่น subscription หรือโควตาใกล้เต็ม) — การแจ้งเตือนโควตา 80%\nส่งทางอีเมล\u002FLINE ไม่ใช่ webhook",[51,154,156],{"id":155},"payload","Payload",[42,158,159,160,163,164,167],{},"Body เป็น JSON ตามนี้เสมอ — ",[59,161,162],{},"created"," เป็น ",[46,165,166],{},"unix seconds"," ไม่ใช่ ISO string",[169,170,175],"pre",{"className":171,"code":172,"language":173,"meta":174,"style":174},"language-json shiki shiki-themes github-light github-dark","{\n  \"event\": \"slip.verified\",\n  \"id\": \"evt_9f3c1a7b2d4e6f8a0b1c2d3e\",\n  \"created\": 1781107927,\n  \"data\": {\n    \"transactionId\": \"8f3c…\",\n    \"transRef\": \"015170106978META…\",\n    \"amount\": 250.0,\n    \"status\": \"SUCCESS\",\n    \"bankCode\": \"002\",\n    \"bankName\": \"ธนาคารกรุงเทพ\",\n    \"sender\": \"นาย ก. …\",\n    \"receiver\": \"ร้าน ข.\",\n    \"verifiedAt\": \"2026-06-17T03:21:06.412Z\",\n    \"latencyMs\": 480\n  }\n}\n","json","",[59,176,177,185,202,215,228,237,250,263,276,289,301,314,327,340,353,364,370],{"__ignoreMap":174},[178,179,181],"span",{"class":180,"line":8},"line",[178,182,184],{"class":183},"sVt8B","{\n",[178,186,188,192,195,199],{"class":180,"line":187},2,[178,189,191],{"class":190},"sj4cs","  \"event\"",[178,193,194],{"class":183},": ",[178,196,198],{"class":197},"sZZnC","\"slip.verified\"",[178,200,201],{"class":183},",\n",[178,203,205,208,210,213],{"class":180,"line":204},3,[178,206,207],{"class":190},"  \"id\"",[178,209,194],{"class":183},[178,211,212],{"class":197},"\"evt_9f3c1a7b2d4e6f8a0b1c2d3e\"",[178,214,201],{"class":183},[178,216,218,221,223,226],{"class":180,"line":217},4,[178,219,220],{"class":190},"  \"created\"",[178,222,194],{"class":183},[178,224,225],{"class":190},"1781107927",[178,227,201],{"class":183},[178,229,231,234],{"class":180,"line":230},5,[178,232,233],{"class":190},"  \"data\"",[178,235,236],{"class":183},": {\n",[178,238,240,243,245,248],{"class":180,"line":239},6,[178,241,242],{"class":190},"    \"transactionId\"",[178,244,194],{"class":183},[178,246,247],{"class":197},"\"8f3c…\"",[178,249,201],{"class":183},[178,251,253,256,258,261],{"class":180,"line":252},7,[178,254,255],{"class":190},"    \"transRef\"",[178,257,194],{"class":183},[178,259,260],{"class":197},"\"015170106978META…\"",[178,262,201],{"class":183},[178,264,266,269,271,274],{"class":180,"line":265},8,[178,267,268],{"class":190},"    \"amount\"",[178,270,194],{"class":183},[178,272,273],{"class":190},"250.0",[178,275,201],{"class":183},[178,277,279,282,284,287],{"class":180,"line":278},9,[178,280,281],{"class":190},"    \"status\"",[178,283,194],{"class":183},[178,285,286],{"class":197},"\"SUCCESS\"",[178,288,201],{"class":183},[178,290,291,294,296,299],{"class":180,"line":12},[178,292,293],{"class":190},"    \"bankCode\"",[178,295,194],{"class":183},[178,297,298],{"class":197},"\"002\"",[178,300,201],{"class":183},[178,302,304,307,309,312],{"class":180,"line":303},11,[178,305,306],{"class":190},"    \"bankName\"",[178,308,194],{"class":183},[178,310,311],{"class":197},"\"ธนาคารกรุงเทพ\"",[178,313,201],{"class":183},[178,315,317,320,322,325],{"class":180,"line":316},12,[178,318,319],{"class":190},"    \"sender\"",[178,321,194],{"class":183},[178,323,324],{"class":197},"\"นาย ก. …\"",[178,326,201],{"class":183},[178,328,330,333,335,338],{"class":180,"line":329},13,[178,331,332],{"class":190},"    \"receiver\"",[178,334,194],{"class":183},[178,336,337],{"class":197},"\"ร้าน ข.\"",[178,339,201],{"class":183},[178,341,343,346,348,351],{"class":180,"line":342},14,[178,344,345],{"class":190},"    \"verifiedAt\"",[178,347,194],{"class":183},[178,349,350],{"class":197},"\"2026-06-17T03:21:06.412Z\"",[178,352,201],{"class":183},[178,354,356,359,361],{"class":180,"line":355},15,[178,357,358],{"class":190},"    \"latencyMs\"",[178,360,194],{"class":183},[178,362,363],{"class":190},"480\n",[178,365,367],{"class":180,"line":366},16,[178,368,369],{"class":183},"  }\n",[178,371,373],{"class":180,"line":372},17,[178,374,375],{"class":183},"}\n",[42,377,378,381,382,163,385,388,389],{},[59,379,380],{},"sender"," \u002F ",[59,383,384],{},"receiver",[46,386,387],{},"string ชื่อ"," ไม่ใช่ object · ค่าที่อ่านไม่ได้จากสลิปจะเป็น ",[59,390,391],{},"null",[42,393,394],{},"Header ที่มากับทุก delivery:",[64,396,397,407],{},[67,398,399],{},[70,400,401,404],{},[73,402,403],{},"Header",[73,405,406],{},"ค่า",[86,408,409,421,431,444],{},[70,410,411,416],{},[91,412,413],{},[59,414,415],{},"X-Slipbolt-Event",[91,417,418,419],{},"ชื่อ event เช่น ",[59,420,61],{},[70,422,423,428],{},[91,424,425],{},[59,426,427],{},"X-Slipbolt-Delivery",[91,429,430],{},"id ของ endpoint ที่ยิงมา",[70,432,433,438],{},[91,434,435],{},[59,436,437],{},"X-Slipbolt-Signature",[91,439,440,443],{},[59,441,442],{},"t=\u003Cunix>,v1=\u003Chex>"," — ดูหัวข้อถัดไป",[70,445,446,451],{},[91,447,448],{},[59,449,450],{},"User-Agent",[91,452,453],{},[59,454,455],{},"Slipbolt-Webhooks\u002F1.0",[51,457,459],{"id":458},"verify-signature","Verify signature",[169,461,465],{"className":462,"code":463,"language":464,"meta":174,"style":174},"language-http shiki shiki-themes github-light github-dark","X-Slipbolt-Signature: t=1781107927,v1=\u003Chex>\n","http",[59,466,467],{"__ignoreMap":174},[178,468,469,472,476],{"class":180,"line":8},[178,470,437],{"class":471},"s9eBZ",[178,473,475],{"class":474},"szBVR",":",[178,477,478],{"class":197}," t=1781107927,v1=\u003Chex>\n",[42,480,481,484,485],{},[59,482,483],{},"v1"," = ",[59,486,487],{},"HMAC-SHA256(secret, \"\u003Cts>.\" + raw_body)",[147,489,491],{"type":490},"warning",[42,492,493,504,505,507,508,511],{},[46,494,495,496,499,500,503],{},"สตริงที่เซ็นคือ ",[59,497,498],{},"\u003Cts>.\u003Cbody>"," — ไม่มี ",[59,501,502],{},"t="," นำหน้า"," · ใส่ ",[59,506,502],{}," เข้าไปด้วยจะได้ signature คนละค่า\nแล้ว verify ไม่ผ่านทุกใบ · และต้องใช้ ",[46,509,510],{},"raw body"," ไม่ใช่ JSON ที่ parse แล้ว re-serialize",[169,513,517],{"className":514,"code":515,"language":516,"meta":174,"style":174},"language-ts shiki shiki-themes github-light github-dark","import { createHmac, timingSafeEqual } from 'node:crypto';\n\nfunction verify(rawBody: string, header: string, secret: string): boolean {\n  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));\n  const ts = parts.t;\n  const sig = parts.v1;\n  if (!ts || !sig) return false;\n  if (Math.abs(Date.now() \u002F 1000 - Number(ts)) > 300) return false; \u002F\u002F กัน replay 5 นาที\n\n  const expected = createHmac('sha256', secret)\n    .update(`${ts}.${rawBody}`)   \u002F\u002F ← จุดที่พลาดกันบ่อย\n    .digest('hex');\n\n  const a = Buffer.from(sig, 'hex');\n  const b = Buffer.from(expected, 'hex');\n  return a.length === b.length && timingSafeEqual(a, b);\n}\n","ts",[59,518,519,536,542,593,647,659,671,702,756,760,780,809,824,828,849,869,897],{"__ignoreMap":174},[178,520,521,524,527,530,533],{"class":180,"line":8},[178,522,523],{"class":474},"import",[178,525,526],{"class":183}," { createHmac, timingSafeEqual } ",[178,528,529],{"class":474},"from",[178,531,532],{"class":197}," 'node:crypto'",[178,534,535],{"class":183},";\n",[178,537,538],{"class":180,"line":187},[178,539,541],{"emptyLinePlaceholder":540},true,"\n",[178,543,544,547,551,554,558,560,563,566,569,571,573,575,578,580,582,585,587,590],{"class":180,"line":204},[178,545,546],{"class":474},"function",[178,548,550],{"class":549},"sScJk"," verify",[178,552,553],{"class":183},"(",[178,555,557],{"class":556},"s4XuR","rawBody",[178,559,475],{"class":474},[178,561,562],{"class":190}," string",[178,564,565],{"class":183},", ",[178,567,568],{"class":556},"header",[178,570,475],{"class":474},[178,572,562],{"class":190},[178,574,565],{"class":183},[178,576,577],{"class":556},"secret",[178,579,475],{"class":474},[178,581,562],{"class":190},[178,583,584],{"class":183},")",[178,586,475],{"class":474},[178,588,589],{"class":190}," boolean",[178,591,592],{"class":183}," {\n",[178,594,595,598,601,604,607,610,613,616,618,621,624,627,629,631,634,637,639,641,644],{"class":180,"line":217},[178,596,597],{"class":474},"  const",[178,599,600],{"class":190}," parts",[178,602,603],{"class":474}," =",[178,605,606],{"class":183}," Object.",[178,608,609],{"class":549},"fromEntries",[178,611,612],{"class":183},"(header.",[178,614,615],{"class":549},"split",[178,617,553],{"class":183},[178,619,620],{"class":197},"','",[178,622,623],{"class":183},").",[178,625,626],{"class":549},"map",[178,628,553],{"class":183},[178,630,42],{"class":556},[178,632,633],{"class":474}," =>",[178,635,636],{"class":183}," p.",[178,638,615],{"class":549},[178,640,553],{"class":183},[178,642,643],{"class":197},"'='",[178,645,646],{"class":183},")));\n",[178,648,649,651,654,656],{"class":180,"line":230},[178,650,597],{"class":474},[178,652,653],{"class":190}," ts",[178,655,603],{"class":474},[178,657,658],{"class":183}," parts.t;\n",[178,660,661,663,666,668],{"class":180,"line":239},[178,662,597],{"class":474},[178,664,665],{"class":190}," sig",[178,667,603],{"class":474},[178,669,670],{"class":183}," parts.v1;\n",[178,672,673,676,679,682,685,688,691,694,697,700],{"class":180,"line":252},[178,674,675],{"class":474},"  if",[178,677,678],{"class":183}," (",[178,680,681],{"class":474},"!",[178,683,684],{"class":183},"ts ",[178,686,687],{"class":474},"||",[178,689,690],{"class":474}," !",[178,692,693],{"class":183},"sig) ",[178,695,696],{"class":474},"return",[178,698,699],{"class":190}," false",[178,701,535],{"class":183},[178,703,704,706,709,712,715,718,721,724,727,730,733,736,739,742,745,747,749,752],{"class":180,"line":265},[178,705,675],{"class":474},[178,707,708],{"class":183}," (Math.",[178,710,711],{"class":549},"abs",[178,713,714],{"class":183},"(Date.",[178,716,717],{"class":549},"now",[178,719,720],{"class":183},"() ",[178,722,723],{"class":474},"\u002F",[178,725,726],{"class":190}," 1000",[178,728,729],{"class":474}," -",[178,731,732],{"class":549}," Number",[178,734,735],{"class":183},"(ts)) ",[178,737,738],{"class":474},">",[178,740,741],{"class":190}," 300",[178,743,744],{"class":183},") ",[178,746,696],{"class":474},[178,748,699],{"class":190},[178,750,751],{"class":183},"; ",[178,753,755],{"class":754},"sJ8bj","\u002F\u002F กัน replay 5 นาที\n",[178,757,758],{"class":180,"line":278},[178,759,541],{"emptyLinePlaceholder":540},[178,761,762,764,767,769,772,774,777],{"class":180,"line":12},[178,763,597],{"class":474},[178,765,766],{"class":190}," expected",[178,768,603],{"class":474},[178,770,771],{"class":549}," createHmac",[178,773,553],{"class":183},[178,775,776],{"class":197},"'sha256'",[178,778,779],{"class":183},", secret)\n",[178,781,782,785,788,790,793,795,798,800,803,806],{"class":180,"line":303},[178,783,784],{"class":183},"    .",[178,786,787],{"class":549},"update",[178,789,553],{"class":183},[178,791,792],{"class":197},"`${",[178,794,516],{"class":183},[178,796,797],{"class":197},"}.${",[178,799,557],{"class":183},[178,801,802],{"class":197},"}`",[178,804,805],{"class":183},")   ",[178,807,808],{"class":754},"\u002F\u002F ← จุดที่พลาดกันบ่อย\n",[178,810,811,813,816,818,821],{"class":180,"line":316},[178,812,784],{"class":183},[178,814,815],{"class":549},"digest",[178,817,553],{"class":183},[178,819,820],{"class":197},"'hex'",[178,822,823],{"class":183},");\n",[178,825,826],{"class":180,"line":329},[178,827,541],{"emptyLinePlaceholder":540},[178,829,830,832,835,837,840,842,845,847],{"class":180,"line":342},[178,831,597],{"class":474},[178,833,834],{"class":190}," a",[178,836,603],{"class":474},[178,838,839],{"class":183}," Buffer.",[178,841,529],{"class":549},[178,843,844],{"class":183},"(sig, ",[178,846,820],{"class":197},[178,848,823],{"class":183},[178,850,851,853,856,858,860,862,865,867],{"class":180,"line":355},[178,852,597],{"class":474},[178,854,855],{"class":190}," b",[178,857,603],{"class":474},[178,859,839],{"class":183},[178,861,529],{"class":549},[178,863,864],{"class":183},"(expected, ",[178,866,820],{"class":197},[178,868,823],{"class":183},[178,870,871,874,877,880,883,886,888,891,894],{"class":180,"line":366},[178,872,873],{"class":474},"  return",[178,875,876],{"class":183}," a.",[178,878,879],{"class":190},"length",[178,881,882],{"class":474}," ===",[178,884,885],{"class":183}," b.",[178,887,879],{"class":190},[178,889,890],{"class":474}," &&",[178,892,893],{"class":549}," timingSafeEqual",[178,895,896],{"class":183},"(a, b);\n",[178,898,899],{"class":180,"line":372},[178,900,375],{"class":183},[42,902,903,904,906],{},"ดู secret ของแต่ละ endpoint ได้ที่ ",[46,905,48],{}," (กดเปิดดูทีละอัน)",[51,908,910],{"id":909},"retry-policy","Retry policy",[912,913,914,921,927,933,940],"ul",{},[915,916,917,920],"li",{},[46,918,919],{},"2xx = สำเร็จ"," · อย่างอื่นทั้งหมดถือว่าล้มเหลว",[915,922,923,926],{},[46,924,925],{},"4xx ก็ retry"," — ไม่ได้ยกเว้นเหมือนบางเจ้า · ถ้าไม่อยากโดนยิงซ้ำ ตอบ 2xx แล้วค่อยไปคัดทิ้งฝั่งคุณ",[915,928,929,932],{},[46,930,931],{},"timeout 10 วินาที"," ต่อครั้ง",[915,934,935,936,939],{},"ลองทั้งหมด ",[46,937,938],{},"5 ครั้ง"," · backoff แบบ exponential เริ่มที่ 2 วินาที (≈ 2s → 4s → 8s → 16s)",[915,941,942,943],{},"ทุกครั้งที่ยิงถูกบันทึกเป็นแถวใน delivery log — ดูได้ที่ ",[46,944,48],{},[147,946,947],{"type":490},[42,948,949,678,952,955],{},[46,950,951],{},"endpoint ที่ล้มเหลวสะสมครบ 25 ครั้งจะถูกปิดอัตโนมัติ",[59,953,954],{},"enabled = false",") และหยุดรับ event\nจนกว่าจะเปิดใหม่เอง · ตัวนับรีเซ็ตทันทีที่มี delivery สำเร็จหนึ่งครั้ง",[51,957,959],{"id":958},"ทดสอบ-endpoint","ทดสอบ endpoint",[42,961,962,963,966,967,969],{},"กด ",[46,964,965],{},"ส่ง event ตัวอย่าง"," ที่ Settings → Webhooks — ระบบยิง ",[59,968,61],{}," ปลอมหนึ่งใบไปที่ endpoint นั้น\nโดยไม่สนว่า subscribe อะไรไว้และไม่แตะโควตา · ใช้ตรวจว่า signature ฝั่งคุณ verify ผ่านจริงก่อนขึ้น production",[51,971,972],{"id":972},"ถัดไป",[912,974,975,981],{},[915,976,977,980],{},[978,979,20],"a",{"href":19}," — endpoint + error code ทั้งหมด",[915,982,983,985],{},[978,984,28],{"href":27}," — การเก็บ secret + สิทธิ์เจ้าของข้อมูล",[987,988,989],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":174,"searchDepth":204,"depth":204,"links":991},[992,993,994,995,996,997],{"id":53,"depth":187,"text":54},{"id":155,"depth":187,"text":156},{"id":458,"depth":187,"text":459},{"id":909,"depth":187,"text":910},{"id":958,"depth":187,"text":959},{"id":972,"depth":187,"text":972},"รับ event แบบ HMAC-signed · retry อัตโนมัติ 5 ครั้ง · delivery log + auto-disable endpoint ที่ล่ม","md",{},{"title":24,"description":998},"docs\u002Fwebhooks","X867fPzuLsyfkz_g0gCdgFLMDZRKmz8TZZ_P_BKl7_Q",[1005,37],{"title":28,"path":27,"stem":1006,"description":1007,"children":-1},"docs\u002Fsecurity","มาตรฐานความปลอดภัย — encryption at rest, HMAC webhook, การจัดการ key, สิทธิ์ตาม PDPA",1789321305994]