[{"data":1,"prerenderedAt":10629},["ShallowReactive",2],{"docs-nav":3,"docs-th-\u002Fdocs\u002Frecipes":58},{"th":4,"en":45},[5,10,14,19,23,27,31,36,40],{"path":6,"title":7,"category":8,"order":9},"\u002Fdocs","Introduction","intro",1,{"path":11,"title":12,"category":8,"order":13},"\u002Fdocs\u002Fgetting-started","เริ่มต้นใช้งาน",10,{"path":15,"title":16,"category":17,"order":18},"\u002Fdocs\u002Fauthentication","Authentication","core",20,{"path":20,"title":21,"category":17,"order":22},"\u002Fdocs\u002Fapi","API Reference",25,{"path":24,"title":25,"category":17,"order":26},"\u002Fdocs\u002Fwebhooks","Webhooks",30,{"path":28,"title":29,"category":17,"order":30},"\u002Fdocs\u002Fsecurity","Security & PDPA",35,{"path":32,"title":33,"category":34,"order":35},"\u002Fdocs\u002Frecipes","ตัวอย่างพร้อมใช้","guides",40,{"path":37,"title":38,"category":34,"order":39},"\u002Fdocs\u002Fmcp","MCP สำหรับ AI",45,{"path":41,"title":42,"category":43,"order":44},"\u002Fdocs\u002Fchangelog","Changelog","meta",90,[46,47,48,49,51,52,54,56,57],{"path":20,"title":21},{"path":15,"title":16},{"path":41,"title":42},{"path":11,"title":50},"Getting started",{"path":6,"title":7},{"path":37,"title":53},"MCP for AI tools",{"path":32,"title":55},"Recipes",{"path":28,"title":29},{"path":24,"title":25},{"id":59,"title":33,"badge":60,"body":61,"category":34,"description":10622,"extension":10623,"meta":10624,"navigation":278,"order":35,"path":32,"seo":10625,"stem":10626,"updatedAt":10627,"__hash__":10628,"translated":278},"docs\u002Fdocs\u002Frecipes.md","Copy & paste",{"type":62,"value":63,"toc":10606},"minimark",[64,73,138,146,174,178,185,237,2264,2267,2521,2524,2527,2537,2542,2616,2640,2644,2651,2910,2913,2920,5374,5398,5401,5414,5525,8281,8293,8297,8313,8320,8341,8348,8359,10255,10258,10268,10272,10279,10481,10496,10500,10503,10522,10537,10541,10602],[65,66,67,68,72],"p",{},"โค้ดในหน้านี้ ",[69,70,71],"strong",{},"รันได้จริงทุกบล็อก"," ก๊อปไปวางแล้วแก้แค่ส่วนฐานข้อมูลของคุณ\nเลือกภาษาที่แท็บครั้งเดียว ทุกบล็อกจะสลับตาม",[74,75,76,89],"table",{},[77,78,79],"thead",{},[80,81,82,86],"tr",{},[83,84,85],"th",{},"ต้องการ",[83,87,88],{},"ไปที่",[90,91,92,105,116,127],"tbody",{},[80,93,94,98],{},[95,96,97],"td",{},"ฟังก์ชันตรวจสลิปที่ retry \u002F timeout ให้เอง",[95,99,100],{},[101,102,104],"a",{"href":103},"#_1-%E0%B9%84%E0%B8%84%E0%B8%A5%E0%B9%80%E0%B8%AD%E0%B8%99%E0%B8%95%E0%B9%8C%E0%B8%9E%E0%B8%A3%E0%B9%89%E0%B8%AD%E0%B8%A1%E0%B9%83%E0%B8%8A%E0%B9%89","1. ไคลเอนต์พร้อมใช้",[80,106,107,110],{},[95,108,109],{},"ลูกค้าอัปโหลดสลิป → ตรวจ → ปิดออเดอร์",[95,111,112],{},[101,113,115],{"href":114},"#_2-%E0%B8%A3%E0%B8%B1%E0%B8%9A%E0%B8%AA%E0%B8%A5%E0%B8%B4%E0%B8%9B%E0%B9%81%E0%B8%A5%E0%B9%89%E0%B8%A7%E0%B8%9B%E0%B8%B4%E0%B8%94%E0%B8%AD%E0%B8%AD%E0%B9%80%E0%B8%94%E0%B8%AD%E0%B8%A3%E0%B9%8C","2. รับสลิปแล้วปิดออเดอร์",[80,117,118,121],{},[95,119,120],{},"ส่งแบบ form upload \u002F base64 \u002F URL \u002F ข้อความ QR",[95,122,123],{},[101,124,126],{"href":125},"#_3-%E0%B8%A3%E0%B8%B9%E0%B8%9B%E0%B8%AD%E0%B8%A2%E0%B8%B9%E0%B9%88%E0%B9%83%E0%B8%99%E0%B8%A3%E0%B8%B9%E0%B8%9B%E0%B9%81%E0%B8%9A%E0%B8%9A%E0%B8%AD%E0%B8%B7%E0%B9%88%E0%B8%99","3. รูปอยู่ในรูปแบบอื่น",[80,128,129,132],{},[95,130,131],{},"ลอง webhook โดยยังไม่ขึ้นเซิร์ฟเวอร์จริง",[95,133,134],{},[101,135,137],{"href":136},"#_4-%E0%B8%97%E0%B8%94%E0%B8%AA%E0%B8%AD%E0%B8%9A-webhook-%E0%B9%83%E0%B8%99%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87","4. ทดสอบ webhook ในเครื่อง",[65,139,140,141,145],{},"ทุกตัวอย่างอ่านคีย์จาก environment variable — ช่วงพัฒนาใช้ ",[142,143,144],"code",{},"sk_test_"," ได้ ไม่กินโควตาของร้าน",[147,148,153],"pre",{"className":149,"code":150,"language":151,"meta":152,"style":152},"language-bash shiki shiki-themes github-light github-dark","export SLIPBOLT_API_KEY=\"sk_test_...\"\n","bash","",[142,154,155],{"__ignoreMap":152},[156,157,159,163,167,170],"span",{"class":158,"line":9},"line",[156,160,162],{"class":161},"szBVR","export",[156,164,166],{"class":165},"sVt8B"," SLIPBOLT_API_KEY",[156,168,169],{"class":161},"=",[156,171,173],{"class":172},"sZZnC","\"sk_test_...\"\n",[175,176,104],"h2",{"id":177},"_1-ไคลเอนต์พร้อมใช้",[65,179,180,181,184],{},"ไฟล์เดียว ไม่มี dependency เพิ่ม (Python ใช้ ",[142,182,183],{},"requests",") — จัดการ 3 เรื่องที่ทุกระบบจริงต้องมี:",[186,187,188,195,217],"ul",{},[189,190,191,194],"li",{},[69,192,193],{},"timeout 30 วินาที"," — ไม่ค้างทั้ง request ของลูกค้าเมื่อเน็ตมีปัญหา",[189,196,197,200,201,204,205,208,209,212,213,216],{},[69,198,199],{},"retry อัตโนมัติ"," เมื่อเน็ตหลุด · ",[142,202,203],{},"429"," (รอตาม ",[142,206,207],{},"Retry-After",") · ",[142,210,211],{},"5xx"," — ปลอดภัยเพราะส่งรูปเดิมซ้ำใน 24 ชม.\nได้ผลเดิมกลับมา (",[142,214,215],{},"cached: true",") ไม่ตรวจซ้ำ ไม่หักโควตาซ้ำ",[189,218,219,228,229,232,233,236],{},[69,220,221,222,225,226],{},"error ที่มี ",[142,223,224],{},"status"," + ",[142,227,142],{}," — แยก \"โควตาหมด\" (",[142,230,231],{},"402",") ออกจาก \"คีย์ผิด\" (",[142,234,235],{},"401",") ได้โดยไม่ต้องอ่านข้อความ",[238,239,240,937,1576],"code-group",{},[147,241,246],{"className":242,"code":243,"filename":244,"language":245,"meta":152,"style":152},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F slipbolt.js — Node.js 18+ · ไม่ต้องลงแพ็กเกจเพิ่ม\nconst BASE = 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1';\n\nexport class SlipBoltError extends Error {\n  constructor(status, body) {\n    super(`${status} ${body.code ?? body.error ?? ''}: ${body.message ?? 'request failed'}`);\n    this.status = status; \u002F\u002F HTTP status เช่น 402\n    this.code = body.code; \u002F\u002F เช่น QUOTA_EXCEEDED\n    this.requestId = body.requestId; \u002F\u002F แนบมาตอนติดต่อทีมงาน\n  }\n}\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\n\u002F** ตรวจสลิป 1 ใบ — คืนก้อน `data` · โยน SlipBoltError เมื่อ API ตอบ error *\u002F\nexport async function verifySlip(image, { apiKey = process.env.SLIPBOLT_API_KEY, retries = 3 } = {}) {\n  for (let attempt = 0; ; attempt++) {\n    let res;\n    try {\n      res = await fetch(`${BASE}\u002Fverify`, {\n        method: 'POST',\n        headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application\u002Foctet-stream' },\n        body: image,\n        signal: AbortSignal.timeout(30_000),\n      });\n    } catch (err) {\n      if (attempt >= retries) throw err; \u002F\u002F เน็ตหลุด \u002F timeout ครบจำนวนครั้งแล้ว\n      await sleep(500 * 2 ** attempt);\n      continue;\n    }\n\n    if ((res.status === 429 || res.status >= 500) && attempt \u003C retries) {\n      await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000);\n      continue;\n    }\n\n    const body = await res.json().catch(() => ({}));\n    if (!res.ok) throw new SlipBoltError(res.status, body);\n    return body.data; \u002F\u002F ผลอยู่ใน data เสมอ\n  }\n}\n","Node.js","js",[142,247,248,254,273,280,301,322,376,393,409,425,430,436,441,485,490,496,547,574,583,591,617,629,657,663,680,685,697,721,746,754,759,764,803,847,854,858,863,894,916,928,932],{"__ignoreMap":152},[156,249,250],{"class":158,"line":9},[156,251,253],{"class":252},"sJ8bj","\u002F\u002F slipbolt.js — Node.js 18+ · ไม่ต้องลงแพ็กเกจเพิ่ม\n",[156,255,257,260,264,267,270],{"class":158,"line":256},2,[156,258,259],{"class":161},"const",[156,261,263],{"class":262},"sj4cs"," BASE",[156,265,266],{"class":161}," =",[156,268,269],{"class":172}," 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1'",[156,271,272],{"class":165},";\n",[156,274,276],{"class":158,"line":275},3,[156,277,279],{"emptyLinePlaceholder":278},true,"\n",[156,281,283,285,288,292,295,298],{"class":158,"line":282},4,[156,284,162],{"class":161},[156,286,287],{"class":161}," class",[156,289,291],{"class":290},"sScJk"," SlipBoltError",[156,293,294],{"class":161}," extends",[156,296,297],{"class":290}," Error",[156,299,300],{"class":165}," {\n",[156,302,304,307,310,313,316,319],{"class":158,"line":303},5,[156,305,306],{"class":161},"  constructor",[156,308,309],{"class":165},"(",[156,311,224],{"class":312},"s4XuR",[156,314,315],{"class":165},", ",[156,317,318],{"class":312},"body",[156,320,321],{"class":165},") {\n",[156,323,325,328,330,333,335,338,340,343,345,348,351,353,356,358,361,363,365,368,370,373],{"class":158,"line":324},6,[156,326,327],{"class":262},"    super",[156,329,309],{"class":165},[156,331,332],{"class":172},"`${",[156,334,224],{"class":165},[156,336,337],{"class":172},"} ${",[156,339,318],{"class":165},[156,341,342],{"class":172},".",[156,344,142],{"class":165},[156,346,347],{"class":161}," ??",[156,349,350],{"class":165}," body",[156,352,342],{"class":172},[156,354,355],{"class":165},"error",[156,357,347],{"class":161},[156,359,360],{"class":172}," ''}: ${",[156,362,318],{"class":165},[156,364,342],{"class":172},[156,366,367],{"class":165},"message",[156,369,347],{"class":161},[156,371,372],{"class":172}," 'request failed'}`",[156,374,375],{"class":165},");\n",[156,377,379,382,385,387,390],{"class":158,"line":378},7,[156,380,381],{"class":262},"    this",[156,383,384],{"class":165},".status ",[156,386,169],{"class":161},[156,388,389],{"class":165}," status; ",[156,391,392],{"class":252},"\u002F\u002F HTTP status เช่น 402\n",[156,394,396,398,401,403,406],{"class":158,"line":395},8,[156,397,381],{"class":262},[156,399,400],{"class":165},".code ",[156,402,169],{"class":161},[156,404,405],{"class":165}," body.code; ",[156,407,408],{"class":252},"\u002F\u002F เช่น QUOTA_EXCEEDED\n",[156,410,412,414,417,419,422],{"class":158,"line":411},9,[156,413,381],{"class":262},[156,415,416],{"class":165},".requestId ",[156,418,169],{"class":161},[156,420,421],{"class":165}," body.requestId; ",[156,423,424],{"class":252},"\u002F\u002F แนบมาตอนติดต่อทีมงาน\n",[156,426,427],{"class":158,"line":13},[156,428,429],{"class":165},"  }\n",[156,431,433],{"class":158,"line":432},11,[156,434,435],{"class":165},"}\n",[156,437,439],{"class":158,"line":438},12,[156,440,279],{"emptyLinePlaceholder":278},[156,442,444,446,449,451,454,457,460,463,466,469,472,475,477,479,482],{"class":158,"line":443},13,[156,445,259],{"class":161},[156,447,448],{"class":290}," sleep",[156,450,266],{"class":161},[156,452,453],{"class":165}," (",[156,455,456],{"class":312},"ms",[156,458,459],{"class":165},") ",[156,461,462],{"class":161},"=>",[156,464,465],{"class":161}," new",[156,467,468],{"class":262}," Promise",[156,470,471],{"class":165},"((",[156,473,474],{"class":312},"resolve",[156,476,459],{"class":165},[156,478,462],{"class":161},[156,480,481],{"class":290}," setTimeout",[156,483,484],{"class":165},"(resolve, ms));\n",[156,486,488],{"class":158,"line":487},14,[156,489,279],{"emptyLinePlaceholder":278},[156,491,493],{"class":158,"line":492},15,[156,494,495],{"class":252},"\u002F** ตรวจสลิป 1 ใบ — คืนก้อน `data` · โยน SlipBoltError เมื่อ API ตอบ error *\u002F\n",[156,497,499,501,504,507,510,512,515,518,521,523,526,529,531,534,536,539,542,544],{"class":158,"line":498},16,[156,500,162],{"class":161},[156,502,503],{"class":161}," async",[156,505,506],{"class":161}," function",[156,508,509],{"class":290}," verifySlip",[156,511,309],{"class":165},[156,513,514],{"class":312},"image",[156,516,517],{"class":165},", { ",[156,519,520],{"class":312},"apiKey",[156,522,266],{"class":161},[156,524,525],{"class":165}," process.env.",[156,527,528],{"class":262},"SLIPBOLT_API_KEY",[156,530,315],{"class":165},[156,532,533],{"class":312},"retries",[156,535,266],{"class":161},[156,537,538],{"class":262}," 3",[156,540,541],{"class":165}," } ",[156,543,169],{"class":161},[156,545,546],{"class":165}," {}) {\n",[156,548,550,553,555,558,561,563,566,569,572],{"class":158,"line":549},17,[156,551,552],{"class":161},"  for",[156,554,453],{"class":165},[156,556,557],{"class":161},"let",[156,559,560],{"class":165}," attempt ",[156,562,169],{"class":161},[156,564,565],{"class":262}," 0",[156,567,568],{"class":165},"; ; attempt",[156,570,571],{"class":161},"++",[156,573,321],{"class":165},[156,575,577,580],{"class":158,"line":576},18,[156,578,579],{"class":161},"    let",[156,581,582],{"class":165}," res;\n",[156,584,586,589],{"class":158,"line":585},19,[156,587,588],{"class":161},"    try",[156,590,300],{"class":165},[156,592,593,596,598,601,604,606,608,611,614],{"class":158,"line":18},[156,594,595],{"class":165},"      res ",[156,597,169],{"class":161},[156,599,600],{"class":161}," await",[156,602,603],{"class":290}," fetch",[156,605,309],{"class":165},[156,607,332],{"class":172},[156,609,610],{"class":262},"BASE",[156,612,613],{"class":172},"}\u002Fverify`",[156,615,616],{"class":165},", {\n",[156,618,620,623,626],{"class":158,"line":619},21,[156,621,622],{"class":165},"        method: ",[156,624,625],{"class":172},"'POST'",[156,627,628],{"class":165},",\n",[156,630,632,635,638,640,643,645,648,651,654],{"class":158,"line":631},22,[156,633,634],{"class":165},"        headers: { Authorization: ",[156,636,637],{"class":172},"`Bearer ${",[156,639,520],{"class":165},[156,641,642],{"class":172},"}`",[156,644,315],{"class":165},[156,646,647],{"class":172},"'Content-Type'",[156,649,650],{"class":165},": ",[156,652,653],{"class":172},"'application\u002Foctet-stream'",[156,655,656],{"class":165}," },\n",[156,658,660],{"class":158,"line":659},23,[156,661,662],{"class":165},"        body: image,\n",[156,664,666,669,672,674,677],{"class":158,"line":665},24,[156,667,668],{"class":165},"        signal: AbortSignal.",[156,670,671],{"class":290},"timeout",[156,673,309],{"class":165},[156,675,676],{"class":262},"30_000",[156,678,679],{"class":165},"),\n",[156,681,682],{"class":158,"line":22},[156,683,684],{"class":165},"      });\n",[156,686,688,691,694],{"class":158,"line":687},26,[156,689,690],{"class":165},"    } ",[156,692,693],{"class":161},"catch",[156,695,696],{"class":165}," (err) {\n",[156,698,700,703,706,709,712,715,718],{"class":158,"line":699},27,[156,701,702],{"class":161},"      if",[156,704,705],{"class":165}," (attempt ",[156,707,708],{"class":161},">=",[156,710,711],{"class":165}," retries) ",[156,713,714],{"class":161},"throw",[156,716,717],{"class":165}," err; ",[156,719,720],{"class":252},"\u002F\u002F เน็ตหลุด \u002F timeout ครบจำนวนครั้งแล้ว\n",[156,722,724,727,729,731,734,737,740,743],{"class":158,"line":723},28,[156,725,726],{"class":161},"      await",[156,728,448],{"class":290},[156,730,309],{"class":165},[156,732,733],{"class":262},"500",[156,735,736],{"class":161}," *",[156,738,739],{"class":262}," 2",[156,741,742],{"class":161}," **",[156,744,745],{"class":165}," attempt);\n",[156,747,749,752],{"class":158,"line":748},29,[156,750,751],{"class":161},"      continue",[156,753,272],{"class":165},[156,755,756],{"class":158,"line":26},[156,757,758],{"class":165},"    }\n",[156,760,762],{"class":158,"line":761},31,[156,763,279],{"emptyLinePlaceholder":278},[156,765,767,770,773,776,779,782,785,787,790,792,795,797,800],{"class":158,"line":766},32,[156,768,769],{"class":161},"    if",[156,771,772],{"class":165}," ((res.status ",[156,774,775],{"class":161},"===",[156,777,778],{"class":262}," 429",[156,780,781],{"class":161}," ||",[156,783,784],{"class":165}," res.status ",[156,786,708],{"class":161},[156,788,789],{"class":262}," 500",[156,791,459],{"class":165},[156,793,794],{"class":161},"&&",[156,796,560],{"class":165},[156,798,799],{"class":161},"\u003C",[156,801,802],{"class":165}," retries) {\n",[156,804,806,808,810,812,815,818,821,823,826,829,832,834,836,839,842,845],{"class":158,"line":805},33,[156,807,726],{"class":161},[156,809,448],{"class":290},[156,811,471],{"class":165},[156,813,814],{"class":290},"Number",[156,816,817],{"class":165},"(res.headers.",[156,819,820],{"class":290},"get",[156,822,309],{"class":165},[156,824,825],{"class":172},"'retry-after'",[156,827,828],{"class":165},")) ",[156,830,831],{"class":161},"||",[156,833,739],{"class":262},[156,835,742],{"class":161},[156,837,838],{"class":165}," attempt) ",[156,840,841],{"class":161},"*",[156,843,844],{"class":262}," 1000",[156,846,375],{"class":165},[156,848,850,852],{"class":158,"line":849},34,[156,851,751],{"class":161},[156,853,272],{"class":165},[156,855,856],{"class":158,"line":30},[156,857,758],{"class":165},[156,859,861],{"class":158,"line":860},36,[156,862,279],{"emptyLinePlaceholder":278},[156,864,866,869,871,873,875,878,881,884,886,889,891],{"class":158,"line":865},37,[156,867,868],{"class":161},"    const",[156,870,350],{"class":262},[156,872,266],{"class":161},[156,874,600],{"class":161},[156,876,877],{"class":165}," res.",[156,879,880],{"class":290},"json",[156,882,883],{"class":165},"().",[156,885,693],{"class":290},[156,887,888],{"class":165},"(() ",[156,890,462],{"class":161},[156,892,893],{"class":165}," ({}));\n",[156,895,897,899,901,904,907,909,911,913],{"class":158,"line":896},38,[156,898,769],{"class":161},[156,900,453],{"class":165},[156,902,903],{"class":161},"!",[156,905,906],{"class":165},"res.ok) ",[156,908,714],{"class":161},[156,910,465],{"class":161},[156,912,291],{"class":290},[156,914,915],{"class":165},"(res.status, body);\n",[156,917,919,922,925],{"class":158,"line":918},39,[156,920,921],{"class":161},"    return",[156,923,924],{"class":165}," body.data; ",[156,926,927],{"class":252},"\u002F\u002F ผลอยู่ใน data เสมอ\n",[156,929,930],{"class":158,"line":35},[156,931,429],{"class":165},[156,933,935],{"class":158,"line":934},41,[156,936,435],{"class":165},[147,938,943],{"className":939,"code":940,"filename":941,"language":942,"meta":152,"style":152},"language-python shiki shiki-themes github-light github-dark","# slipbolt.py — pip install requests\nimport os\nimport time\n\nimport requests\n\nBASE = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\"\n\n\nclass SlipBoltError(Exception):\n    def __init__(self, status: int, body: dict):\n        super().__init__(\n            f\"{status} {body.get('code') or body.get('error') or ''}: {body.get('message') or 'request failed'}\"\n        )\n        self.status = status  # HTTP status เช่น 402\n        self.code = body.get(\"code\")  # เช่น QUOTA_EXCEEDED\n        self.request_id = body.get(\"requestId\")  # แนบมาตอนติดต่อทีมงาน\n\n\ndef verify_slip(image: bytes, api_key: str = \"\", retries: int = 3) -> dict:\n    \"\"\"ตรวจสลิป 1 ใบ — คืนก้อน data · โยน SlipBoltError เมื่อ API ตอบ error\"\"\"\n    api_key = api_key or os.environ[\"SLIPBOLT_API_KEY\"]\n    for attempt in range(retries + 1):\n        last = attempt == retries\n        try:\n            res = requests.post(\n                f\"{BASE}\u002Fverify\",\n                headers={\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application\u002Foctet-stream\"},\n                data=image,\n                timeout=30,\n            )\n        except requests.RequestException:\n            if last:\n                raise  # เน็ตหลุด \u002F timeout ครบจำนวนครั้งแล้ว\n            time.sleep(0.5 * 2**attempt)\n            continue\n\n        if (res.status_code == 429 or res.status_code >= 500) and not last:\n            time.sleep(float(res.headers.get(\"Retry-After\") or 2**attempt))\n            continue\n\n        try:\n            body = res.json()\n        except ValueError:\n            body = {}\n        if not res.ok:\n            raise SlipBoltError(res.status_code, body)\n        return body[\"data\"]  # ผลอยู่ใน data เสมอ\n","Python","python",[142,944,945,950,958,965,969,976,980,989,993,997,1012,1034,1047,1113,1118,1133,1152,1171,1175,1179,1221,1226,1247,1271,1286,1293,1303,1318,1360,1370,1382,1387,1395,1403,1411,1429,1434,1438,1470,1494,1498,1502,1509,1520,1530,1539,1549,1558],{"__ignoreMap":152},[156,946,947],{"class":158,"line":9},[156,948,949],{"class":252},"# slipbolt.py — pip install requests\n",[156,951,952,955],{"class":158,"line":256},[156,953,954],{"class":161},"import",[156,956,957],{"class":165}," os\n",[156,959,960,962],{"class":158,"line":275},[156,961,954],{"class":161},[156,963,964],{"class":165}," time\n",[156,966,967],{"class":158,"line":282},[156,968,279],{"emptyLinePlaceholder":278},[156,970,971,973],{"class":158,"line":303},[156,972,954],{"class":161},[156,974,975],{"class":165}," requests\n",[156,977,978],{"class":158,"line":324},[156,979,279],{"emptyLinePlaceholder":278},[156,981,982,984,986],{"class":158,"line":378},[156,983,610],{"class":262},[156,985,266],{"class":161},[156,987,988],{"class":172}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\"\n",[156,990,991],{"class":158,"line":395},[156,992,279],{"emptyLinePlaceholder":278},[156,994,995],{"class":158,"line":411},[156,996,279],{"emptyLinePlaceholder":278},[156,998,999,1002,1004,1006,1009],{"class":158,"line":13},[156,1000,1001],{"class":161},"class",[156,1003,291],{"class":290},[156,1005,309],{"class":165},[156,1007,1008],{"class":262},"Exception",[156,1010,1011],{"class":165},"):\n",[156,1013,1014,1017,1020,1023,1026,1029,1032],{"class":158,"line":432},[156,1015,1016],{"class":161},"    def",[156,1018,1019],{"class":262}," __init__",[156,1021,1022],{"class":165},"(self, status: ",[156,1024,1025],{"class":262},"int",[156,1027,1028],{"class":165},", body: ",[156,1030,1031],{"class":262},"dict",[156,1033,1011],{"class":165},[156,1035,1036,1039,1041,1044],{"class":158,"line":438},[156,1037,1038],{"class":262},"        super",[156,1040,883],{"class":165},[156,1042,1043],{"class":262},"__init__",[156,1045,1046],{"class":165},"(\n",[156,1048,1049,1052,1055,1058,1060,1063,1066,1069,1072,1074,1077,1080,1083,1085,1087,1090,1092,1094,1096,1098,1101,1103,1105,1108,1110],{"class":158,"line":443},[156,1050,1051],{"class":161},"            f",[156,1053,1054],{"class":172},"\"",[156,1056,1057],{"class":262},"{",[156,1059,224],{"class":165},[156,1061,1062],{"class":262},"}",[156,1064,1065],{"class":262}," {",[156,1067,1068],{"class":165},"body.get(",[156,1070,1071],{"class":172},"'code'",[156,1073,459],{"class":165},[156,1075,1076],{"class":161},"or",[156,1078,1079],{"class":165}," body.get(",[156,1081,1082],{"class":172},"'error'",[156,1084,459],{"class":165},[156,1086,1076],{"class":161},[156,1088,1089],{"class":172}," ''",[156,1091,1062],{"class":262},[156,1093,650],{"class":172},[156,1095,1057],{"class":262},[156,1097,1068],{"class":165},[156,1099,1100],{"class":172},"'message'",[156,1102,459],{"class":165},[156,1104,1076],{"class":161},[156,1106,1107],{"class":172}," 'request failed'",[156,1109,1062],{"class":262},[156,1111,1112],{"class":172},"\"\n",[156,1114,1115],{"class":158,"line":487},[156,1116,1117],{"class":165},"        )\n",[156,1119,1120,1123,1125,1127,1130],{"class":158,"line":492},[156,1121,1122],{"class":262},"        self",[156,1124,384],{"class":165},[156,1126,169],{"class":161},[156,1128,1129],{"class":165}," status  ",[156,1131,1132],{"class":252},"# HTTP status เช่น 402\n",[156,1134,1135,1137,1139,1141,1143,1146,1149],{"class":158,"line":498},[156,1136,1122],{"class":262},[156,1138,400],{"class":165},[156,1140,169],{"class":161},[156,1142,1079],{"class":165},[156,1144,1145],{"class":172},"\"code\"",[156,1147,1148],{"class":165},")  ",[156,1150,1151],{"class":252},"# เช่น QUOTA_EXCEEDED\n",[156,1153,1154,1156,1159,1161,1163,1166,1168],{"class":158,"line":549},[156,1155,1122],{"class":262},[156,1157,1158],{"class":165},".request_id ",[156,1160,169],{"class":161},[156,1162,1079],{"class":165},[156,1164,1165],{"class":172},"\"requestId\"",[156,1167,1148],{"class":165},[156,1169,1170],{"class":252},"# แนบมาตอนติดต่อทีมงาน\n",[156,1172,1173],{"class":158,"line":576},[156,1174,279],{"emptyLinePlaceholder":278},[156,1176,1177],{"class":158,"line":585},[156,1178,279],{"emptyLinePlaceholder":278},[156,1180,1181,1184,1187,1190,1193,1196,1199,1201,1204,1207,1209,1211,1213,1216,1218],{"class":158,"line":18},[156,1182,1183],{"class":161},"def",[156,1185,1186],{"class":290}," verify_slip",[156,1188,1189],{"class":165},"(image: ",[156,1191,1192],{"class":262},"bytes",[156,1194,1195],{"class":165},", api_key: ",[156,1197,1198],{"class":262},"str",[156,1200,266],{"class":161},[156,1202,1203],{"class":172}," \"\"",[156,1205,1206],{"class":165},", retries: ",[156,1208,1025],{"class":262},[156,1210,266],{"class":161},[156,1212,538],{"class":262},[156,1214,1215],{"class":165},") -> ",[156,1217,1031],{"class":262},[156,1219,1220],{"class":165},":\n",[156,1222,1223],{"class":158,"line":619},[156,1224,1225],{"class":172},"    \"\"\"ตรวจสลิป 1 ใบ — คืนก้อน data · โยน SlipBoltError เมื่อ API ตอบ error\"\"\"\n",[156,1227,1228,1231,1233,1236,1238,1241,1244],{"class":158,"line":631},[156,1229,1230],{"class":165},"    api_key ",[156,1232,169],{"class":161},[156,1234,1235],{"class":165}," api_key ",[156,1237,1076],{"class":161},[156,1239,1240],{"class":165}," os.environ[",[156,1242,1243],{"class":172},"\"SLIPBOLT_API_KEY\"",[156,1245,1246],{"class":165},"]\n",[156,1248,1249,1252,1254,1257,1260,1263,1266,1269],{"class":158,"line":659},[156,1250,1251],{"class":161},"    for",[156,1253,560],{"class":165},[156,1255,1256],{"class":161},"in",[156,1258,1259],{"class":262}," range",[156,1261,1262],{"class":165},"(retries ",[156,1264,1265],{"class":161},"+",[156,1267,1268],{"class":262}," 1",[156,1270,1011],{"class":165},[156,1272,1273,1276,1278,1280,1283],{"class":158,"line":665},[156,1274,1275],{"class":165},"        last ",[156,1277,169],{"class":161},[156,1279,560],{"class":165},[156,1281,1282],{"class":161},"==",[156,1284,1285],{"class":165}," retries\n",[156,1287,1288,1291],{"class":158,"line":22},[156,1289,1290],{"class":161},"        try",[156,1292,1220],{"class":165},[156,1294,1295,1298,1300],{"class":158,"line":687},[156,1296,1297],{"class":165},"            res ",[156,1299,169],{"class":161},[156,1301,1302],{"class":165}," requests.post(\n",[156,1304,1305,1308,1310,1313,1316],{"class":158,"line":699},[156,1306,1307],{"class":161},"                f",[156,1309,1054],{"class":172},[156,1311,1312],{"class":262},"{BASE}",[156,1314,1315],{"class":172},"\u002Fverify\"",[156,1317,628],{"class":165},[156,1319,1320,1323,1325,1327,1330,1332,1335,1338,1340,1343,1345,1347,1349,1352,1354,1357],{"class":158,"line":723},[156,1321,1322],{"class":312},"                headers",[156,1324,169],{"class":161},[156,1326,1057],{"class":165},[156,1328,1329],{"class":172},"\"Authorization\"",[156,1331,650],{"class":165},[156,1333,1334],{"class":161},"f",[156,1336,1337],{"class":172},"\"Bearer ",[156,1339,1057],{"class":262},[156,1341,1342],{"class":165},"api_key",[156,1344,1062],{"class":262},[156,1346,1054],{"class":172},[156,1348,315],{"class":165},[156,1350,1351],{"class":172},"\"Content-Type\"",[156,1353,650],{"class":165},[156,1355,1356],{"class":172},"\"application\u002Foctet-stream\"",[156,1358,1359],{"class":165},"},\n",[156,1361,1362,1365,1367],{"class":158,"line":748},[156,1363,1364],{"class":312},"                data",[156,1366,169],{"class":161},[156,1368,1369],{"class":165},"image,\n",[156,1371,1372,1375,1377,1380],{"class":158,"line":26},[156,1373,1374],{"class":312},"                timeout",[156,1376,169],{"class":161},[156,1378,1379],{"class":262},"30",[156,1381,628],{"class":165},[156,1383,1384],{"class":158,"line":761},[156,1385,1386],{"class":165},"            )\n",[156,1388,1389,1392],{"class":158,"line":766},[156,1390,1391],{"class":161},"        except",[156,1393,1394],{"class":165}," requests.RequestException:\n",[156,1396,1397,1400],{"class":158,"line":805},[156,1398,1399],{"class":161},"            if",[156,1401,1402],{"class":165}," last:\n",[156,1404,1405,1408],{"class":158,"line":849},[156,1406,1407],{"class":161},"                raise",[156,1409,1410],{"class":252},"  # เน็ตหลุด \u002F timeout ครบจำนวนครั้งแล้ว\n",[156,1412,1413,1416,1419,1421,1423,1426],{"class":158,"line":30},[156,1414,1415],{"class":165},"            time.sleep(",[156,1417,1418],{"class":262},"0.5",[156,1420,736],{"class":161},[156,1422,739],{"class":262},[156,1424,1425],{"class":161},"**",[156,1427,1428],{"class":165},"attempt)\n",[156,1430,1431],{"class":158,"line":860},[156,1432,1433],{"class":161},"            continue\n",[156,1435,1436],{"class":158,"line":865},[156,1437,279],{"emptyLinePlaceholder":278},[156,1439,1440,1443,1446,1448,1450,1453,1456,1458,1460,1462,1465,1468],{"class":158,"line":896},[156,1441,1442],{"class":161},"        if",[156,1444,1445],{"class":165}," (res.status_code ",[156,1447,1282],{"class":161},[156,1449,778],{"class":262},[156,1451,1452],{"class":161}," or",[156,1454,1455],{"class":165}," res.status_code ",[156,1457,708],{"class":161},[156,1459,789],{"class":262},[156,1461,459],{"class":165},[156,1463,1464],{"class":161},"and",[156,1466,1467],{"class":161}," not",[156,1469,1402],{"class":165},[156,1471,1472,1474,1477,1480,1483,1485,1487,1489,1491],{"class":158,"line":918},[156,1473,1415],{"class":165},[156,1475,1476],{"class":262},"float",[156,1478,1479],{"class":165},"(res.headers.get(",[156,1481,1482],{"class":172},"\"Retry-After\"",[156,1484,459],{"class":165},[156,1486,1076],{"class":161},[156,1488,739],{"class":262},[156,1490,1425],{"class":161},[156,1492,1493],{"class":165},"attempt))\n",[156,1495,1496],{"class":158,"line":35},[156,1497,1433],{"class":161},[156,1499,1500],{"class":158,"line":934},[156,1501,279],{"emptyLinePlaceholder":278},[156,1503,1505,1507],{"class":158,"line":1504},42,[156,1506,1290],{"class":161},[156,1508,1220],{"class":165},[156,1510,1512,1515,1517],{"class":158,"line":1511},43,[156,1513,1514],{"class":165},"            body ",[156,1516,169],{"class":161},[156,1518,1519],{"class":165}," res.json()\n",[156,1521,1523,1525,1528],{"class":158,"line":1522},44,[156,1524,1391],{"class":161},[156,1526,1527],{"class":262}," ValueError",[156,1529,1220],{"class":165},[156,1531,1532,1534,1536],{"class":158,"line":39},[156,1533,1514],{"class":165},[156,1535,169],{"class":161},[156,1537,1538],{"class":165}," {}\n",[156,1540,1542,1544,1546],{"class":158,"line":1541},46,[156,1543,1442],{"class":161},[156,1545,1467],{"class":161},[156,1547,1548],{"class":165}," res.ok:\n",[156,1550,1552,1555],{"class":158,"line":1551},47,[156,1553,1554],{"class":161},"            raise",[156,1556,1557],{"class":165}," SlipBoltError(res.status_code, body)\n",[156,1559,1561,1564,1567,1570,1573],{"class":158,"line":1560},48,[156,1562,1563],{"class":161},"        return",[156,1565,1566],{"class":165}," body[",[156,1568,1569],{"class":172},"\"data\"",[156,1571,1572],{"class":165},"]  ",[156,1574,1575],{"class":252},"# ผลอยู่ใน data เสมอ\n",[147,1577,1582],{"className":1578,"code":1579,"filename":1580,"language":1581,"meta":152,"style":152},"language-php shiki shiki-themes github-light github-dark","\u003C?php\n\u002F\u002F slipbolt.php — PHP 8.1+ · ใช้ ext-curl ไม่ต้องใช้ Composer\n\nclass SlipBoltError extends RuntimeException\n{\n    public function __construct(public int $status, public array $body)\n    {\n        parent::__construct(\n            \"$status \" . ($body['code'] ?? $body['error'] ?? '') . ': ' . ($body['message'] ?? 'request failed')\n        );\n    }\n}\n\n\u002F** ตรวจสลิป 1 ใบ — คืนก้อน data · โยน SlipBoltError เมื่อ API ตอบ error *\u002F\nfunction slipbolt_verify(string $image, int $retries = 3): array\n{\n    for ($attempt = 0; ; $attempt++) {\n        $retryAfter = 0;\n        $ch = curl_init('https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify');\n        curl_setopt_array($ch, [\n            CURLOPT_POST           => true,\n            CURLOPT_HTTPHEADER     => [\n                'Authorization: Bearer ' . getenv('SLIPBOLT_API_KEY'),\n                'Content-Type: application\u002Foctet-stream',\n            ],\n            CURLOPT_POSTFIELDS     => $image,\n            CURLOPT_RETURNTRANSFER => true,\n            CURLOPT_TIMEOUT        => 30,\n            CURLOPT_HEADERFUNCTION => function ($ch, string $line) use (&$retryAfter) {\n                if (stripos($line, 'retry-after:') === 0) {\n                    $retryAfter = (int) trim(substr($line, 12));\n                }\n                return strlen($line);\n            },\n        ]);\n        $raw    = curl_exec($ch);\n        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n\n        \u002F\u002F เน็ตหลุด \u002F timeout \u002F 429 \u002F 5xx → รอแล้วลองใหม่\n        if (($raw === false || $status === 429 || $status >= 500) && $attempt \u003C $retries) {\n            sleep($retryAfter ?: 2 ** $attempt);\n            continue;\n        }\n        if ($raw === false) {\n            throw new RuntimeException('เชื่อมต่อไม่ได้: ' . curl_error($ch));\n        }\n\n        $body = json_decode($raw, true) ?? [];\n        if ($status !== 200) {\n            throw new SlipBoltError($status, $body);\n        }\n        return $body['data']; \u002F\u002F ผลอยู่ใน data เสมอ\n    }\n}\n","PHP","php",[142,1583,1584,1592,1597,1601,1612,1617,1646,1651,1661,1719,1724,1728,1732,1736,1741,1775,1779,1797,1808,1825,1833,1846,1857,1874,1881,1886,1896,1908,1921,1949,1973,2002,2007,2018,2023,2028,2041,2059,2063,2068,2109,2127,2134,2139,2152,2175,2179,2183,2206,2222,2234,2239,2254,2259],{"__ignoreMap":152},[156,1585,1586,1589],{"class":158,"line":9},[156,1587,1588],{"class":161},"\u003C?",[156,1590,1591],{"class":262},"php\n",[156,1593,1594],{"class":158,"line":256},[156,1595,1596],{"class":252},"\u002F\u002F slipbolt.php — PHP 8.1+ · ใช้ ext-curl ไม่ต้องใช้ Composer\n",[156,1598,1599],{"class":158,"line":275},[156,1600,279],{"emptyLinePlaceholder":278},[156,1602,1603,1605,1607,1609],{"class":158,"line":282},[156,1604,1001],{"class":161},[156,1606,291],{"class":290},[156,1608,294],{"class":161},[156,1610,1611],{"class":262}," RuntimeException\n",[156,1613,1614],{"class":158,"line":303},[156,1615,1616],{"class":165},"{\n",[156,1618,1619,1622,1624,1627,1629,1632,1635,1638,1640,1643],{"class":158,"line":324},[156,1620,1621],{"class":161},"    public",[156,1623,506],{"class":161},[156,1625,1626],{"class":262}," __construct",[156,1628,309],{"class":165},[156,1630,1631],{"class":161},"public",[156,1633,1634],{"class":161}," int",[156,1636,1637],{"class":165}," $status, ",[156,1639,1631],{"class":161},[156,1641,1642],{"class":161}," array",[156,1644,1645],{"class":165}," $body)\n",[156,1647,1648],{"class":158,"line":378},[156,1649,1650],{"class":165},"    {\n",[156,1652,1653,1656,1659],{"class":158,"line":395},[156,1654,1655],{"class":161},"        parent::",[156,1657,1658],{"class":290},"__construct",[156,1660,1046],{"class":165},[156,1662,1663,1666,1669,1672,1675,1678,1680,1683,1686,1689,1691,1693,1695,1697,1699,1701,1704,1706,1708,1710,1712,1714,1716],{"class":158,"line":411},[156,1664,1665],{"class":172},"            \"",[156,1667,1668],{"class":165},"$status",[156,1670,1671],{"class":172}," \"",[156,1673,1674],{"class":161}," .",[156,1676,1677],{"class":165}," ($body[",[156,1679,1071],{"class":172},[156,1681,1682],{"class":165},"] ",[156,1684,1685],{"class":161},"??",[156,1687,1688],{"class":165}," $body[",[156,1690,1082],{"class":172},[156,1692,1682],{"class":165},[156,1694,1685],{"class":161},[156,1696,1089],{"class":172},[156,1698,459],{"class":165},[156,1700,342],{"class":161},[156,1702,1703],{"class":172}," ': '",[156,1705,1674],{"class":161},[156,1707,1677],{"class":165},[156,1709,1100],{"class":172},[156,1711,1682],{"class":165},[156,1713,1685],{"class":161},[156,1715,1107],{"class":172},[156,1717,1718],{"class":165},")\n",[156,1720,1721],{"class":158,"line":13},[156,1722,1723],{"class":165},"        );\n",[156,1725,1726],{"class":158,"line":432},[156,1727,758],{"class":165},[156,1729,1730],{"class":158,"line":438},[156,1731,435],{"class":165},[156,1733,1734],{"class":158,"line":443},[156,1735,279],{"emptyLinePlaceholder":278},[156,1737,1738],{"class":158,"line":487},[156,1739,1740],{"class":252},"\u002F** ตรวจสลิป 1 ใบ — คืนก้อน data · โยน SlipBoltError เมื่อ API ตอบ error *\u002F\n",[156,1742,1743,1746,1749,1751,1754,1757,1759,1762,1764,1766,1769,1772],{"class":158,"line":492},[156,1744,1745],{"class":161},"function",[156,1747,1748],{"class":290}," slipbolt_verify",[156,1750,309],{"class":165},[156,1752,1753],{"class":161},"string",[156,1755,1756],{"class":165}," $image, ",[156,1758,1025],{"class":161},[156,1760,1761],{"class":165}," $retries ",[156,1763,169],{"class":161},[156,1765,538],{"class":262},[156,1767,1768],{"class":165},")",[156,1770,1771],{"class":161},":",[156,1773,1774],{"class":161}," array\n",[156,1776,1777],{"class":158,"line":498},[156,1778,1616],{"class":165},[156,1780,1781,1783,1786,1788,1790,1793,1795],{"class":158,"line":549},[156,1782,1251],{"class":161},[156,1784,1785],{"class":165}," ($attempt ",[156,1787,169],{"class":161},[156,1789,565],{"class":262},[156,1791,1792],{"class":165},"; ; $attempt",[156,1794,571],{"class":161},[156,1796,321],{"class":165},[156,1798,1799,1802,1804,1806],{"class":158,"line":576},[156,1800,1801],{"class":165},"        $retryAfter ",[156,1803,169],{"class":161},[156,1805,565],{"class":262},[156,1807,272],{"class":165},[156,1809,1810,1813,1815,1818,1820,1823],{"class":158,"line":585},[156,1811,1812],{"class":165},"        $ch ",[156,1814,169],{"class":161},[156,1816,1817],{"class":262}," curl_init",[156,1819,309],{"class":165},[156,1821,1822],{"class":172},"'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify'",[156,1824,375],{"class":165},[156,1826,1827,1830],{"class":158,"line":18},[156,1828,1829],{"class":262},"        curl_setopt_array",[156,1831,1832],{"class":165},"($ch, [\n",[156,1834,1835,1838,1841,1844],{"class":158,"line":619},[156,1836,1837],{"class":262},"            CURLOPT_POST",[156,1839,1840],{"class":161},"           =>",[156,1842,1843],{"class":262}," true",[156,1845,628],{"class":165},[156,1847,1848,1851,1854],{"class":158,"line":631},[156,1849,1850],{"class":262},"            CURLOPT_HTTPHEADER",[156,1852,1853],{"class":161},"     =>",[156,1855,1856],{"class":165}," [\n",[156,1858,1859,1862,1864,1867,1869,1872],{"class":158,"line":659},[156,1860,1861],{"class":172},"                'Authorization: Bearer '",[156,1863,1674],{"class":161},[156,1865,1866],{"class":262}," getenv",[156,1868,309],{"class":165},[156,1870,1871],{"class":172},"'SLIPBOLT_API_KEY'",[156,1873,679],{"class":165},[156,1875,1876,1879],{"class":158,"line":665},[156,1877,1878],{"class":172},"                'Content-Type: application\u002Foctet-stream'",[156,1880,628],{"class":165},[156,1882,1883],{"class":158,"line":22},[156,1884,1885],{"class":165},"            ],\n",[156,1887,1888,1891,1893],{"class":158,"line":687},[156,1889,1890],{"class":262},"            CURLOPT_POSTFIELDS",[156,1892,1853],{"class":161},[156,1894,1895],{"class":165}," $image,\n",[156,1897,1898,1901,1904,1906],{"class":158,"line":699},[156,1899,1900],{"class":262},"            CURLOPT_RETURNTRANSFER",[156,1902,1903],{"class":161}," =>",[156,1905,1843],{"class":262},[156,1907,628],{"class":165},[156,1909,1910,1913,1916,1919],{"class":158,"line":723},[156,1911,1912],{"class":262},"            CURLOPT_TIMEOUT",[156,1914,1915],{"class":161},"        =>",[156,1917,1918],{"class":262}," 30",[156,1920,628],{"class":165},[156,1922,1923,1926,1928,1930,1933,1935,1938,1941,1943,1946],{"class":158,"line":748},[156,1924,1925],{"class":262},"            CURLOPT_HEADERFUNCTION",[156,1927,1903],{"class":161},[156,1929,506],{"class":161},[156,1931,1932],{"class":165}," ($ch, ",[156,1934,1753],{"class":161},[156,1936,1937],{"class":165}," $line) ",[156,1939,1940],{"class":161},"use",[156,1942,453],{"class":165},[156,1944,1945],{"class":161},"&",[156,1947,1948],{"class":165},"$retryAfter) {\n",[156,1950,1951,1954,1956,1959,1962,1965,1967,1969,1971],{"class":158,"line":26},[156,1952,1953],{"class":161},"                if",[156,1955,453],{"class":165},[156,1957,1958],{"class":262},"stripos",[156,1960,1961],{"class":165},"($line, ",[156,1963,1964],{"class":172},"'retry-after:'",[156,1966,459],{"class":165},[156,1968,775],{"class":161},[156,1970,565],{"class":262},[156,1972,321],{"class":165},[156,1974,1975,1978,1980,1982,1984,1986,1989,1991,1994,1996,1999],{"class":158,"line":761},[156,1976,1977],{"class":165},"                    $retryAfter ",[156,1979,169],{"class":161},[156,1981,453],{"class":165},[156,1983,1025],{"class":161},[156,1985,459],{"class":165},[156,1987,1988],{"class":262},"trim",[156,1990,309],{"class":165},[156,1992,1993],{"class":262},"substr",[156,1995,1961],{"class":165},[156,1997,1998],{"class":262},"12",[156,2000,2001],{"class":165},"));\n",[156,2003,2004],{"class":158,"line":766},[156,2005,2006],{"class":165},"                }\n",[156,2008,2009,2012,2015],{"class":158,"line":805},[156,2010,2011],{"class":161},"                return",[156,2013,2014],{"class":262}," strlen",[156,2016,2017],{"class":165},"($line);\n",[156,2019,2020],{"class":158,"line":849},[156,2021,2022],{"class":165},"            },\n",[156,2024,2025],{"class":158,"line":30},[156,2026,2027],{"class":165},"        ]);\n",[156,2029,2030,2033,2035,2038],{"class":158,"line":860},[156,2031,2032],{"class":165},"        $raw    ",[156,2034,169],{"class":161},[156,2036,2037],{"class":262}," curl_exec",[156,2039,2040],{"class":165},"($ch);\n",[156,2042,2043,2046,2048,2051,2054,2057],{"class":158,"line":865},[156,2044,2045],{"class":165},"        $status ",[156,2047,169],{"class":161},[156,2049,2050],{"class":262}," curl_getinfo",[156,2052,2053],{"class":165},"($ch, ",[156,2055,2056],{"class":262},"CURLINFO_HTTP_CODE",[156,2058,375],{"class":165},[156,2060,2061],{"class":158,"line":896},[156,2062,279],{"emptyLinePlaceholder":278},[156,2064,2065],{"class":158,"line":918},[156,2066,2067],{"class":252},"        \u002F\u002F เน็ตหลุด \u002F timeout \u002F 429 \u002F 5xx → รอแล้วลองใหม่\n",[156,2069,2070,2072,2075,2077,2080,2082,2085,2087,2089,2091,2093,2095,2097,2099,2101,2104,2106],{"class":158,"line":35},[156,2071,1442],{"class":161},[156,2073,2074],{"class":165}," (($raw ",[156,2076,775],{"class":161},[156,2078,2079],{"class":262}," false",[156,2081,781],{"class":161},[156,2083,2084],{"class":165}," $status ",[156,2086,775],{"class":161},[156,2088,778],{"class":262},[156,2090,781],{"class":161},[156,2092,2084],{"class":165},[156,2094,708],{"class":161},[156,2096,789],{"class":262},[156,2098,459],{"class":165},[156,2100,794],{"class":161},[156,2102,2103],{"class":165}," $attempt ",[156,2105,799],{"class":161},[156,2107,2108],{"class":165}," $retries) {\n",[156,2110,2111,2114,2117,2120,2122,2124],{"class":158,"line":934},[156,2112,2113],{"class":262},"            sleep",[156,2115,2116],{"class":165},"($retryAfter ",[156,2118,2119],{"class":161},"?:",[156,2121,739],{"class":262},[156,2123,742],{"class":161},[156,2125,2126],{"class":165}," $attempt);\n",[156,2128,2129,2132],{"class":158,"line":1504},[156,2130,2131],{"class":161},"            continue",[156,2133,272],{"class":165},[156,2135,2136],{"class":158,"line":1511},[156,2137,2138],{"class":165},"        }\n",[156,2140,2141,2143,2146,2148,2150],{"class":158,"line":1522},[156,2142,1442],{"class":161},[156,2144,2145],{"class":165}," ($raw ",[156,2147,775],{"class":161},[156,2149,2079],{"class":262},[156,2151,321],{"class":165},[156,2153,2154,2157,2159,2162,2164,2167,2169,2172],{"class":158,"line":39},[156,2155,2156],{"class":161},"            throw",[156,2158,465],{"class":161},[156,2160,2161],{"class":262}," RuntimeException",[156,2163,309],{"class":165},[156,2165,2166],{"class":172},"'เชื่อมต่อไม่ได้: '",[156,2168,1674],{"class":161},[156,2170,2171],{"class":262}," curl_error",[156,2173,2174],{"class":165},"($ch));\n",[156,2176,2177],{"class":158,"line":1541},[156,2178,2138],{"class":165},[156,2180,2181],{"class":158,"line":1551},[156,2182,279],{"emptyLinePlaceholder":278},[156,2184,2185,2188,2190,2193,2196,2199,2201,2203],{"class":158,"line":1560},[156,2186,2187],{"class":165},"        $body ",[156,2189,169],{"class":161},[156,2191,2192],{"class":262}," json_decode",[156,2194,2195],{"class":165},"($raw, ",[156,2197,2198],{"class":262},"true",[156,2200,459],{"class":165},[156,2202,1685],{"class":161},[156,2204,2205],{"class":165}," [];\n",[156,2207,2209,2211,2214,2217,2220],{"class":158,"line":2208},49,[156,2210,1442],{"class":161},[156,2212,2213],{"class":165}," ($status ",[156,2215,2216],{"class":161},"!==",[156,2218,2219],{"class":262}," 200",[156,2221,321],{"class":165},[156,2223,2225,2227,2229,2231],{"class":158,"line":2224},50,[156,2226,2156],{"class":161},[156,2228,465],{"class":161},[156,2230,291],{"class":262},[156,2232,2233],{"class":165},"($status, $body);\n",[156,2235,2237],{"class":158,"line":2236},51,[156,2238,2138],{"class":165},[156,2240,2242,2244,2246,2249,2252],{"class":158,"line":2241},52,[156,2243,1563],{"class":161},[156,2245,1688],{"class":165},[156,2247,2248],{"class":172},"'data'",[156,2250,2251],{"class":165},"]; ",[156,2253,927],{"class":252},[156,2255,2257],{"class":158,"line":2256},53,[156,2258,758],{"class":165},[156,2260,2262],{"class":158,"line":2261},54,[156,2263,435],{"class":165},[65,2265,2266],{},"เรียกใช้:",[238,2268,2269,2346,2428],{},[147,2270,2272],{"className":242,"code":2271,"filename":244,"language":245,"meta":152,"style":152},"import { readFile } from 'node:fs\u002Fpromises';\nimport { verifySlip } from '.\u002Fslipbolt.js';\n\nconst slip = await verifySlip(await readFile('slip.jpg'));\nconsole.log(slip.status, slip.amount, slip.transRef);\n",[142,2273,2274,2289,2303,2307,2335],{"__ignoreMap":152},[156,2275,2276,2278,2281,2284,2287],{"class":158,"line":9},[156,2277,954],{"class":161},[156,2279,2280],{"class":165}," { readFile } ",[156,2282,2283],{"class":161},"from",[156,2285,2286],{"class":172}," 'node:fs\u002Fpromises'",[156,2288,272],{"class":165},[156,2290,2291,2293,2296,2298,2301],{"class":158,"line":256},[156,2292,954],{"class":161},[156,2294,2295],{"class":165}," { verifySlip } ",[156,2297,2283],{"class":161},[156,2299,2300],{"class":172}," '.\u002Fslipbolt.js'",[156,2302,272],{"class":165},[156,2304,2305],{"class":158,"line":275},[156,2306,279],{"emptyLinePlaceholder":278},[156,2308,2309,2311,2314,2316,2318,2320,2322,2325,2328,2330,2333],{"class":158,"line":282},[156,2310,259],{"class":161},[156,2312,2313],{"class":262}," slip",[156,2315,266],{"class":161},[156,2317,600],{"class":161},[156,2319,509],{"class":290},[156,2321,309],{"class":165},[156,2323,2324],{"class":161},"await",[156,2326,2327],{"class":290}," readFile",[156,2329,309],{"class":165},[156,2331,2332],{"class":172},"'slip.jpg'",[156,2334,2001],{"class":165},[156,2336,2337,2340,2343],{"class":158,"line":303},[156,2338,2339],{"class":165},"console.",[156,2341,2342],{"class":290},"log",[156,2344,2345],{"class":165},"(slip.status, slip.amount, slip.transRef);\n",[147,2347,2349],{"className":939,"code":2348,"filename":941,"language":942,"meta":152,"style":152},"from slipbolt import verify_slip\n\nwith open(\"slip.jpg\", \"rb\") as f:\n    slip = verify_slip(f.read())\nprint(slip[\"status\"], slip[\"amount\"], slip[\"transRef\"])\n",[142,2350,2351,2363,2367,2393,2403],{"__ignoreMap":152},[156,2352,2353,2355,2358,2360],{"class":158,"line":9},[156,2354,2283],{"class":161},[156,2356,2357],{"class":165}," slipbolt ",[156,2359,954],{"class":161},[156,2361,2362],{"class":165}," verify_slip\n",[156,2364,2365],{"class":158,"line":256},[156,2366,279],{"emptyLinePlaceholder":278},[156,2368,2369,2372,2375,2377,2380,2382,2385,2387,2390],{"class":158,"line":275},[156,2370,2371],{"class":161},"with",[156,2373,2374],{"class":262}," open",[156,2376,309],{"class":165},[156,2378,2379],{"class":172},"\"slip.jpg\"",[156,2381,315],{"class":165},[156,2383,2384],{"class":172},"\"rb\"",[156,2386,459],{"class":165},[156,2388,2389],{"class":161},"as",[156,2391,2392],{"class":165}," f:\n",[156,2394,2395,2398,2400],{"class":158,"line":282},[156,2396,2397],{"class":165},"    slip ",[156,2399,169],{"class":161},[156,2401,2402],{"class":165}," verify_slip(f.read())\n",[156,2404,2405,2408,2411,2414,2417,2420,2422,2425],{"class":158,"line":303},[156,2406,2407],{"class":262},"print",[156,2409,2410],{"class":165},"(slip[",[156,2412,2413],{"class":172},"\"status\"",[156,2415,2416],{"class":165},"], slip[",[156,2418,2419],{"class":172},"\"amount\"",[156,2421,2416],{"class":165},[156,2423,2424],{"class":172},"\"transRef\"",[156,2426,2427],{"class":165},"])\n",[147,2429,2431],{"className":1578,"code":2430,"filename":1580,"language":1581,"meta":152,"style":152},"\u003C?php\nrequire __DIR__ . '\u002Fslipbolt.php';\n\n$slip = slipbolt_verify(file_get_contents('slip.jpg'));\necho $slip['status'], ' ', $slip['amount'], ' ', $slip['transRef'], \"\\n\";\n",[142,2432,2433,2439,2454,2458,2478],{"__ignoreMap":152},[156,2434,2435,2437],{"class":158,"line":9},[156,2436,1588],{"class":161},[156,2438,1591],{"class":262},[156,2440,2441,2444,2447,2449,2452],{"class":158,"line":256},[156,2442,2443],{"class":161},"require",[156,2445,2446],{"class":262}," __DIR__",[156,2448,1674],{"class":161},[156,2450,2451],{"class":172}," '\u002Fslipbolt.php'",[156,2453,272],{"class":165},[156,2455,2456],{"class":158,"line":275},[156,2457,279],{"emptyLinePlaceholder":278},[156,2459,2460,2463,2465,2467,2469,2472,2474,2476],{"class":158,"line":282},[156,2461,2462],{"class":165},"$slip ",[156,2464,169],{"class":161},[156,2466,1748],{"class":290},[156,2468,309],{"class":165},[156,2470,2471],{"class":262},"file_get_contents",[156,2473,309],{"class":165},[156,2475,2332],{"class":172},[156,2477,2001],{"class":165},[156,2479,2480,2483,2486,2489,2492,2495,2498,2501,2503,2505,2507,2510,2512,2514,2517,2519],{"class":158,"line":303},[156,2481,2482],{"class":262},"echo",[156,2484,2485],{"class":165}," $slip[",[156,2487,2488],{"class":172},"'status'",[156,2490,2491],{"class":165},"], ",[156,2493,2494],{"class":172},"' '",[156,2496,2497],{"class":165},", $slip[",[156,2499,2500],{"class":172},"'amount'",[156,2502,2491],{"class":165},[156,2504,2494],{"class":172},[156,2506,2497],{"class":165},[156,2508,2509],{"class":172},"'transRef'",[156,2511,2491],{"class":165},[156,2513,1054],{"class":172},[156,2515,2516],{"class":262},"\\n",[156,2518,1054],{"class":172},[156,2520,272],{"class":165},[175,2522,115],{"id":2523},"_2-รับสลิปแล้วปิดออเดอร์",[65,2525,2526],{},"โจทย์ที่เจอบ่อยที่สุด: ลูกค้าอัปโหลดสลิปในหน้าชำระเงิน → เซิร์ฟเวอร์คุณตรวจ → ปิดออเดอร์อัตโนมัติ",[2528,2529,2531],"callout",{"type":2530},"warning",[65,2532,2533,2536],{},[69,2534,2535],{},"เรียก SlipBolt จากเซิร์ฟเวอร์ของคุณเท่านั้น"," — ห้ามยิงจาก JavaScript ในเบราว์เซอร์หรือแอปมือถือโดยตรง\nเพราะ API key จะหลุดไปกับโค้ดฝั่งลูกค้า · เบราว์เซอร์ส่งรูปให้เซิร์ฟเวอร์คุณ แล้วเซิร์ฟเวอร์คุณค่อยส่งต่อ",[2538,2539,2541],"h3",{"id":2540},"ปล่อยของได้เมื่อผ่านครบ-4-ข้อ","ปล่อยของได้เมื่อผ่านครบ 4 ข้อ",[74,2543,2544,2557],{},[77,2545,2546],{},[80,2547,2548,2551,2554],{},[83,2549,2550],{},"#",[83,2552,2553],{},"เช็ค",[83,2555,2556],{},"ถ้าข้าม",[90,2558,2559,2572,2585,2599],{},[80,2560,2561,2564,2569],{},[95,2562,2563],{},"1",[95,2565,2566],{},[142,2567,2568],{},"verified === true",[95,2570,2571],{},"รับสลิปปลอม \u002F สลิปที่โอนเข้าบัญชีคนอื่น",[80,2573,2574,2577,2582],{},[95,2575,2576],{},"2",[95,2578,2579],{},[142,2580,2581],{},"duplicate === false",[95,2583,2584],{},"ลูกค้าส่งสลิปเก่าที่เคยใช้แล้วมาอีกรอบ",[80,2586,2587,2590,2596],{},[95,2588,2589],{},"3",[95,2591,2592,2595],{},[142,2593,2594],{},"amount"," ตรงกับยอดออเดอร์",[95,2597,2598],{},"ลูกค้าโอน 1 บาทแล้วส่งสลิปมา — สลิปก็ยัง \"จริง\"",[80,2600,2601,2604,2613],{},[95,2602,2603],{},"4",[95,2605,2606,2609,2610],{},[142,2607,2608],{},"transRef"," ยังไม่เคยผูกกับออเดอร์อื่น ",[69,2611,2612],{},"ในระบบคุณ",[95,2614,2615],{},"สลิปใบเดียวปิดได้สองออเดอร์",[2528,2617,2618],{"type":2530},[65,2619,2620,2623,2624,2626,2627,2626,2630,2633,2634],{},[69,2621,2622],{},"ข้อ 4 ข้ามไม่ได้"," — ส่งรูปเดิมซ้ำภายใน 24 ชม. ระบบคืนผลเดิม (",[142,2625,215],{}," · ",[142,2628,2629],{},"verified: true",[142,2631,2632],{},"duplicate: false",")\nเพื่อให้ retry ได้ปลอดภัย ⇒ ถ้าลูกค้าเอารูปเดียวกันไปอัปโหลดกับอีกออเดอร์ ข้อ 1–3 จะผ่านหมด\nตัวกันจริงคือ ",[69,2635,2636,2637,2639],{},"คอลัมน์ ",[142,2638,2608],{}," ที่ติด UNIQUE ในตารางออเดอร์ของคุณ",[2538,2641,2643],{"id":2642},"หน้าเว็บ-ฝั่งลูกค้า","หน้าเว็บ (ฝั่งลูกค้า)",[65,2645,2646,2647,2650],{},"ส่งไฟล์เป็น body ตรง ๆ ไม่ต้องใช้ ",[142,2648,2649],{},"FormData"," — ใช้ได้กับเซิร์ฟเวอร์ทั้งสามภาษาด้านล่าง",[147,2652,2656],{"className":2653,"code":2654,"language":2655,"meta":152,"style":152},"language-html shiki shiki-themes github-light github-dark","\u003Cinput type=\"file\" id=\"slip\" accept=\"image\u002F*\">\n\u003Cp id=\"result\">\u003C\u002Fp>\n\n\u003Cscript>\n  document.getElementById('slip').addEventListener('change', async (e) => {\n    const file = e.target.files[0];\n    if (!file) return;\n\n    \u002F\u002F PHP ใช้ '\u002Fpay.php?order=1001' แทน\n    const res = await fetch('\u002Forders\u002F1001\u002Fslip', {\n      method: 'POST',\n      headers: { 'Content-Type': file.type },\n      body: file,\n    });\n    const out = await res.json();\n    document.getElementById('result').textContent = out.message;\n  });\n\u003C\u002Fscript>\n","html",[142,2657,2658,2693,2713,2717,2726,2766,2784,2800,2804,2809,2829,2838,2848,2853,2858,2876,2896,2901],{"__ignoreMap":152},[156,2659,2660,2662,2666,2669,2671,2674,2677,2679,2682,2685,2687,2690],{"class":158,"line":9},[156,2661,799],{"class":165},[156,2663,2665],{"class":2664},"s9eBZ","input",[156,2667,2668],{"class":290}," type",[156,2670,169],{"class":165},[156,2672,2673],{"class":172},"\"file\"",[156,2675,2676],{"class":290}," id",[156,2678,169],{"class":165},[156,2680,2681],{"class":172},"\"slip\"",[156,2683,2684],{"class":290}," accept",[156,2686,169],{"class":165},[156,2688,2689],{"class":172},"\"image\u002F*\"",[156,2691,2692],{"class":165},">\n",[156,2694,2695,2697,2699,2701,2703,2706,2709,2711],{"class":158,"line":256},[156,2696,799],{"class":165},[156,2698,65],{"class":2664},[156,2700,2676],{"class":290},[156,2702,169],{"class":165},[156,2704,2705],{"class":172},"\"result\"",[156,2707,2708],{"class":165},">\u003C\u002F",[156,2710,65],{"class":2664},[156,2712,2692],{"class":165},[156,2714,2715],{"class":158,"line":275},[156,2716,279],{"emptyLinePlaceholder":278},[156,2718,2719,2721,2724],{"class":158,"line":282},[156,2720,799],{"class":165},[156,2722,2723],{"class":2664},"script",[156,2725,2692],{"class":165},[156,2727,2728,2731,2734,2736,2739,2742,2745,2747,2750,2752,2755,2757,2760,2762,2764],{"class":158,"line":303},[156,2729,2730],{"class":165},"  document.",[156,2732,2733],{"class":290},"getElementById",[156,2735,309],{"class":165},[156,2737,2738],{"class":172},"'slip'",[156,2740,2741],{"class":165},").",[156,2743,2744],{"class":290},"addEventListener",[156,2746,309],{"class":165},[156,2748,2749],{"class":172},"'change'",[156,2751,315],{"class":165},[156,2753,2754],{"class":161},"async",[156,2756,453],{"class":165},[156,2758,2759],{"class":312},"e",[156,2761,459],{"class":165},[156,2763,462],{"class":161},[156,2765,300],{"class":165},[156,2767,2768,2770,2773,2775,2778,2781],{"class":158,"line":324},[156,2769,868],{"class":161},[156,2771,2772],{"class":262}," file",[156,2774,266],{"class":161},[156,2776,2777],{"class":165}," e.target.files[",[156,2779,2780],{"class":262},"0",[156,2782,2783],{"class":165},"];\n",[156,2785,2786,2788,2790,2792,2795,2798],{"class":158,"line":378},[156,2787,769],{"class":161},[156,2789,453],{"class":165},[156,2791,903],{"class":161},[156,2793,2794],{"class":165},"file) ",[156,2796,2797],{"class":161},"return",[156,2799,272],{"class":165},[156,2801,2802],{"class":158,"line":395},[156,2803,279],{"emptyLinePlaceholder":278},[156,2805,2806],{"class":158,"line":411},[156,2807,2808],{"class":252},"    \u002F\u002F PHP ใช้ '\u002Fpay.php?order=1001' แทน\n",[156,2810,2811,2813,2816,2818,2820,2822,2824,2827],{"class":158,"line":13},[156,2812,868],{"class":161},[156,2814,2815],{"class":262}," res",[156,2817,266],{"class":161},[156,2819,600],{"class":161},[156,2821,603],{"class":290},[156,2823,309],{"class":165},[156,2825,2826],{"class":172},"'\u002Forders\u002F1001\u002Fslip'",[156,2828,616],{"class":165},[156,2830,2831,2834,2836],{"class":158,"line":432},[156,2832,2833],{"class":165},"      method: ",[156,2835,625],{"class":172},[156,2837,628],{"class":165},[156,2839,2840,2843,2845],{"class":158,"line":438},[156,2841,2842],{"class":165},"      headers: { ",[156,2844,647],{"class":172},[156,2846,2847],{"class":165},": file.type },\n",[156,2849,2850],{"class":158,"line":443},[156,2851,2852],{"class":165},"      body: file,\n",[156,2854,2855],{"class":158,"line":487},[156,2856,2857],{"class":165},"    });\n",[156,2859,2860,2862,2865,2867,2869,2871,2873],{"class":158,"line":492},[156,2861,868],{"class":161},[156,2863,2864],{"class":262}," out",[156,2866,266],{"class":161},[156,2868,600],{"class":161},[156,2870,877],{"class":165},[156,2872,880],{"class":290},[156,2874,2875],{"class":165},"();\n",[156,2877,2878,2881,2883,2885,2888,2891,2893],{"class":158,"line":498},[156,2879,2880],{"class":165},"    document.",[156,2882,2733],{"class":290},[156,2884,309],{"class":165},[156,2886,2887],{"class":172},"'result'",[156,2889,2890],{"class":165},").textContent ",[156,2892,169],{"class":161},[156,2894,2895],{"class":165}," out.message;\n",[156,2897,2898],{"class":158,"line":549},[156,2899,2900],{"class":165},"  });\n",[156,2902,2903,2906,2908],{"class":158,"line":576},[156,2904,2905],{"class":165},"\u003C\u002F",[156,2907,2723],{"class":2664},[156,2909,2692],{"class":165},[2538,2911,2912],{"id":2912},"เซิร์ฟเวอร์",[65,2914,2915,2916,2919],{},"ใช้ไฟล์ไคลเอนต์จาก",[101,2917,2918],{"href":103},"ข้อ 1"," · ตัวอย่าง Node.js \u002F Python เก็บออเดอร์ในหน่วยความจำให้รันได้ทันที —\nของจริงเปลี่ยนเป็นตารางในฐานข้อมูลของคุณ (ตัวอย่าง PHP ใช้ PDO ให้ดูเป็นแนว)",[238,2921,2922,3701,4474],{},[147,2923,2926],{"className":242,"code":2924,"filename":2925,"language":245,"meta":152,"style":152},"\u002F\u002F server.js — npm install express\nimport express from 'express';\nimport { verifySlip } from '.\u002Fslipbolt.js';\n\nconst app = express();\n\n\u002F\u002F ของจริง = ตารางในฐานข้อมูล · usedRefs = คอลัมน์ transRef ที่ติด UNIQUE\nconst orders = new Map([['1001', { total: 250, paid: false }]]);\nconst usedRefs = new Set();\n\n\u002F\u002F ข้อความที่บอกลูกค้าเมื่อสลิปไม่ผ่าน\nconst REJECT = {\n  DUPLICATE: 'สลิปนี้ถูกใช้ไปแล้ว',\n  FRAUD: 'สลิปไม่ถูกต้อง กรุณาติดต่อร้าน',\n  RECEIVER_MISMATCH: 'สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน',\n  INVALID: 'อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ',\n  PROVIDER_ERROR: 'ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง',\n};\n\napp.post('\u002Forders\u002F:id\u002Fslip', express.raw({ type: 'image\u002F*', limit: '5mb' }), async (req, res) => {\n  const order = orders.get(req.params.id);\n  if (!order) return res.status(404).json({ ok: false, message: 'ไม่พบออเดอร์' });\n  if (order.paid) return res.json({ ok: true, message: 'ออเดอร์นี้ชำระแล้ว' });\n  if (!Buffer.isBuffer(req.body) || req.body.length === 0) {\n    return res.status(400).json({ ok: false, message: 'กรุณาแนบรูปสลิป' });\n  }\n\n  let slip;\n  try {\n    slip = await verifySlip(req.body);\n  } catch (err) {\n    console.error('SlipBolt:', err); \u002F\u002F 402 = โควตาร้านหมด · 401\u002F403 = คีย์หรือแพ็ก → แจ้งเตือนทีมคุณ\n    return res.status(503).json({ ok: false, message: 'ตรวจสลิปอัตโนมัติไม่ได้ชั่วคราว ลองใหม่หรือติดต่อร้าน' });\n  }\n\n  \u002F\u002F 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\n  if (!slip.verified || slip.duplicate) {\n    return res.status(422).json({ ok: false, message: REJECT[slip.status] ?? 'สลิปไม่ผ่านการตรวจ' });\n  }\n  \u002F\u002F 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\n  if (Math.abs(slip.amount - order.total) > 0.001) {\n    return res.status(422).json({\n      ok: false,\n      message: `ยอดโอน ${slip.amount} บาท ไม่ตรงกับยอดออเดอร์ ${order.total} บาท`,\n    });\n  }\n  \u002F\u002F 4) สลิปใบเดียวปิดได้ออเดอร์เดียว\n  if (usedRefs.has(slip.transRef)) {\n    return res.status(422).json({ ok: false, message: 'สลิปนี้ถูกใช้กับออเดอร์อื่นแล้ว' });\n  }\n\n  usedRefs.add(slip.transRef);\n  order.paid = true;\n  order.transRef = slip.transRef;\n  res.json({ ok: true, message: 'ชำระเงินเรียบร้อย ขอบคุณค่ะ', transRef: slip.transRef });\n});\n\napp.listen(3000);\n","Node.js (Express)",[142,2927,2928,2933,2947,2959,2963,2977,2981,2986,3021,3037,3041,3046,3057,3067,3077,3087,3097,3107,3112,3116,3168,3186,3227,3251,3283,3311,3315,3319,3327,3334,3347,3356,3374,3402,3406,3410,3415,3431,3467,3471,3476,3503,3522,3531,3562,3566,3570,3575,3588,3615,3619,3623,3634,3645,3655,3675,3681,3686],{"__ignoreMap":152},[156,2929,2930],{"class":158,"line":9},[156,2931,2932],{"class":252},"\u002F\u002F server.js — npm install express\n",[156,2934,2935,2937,2940,2942,2945],{"class":158,"line":256},[156,2936,954],{"class":161},[156,2938,2939],{"class":165}," express ",[156,2941,2283],{"class":161},[156,2943,2944],{"class":172}," 'express'",[156,2946,272],{"class":165},[156,2948,2949,2951,2953,2955,2957],{"class":158,"line":275},[156,2950,954],{"class":161},[156,2952,2295],{"class":165},[156,2954,2283],{"class":161},[156,2956,2300],{"class":172},[156,2958,272],{"class":165},[156,2960,2961],{"class":158,"line":282},[156,2962,279],{"emptyLinePlaceholder":278},[156,2964,2965,2967,2970,2972,2975],{"class":158,"line":303},[156,2966,259],{"class":161},[156,2968,2969],{"class":262}," app",[156,2971,266],{"class":161},[156,2973,2974],{"class":290}," express",[156,2976,2875],{"class":165},[156,2978,2979],{"class":158,"line":324},[156,2980,279],{"emptyLinePlaceholder":278},[156,2982,2983],{"class":158,"line":378},[156,2984,2985],{"class":252},"\u002F\u002F ของจริง = ตารางในฐานข้อมูล · usedRefs = คอลัมน์ transRef ที่ติด UNIQUE\n",[156,2987,2988,2990,2993,2995,2997,3000,3003,3006,3009,3012,3015,3018],{"class":158,"line":395},[156,2989,259],{"class":161},[156,2991,2992],{"class":262}," orders",[156,2994,266],{"class":161},[156,2996,465],{"class":161},[156,2998,2999],{"class":290}," Map",[156,3001,3002],{"class":165},"([[",[156,3004,3005],{"class":172},"'1001'",[156,3007,3008],{"class":165},", { total: ",[156,3010,3011],{"class":262},"250",[156,3013,3014],{"class":165},", paid: ",[156,3016,3017],{"class":262},"false",[156,3019,3020],{"class":165}," }]]);\n",[156,3022,3023,3025,3028,3030,3032,3035],{"class":158,"line":411},[156,3024,259],{"class":161},[156,3026,3027],{"class":262}," usedRefs",[156,3029,266],{"class":161},[156,3031,465],{"class":161},[156,3033,3034],{"class":290}," Set",[156,3036,2875],{"class":165},[156,3038,3039],{"class":158,"line":13},[156,3040,279],{"emptyLinePlaceholder":278},[156,3042,3043],{"class":158,"line":432},[156,3044,3045],{"class":252},"\u002F\u002F ข้อความที่บอกลูกค้าเมื่อสลิปไม่ผ่าน\n",[156,3047,3048,3050,3053,3055],{"class":158,"line":438},[156,3049,259],{"class":161},[156,3051,3052],{"class":262}," REJECT",[156,3054,266],{"class":161},[156,3056,300],{"class":165},[156,3058,3059,3062,3065],{"class":158,"line":443},[156,3060,3061],{"class":165},"  DUPLICATE: ",[156,3063,3064],{"class":172},"'สลิปนี้ถูกใช้ไปแล้ว'",[156,3066,628],{"class":165},[156,3068,3069,3072,3075],{"class":158,"line":487},[156,3070,3071],{"class":165},"  FRAUD: ",[156,3073,3074],{"class":172},"'สลิปไม่ถูกต้อง กรุณาติดต่อร้าน'",[156,3076,628],{"class":165},[156,3078,3079,3082,3085],{"class":158,"line":492},[156,3080,3081],{"class":165},"  RECEIVER_MISMATCH: ",[156,3083,3084],{"class":172},"'สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน'",[156,3086,628],{"class":165},[156,3088,3089,3092,3095],{"class":158,"line":498},[156,3090,3091],{"class":165},"  INVALID: ",[156,3093,3094],{"class":172},"'อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ'",[156,3096,628],{"class":165},[156,3098,3099,3102,3105],{"class":158,"line":549},[156,3100,3101],{"class":165},"  PROVIDER_ERROR: ",[156,3103,3104],{"class":172},"'ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง'",[156,3106,628],{"class":165},[156,3108,3109],{"class":158,"line":576},[156,3110,3111],{"class":165},"};\n",[156,3113,3114],{"class":158,"line":585},[156,3115,279],{"emptyLinePlaceholder":278},[156,3117,3118,3121,3124,3126,3129,3132,3135,3138,3141,3144,3147,3150,3152,3154,3157,3159,3162,3164,3166],{"class":158,"line":18},[156,3119,3120],{"class":165},"app.",[156,3122,3123],{"class":290},"post",[156,3125,309],{"class":165},[156,3127,3128],{"class":172},"'\u002Forders\u002F:id\u002Fslip'",[156,3130,3131],{"class":165},", express.",[156,3133,3134],{"class":290},"raw",[156,3136,3137],{"class":165},"({ type: ",[156,3139,3140],{"class":172},"'image\u002F*'",[156,3142,3143],{"class":165},", limit: ",[156,3145,3146],{"class":172},"'5mb'",[156,3148,3149],{"class":165}," }), ",[156,3151,2754],{"class":161},[156,3153,453],{"class":165},[156,3155,3156],{"class":312},"req",[156,3158,315],{"class":165},[156,3160,3161],{"class":312},"res",[156,3163,459],{"class":165},[156,3165,462],{"class":161},[156,3167,300],{"class":165},[156,3169,3170,3173,3176,3178,3181,3183],{"class":158,"line":619},[156,3171,3172],{"class":161},"  const",[156,3174,3175],{"class":262}," order",[156,3177,266],{"class":161},[156,3179,3180],{"class":165}," orders.",[156,3182,820],{"class":290},[156,3184,3185],{"class":165},"(req.params.id);\n",[156,3187,3188,3191,3193,3195,3198,3200,3202,3204,3206,3209,3211,3213,3216,3218,3221,3224],{"class":158,"line":631},[156,3189,3190],{"class":161},"  if",[156,3192,453],{"class":165},[156,3194,903],{"class":161},[156,3196,3197],{"class":165},"order) ",[156,3199,2797],{"class":161},[156,3201,877],{"class":165},[156,3203,224],{"class":290},[156,3205,309],{"class":165},[156,3207,3208],{"class":262},"404",[156,3210,2741],{"class":165},[156,3212,880],{"class":290},[156,3214,3215],{"class":165},"({ ok: ",[156,3217,3017],{"class":262},[156,3219,3220],{"class":165},", message: ",[156,3222,3223],{"class":172},"'ไม่พบออเดอร์'",[156,3225,3226],{"class":165}," });\n",[156,3228,3229,3231,3234,3236,3238,3240,3242,3244,3246,3249],{"class":158,"line":659},[156,3230,3190],{"class":161},[156,3232,3233],{"class":165}," (order.paid) ",[156,3235,2797],{"class":161},[156,3237,877],{"class":165},[156,3239,880],{"class":290},[156,3241,3215],{"class":165},[156,3243,2198],{"class":262},[156,3245,3220],{"class":165},[156,3247,3248],{"class":172},"'ออเดอร์นี้ชำระแล้ว'",[156,3250,3226],{"class":165},[156,3252,3253,3255,3257,3259,3262,3265,3268,3270,3273,3276,3279,3281],{"class":158,"line":665},[156,3254,3190],{"class":161},[156,3256,453],{"class":165},[156,3258,903],{"class":161},[156,3260,3261],{"class":165},"Buffer.",[156,3263,3264],{"class":290},"isBuffer",[156,3266,3267],{"class":165},"(req.body) ",[156,3269,831],{"class":161},[156,3271,3272],{"class":165}," req.body.",[156,3274,3275],{"class":262},"length",[156,3277,3278],{"class":161}," ===",[156,3280,565],{"class":262},[156,3282,321],{"class":165},[156,3284,3285,3287,3289,3291,3293,3296,3298,3300,3302,3304,3306,3309],{"class":158,"line":22},[156,3286,921],{"class":161},[156,3288,877],{"class":165},[156,3290,224],{"class":290},[156,3292,309],{"class":165},[156,3294,3295],{"class":262},"400",[156,3297,2741],{"class":165},[156,3299,880],{"class":290},[156,3301,3215],{"class":165},[156,3303,3017],{"class":262},[156,3305,3220],{"class":165},[156,3307,3308],{"class":172},"'กรุณาแนบรูปสลิป'",[156,3310,3226],{"class":165},[156,3312,3313],{"class":158,"line":687},[156,3314,429],{"class":165},[156,3316,3317],{"class":158,"line":699},[156,3318,279],{"emptyLinePlaceholder":278},[156,3320,3321,3324],{"class":158,"line":723},[156,3322,3323],{"class":161},"  let",[156,3325,3326],{"class":165}," slip;\n",[156,3328,3329,3332],{"class":158,"line":748},[156,3330,3331],{"class":161},"  try",[156,3333,300],{"class":165},[156,3335,3336,3338,3340,3342,3344],{"class":158,"line":26},[156,3337,2397],{"class":165},[156,3339,169],{"class":161},[156,3341,600],{"class":161},[156,3343,509],{"class":290},[156,3345,3346],{"class":165},"(req.body);\n",[156,3348,3349,3352,3354],{"class":158,"line":761},[156,3350,3351],{"class":165},"  } ",[156,3353,693],{"class":161},[156,3355,696],{"class":165},[156,3357,3358,3361,3363,3365,3368,3371],{"class":158,"line":766},[156,3359,3360],{"class":165},"    console.",[156,3362,355],{"class":290},[156,3364,309],{"class":165},[156,3366,3367],{"class":172},"'SlipBolt:'",[156,3369,3370],{"class":165},", err); ",[156,3372,3373],{"class":252},"\u002F\u002F 402 = โควตาร้านหมด · 401\u002F403 = คีย์หรือแพ็ก → แจ้งเตือนทีมคุณ\n",[156,3375,3376,3378,3380,3382,3384,3387,3389,3391,3393,3395,3397,3400],{"class":158,"line":805},[156,3377,921],{"class":161},[156,3379,877],{"class":165},[156,3381,224],{"class":290},[156,3383,309],{"class":165},[156,3385,3386],{"class":262},"503",[156,3388,2741],{"class":165},[156,3390,880],{"class":290},[156,3392,3215],{"class":165},[156,3394,3017],{"class":262},[156,3396,3220],{"class":165},[156,3398,3399],{"class":172},"'ตรวจสลิปอัตโนมัติไม่ได้ชั่วคราว ลองใหม่หรือติดต่อร้าน'",[156,3401,3226],{"class":165},[156,3403,3404],{"class":158,"line":849},[156,3405,429],{"class":165},[156,3407,3408],{"class":158,"line":30},[156,3409,279],{"emptyLinePlaceholder":278},[156,3411,3412],{"class":158,"line":860},[156,3413,3414],{"class":252},"  \u002F\u002F 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\n",[156,3416,3417,3419,3421,3423,3426,3428],{"class":158,"line":865},[156,3418,3190],{"class":161},[156,3420,453],{"class":165},[156,3422,903],{"class":161},[156,3424,3425],{"class":165},"slip.verified ",[156,3427,831],{"class":161},[156,3429,3430],{"class":165}," slip.duplicate) {\n",[156,3432,3433,3435,3437,3439,3441,3444,3446,3448,3450,3452,3454,3457,3460,3462,3465],{"class":158,"line":896},[156,3434,921],{"class":161},[156,3436,877],{"class":165},[156,3438,224],{"class":290},[156,3440,309],{"class":165},[156,3442,3443],{"class":262},"422",[156,3445,2741],{"class":165},[156,3447,880],{"class":290},[156,3449,3215],{"class":165},[156,3451,3017],{"class":262},[156,3453,3220],{"class":165},[156,3455,3456],{"class":262},"REJECT",[156,3458,3459],{"class":165},"[slip.status] ",[156,3461,1685],{"class":161},[156,3463,3464],{"class":172}," 'สลิปไม่ผ่านการตรวจ'",[156,3466,3226],{"class":165},[156,3468,3469],{"class":158,"line":918},[156,3470,429],{"class":165},[156,3472,3473],{"class":158,"line":35},[156,3474,3475],{"class":252},"  \u002F\u002F 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\n",[156,3477,3478,3480,3483,3486,3489,3492,3495,3498,3501],{"class":158,"line":934},[156,3479,3190],{"class":161},[156,3481,3482],{"class":165}," (Math.",[156,3484,3485],{"class":290},"abs",[156,3487,3488],{"class":165},"(slip.amount ",[156,3490,3491],{"class":161},"-",[156,3493,3494],{"class":165}," order.total) ",[156,3496,3497],{"class":161},">",[156,3499,3500],{"class":262}," 0.001",[156,3502,321],{"class":165},[156,3504,3505,3507,3509,3511,3513,3515,3517,3519],{"class":158,"line":1504},[156,3506,921],{"class":161},[156,3508,877],{"class":165},[156,3510,224],{"class":290},[156,3512,309],{"class":165},[156,3514,3443],{"class":262},[156,3516,2741],{"class":165},[156,3518,880],{"class":290},[156,3520,3521],{"class":165},"({\n",[156,3523,3524,3527,3529],{"class":158,"line":1511},[156,3525,3526],{"class":165},"      ok: ",[156,3528,3017],{"class":262},[156,3530,628],{"class":165},[156,3532,3533,3536,3539,3542,3544,3546,3549,3552,3554,3557,3560],{"class":158,"line":1522},[156,3534,3535],{"class":165},"      message: ",[156,3537,3538],{"class":172},"`ยอดโอน ${",[156,3540,3541],{"class":165},"slip",[156,3543,342],{"class":172},[156,3545,2594],{"class":165},[156,3547,3548],{"class":172},"} บาท ไม่ตรงกับยอดออเดอร์ ${",[156,3550,3551],{"class":165},"order",[156,3553,342],{"class":172},[156,3555,3556],{"class":165},"total",[156,3558,3559],{"class":172},"} บาท`",[156,3561,628],{"class":165},[156,3563,3564],{"class":158,"line":39},[156,3565,2857],{"class":165},[156,3567,3568],{"class":158,"line":1541},[156,3569,429],{"class":165},[156,3571,3572],{"class":158,"line":1551},[156,3573,3574],{"class":252},"  \u002F\u002F 4) สลิปใบเดียวปิดได้ออเดอร์เดียว\n",[156,3576,3577,3579,3582,3585],{"class":158,"line":1560},[156,3578,3190],{"class":161},[156,3580,3581],{"class":165}," (usedRefs.",[156,3583,3584],{"class":290},"has",[156,3586,3587],{"class":165},"(slip.transRef)) {\n",[156,3589,3590,3592,3594,3596,3598,3600,3602,3604,3606,3608,3610,3613],{"class":158,"line":2208},[156,3591,921],{"class":161},[156,3593,877],{"class":165},[156,3595,224],{"class":290},[156,3597,309],{"class":165},[156,3599,3443],{"class":262},[156,3601,2741],{"class":165},[156,3603,880],{"class":290},[156,3605,3215],{"class":165},[156,3607,3017],{"class":262},[156,3609,3220],{"class":165},[156,3611,3612],{"class":172},"'สลิปนี้ถูกใช้กับออเดอร์อื่นแล้ว'",[156,3614,3226],{"class":165},[156,3616,3617],{"class":158,"line":2224},[156,3618,429],{"class":165},[156,3620,3621],{"class":158,"line":2236},[156,3622,279],{"emptyLinePlaceholder":278},[156,3624,3625,3628,3631],{"class":158,"line":2241},[156,3626,3627],{"class":165},"  usedRefs.",[156,3629,3630],{"class":290},"add",[156,3632,3633],{"class":165},"(slip.transRef);\n",[156,3635,3636,3639,3641,3643],{"class":158,"line":2256},[156,3637,3638],{"class":165},"  order.paid ",[156,3640,169],{"class":161},[156,3642,1843],{"class":262},[156,3644,272],{"class":165},[156,3646,3647,3650,3652],{"class":158,"line":2261},[156,3648,3649],{"class":165},"  order.transRef ",[156,3651,169],{"class":161},[156,3653,3654],{"class":165}," slip.transRef;\n",[156,3656,3658,3661,3663,3665,3667,3669,3672],{"class":158,"line":3657},55,[156,3659,3660],{"class":165},"  res.",[156,3662,880],{"class":290},[156,3664,3215],{"class":165},[156,3666,2198],{"class":262},[156,3668,3220],{"class":165},[156,3670,3671],{"class":172},"'ชำระเงินเรียบร้อย ขอบคุณค่ะ'",[156,3673,3674],{"class":165},", transRef: slip.transRef });\n",[156,3676,3678],{"class":158,"line":3677},56,[156,3679,3680],{"class":165},"});\n",[156,3682,3684],{"class":158,"line":3683},57,[156,3685,279],{"emptyLinePlaceholder":278},[156,3687,3689,3691,3694,3696,3699],{"class":158,"line":3688},58,[156,3690,3120],{"class":165},[156,3692,3693],{"class":290},"listen",[156,3695,309],{"class":165},[156,3697,3698],{"class":262},"3000",[156,3700,375],{"class":165},[147,3702,3705],{"className":939,"code":3703,"filename":3704,"language":942,"meta":152,"style":152},"# app.py — pip install flask requests\nfrom flask import Flask, jsonify, request\n\nfrom slipbolt import verify_slip\n\napp = Flask(__name__)\n\n# ของจริง = ตารางในฐานข้อมูล · used_refs = คอลัมน์ transRef ที่ติด UNIQUE\norders = {\"1001\": {\"total\": 250, \"paid\": False}}\nused_refs: set[str] = set()\n\n# ข้อความที่บอกลูกค้าเมื่อสลิปไม่ผ่าน\nREJECT = {\n    \"DUPLICATE\": \"สลิปนี้ถูกใช้ไปแล้ว\",\n    \"FRAUD\": \"สลิปไม่ถูกต้อง กรุณาติดต่อร้าน\",\n    \"RECEIVER_MISMATCH\": \"สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน\",\n    \"INVALID\": \"อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ\",\n    \"PROVIDER_ERROR\": \"ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง\",\n}\n\n\ndef reply(status: int, ok: bool, message: str, **extra):\n    return jsonify(ok=ok, message=message, **extra), status\n\n\n@app.post(\"\u002Forders\u002F\u003Corder_id>\u002Fslip\")\ndef pay_with_slip(order_id: str):\n    order = orders.get(order_id)\n    if order is None:\n        return reply(404, False, \"ไม่พบออเดอร์\")\n    if order[\"paid\"]:\n        return reply(200, True, \"ออเดอร์นี้ชำระแล้ว\")\n    image = request.get_data()\n    if not image:\n        return reply(400, False, \"กรุณาแนบรูปสลิป\")\n\n    try:\n        slip = verify_slip(image)\n    except Exception as err:  # 402 = โควตาร้านหมด · 401\u002F403 = คีย์หรือแพ็ก → แจ้งเตือนทีมคุณ\n        app.logger.error(\"SlipBolt: %s\", err)\n        return reply(503, False, \"ตรวจสลิปอัตโนมัติไม่ได้ชั่วคราว ลองใหม่หรือติดต่อร้าน\")\n\n    # 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\n    if not slip[\"verified\"] or slip[\"duplicate\"]:\n        return reply(422, False, REJECT.get(slip[\"status\"], \"สลิปไม่ผ่านการตรวจ\"))\n    # 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\n    if abs(slip[\"amount\"] - order[\"total\"]) > 0.001:\n        return reply(422, False, f\"ยอดโอน {slip['amount']} บาท ไม่ตรงกับยอดออเดอร์ {order['total']} บาท\")\n    # 4) สลิปใบเดียวปิดได้ออเดอร์เดียว\n    if slip[\"transRef\"] in used_refs:\n        return reply(422, False, \"สลิปนี้ถูกใช้กับออเดอร์อื่นแล้ว\")\n\n    used_refs.add(slip[\"transRef\"])\n    order.update(paid=True, transRef=slip[\"transRef\"])\n    return reply(200, True, \"ชำระเงินเรียบร้อย ขอบคุณค่ะ\", transRef=slip[\"transRef\"])\n\n\nif __name__ == \"__main__\":\n    app.run(port=3000)\n","Python (Flask)",[142,3706,3707,3712,3724,3728,3738,3742,3757,3761,3766,3801,3818,3822,3827,3835,3847,3859,3871,3883,3895,3899,3903,3907,3936,3963,3967,3971,3983,3997,4007,4022,4042,4054,4075,4085,4094,4113,4117,4123,4133,4150,4166,4185,4189,4194,4217,4246,4251,4279,4330,4335,4350,4369,4373,4382,4406,4435,4439,4443,4459],{"__ignoreMap":152},[156,3708,3709],{"class":158,"line":9},[156,3710,3711],{"class":252},"# app.py — pip install flask requests\n",[156,3713,3714,3716,3719,3721],{"class":158,"line":256},[156,3715,2283],{"class":161},[156,3717,3718],{"class":165}," flask ",[156,3720,954],{"class":161},[156,3722,3723],{"class":165}," Flask, jsonify, request\n",[156,3725,3726],{"class":158,"line":275},[156,3727,279],{"emptyLinePlaceholder":278},[156,3729,3730,3732,3734,3736],{"class":158,"line":282},[156,3731,2283],{"class":161},[156,3733,2357],{"class":165},[156,3735,954],{"class":161},[156,3737,2362],{"class":165},[156,3739,3740],{"class":158,"line":303},[156,3741,279],{"emptyLinePlaceholder":278},[156,3743,3744,3747,3749,3752,3755],{"class":158,"line":324},[156,3745,3746],{"class":165},"app ",[156,3748,169],{"class":161},[156,3750,3751],{"class":165}," Flask(",[156,3753,3754],{"class":262},"__name__",[156,3756,1718],{"class":165},[156,3758,3759],{"class":158,"line":378},[156,3760,279],{"emptyLinePlaceholder":278},[156,3762,3763],{"class":158,"line":395},[156,3764,3765],{"class":252},"# ของจริง = ตารางในฐานข้อมูล · used_refs = คอลัมน์ transRef ที่ติด UNIQUE\n",[156,3767,3768,3771,3773,3775,3778,3781,3784,3786,3788,3790,3793,3795,3798],{"class":158,"line":411},[156,3769,3770],{"class":165},"orders ",[156,3772,169],{"class":161},[156,3774,1065],{"class":165},[156,3776,3777],{"class":172},"\"1001\"",[156,3779,3780],{"class":165},": {",[156,3782,3783],{"class":172},"\"total\"",[156,3785,650],{"class":165},[156,3787,3011],{"class":262},[156,3789,315],{"class":165},[156,3791,3792],{"class":172},"\"paid\"",[156,3794,650],{"class":165},[156,3796,3797],{"class":262},"False",[156,3799,3800],{"class":165},"}}\n",[156,3802,3803,3806,3808,3810,3812,3815],{"class":158,"line":13},[156,3804,3805],{"class":165},"used_refs: set[",[156,3807,1198],{"class":262},[156,3809,1682],{"class":165},[156,3811,169],{"class":161},[156,3813,3814],{"class":262}," set",[156,3816,3817],{"class":165},"()\n",[156,3819,3820],{"class":158,"line":432},[156,3821,279],{"emptyLinePlaceholder":278},[156,3823,3824],{"class":158,"line":438},[156,3825,3826],{"class":252},"# ข้อความที่บอกลูกค้าเมื่อสลิปไม่ผ่าน\n",[156,3828,3829,3831,3833],{"class":158,"line":443},[156,3830,3456],{"class":262},[156,3832,266],{"class":161},[156,3834,300],{"class":165},[156,3836,3837,3840,3842,3845],{"class":158,"line":487},[156,3838,3839],{"class":172},"    \"DUPLICATE\"",[156,3841,650],{"class":165},[156,3843,3844],{"class":172},"\"สลิปนี้ถูกใช้ไปแล้ว\"",[156,3846,628],{"class":165},[156,3848,3849,3852,3854,3857],{"class":158,"line":492},[156,3850,3851],{"class":172},"    \"FRAUD\"",[156,3853,650],{"class":165},[156,3855,3856],{"class":172},"\"สลิปไม่ถูกต้อง กรุณาติดต่อร้าน\"",[156,3858,628],{"class":165},[156,3860,3861,3864,3866,3869],{"class":158,"line":498},[156,3862,3863],{"class":172},"    \"RECEIVER_MISMATCH\"",[156,3865,650],{"class":165},[156,3867,3868],{"class":172},"\"สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน\"",[156,3870,628],{"class":165},[156,3872,3873,3876,3878,3881],{"class":158,"line":549},[156,3874,3875],{"class":172},"    \"INVALID\"",[156,3877,650],{"class":165},[156,3879,3880],{"class":172},"\"อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ\"",[156,3882,628],{"class":165},[156,3884,3885,3888,3890,3893],{"class":158,"line":576},[156,3886,3887],{"class":172},"    \"PROVIDER_ERROR\"",[156,3889,650],{"class":165},[156,3891,3892],{"class":172},"\"ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง\"",[156,3894,628],{"class":165},[156,3896,3897],{"class":158,"line":585},[156,3898,435],{"class":165},[156,3900,3901],{"class":158,"line":18},[156,3902,279],{"emptyLinePlaceholder":278},[156,3904,3905],{"class":158,"line":619},[156,3906,279],{"emptyLinePlaceholder":278},[156,3908,3909,3911,3914,3917,3919,3922,3925,3927,3929,3931,3933],{"class":158,"line":631},[156,3910,1183],{"class":161},[156,3912,3913],{"class":290}," reply",[156,3915,3916],{"class":165},"(status: ",[156,3918,1025],{"class":262},[156,3920,3921],{"class":165},", ok: ",[156,3923,3924],{"class":262},"bool",[156,3926,3220],{"class":165},[156,3928,1198],{"class":262},[156,3930,315],{"class":165},[156,3932,1425],{"class":161},[156,3934,3935],{"class":165},"extra):\n",[156,3937,3938,3940,3943,3946,3948,3951,3953,3955,3958,3960],{"class":158,"line":659},[156,3939,921],{"class":161},[156,3941,3942],{"class":165}," jsonify(",[156,3944,3945],{"class":312},"ok",[156,3947,169],{"class":161},[156,3949,3950],{"class":165},"ok, ",[156,3952,367],{"class":312},[156,3954,169],{"class":161},[156,3956,3957],{"class":165},"message, ",[156,3959,1425],{"class":161},[156,3961,3962],{"class":165},"extra), status\n",[156,3964,3965],{"class":158,"line":665},[156,3966,279],{"emptyLinePlaceholder":278},[156,3968,3969],{"class":158,"line":22},[156,3970,279],{"emptyLinePlaceholder":278},[156,3972,3973,3976,3978,3981],{"class":158,"line":687},[156,3974,3975],{"class":290},"@app.post",[156,3977,309],{"class":165},[156,3979,3980],{"class":172},"\"\u002Forders\u002F\u003Corder_id>\u002Fslip\"",[156,3982,1718],{"class":165},[156,3984,3985,3987,3990,3993,3995],{"class":158,"line":699},[156,3986,1183],{"class":161},[156,3988,3989],{"class":290}," pay_with_slip",[156,3991,3992],{"class":165},"(order_id: ",[156,3994,1198],{"class":262},[156,3996,1011],{"class":165},[156,3998,3999,4002,4004],{"class":158,"line":723},[156,4000,4001],{"class":165},"    order ",[156,4003,169],{"class":161},[156,4005,4006],{"class":165}," orders.get(order_id)\n",[156,4008,4009,4011,4014,4017,4020],{"class":158,"line":748},[156,4010,769],{"class":161},[156,4012,4013],{"class":165}," order ",[156,4015,4016],{"class":161},"is",[156,4018,4019],{"class":262}," None",[156,4021,1220],{"class":165},[156,4023,4024,4026,4029,4031,4033,4035,4037,4040],{"class":158,"line":26},[156,4025,1563],{"class":161},[156,4027,4028],{"class":165}," reply(",[156,4030,3208],{"class":262},[156,4032,315],{"class":165},[156,4034,3797],{"class":262},[156,4036,315],{"class":165},[156,4038,4039],{"class":172},"\"ไม่พบออเดอร์\"",[156,4041,1718],{"class":165},[156,4043,4044,4046,4049,4051],{"class":158,"line":761},[156,4045,769],{"class":161},[156,4047,4048],{"class":165}," order[",[156,4050,3792],{"class":172},[156,4052,4053],{"class":165},"]:\n",[156,4055,4056,4058,4060,4063,4065,4068,4070,4073],{"class":158,"line":766},[156,4057,1563],{"class":161},[156,4059,4028],{"class":165},[156,4061,4062],{"class":262},"200",[156,4064,315],{"class":165},[156,4066,4067],{"class":262},"True",[156,4069,315],{"class":165},[156,4071,4072],{"class":172},"\"ออเดอร์นี้ชำระแล้ว\"",[156,4074,1718],{"class":165},[156,4076,4077,4080,4082],{"class":158,"line":805},[156,4078,4079],{"class":165},"    image ",[156,4081,169],{"class":161},[156,4083,4084],{"class":165}," request.get_data()\n",[156,4086,4087,4089,4091],{"class":158,"line":849},[156,4088,769],{"class":161},[156,4090,1467],{"class":161},[156,4092,4093],{"class":165}," image:\n",[156,4095,4096,4098,4100,4102,4104,4106,4108,4111],{"class":158,"line":30},[156,4097,1563],{"class":161},[156,4099,4028],{"class":165},[156,4101,3295],{"class":262},[156,4103,315],{"class":165},[156,4105,3797],{"class":262},[156,4107,315],{"class":165},[156,4109,4110],{"class":172},"\"กรุณาแนบรูปสลิป\"",[156,4112,1718],{"class":165},[156,4114,4115],{"class":158,"line":860},[156,4116,279],{"emptyLinePlaceholder":278},[156,4118,4119,4121],{"class":158,"line":865},[156,4120,588],{"class":161},[156,4122,1220],{"class":165},[156,4124,4125,4128,4130],{"class":158,"line":896},[156,4126,4127],{"class":165},"        slip ",[156,4129,169],{"class":161},[156,4131,4132],{"class":165}," verify_slip(image)\n",[156,4134,4135,4138,4141,4144,4147],{"class":158,"line":918},[156,4136,4137],{"class":161},"    except",[156,4139,4140],{"class":262}," Exception",[156,4142,4143],{"class":161}," as",[156,4145,4146],{"class":165}," err:  ",[156,4148,4149],{"class":252},"# 402 = โควตาร้านหมด · 401\u002F403 = คีย์หรือแพ็ก → แจ้งเตือนทีมคุณ\n",[156,4151,4152,4155,4158,4161,4163],{"class":158,"line":35},[156,4153,4154],{"class":165},"        app.logger.error(",[156,4156,4157],{"class":172},"\"SlipBolt: ",[156,4159,4160],{"class":262},"%s",[156,4162,1054],{"class":172},[156,4164,4165],{"class":165},", err)\n",[156,4167,4168,4170,4172,4174,4176,4178,4180,4183],{"class":158,"line":934},[156,4169,1563],{"class":161},[156,4171,4028],{"class":165},[156,4173,3386],{"class":262},[156,4175,315],{"class":165},[156,4177,3797],{"class":262},[156,4179,315],{"class":165},[156,4181,4182],{"class":172},"\"ตรวจสลิปอัตโนมัติไม่ได้ชั่วคราว ลองใหม่หรือติดต่อร้าน\"",[156,4184,1718],{"class":165},[156,4186,4187],{"class":158,"line":1504},[156,4188,279],{"emptyLinePlaceholder":278},[156,4190,4191],{"class":158,"line":1511},[156,4192,4193],{"class":252},"    # 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\n",[156,4195,4196,4198,4200,4203,4206,4208,4210,4212,4215],{"class":158,"line":1522},[156,4197,769],{"class":161},[156,4199,1467],{"class":161},[156,4201,4202],{"class":165}," slip[",[156,4204,4205],{"class":172},"\"verified\"",[156,4207,1682],{"class":165},[156,4209,1076],{"class":161},[156,4211,4202],{"class":165},[156,4213,4214],{"class":172},"\"duplicate\"",[156,4216,4053],{"class":165},[156,4218,4219,4221,4223,4225,4227,4229,4231,4233,4236,4238,4240,4243],{"class":158,"line":39},[156,4220,1563],{"class":161},[156,4222,4028],{"class":165},[156,4224,3443],{"class":262},[156,4226,315],{"class":165},[156,4228,3797],{"class":262},[156,4230,315],{"class":165},[156,4232,3456],{"class":262},[156,4234,4235],{"class":165},".get(slip[",[156,4237,2413],{"class":172},[156,4239,2491],{"class":165},[156,4241,4242],{"class":172},"\"สลิปไม่ผ่านการตรวจ\"",[156,4244,4245],{"class":165},"))\n",[156,4247,4248],{"class":158,"line":1541},[156,4249,4250],{"class":252},"    # 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\n",[156,4252,4253,4255,4258,4260,4262,4264,4266,4268,4270,4273,4275,4277],{"class":158,"line":1551},[156,4254,769],{"class":161},[156,4256,4257],{"class":262}," abs",[156,4259,2410],{"class":165},[156,4261,2419],{"class":172},[156,4263,1682],{"class":165},[156,4265,3491],{"class":161},[156,4267,4048],{"class":165},[156,4269,3783],{"class":172},[156,4271,4272],{"class":165},"]) ",[156,4274,3497],{"class":161},[156,4276,3500],{"class":262},[156,4278,1220],{"class":165},[156,4280,4281,4283,4285,4287,4289,4291,4293,4295,4298,4300,4303,4305,4308,4310,4313,4315,4318,4321,4323,4325,4328],{"class":158,"line":1560},[156,4282,1563],{"class":161},[156,4284,4028],{"class":165},[156,4286,3443],{"class":262},[156,4288,315],{"class":165},[156,4290,3797],{"class":262},[156,4292,315],{"class":165},[156,4294,1334],{"class":161},[156,4296,4297],{"class":172},"\"ยอดโอน ",[156,4299,1057],{"class":262},[156,4301,4302],{"class":165},"slip[",[156,4304,2500],{"class":172},[156,4306,4307],{"class":165},"]",[156,4309,1062],{"class":262},[156,4311,4312],{"class":172}," บาท ไม่ตรงกับยอดออเดอร์ ",[156,4314,1057],{"class":262},[156,4316,4317],{"class":165},"order[",[156,4319,4320],{"class":172},"'total'",[156,4322,4307],{"class":165},[156,4324,1062],{"class":262},[156,4326,4327],{"class":172}," บาท\"",[156,4329,1718],{"class":165},[156,4331,4332],{"class":158,"line":2208},[156,4333,4334],{"class":252},"    # 4) สลิปใบเดียวปิดได้ออเดอร์เดียว\n",[156,4336,4337,4339,4341,4343,4345,4347],{"class":158,"line":2224},[156,4338,769],{"class":161},[156,4340,4202],{"class":165},[156,4342,2424],{"class":172},[156,4344,1682],{"class":165},[156,4346,1256],{"class":161},[156,4348,4349],{"class":165}," used_refs:\n",[156,4351,4352,4354,4356,4358,4360,4362,4364,4367],{"class":158,"line":2236},[156,4353,1563],{"class":161},[156,4355,4028],{"class":165},[156,4357,3443],{"class":262},[156,4359,315],{"class":165},[156,4361,3797],{"class":262},[156,4363,315],{"class":165},[156,4365,4366],{"class":172},"\"สลิปนี้ถูกใช้กับออเดอร์อื่นแล้ว\"",[156,4368,1718],{"class":165},[156,4370,4371],{"class":158,"line":2241},[156,4372,279],{"emptyLinePlaceholder":278},[156,4374,4375,4378,4380],{"class":158,"line":2256},[156,4376,4377],{"class":165},"    used_refs.add(slip[",[156,4379,2424],{"class":172},[156,4381,2427],{"class":165},[156,4383,4384,4387,4390,4392,4394,4396,4398,4400,4402,4404],{"class":158,"line":2261},[156,4385,4386],{"class":165},"    order.update(",[156,4388,4389],{"class":312},"paid",[156,4391,169],{"class":161},[156,4393,4067],{"class":262},[156,4395,315],{"class":165},[156,4397,2608],{"class":312},[156,4399,169],{"class":161},[156,4401,4302],{"class":165},[156,4403,2424],{"class":172},[156,4405,2427],{"class":165},[156,4407,4408,4410,4412,4414,4416,4418,4420,4423,4425,4427,4429,4431,4433],{"class":158,"line":3657},[156,4409,921],{"class":161},[156,4411,4028],{"class":165},[156,4413,4062],{"class":262},[156,4415,315],{"class":165},[156,4417,4067],{"class":262},[156,4419,315],{"class":165},[156,4421,4422],{"class":172},"\"ชำระเงินเรียบร้อย ขอบคุณค่ะ\"",[156,4424,315],{"class":165},[156,4426,2608],{"class":312},[156,4428,169],{"class":161},[156,4430,4302],{"class":165},[156,4432,2424],{"class":172},[156,4434,2427],{"class":165},[156,4436,4437],{"class":158,"line":3677},[156,4438,279],{"emptyLinePlaceholder":278},[156,4440,4441],{"class":158,"line":3683},[156,4442,279],{"emptyLinePlaceholder":278},[156,4444,4445,4448,4451,4454,4457],{"class":158,"line":3688},[156,4446,4447],{"class":161},"if",[156,4449,4450],{"class":262}," __name__",[156,4452,4453],{"class":161}," ==",[156,4455,4456],{"class":172}," \"__main__\"",[156,4458,1220],{"class":165},[156,4460,4462,4465,4468,4470,4472],{"class":158,"line":4461},59,[156,4463,4464],{"class":165},"    app.run(",[156,4466,4467],{"class":312},"port",[156,4469,169],{"class":161},[156,4471,3698],{"class":262},[156,4473,1718],{"class":165},[147,4475,4477],{"className":1578,"code":4476,"filename":1580,"language":1581,"meta":152,"style":152},"\u003C?php\n\u002F\u002F pay.php?order=1001 — ตาราง: orders(id, total, trans_ref UNIQUE NULL)\nrequire __DIR__ . '\u002Fslipbolt.php';\n\nfunction reply(int $status, bool $ok, string $message): never\n{\n    http_response_code($status);\n    header('Content-Type: application\u002Fjson; charset=utf-8');\n    echo json_encode(['ok' => $ok, 'message' => $message], JSON_UNESCAPED_UNICODE);\n    exit;\n}\n\n\u002F\u002F ข้อความที่บอกลูกค้าเมื่อสลิปไม่ผ่าน\nconst REJECT = [\n    'DUPLICATE'         => 'สลิปนี้ถูกใช้ไปแล้ว',\n    'FRAUD'             => 'สลิปไม่ถูกต้อง กรุณาติดต่อร้าน',\n    'RECEIVER_MISMATCH' => 'สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน',\n    'INVALID'           => 'อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ',\n    'PROVIDER_ERROR'    => 'ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง',\n];\n\n$pdo = new PDO(getenv('DB_DSN'), getenv('DB_USER') ?: null, getenv('DB_PASS') ?: null, [\n    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n]);\n\n$find = $pdo->prepare('SELECT id, total, trans_ref FROM orders WHERE id = ?');\n$find->execute([$_GET['order'] ?? '']);\n$order = $find->fetch(PDO::FETCH_ASSOC);\nif (!$order) reply(404, false, 'ไม่พบออเดอร์');\nif ($order['trans_ref'] !== null) reply(200, true, 'ออเดอร์นี้ชำระแล้ว');\n\n$image = file_get_contents('php:\u002F\u002Finput'); \u002F\u002F รูปสลิปที่เบราว์เซอร์ส่งมาเป็น body\nif ($image === '' || $image === false) reply(400, false, 'กรุณาแนบรูปสลิป');\n\ntry {\n    $slip = slipbolt_verify($image);\n} catch (Throwable $err) { \u002F\u002F 402 = โควตาร้านหมด · 401\u002F403 = คีย์หรือแพ็ก → แจ้งเตือนทีมคุณ\n    error_log('SlipBolt: ' . $err->getMessage());\n    reply(503, false, 'ตรวจสลิปอัตโนมัติไม่ได้ชั่วคราว ลองใหม่หรือติดต่อร้าน');\n}\n\n\u002F\u002F 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\nif (!$slip['verified'] || $slip['duplicate']) {\n    reply(422, false, REJECT[$slip['status']] ?? 'สลิปไม่ผ่านการตรวจ');\n}\n\u002F\u002F 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\nif (abs($slip['amount'] - (float) $order['total']) > 0.001) {\n    reply(422, false, \"ยอดโอน {$slip['amount']} บาท ไม่ตรงกับยอดออเดอร์ {$order['total']} บาท\");\n}\n\u002F\u002F 4) สลิปใบเดียวปิดได้ออเดอร์เดียว — ให้ UNIQUE ของฐานข้อมูลเป็นคนตัดสิน (กันสองคำขอชนกันได้ด้วย)\ntry {\n    $pay = $pdo->prepare('UPDATE orders SET trans_ref = ? WHERE id = ? AND trans_ref IS NULL');\n    $pay->execute([$slip['transRef'], $order['id']]);\n} catch (PDOException $err) {\n    reply(422, false, 'สลิปนี้ถูกใช้กับออเดอร์อื่นแล้ว');\n}\n\nreply(200, true, 'ชำระเงินเรียบร้อย ขอบคุณค่ะ');\n",[142,4478,4479,4485,4490,4502,4506,4533,4537,4545,4557,4587,4594,4598,4602,4606,4616,4629,4642,4654,4666,4679,4683,4687,4744,4766,4771,4775,4821,4845,4872,4900,4934,4938,4959,4997,5001,5008,5020,5037,5060,5079,5083,5087,5092,5118,5148,5152,5157,5191,5222,5226,5231,5237,5293,5316,5330,5348,5352,5356],{"__ignoreMap":152},[156,4480,4481,4483],{"class":158,"line":9},[156,4482,1588],{"class":161},[156,4484,1591],{"class":262},[156,4486,4487],{"class":158,"line":256},[156,4488,4489],{"class":252},"\u002F\u002F pay.php?order=1001 — ตาราง: orders(id, total, trans_ref UNIQUE NULL)\n",[156,4491,4492,4494,4496,4498,4500],{"class":158,"line":275},[156,4493,2443],{"class":161},[156,4495,2446],{"class":262},[156,4497,1674],{"class":161},[156,4499,2451],{"class":172},[156,4501,272],{"class":165},[156,4503,4504],{"class":158,"line":282},[156,4505,279],{"emptyLinePlaceholder":278},[156,4507,4508,4510,4512,4514,4516,4518,4520,4523,4525,4528,4530],{"class":158,"line":303},[156,4509,1745],{"class":161},[156,4511,3913],{"class":290},[156,4513,309],{"class":165},[156,4515,1025],{"class":161},[156,4517,1637],{"class":165},[156,4519,3924],{"class":161},[156,4521,4522],{"class":165}," $ok, ",[156,4524,1753],{"class":161},[156,4526,4527],{"class":165}," $message)",[156,4529,1771],{"class":161},[156,4531,4532],{"class":161}," never\n",[156,4534,4535],{"class":158,"line":324},[156,4536,1616],{"class":165},[156,4538,4539,4542],{"class":158,"line":378},[156,4540,4541],{"class":262},"    http_response_code",[156,4543,4544],{"class":165},"($status);\n",[156,4546,4547,4550,4552,4555],{"class":158,"line":395},[156,4548,4549],{"class":262},"    header",[156,4551,309],{"class":165},[156,4553,4554],{"class":172},"'Content-Type: application\u002Fjson; charset=utf-8'",[156,4556,375],{"class":165},[156,4558,4559,4562,4565,4568,4571,4573,4575,4577,4579,4582,4585],{"class":158,"line":411},[156,4560,4561],{"class":262},"    echo",[156,4563,4564],{"class":262}," json_encode",[156,4566,4567],{"class":165},"([",[156,4569,4570],{"class":172},"'ok'",[156,4572,1903],{"class":161},[156,4574,4522],{"class":165},[156,4576,1100],{"class":172},[156,4578,1903],{"class":161},[156,4580,4581],{"class":165}," $message], ",[156,4583,4584],{"class":262},"JSON_UNESCAPED_UNICODE",[156,4586,375],{"class":165},[156,4588,4589,4592],{"class":158,"line":13},[156,4590,4591],{"class":161},"    exit",[156,4593,272],{"class":165},[156,4595,4596],{"class":158,"line":432},[156,4597,435],{"class":165},[156,4599,4600],{"class":158,"line":438},[156,4601,279],{"emptyLinePlaceholder":278},[156,4603,4604],{"class":158,"line":443},[156,4605,3045],{"class":252},[156,4607,4608,4610,4612,4614],{"class":158,"line":487},[156,4609,259],{"class":161},[156,4611,3052],{"class":262},[156,4613,266],{"class":161},[156,4615,1856],{"class":165},[156,4617,4618,4621,4624,4627],{"class":158,"line":492},[156,4619,4620],{"class":172},"    'DUPLICATE'",[156,4622,4623],{"class":161},"         =>",[156,4625,4626],{"class":172}," 'สลิปนี้ถูกใช้ไปแล้ว'",[156,4628,628],{"class":165},[156,4630,4631,4634,4637,4640],{"class":158,"line":498},[156,4632,4633],{"class":172},"    'FRAUD'",[156,4635,4636],{"class":161},"             =>",[156,4638,4639],{"class":172}," 'สลิปไม่ถูกต้อง กรุณาติดต่อร้าน'",[156,4641,628],{"class":165},[156,4643,4644,4647,4649,4652],{"class":158,"line":549},[156,4645,4646],{"class":172},"    'RECEIVER_MISMATCH'",[156,4648,1903],{"class":161},[156,4650,4651],{"class":172}," 'สลิปนี้ไม่ได้โอนเข้าบัญชีของร้าน'",[156,4653,628],{"class":165},[156,4655,4656,4659,4661,4664],{"class":158,"line":576},[156,4657,4658],{"class":172},"    'INVALID'",[156,4660,1840],{"class":161},[156,4662,4663],{"class":172}," 'อ่านสลิปไม่ได้ ลองอัปโหลดรูปที่เห็น QR ชัด ๆ'",[156,4665,628],{"class":165},[156,4667,4668,4671,4674,4677],{"class":158,"line":585},[156,4669,4670],{"class":172},"    'PROVIDER_ERROR'",[156,4672,4673],{"class":161},"    =>",[156,4675,4676],{"class":172}," 'ระบบตรวจสลิปขัดข้องชั่วคราว ลองส่งใหม่อีกครั้ง'",[156,4678,628],{"class":165},[156,4680,4681],{"class":158,"line":18},[156,4682,2783],{"class":165},[156,4684,4685],{"class":158,"line":619},[156,4686,279],{"emptyLinePlaceholder":278},[156,4688,4689,4692,4694,4696,4699,4701,4704,4706,4709,4712,4714,4716,4719,4721,4723,4726,4728,4730,4732,4735,4737,4739,4741],{"class":158,"line":631},[156,4690,4691],{"class":165},"$pdo ",[156,4693,169],{"class":161},[156,4695,465],{"class":161},[156,4697,4698],{"class":262}," PDO",[156,4700,309],{"class":165},[156,4702,4703],{"class":262},"getenv",[156,4705,309],{"class":165},[156,4707,4708],{"class":172},"'DB_DSN'",[156,4710,4711],{"class":165},"), ",[156,4713,4703],{"class":262},[156,4715,309],{"class":165},[156,4717,4718],{"class":172},"'DB_USER'",[156,4720,459],{"class":165},[156,4722,2119],{"class":161},[156,4724,4725],{"class":262}," null",[156,4727,315],{"class":165},[156,4729,4703],{"class":262},[156,4731,309],{"class":165},[156,4733,4734],{"class":172},"'DB_PASS'",[156,4736,459],{"class":165},[156,4738,2119],{"class":161},[156,4740,4725],{"class":262},[156,4742,4743],{"class":165},", [\n",[156,4745,4746,4749,4752,4755,4757,4759,4761,4764],{"class":158,"line":659},[156,4747,4748],{"class":262},"    PDO",[156,4750,4751],{"class":161},"::",[156,4753,4754],{"class":262},"ATTR_ERRMODE",[156,4756,1903],{"class":161},[156,4758,4698],{"class":262},[156,4760,4751],{"class":161},[156,4762,4763],{"class":262},"ERRMODE_EXCEPTION",[156,4765,628],{"class":165},[156,4767,4768],{"class":158,"line":665},[156,4769,4770],{"class":165},"]);\n",[156,4772,4773],{"class":158,"line":22},[156,4774,279],{"emptyLinePlaceholder":278},[156,4776,4777,4780,4782,4785,4788,4791,4793,4796,4799,4802,4805,4808,4811,4814,4816,4819],{"class":158,"line":687},[156,4778,4779],{"class":165},"$find ",[156,4781,169],{"class":161},[156,4783,4784],{"class":165}," $pdo",[156,4786,4787],{"class":161},"->",[156,4789,4790],{"class":290},"prepare",[156,4792,309],{"class":165},[156,4794,4795],{"class":172},"'",[156,4797,4798],{"class":161},"SELECT",[156,4800,4801],{"class":172}," id, total, trans_ref ",[156,4803,4804],{"class":161},"FROM",[156,4806,4807],{"class":172}," orders ",[156,4809,4810],{"class":161},"WHERE",[156,4812,4813],{"class":172}," id ",[156,4815,169],{"class":161},[156,4817,4818],{"class":172}," ?'",[156,4820,375],{"class":165},[156,4822,4823,4826,4828,4831,4834,4837,4839,4841,4843],{"class":158,"line":699},[156,4824,4825],{"class":165},"$find",[156,4827,4787],{"class":161},[156,4829,4830],{"class":290},"execute",[156,4832,4833],{"class":165},"([$_GET[",[156,4835,4836],{"class":172},"'order'",[156,4838,1682],{"class":165},[156,4840,1685],{"class":161},[156,4842,1089],{"class":172},[156,4844,4770],{"class":165},[156,4846,4847,4850,4852,4855,4857,4860,4862,4865,4867,4870],{"class":158,"line":723},[156,4848,4849],{"class":165},"$order ",[156,4851,169],{"class":161},[156,4853,4854],{"class":165}," $find",[156,4856,4787],{"class":161},[156,4858,4859],{"class":290},"fetch",[156,4861,309],{"class":165},[156,4863,4864],{"class":262},"PDO",[156,4866,4751],{"class":161},[156,4868,4869],{"class":262},"FETCH_ASSOC",[156,4871,375],{"class":165},[156,4873,4874,4876,4878,4880,4883,4886,4888,4890,4892,4894,4896,4898],{"class":158,"line":748},[156,4875,4447],{"class":161},[156,4877,453],{"class":165},[156,4879,903],{"class":161},[156,4881,4882],{"class":165},"$order) ",[156,4884,4885],{"class":290},"reply",[156,4887,309],{"class":165},[156,4889,3208],{"class":262},[156,4891,315],{"class":165},[156,4893,3017],{"class":262},[156,4895,315],{"class":165},[156,4897,3223],{"class":172},[156,4899,375],{"class":165},[156,4901,4902,4904,4907,4910,4912,4914,4916,4918,4920,4922,4924,4926,4928,4930,4932],{"class":158,"line":26},[156,4903,4447],{"class":161},[156,4905,4906],{"class":165}," ($order[",[156,4908,4909],{"class":172},"'trans_ref'",[156,4911,1682],{"class":165},[156,4913,2216],{"class":161},[156,4915,4725],{"class":262},[156,4917,459],{"class":165},[156,4919,4885],{"class":290},[156,4921,309],{"class":165},[156,4923,4062],{"class":262},[156,4925,315],{"class":165},[156,4927,2198],{"class":262},[156,4929,315],{"class":165},[156,4931,3248],{"class":172},[156,4933,375],{"class":165},[156,4935,4936],{"class":158,"line":761},[156,4937,279],{"emptyLinePlaceholder":278},[156,4939,4940,4943,4945,4948,4950,4953,4956],{"class":158,"line":766},[156,4941,4942],{"class":165},"$image ",[156,4944,169],{"class":161},[156,4946,4947],{"class":262}," file_get_contents",[156,4949,309],{"class":165},[156,4951,4952],{"class":172},"'php:\u002F\u002Finput'",[156,4954,4955],{"class":165},"); ",[156,4957,4958],{"class":252},"\u002F\u002F รูปสลิปที่เบราว์เซอร์ส่งมาเป็น body\n",[156,4960,4961,4963,4966,4968,4970,4972,4975,4977,4979,4981,4983,4985,4987,4989,4991,4993,4995],{"class":158,"line":805},[156,4962,4447],{"class":161},[156,4964,4965],{"class":165}," ($image ",[156,4967,775],{"class":161},[156,4969,1089],{"class":172},[156,4971,781],{"class":161},[156,4973,4974],{"class":165}," $image ",[156,4976,775],{"class":161},[156,4978,2079],{"class":262},[156,4980,459],{"class":165},[156,4982,4885],{"class":290},[156,4984,309],{"class":165},[156,4986,3295],{"class":262},[156,4988,315],{"class":165},[156,4990,3017],{"class":262},[156,4992,315],{"class":165},[156,4994,3308],{"class":172},[156,4996,375],{"class":165},[156,4998,4999],{"class":158,"line":849},[156,5000,279],{"emptyLinePlaceholder":278},[156,5002,5003,5006],{"class":158,"line":30},[156,5004,5005],{"class":161},"try",[156,5007,300],{"class":165},[156,5009,5010,5013,5015,5017],{"class":158,"line":860},[156,5011,5012],{"class":165},"    $slip ",[156,5014,169],{"class":161},[156,5016,1748],{"class":290},[156,5018,5019],{"class":165},"($image);\n",[156,5021,5022,5025,5027,5029,5032,5035],{"class":158,"line":865},[156,5023,5024],{"class":165},"} ",[156,5026,693],{"class":161},[156,5028,453],{"class":165},[156,5030,5031],{"class":262},"Throwable",[156,5033,5034],{"class":165}," $err) { ",[156,5036,3373],{"class":252},[156,5038,5039,5042,5044,5047,5049,5052,5054,5057],{"class":158,"line":896},[156,5040,5041],{"class":262},"    error_log",[156,5043,309],{"class":165},[156,5045,5046],{"class":172},"'SlipBolt: '",[156,5048,1674],{"class":161},[156,5050,5051],{"class":165}," $err",[156,5053,4787],{"class":161},[156,5055,5056],{"class":290},"getMessage",[156,5058,5059],{"class":165},"());\n",[156,5061,5062,5065,5067,5069,5071,5073,5075,5077],{"class":158,"line":918},[156,5063,5064],{"class":290},"    reply",[156,5066,309],{"class":165},[156,5068,3386],{"class":262},[156,5070,315],{"class":165},[156,5072,3017],{"class":262},[156,5074,315],{"class":165},[156,5076,3399],{"class":172},[156,5078,375],{"class":165},[156,5080,5081],{"class":158,"line":35},[156,5082,435],{"class":165},[156,5084,5085],{"class":158,"line":934},[156,5086,279],{"emptyLinePlaceholder":278},[156,5088,5089],{"class":158,"line":1504},[156,5090,5091],{"class":252},"\u002F\u002F 1) สลิปจริงและเข้าบัญชีร้าน  2) ไม่ใช่สลิปที่เคยตรวจแล้ว\n",[156,5093,5094,5096,5098,5100,5103,5106,5108,5110,5112,5115],{"class":158,"line":1511},[156,5095,4447],{"class":161},[156,5097,453],{"class":165},[156,5099,903],{"class":161},[156,5101,5102],{"class":165},"$slip[",[156,5104,5105],{"class":172},"'verified'",[156,5107,1682],{"class":165},[156,5109,831],{"class":161},[156,5111,2485],{"class":165},[156,5113,5114],{"class":172},"'duplicate'",[156,5116,5117],{"class":165},"]) {\n",[156,5119,5120,5122,5124,5126,5128,5130,5132,5134,5137,5139,5142,5144,5146],{"class":158,"line":1522},[156,5121,5064],{"class":290},[156,5123,309],{"class":165},[156,5125,3443],{"class":262},[156,5127,315],{"class":165},[156,5129,3017],{"class":262},[156,5131,315],{"class":165},[156,5133,3456],{"class":262},[156,5135,5136],{"class":165},"[$slip[",[156,5138,2488],{"class":172},[156,5140,5141],{"class":165},"]] ",[156,5143,1685],{"class":161},[156,5145,3464],{"class":172},[156,5147,375],{"class":165},[156,5149,5150],{"class":158,"line":39},[156,5151,435],{"class":165},[156,5153,5154],{"class":158,"line":1541},[156,5155,5156],{"class":252},"\u002F\u002F 3) ยอดตรงกับออเดอร์ — API ไม่รู้ว่าออเดอร์นี้ต้องจ่ายเท่าไร\n",[156,5158,5159,5161,5163,5165,5168,5170,5172,5174,5176,5178,5181,5183,5185,5187,5189],{"class":158,"line":1551},[156,5160,4447],{"class":161},[156,5162,453],{"class":165},[156,5164,3485],{"class":262},[156,5166,5167],{"class":165},"($slip[",[156,5169,2500],{"class":172},[156,5171,1682],{"class":165},[156,5173,3491],{"class":161},[156,5175,453],{"class":165},[156,5177,1476],{"class":161},[156,5179,5180],{"class":165},") $order[",[156,5182,4320],{"class":172},[156,5184,4272],{"class":165},[156,5186,3497],{"class":161},[156,5188,3500],{"class":262},[156,5190,321],{"class":165},[156,5192,5193,5195,5197,5199,5201,5203,5205,5208,5211,5214,5217,5220],{"class":158,"line":1560},[156,5194,5064],{"class":290},[156,5196,309],{"class":165},[156,5198,3443],{"class":262},[156,5200,315],{"class":165},[156,5202,3017],{"class":262},[156,5204,315],{"class":165},[156,5206,5207],{"class":172},"\"ยอดโอน {",[156,5209,5210],{"class":165},"$slip",[156,5212,5213],{"class":172},"['amount']} บาท ไม่ตรงกับยอดออเดอร์ {",[156,5215,5216],{"class":165},"$order",[156,5218,5219],{"class":172},"['total']} บาท\"",[156,5221,375],{"class":165},[156,5223,5224],{"class":158,"line":2208},[156,5225,435],{"class":165},[156,5227,5228],{"class":158,"line":2224},[156,5229,5230],{"class":252},"\u002F\u002F 4) สลิปใบเดียวปิดได้ออเดอร์เดียว — ให้ UNIQUE ของฐานข้อมูลเป็นคนตัดสิน (กันสองคำขอชนกันได้ด้วย)\n",[156,5232,5233,5235],{"class":158,"line":2236},[156,5234,5005],{"class":161},[156,5236,300],{"class":165},[156,5238,5239,5242,5244,5246,5248,5250,5252,5254,5257,5259,5262,5265,5267,5270,5272,5274,5276,5278,5281,5283,5286,5289,5291],{"class":158,"line":2241},[156,5240,5241],{"class":165},"    $pay ",[156,5243,169],{"class":161},[156,5245,4784],{"class":165},[156,5247,4787],{"class":161},[156,5249,4790],{"class":290},[156,5251,309],{"class":165},[156,5253,4795],{"class":172},[156,5255,5256],{"class":161},"UPDATE",[156,5258,4807],{"class":172},[156,5260,5261],{"class":161},"SET",[156,5263,5264],{"class":172}," trans_ref ",[156,5266,169],{"class":161},[156,5268,5269],{"class":172}," ? ",[156,5271,4810],{"class":161},[156,5273,4813],{"class":172},[156,5275,169],{"class":161},[156,5277,5269],{"class":172},[156,5279,5280],{"class":161},"AND",[156,5282,5264],{"class":172},[156,5284,5285],{"class":161},"IS",[156,5287,5288],{"class":161}," NULL",[156,5290,4795],{"class":172},[156,5292,375],{"class":165},[156,5294,5295,5298,5300,5302,5305,5307,5310,5313],{"class":158,"line":2256},[156,5296,5297],{"class":165},"    $pay",[156,5299,4787],{"class":161},[156,5301,4830],{"class":290},[156,5303,5304],{"class":165},"([$slip[",[156,5306,2509],{"class":172},[156,5308,5309],{"class":165},"], $order[",[156,5311,5312],{"class":172},"'id'",[156,5314,5315],{"class":165},"]]);\n",[156,5317,5318,5320,5322,5324,5327],{"class":158,"line":2261},[156,5319,5024],{"class":165},[156,5321,693],{"class":161},[156,5323,453],{"class":165},[156,5325,5326],{"class":262},"PDOException",[156,5328,5329],{"class":165}," $err) {\n",[156,5331,5332,5334,5336,5338,5340,5342,5344,5346],{"class":158,"line":3657},[156,5333,5064],{"class":290},[156,5335,309],{"class":165},[156,5337,3443],{"class":262},[156,5339,315],{"class":165},[156,5341,3017],{"class":262},[156,5343,315],{"class":165},[156,5345,3612],{"class":172},[156,5347,375],{"class":165},[156,5349,5350],{"class":158,"line":3677},[156,5351,435],{"class":165},[156,5353,5354],{"class":158,"line":3683},[156,5355,279],{"emptyLinePlaceholder":278},[156,5357,5358,5360,5362,5364,5366,5368,5370,5372],{"class":158,"line":3688},[156,5359,4885],{"class":290},[156,5361,309],{"class":165},[156,5363,4062],{"class":262},[156,5365,315],{"class":165},[156,5367,2198],{"class":262},[156,5369,315],{"class":165},[156,5371,3671],{"class":172},[156,5373,375],{"class":165},[2528,5375,5377],{"type":5376},"info",[65,5378,5379,5382,5383,5386,5389,5390,5393,5394,5397],{},[69,5380,5381],{},"อยากได้ผลแบบไม่ต้องให้ลูกค้ารอ?"," ลูกค้าส่งสลิปใน LINE OA ของร้านแล้วให้ระบบยิง ",[101,5384,5385],{"href":24},"Webhook",[142,5387,5388],{},"slip.verified"," มาที่เซิร์ฟเวอร์คุณแทน — เช็ค 4 ข้อเดิมจาก ",[142,5391,5392],{},"data.amount"," \u002F ",[142,5395,5396],{},"data.transRef"," ได้เหมือนกัน",[175,5399,126],{"id":5400},"_3-รูปอยู่ในรูปแบบอื่น",[65,5402,5403,5406,5407,5410,5411,5413],{},[142,5404,5405],{},"POST \u002Fverify"," รับสลิปได้ ",[69,5408,5409],{},"5 แบบ"," — ผลลัพธ์ โควตา และแคช 24 ชม. เหมือนกันทุกแบบ\n(ส่งรูปเดิมซ้ำคนละแบบก็ยังได้ ",[142,5412,215],{}," ไม่หักโควตาซ้ำ)",[74,5415,5416,5431],{},[77,5417,5418],{},[80,5419,5420,5423,5426],{},[83,5421,5422],{},"มีอยู่ในมือ",[83,5424,5425],{},"ส่งอย่างไร",[83,5427,5428],{},[142,5429,5430],{},"Content-Type",[90,5432,5433,5456,5474,5492,5509],{},[80,5434,5435,5438,5444],{},[95,5436,5437],{},"ไฟล์รูป \u002F Buffer \u002F bytes",[95,5439,5440,5441],{},"ส่งเป็น body ตรง ๆ — เล็กและเร็วที่สุด ",[69,5442,5443],{},"แนะนำ",[95,5445,5446,5449,5450,2626,5453,1768],{},[142,5447,5448],{},"application\u002Foctet-stream"," (หรือ ",[142,5451,5452],{},"image\u002Fjpeg",[142,5454,5455],{},"image\u002Fpng",[80,5457,5458,5461,5469],{},[95,5459,5460],{},"ไฟล์จากฟอร์มอัปโหลด",[95,5462,5463,5464],{},"ส่งต่อเป็น multipart ฟิลด์ไฟล์ชื่อ ",[69,5465,5466],{},[142,5467,5468],{},"file",[95,5470,5471],{},[142,5472,5473],{},"multipart\u002Fform-data",[80,5475,5476,5479,5487],{},[95,5477,5478],{},"base64 หรือ data URL",[95,5480,5481,5482,5486],{},"ใส่ในฟิลด์ ",[69,5483,5484],{},[142,5485,514],{}," ของ JSON",[95,5488,5489],{},[142,5490,5491],{},"application\u002Fjson",[80,5493,5494,5497,5505],{},[95,5495,5496],{},"URL ของรูป (S3, CDN)",[95,5498,5481,5499,5504],{},[69,5500,5501],{},[142,5502,5503],{},"url"," ของ JSON — เราดาวน์โหลดให้",[95,5506,5507],{},[142,5508,5491],{},[80,5510,5511,5514,5521],{},[95,5512,5513],{},"ข้อความใน QR ของสลิป (ไม่มีรูป)",[95,5515,5481,5516,5486],{},[69,5517,5518],{},[142,5519,5520],{},"qr",[95,5522,5523],{},[142,5524,5491],{},[238,5526,5527,5817,6124,6391,6720,7091,8099],{},[147,5528,5531],{"className":149,"code":5529,"filename":5530,"language":151,"meta":152,"style":152},"API=\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n\n# 1) raw bytes\ncurl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n  -H \"Content-Type: application\u002Foctet-stream\" --data-binary \"@slip.jpg\"\n\n# 2) multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\ncurl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n  -F \"file=@slip.jpg\"\n\n# 3) JSON base64\nbase64 \u003C slip.jpg | tr -d '\\n' | sed 's\u002F.*\u002F{\"image\":\"&\"}\u002F' |\n  curl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n    -H \"Content-Type: application\u002Fjson\" --data-binary @-\n\n# 4) JSON url — ลิงก์ https ของรูปที่เปิดได้จากอินเทอร์เน็ต\ncurl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"url\":\"https:\u002F\u002Fcdn.example.com\u002Fslips\u002F1001.jpg\"}'\n\n# 5) JSON qr — ข้อความที่สแกนได้จาก QR บนสลิป\ncurl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"qr\":\"0046000600000101030140225202610075020019535816MIR5102TH9104A1B2\"}'\n","cURL",[142,5532,5533,5543,5547,5552,5584,5598,5602,5607,5631,5639,5643,5648,5682,5707,5720,5724,5729,5753,5761,5769,5773,5778,5802,5810],{"__ignoreMap":152},[156,5534,5535,5538,5540],{"class":158,"line":9},[156,5536,5537],{"class":165},"API",[156,5539,169],{"class":161},[156,5541,5542],{"class":172},"\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[156,5544,5545],{"class":158,"line":256},[156,5546,279],{"emptyLinePlaceholder":278},[156,5548,5549],{"class":158,"line":275},[156,5550,5551],{"class":252},"# 1) raw bytes\n",[156,5553,5554,5557,5560,5563,5565,5568,5570,5573,5576,5579,5581],{"class":158,"line":282},[156,5555,5556],{"class":290},"curl",[156,5558,5559],{"class":262}," -X",[156,5561,5562],{"class":172}," POST",[156,5564,1671],{"class":172},[156,5566,5567],{"class":165},"$API",[156,5569,1054],{"class":172},[156,5571,5572],{"class":262}," -H",[156,5574,5575],{"class":172}," \"Authorization: Bearer ",[156,5577,5578],{"class":165},"$SLIPBOLT_API_KEY",[156,5580,1054],{"class":172},[156,5582,5583],{"class":262}," \\\n",[156,5585,5586,5589,5592,5595],{"class":158,"line":303},[156,5587,5588],{"class":262},"  -H",[156,5590,5591],{"class":172}," \"Content-Type: application\u002Foctet-stream\"",[156,5593,5594],{"class":262}," --data-binary",[156,5596,5597],{"class":172}," \"@slip.jpg\"\n",[156,5599,5600],{"class":158,"line":324},[156,5601,279],{"emptyLinePlaceholder":278},[156,5603,5604],{"class":158,"line":378},[156,5605,5606],{"class":252},"# 2) multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n",[156,5608,5609,5611,5613,5615,5617,5619,5621,5623,5625,5627,5629],{"class":158,"line":395},[156,5610,5556],{"class":290},[156,5612,5559],{"class":262},[156,5614,5562],{"class":172},[156,5616,1671],{"class":172},[156,5618,5567],{"class":165},[156,5620,1054],{"class":172},[156,5622,5572],{"class":262},[156,5624,5575],{"class":172},[156,5626,5578],{"class":165},[156,5628,1054],{"class":172},[156,5630,5583],{"class":262},[156,5632,5633,5636],{"class":158,"line":411},[156,5634,5635],{"class":262},"  -F",[156,5637,5638],{"class":172}," \"file=@slip.jpg\"\n",[156,5640,5641],{"class":158,"line":13},[156,5642,279],{"emptyLinePlaceholder":278},[156,5644,5645],{"class":158,"line":432},[156,5646,5647],{"class":252},"# 3) JSON base64\n",[156,5649,5650,5653,5656,5659,5662,5665,5668,5671,5673,5676,5679],{"class":158,"line":438},[156,5651,5652],{"class":290},"base64",[156,5654,5655],{"class":161}," \u003C",[156,5657,5658],{"class":172}," slip.jpg",[156,5660,5661],{"class":161}," |",[156,5663,5664],{"class":290}," tr",[156,5666,5667],{"class":262}," -d",[156,5669,5670],{"class":172}," '\\n'",[156,5672,5661],{"class":161},[156,5674,5675],{"class":290}," sed",[156,5677,5678],{"class":172}," 's\u002F.*\u002F{\"image\":\"&\"}\u002F'",[156,5680,5681],{"class":161}," |\n",[156,5683,5684,5687,5689,5691,5693,5695,5697,5699,5701,5703,5705],{"class":158,"line":443},[156,5685,5686],{"class":290},"  curl",[156,5688,5559],{"class":262},[156,5690,5562],{"class":172},[156,5692,1671],{"class":172},[156,5694,5567],{"class":165},[156,5696,1054],{"class":172},[156,5698,5572],{"class":262},[156,5700,5575],{"class":172},[156,5702,5578],{"class":165},[156,5704,1054],{"class":172},[156,5706,5583],{"class":262},[156,5708,5709,5712,5715,5717],{"class":158,"line":487},[156,5710,5711],{"class":262},"    -H",[156,5713,5714],{"class":172}," \"Content-Type: application\u002Fjson\"",[156,5716,5594],{"class":262},[156,5718,5719],{"class":172}," @-\n",[156,5721,5722],{"class":158,"line":492},[156,5723,279],{"emptyLinePlaceholder":278},[156,5725,5726],{"class":158,"line":498},[156,5727,5728],{"class":252},"# 4) JSON url — ลิงก์ https ของรูปที่เปิดได้จากอินเทอร์เน็ต\n",[156,5730,5731,5733,5735,5737,5739,5741,5743,5745,5747,5749,5751],{"class":158,"line":549},[156,5732,5556],{"class":290},[156,5734,5559],{"class":262},[156,5736,5562],{"class":172},[156,5738,1671],{"class":172},[156,5740,5567],{"class":165},[156,5742,1054],{"class":172},[156,5744,5572],{"class":262},[156,5746,5575],{"class":172},[156,5748,5578],{"class":165},[156,5750,1054],{"class":172},[156,5752,5583],{"class":262},[156,5754,5755,5757,5759],{"class":158,"line":576},[156,5756,5588],{"class":262},[156,5758,5714],{"class":172},[156,5760,5583],{"class":262},[156,5762,5763,5766],{"class":158,"line":585},[156,5764,5765],{"class":262},"  -d",[156,5767,5768],{"class":172}," '{\"url\":\"https:\u002F\u002Fcdn.example.com\u002Fslips\u002F1001.jpg\"}'\n",[156,5770,5771],{"class":158,"line":18},[156,5772,279],{"emptyLinePlaceholder":278},[156,5774,5775],{"class":158,"line":619},[156,5776,5777],{"class":252},"# 5) JSON qr — ข้อความที่สแกนได้จาก QR บนสลิป\n",[156,5779,5780,5782,5784,5786,5788,5790,5792,5794,5796,5798,5800],{"class":158,"line":631},[156,5781,5556],{"class":290},[156,5783,5559],{"class":262},[156,5785,5562],{"class":172},[156,5787,1671],{"class":172},[156,5789,5567],{"class":165},[156,5791,1054],{"class":172},[156,5793,5572],{"class":262},[156,5795,5575],{"class":172},[156,5797,5578],{"class":165},[156,5799,1054],{"class":172},[156,5801,5583],{"class":262},[156,5803,5804,5806,5808],{"class":158,"line":659},[156,5805,5588],{"class":262},[156,5807,5714],{"class":172},[156,5809,5583],{"class":262},[156,5811,5812,5814],{"class":158,"line":665},[156,5813,5765],{"class":262},[156,5815,5816],{"class":172}," '{\"qr\":\"0046000600000101030140225202610075020019535816MIR5102TH9104A1B2\"}'\n",[147,5818,5820],{"className":242,"code":5819,"filename":244,"language":245,"meta":152,"style":152},"import { readFile } from 'node:fs\u002Fpromises';\n\nconst API = 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify';\nconst auth = { Authorization: `Bearer ${process.env.SLIPBOLT_API_KEY}` };\nconst bytes = await readFile('slip.jpg');\n\n\u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\nconst form = new FormData();\nform.append('file', new Blob([bytes]), 'slip.jpg');\nconst viaForm = await fetch(API, { method: 'POST', headers: auth, body: form });\n\n\u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\nconst viaJson = await fetch(API, {\n  method: 'POST',\n  headers: { ...auth, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({ image: bytes.toString('base64') }),\n});\n\nfor (const res of [viaForm, viaJson]) {\n  const body = await res.json();\n  console.log(res.status, body.data?.status ?? body.message);\n}\n",[142,5821,5822,5834,5838,5852,5883,5902,5906,5911,5927,5955,5980,5984,5989,6008,6017,6037,6064,6068,6072,6089,6105,6120],{"__ignoreMap":152},[156,5823,5824,5826,5828,5830,5832],{"class":158,"line":9},[156,5825,954],{"class":161},[156,5827,2280],{"class":165},[156,5829,2283],{"class":161},[156,5831,2286],{"class":172},[156,5833,272],{"class":165},[156,5835,5836],{"class":158,"line":256},[156,5837,279],{"emptyLinePlaceholder":278},[156,5839,5840,5842,5845,5847,5850],{"class":158,"line":275},[156,5841,259],{"class":161},[156,5843,5844],{"class":262}," API",[156,5846,266],{"class":161},[156,5848,5849],{"class":172}," 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify'",[156,5851,272],{"class":165},[156,5853,5854,5856,5859,5861,5864,5866,5869,5871,5874,5876,5878,5880],{"class":158,"line":282},[156,5855,259],{"class":161},[156,5857,5858],{"class":262}," auth",[156,5860,266],{"class":161},[156,5862,5863],{"class":165}," { Authorization: ",[156,5865,637],{"class":172},[156,5867,5868],{"class":165},"process",[156,5870,342],{"class":172},[156,5872,5873],{"class":165},"env",[156,5875,342],{"class":172},[156,5877,528],{"class":262},[156,5879,642],{"class":172},[156,5881,5882],{"class":165}," };\n",[156,5884,5885,5887,5890,5892,5894,5896,5898,5900],{"class":158,"line":303},[156,5886,259],{"class":161},[156,5888,5889],{"class":262}," bytes",[156,5891,266],{"class":161},[156,5893,600],{"class":161},[156,5895,2327],{"class":290},[156,5897,309],{"class":165},[156,5899,2332],{"class":172},[156,5901,375],{"class":165},[156,5903,5904],{"class":158,"line":324},[156,5905,279],{"emptyLinePlaceholder":278},[156,5907,5908],{"class":158,"line":378},[156,5909,5910],{"class":252},"\u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n",[156,5912,5913,5915,5918,5920,5922,5925],{"class":158,"line":395},[156,5914,259],{"class":161},[156,5916,5917],{"class":262}," form",[156,5919,266],{"class":161},[156,5921,465],{"class":161},[156,5923,5924],{"class":290}," FormData",[156,5926,2875],{"class":165},[156,5928,5929,5932,5935,5937,5940,5942,5945,5948,5951,5953],{"class":158,"line":411},[156,5930,5931],{"class":165},"form.",[156,5933,5934],{"class":290},"append",[156,5936,309],{"class":165},[156,5938,5939],{"class":172},"'file'",[156,5941,315],{"class":165},[156,5943,5944],{"class":161},"new",[156,5946,5947],{"class":290}," Blob",[156,5949,5950],{"class":165},"([bytes]), ",[156,5952,2332],{"class":172},[156,5954,375],{"class":165},[156,5956,5957,5959,5962,5964,5966,5968,5970,5972,5975,5977],{"class":158,"line":13},[156,5958,259],{"class":161},[156,5960,5961],{"class":262}," viaForm",[156,5963,266],{"class":161},[156,5965,600],{"class":161},[156,5967,603],{"class":290},[156,5969,309],{"class":165},[156,5971,5537],{"class":262},[156,5973,5974],{"class":165},", { method: ",[156,5976,625],{"class":172},[156,5978,5979],{"class":165},", headers: auth, body: form });\n",[156,5981,5982],{"class":158,"line":432},[156,5983,279],{"emptyLinePlaceholder":278},[156,5985,5986],{"class":158,"line":438},[156,5987,5988],{"class":252},"\u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n",[156,5990,5991,5993,5996,5998,6000,6002,6004,6006],{"class":158,"line":443},[156,5992,259],{"class":161},[156,5994,5995],{"class":262}," viaJson",[156,5997,266],{"class":161},[156,5999,600],{"class":161},[156,6001,603],{"class":290},[156,6003,309],{"class":165},[156,6005,5537],{"class":262},[156,6007,616],{"class":165},[156,6009,6010,6013,6015],{"class":158,"line":487},[156,6011,6012],{"class":165},"  method: ",[156,6014,625],{"class":172},[156,6016,628],{"class":165},[156,6018,6019,6022,6025,6028,6030,6032,6035],{"class":158,"line":492},[156,6020,6021],{"class":165},"  headers: { ",[156,6023,6024],{"class":161},"...",[156,6026,6027],{"class":165},"auth, ",[156,6029,647],{"class":172},[156,6031,650],{"class":165},[156,6033,6034],{"class":172},"'application\u002Fjson'",[156,6036,656],{"class":165},[156,6038,6039,6042,6045,6047,6050,6053,6056,6058,6061],{"class":158,"line":498},[156,6040,6041],{"class":165},"  body: ",[156,6043,6044],{"class":262},"JSON",[156,6046,342],{"class":165},[156,6048,6049],{"class":290},"stringify",[156,6051,6052],{"class":165},"({ image: bytes.",[156,6054,6055],{"class":290},"toString",[156,6057,309],{"class":165},[156,6059,6060],{"class":172},"'base64'",[156,6062,6063],{"class":165},") }),\n",[156,6065,6066],{"class":158,"line":549},[156,6067,3680],{"class":165},[156,6069,6070],{"class":158,"line":576},[156,6071,279],{"emptyLinePlaceholder":278},[156,6073,6074,6077,6079,6081,6083,6086],{"class":158,"line":585},[156,6075,6076],{"class":161},"for",[156,6078,453],{"class":165},[156,6080,259],{"class":161},[156,6082,2815],{"class":262},[156,6084,6085],{"class":161}," of",[156,6087,6088],{"class":165}," [viaForm, viaJson]) {\n",[156,6090,6091,6093,6095,6097,6099,6101,6103],{"class":158,"line":18},[156,6092,3172],{"class":161},[156,6094,350],{"class":262},[156,6096,266],{"class":161},[156,6098,600],{"class":161},[156,6100,877],{"class":165},[156,6102,880],{"class":290},[156,6104,2875],{"class":165},[156,6106,6107,6110,6112,6115,6117],{"class":158,"line":619},[156,6108,6109],{"class":165},"  console.",[156,6111,2342],{"class":290},[156,6113,6114],{"class":165},"(res.status, body.data?.status ",[156,6116,1685],{"class":161},[156,6118,6119],{"class":165}," body.message);\n",[156,6121,6122],{"class":158,"line":631},[156,6123,435],{"class":165},[147,6125,6127],{"className":939,"code":6126,"filename":941,"language":942,"meta":152,"style":152},"import base64\nimport os\n\nimport requests\n\nAPI = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\nauth = {\"Authorization\": f\"Bearer {os.environ['SLIPBOLT_API_KEY']}\"}\n\nwith open(\"slip.jpg\", \"rb\") as f:\n    data = f.read()\n\n# multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\nvia_form = requests.post(API, headers=auth, files={\"file\": (\"slip.jpg\", data)}, timeout=30)\n\n# JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\nvia_json = requests.post(API, headers=auth, json={\"image\": base64.b64encode(data).decode()}, timeout=30)\n\nfor res in (via_form, via_json):\n    body = res.json()\n    print(res.status_code, body[\"data\"][\"status\"] if res.ok else body[\"message\"])\n",[142,6128,6129,6136,6142,6146,6152,6156,6165,6197,6201,6221,6231,6235,6240,6286,6290,6295,6334,6338,6350,6359],{"__ignoreMap":152},[156,6130,6131,6133],{"class":158,"line":9},[156,6132,954],{"class":161},[156,6134,6135],{"class":165}," base64\n",[156,6137,6138,6140],{"class":158,"line":256},[156,6139,954],{"class":161},[156,6141,957],{"class":165},[156,6143,6144],{"class":158,"line":275},[156,6145,279],{"emptyLinePlaceholder":278},[156,6147,6148,6150],{"class":158,"line":282},[156,6149,954],{"class":161},[156,6151,975],{"class":165},[156,6153,6154],{"class":158,"line":303},[156,6155,279],{"emptyLinePlaceholder":278},[156,6157,6158,6160,6162],{"class":158,"line":324},[156,6159,5537],{"class":262},[156,6161,266],{"class":161},[156,6163,6164],{"class":172}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[156,6166,6167,6170,6172,6174,6176,6178,6180,6182,6184,6187,6189,6191,6193,6195],{"class":158,"line":378},[156,6168,6169],{"class":165},"auth ",[156,6171,169],{"class":161},[156,6173,1065],{"class":165},[156,6175,1329],{"class":172},[156,6177,650],{"class":165},[156,6179,1334],{"class":161},[156,6181,1337],{"class":172},[156,6183,1057],{"class":262},[156,6185,6186],{"class":165},"os.environ[",[156,6188,1871],{"class":172},[156,6190,4307],{"class":165},[156,6192,1062],{"class":262},[156,6194,1054],{"class":172},[156,6196,435],{"class":165},[156,6198,6199],{"class":158,"line":395},[156,6200,279],{"emptyLinePlaceholder":278},[156,6202,6203,6205,6207,6209,6211,6213,6215,6217,6219],{"class":158,"line":411},[156,6204,2371],{"class":161},[156,6206,2374],{"class":262},[156,6208,309],{"class":165},[156,6210,2379],{"class":172},[156,6212,315],{"class":165},[156,6214,2384],{"class":172},[156,6216,459],{"class":165},[156,6218,2389],{"class":161},[156,6220,2392],{"class":165},[156,6222,6223,6226,6228],{"class":158,"line":13},[156,6224,6225],{"class":165},"    data ",[156,6227,169],{"class":161},[156,6229,6230],{"class":165}," f.read()\n",[156,6232,6233],{"class":158,"line":432},[156,6234,279],{"emptyLinePlaceholder":278},[156,6236,6237],{"class":158,"line":438},[156,6238,6239],{"class":252},"# multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n",[156,6241,6242,6245,6247,6250,6252,6254,6257,6259,6261,6264,6266,6268,6270,6273,6275,6278,6280,6282,6284],{"class":158,"line":443},[156,6243,6244],{"class":165},"via_form ",[156,6246,169],{"class":161},[156,6248,6249],{"class":165}," requests.post(",[156,6251,5537],{"class":262},[156,6253,315],{"class":165},[156,6255,6256],{"class":312},"headers",[156,6258,169],{"class":161},[156,6260,6027],{"class":165},[156,6262,6263],{"class":312},"files",[156,6265,169],{"class":161},[156,6267,1057],{"class":165},[156,6269,2673],{"class":172},[156,6271,6272],{"class":165},": (",[156,6274,2379],{"class":172},[156,6276,6277],{"class":165},", data)}, ",[156,6279,671],{"class":312},[156,6281,169],{"class":161},[156,6283,1379],{"class":262},[156,6285,1718],{"class":165},[156,6287,6288],{"class":158,"line":487},[156,6289,279],{"emptyLinePlaceholder":278},[156,6291,6292],{"class":158,"line":492},[156,6293,6294],{"class":252},"# JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n",[156,6296,6297,6300,6302,6304,6306,6308,6310,6312,6314,6316,6318,6320,6323,6326,6328,6330,6332],{"class":158,"line":498},[156,6298,6299],{"class":165},"via_json ",[156,6301,169],{"class":161},[156,6303,6249],{"class":165},[156,6305,5537],{"class":262},[156,6307,315],{"class":165},[156,6309,6256],{"class":312},[156,6311,169],{"class":161},[156,6313,6027],{"class":165},[156,6315,880],{"class":312},[156,6317,169],{"class":161},[156,6319,1057],{"class":165},[156,6321,6322],{"class":172},"\"image\"",[156,6324,6325],{"class":165},": base64.b64encode(data).decode()}, ",[156,6327,671],{"class":312},[156,6329,169],{"class":161},[156,6331,1379],{"class":262},[156,6333,1718],{"class":165},[156,6335,6336],{"class":158,"line":549},[156,6337,279],{"emptyLinePlaceholder":278},[156,6339,6340,6342,6345,6347],{"class":158,"line":576},[156,6341,6076],{"class":161},[156,6343,6344],{"class":165}," res ",[156,6346,1256],{"class":161},[156,6348,6349],{"class":165}," (via_form, via_json):\n",[156,6351,6352,6355,6357],{"class":158,"line":585},[156,6353,6354],{"class":165},"    body ",[156,6356,169],{"class":161},[156,6358,1519],{"class":165},[156,6360,6361,6364,6367,6369,6372,6374,6376,6378,6381,6384,6386,6389],{"class":158,"line":18},[156,6362,6363],{"class":262},"    print",[156,6365,6366],{"class":165},"(res.status_code, body[",[156,6368,1569],{"class":172},[156,6370,6371],{"class":165},"][",[156,6373,2413],{"class":172},[156,6375,1682],{"class":165},[156,6377,4447],{"class":161},[156,6379,6380],{"class":165}," res.ok ",[156,6382,6383],{"class":161},"else",[156,6385,1566],{"class":165},[156,6387,6388],{"class":172},"\"message\"",[156,6390,2427],{"class":165},[147,6392,6394],{"className":1578,"code":6393,"filename":1580,"language":1581,"meta":152,"style":152},"\u003C?php\nfunction slipbolt_post(array $headers, $payload): array\n{\n    $ch = curl_init('https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify');\n    curl_setopt_array($ch, [\n        CURLOPT_POST           => true,\n        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . getenv('SLIPBOLT_API_KEY'), ...$headers],\n        CURLOPT_POSTFIELDS     => $payload,\n        CURLOPT_RETURNTRANSFER => true,\n        CURLOPT_TIMEOUT        => 30,\n    ]);\n    $body = json_decode(curl_exec($ch), true) ?? [];\n    return [curl_getinfo($ch, CURLINFO_HTTP_CODE), $body];\n}\n\n\u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n$viaForm = slipbolt_post([], ['file' => new CURLFile('slip.jpg')]);\n\n\u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n$viaJson = slipbolt_post(\n    ['Content-Type: application\u002Fjson'],\n    json_encode(['image' => base64_encode(file_get_contents('slip.jpg'))])\n);\n\nforeach ([$viaForm, $viaJson] as [$status, $body]) {\n    echo $status, ' ', $body['data']['status'] ?? $body['message'], \"\\n\";\n}\n",[142,6395,6396,6402,6421,6425,6440,6447,6458,6486,6496,6507,6518,6523,6548,6564,6568,6572,6576,6604,6608,6612,6623,6634,6660,6664,6668,6681,6716],{"__ignoreMap":152},[156,6397,6398,6400],{"class":158,"line":9},[156,6399,1588],{"class":161},[156,6401,1591],{"class":262},[156,6403,6404,6406,6409,6411,6414,6417,6419],{"class":158,"line":256},[156,6405,1745],{"class":161},[156,6407,6408],{"class":290}," slipbolt_post",[156,6410,309],{"class":165},[156,6412,6413],{"class":161},"array",[156,6415,6416],{"class":165}," $headers, $payload)",[156,6418,1771],{"class":161},[156,6420,1774],{"class":161},[156,6422,6423],{"class":158,"line":275},[156,6424,1616],{"class":165},[156,6426,6427,6430,6432,6434,6436,6438],{"class":158,"line":282},[156,6428,6429],{"class":165},"    $ch ",[156,6431,169],{"class":161},[156,6433,1817],{"class":262},[156,6435,309],{"class":165},[156,6437,1822],{"class":172},[156,6439,375],{"class":165},[156,6441,6442,6445],{"class":158,"line":303},[156,6443,6444],{"class":262},"    curl_setopt_array",[156,6446,1832],{"class":165},[156,6448,6449,6452,6454,6456],{"class":158,"line":324},[156,6450,6451],{"class":262},"        CURLOPT_POST",[156,6453,1840],{"class":161},[156,6455,1843],{"class":262},[156,6457,628],{"class":165},[156,6459,6460,6463,6465,6468,6471,6473,6475,6477,6479,6481,6483],{"class":158,"line":378},[156,6461,6462],{"class":262},"        CURLOPT_HTTPHEADER",[156,6464,1853],{"class":161},[156,6466,6467],{"class":165}," [",[156,6469,6470],{"class":172},"'Authorization: Bearer '",[156,6472,1674],{"class":161},[156,6474,1866],{"class":262},[156,6476,309],{"class":165},[156,6478,1871],{"class":172},[156,6480,4711],{"class":165},[156,6482,6024],{"class":161},[156,6484,6485],{"class":165},"$headers],\n",[156,6487,6488,6491,6493],{"class":158,"line":395},[156,6489,6490],{"class":262},"        CURLOPT_POSTFIELDS",[156,6492,1853],{"class":161},[156,6494,6495],{"class":165}," $payload,\n",[156,6497,6498,6501,6503,6505],{"class":158,"line":411},[156,6499,6500],{"class":262},"        CURLOPT_RETURNTRANSFER",[156,6502,1903],{"class":161},[156,6504,1843],{"class":262},[156,6506,628],{"class":165},[156,6508,6509,6512,6514,6516],{"class":158,"line":13},[156,6510,6511],{"class":262},"        CURLOPT_TIMEOUT",[156,6513,1915],{"class":161},[156,6515,1918],{"class":262},[156,6517,628],{"class":165},[156,6519,6520],{"class":158,"line":432},[156,6521,6522],{"class":165},"    ]);\n",[156,6524,6525,6528,6530,6532,6534,6537,6540,6542,6544,6546],{"class":158,"line":438},[156,6526,6527],{"class":165},"    $body ",[156,6529,169],{"class":161},[156,6531,2192],{"class":262},[156,6533,309],{"class":165},[156,6535,6536],{"class":262},"curl_exec",[156,6538,6539],{"class":165},"($ch), ",[156,6541,2198],{"class":262},[156,6543,459],{"class":165},[156,6545,1685],{"class":161},[156,6547,2205],{"class":165},[156,6549,6550,6552,6554,6557,6559,6561],{"class":158,"line":443},[156,6551,921],{"class":161},[156,6553,6467],{"class":165},[156,6555,6556],{"class":262},"curl_getinfo",[156,6558,2053],{"class":165},[156,6560,2056],{"class":262},[156,6562,6563],{"class":165},"), $body];\n",[156,6565,6566],{"class":158,"line":487},[156,6567,435],{"class":165},[156,6569,6570],{"class":158,"line":492},[156,6571,279],{"emptyLinePlaceholder":278},[156,6573,6574],{"class":158,"line":498},[156,6575,5910],{"class":252},[156,6577,6578,6581,6583,6585,6588,6590,6592,6594,6597,6599,6601],{"class":158,"line":549},[156,6579,6580],{"class":165},"$viaForm ",[156,6582,169],{"class":161},[156,6584,6408],{"class":290},[156,6586,6587],{"class":165},"([], [",[156,6589,5939],{"class":172},[156,6591,1903],{"class":161},[156,6593,465],{"class":161},[156,6595,6596],{"class":262}," CURLFile",[156,6598,309],{"class":165},[156,6600,2332],{"class":172},[156,6602,6603],{"class":165},")]);\n",[156,6605,6606],{"class":158,"line":576},[156,6607,279],{"emptyLinePlaceholder":278},[156,6609,6610],{"class":158,"line":585},[156,6611,5988],{"class":252},[156,6613,6614,6617,6619,6621],{"class":158,"line":18},[156,6615,6616],{"class":165},"$viaJson ",[156,6618,169],{"class":161},[156,6620,6408],{"class":290},[156,6622,1046],{"class":165},[156,6624,6625,6628,6631],{"class":158,"line":619},[156,6626,6627],{"class":165},"    [",[156,6629,6630],{"class":172},"'Content-Type: application\u002Fjson'",[156,6632,6633],{"class":165},"],\n",[156,6635,6636,6639,6641,6644,6646,6649,6651,6653,6655,6657],{"class":158,"line":631},[156,6637,6638],{"class":262},"    json_encode",[156,6640,4567],{"class":165},[156,6642,6643],{"class":172},"'image'",[156,6645,1903],{"class":161},[156,6647,6648],{"class":262}," base64_encode",[156,6650,309],{"class":165},[156,6652,2471],{"class":262},[156,6654,309],{"class":165},[156,6656,2332],{"class":172},[156,6658,6659],{"class":165},"))])\n",[156,6661,6662],{"class":158,"line":659},[156,6663,375],{"class":165},[156,6665,6666],{"class":158,"line":665},[156,6667,279],{"emptyLinePlaceholder":278},[156,6669,6670,6673,6676,6678],{"class":158,"line":22},[156,6671,6672],{"class":161},"foreach",[156,6674,6675],{"class":165}," ([$viaForm, $viaJson] ",[156,6677,2389],{"class":161},[156,6679,6680],{"class":165}," [$status, $body]) {\n",[156,6682,6683,6685,6687,6689,6692,6694,6696,6698,6700,6702,6704,6706,6708,6710,6712,6714],{"class":158,"line":687},[156,6684,4561],{"class":262},[156,6686,1637],{"class":165},[156,6688,2494],{"class":172},[156,6690,6691],{"class":165},", $body[",[156,6693,2248],{"class":172},[156,6695,6371],{"class":165},[156,6697,2488],{"class":172},[156,6699,1682],{"class":165},[156,6701,1685],{"class":161},[156,6703,1688],{"class":165},[156,6705,1100],{"class":172},[156,6707,2491],{"class":165},[156,6709,1054],{"class":172},[156,6711,2516],{"class":262},[156,6713,1054],{"class":172},[156,6715,272],{"class":165},[156,6717,6718],{"class":158,"line":699},[156,6719,435],{"class":165},[147,6721,6726],{"className":6722,"code":6723,"filename":6724,"language":6725,"meta":152,"style":152},"language-go shiki shiki-themes github-light github-dark","package main\n\nimport (\n    \"bytes\"\n    \"encoding\u002Fbase64\"\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"io\"\n    \"mime\u002Fmultipart\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"time\"\n)\n\nfunc main() {\n    api := \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n    key := os.Getenv(\"SLIPBOLT_API_KEY\")\n    data, err := os.ReadFile(\"slip.jpg\")\n    if err != nil {\n        panic(err)\n    }\n    client := &http.Client{Timeout: 30 * time.Second}\n\n    \u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n    var form bytes.Buffer\n    w := multipart.NewWriter(&form)\n    part, err := w.CreateFormFile(\"file\", \"slip.jpg\")\n    if err != nil {\n        panic(err)\n    }\n    if _, err = part.Write(data); err != nil {\n        panic(err)\n    }\n    if err = w.Close(); err != nil {\n        panic(err)\n    }\n    viaForm := post(client, api, key, w.FormDataContentType(), form.Bytes())\n\n    \u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n    payload, _ := json.Marshal(map[string]string{\"image\": base64.StdEncoding.EncodeToString(data)})\n    viaJSON := post(client, api, key, \"application\u002Fjson\", payload)\n\n    for _, res := range []*http.Response{viaForm, viaJSON} {\n        show(res)\n    }\n}\n\nfunc post(client *http.Client, api, key, contentType string, body []byte) *http.Response {\n    req, err := http.NewRequest(http.MethodPost, api, bytes.NewReader(body))\n    if err != nil {\n        panic(err)\n    }\n    req.Header.Set(\"Authorization\", \"Bearer \"+key)\n    req.Header.Set(\"Content-Type\", contentType)\n    res, err := client.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    return res\n}\n\nfunc show(res *http.Response) {\n    defer res.Body.Close()\n    raw, _ := io.ReadAll(res.Body)\n    var body struct {\n        Data    struct{ Status string } `json:\"data\"`\n        Message string                   `json:\"message\"`\n    }\n    _ = json.Unmarshal(raw, &body)\n    status := body.Data.Status\n    if status == \"\" {\n        status = body.Message\n    }\n    fmt.Println(res.StatusCode, status)\n}\n","Go","go",[142,6727,6728,6733,6737,6742,6747,6752,6757,6762,6767,6772,6777,6782,6787,6791,6795,6800,6805,6810,6815,6820,6825,6829,6834,6838,6843,6848,6853,6858,6862,6866,6870,6875,6879,6883,6888,6892,6896,6901,6905,6910,6915,6920,6924,6929,6934,6938,6942,6946,6951,6956,6960,6964,6968,6973,6978,6983,6987,6991,6995,7000,7005,7010,7016,7022,7028,7034,7040,7046,7051,7057,7063,7069,7075,7080,7086],{"__ignoreMap":152},[156,6729,6730],{"class":158,"line":9},[156,6731,6732],{},"package main\n",[156,6734,6735],{"class":158,"line":256},[156,6736,279],{"emptyLinePlaceholder":278},[156,6738,6739],{"class":158,"line":275},[156,6740,6741],{},"import (\n",[156,6743,6744],{"class":158,"line":282},[156,6745,6746],{},"    \"bytes\"\n",[156,6748,6749],{"class":158,"line":303},[156,6750,6751],{},"    \"encoding\u002Fbase64\"\n",[156,6753,6754],{"class":158,"line":324},[156,6755,6756],{},"    \"encoding\u002Fjson\"\n",[156,6758,6759],{"class":158,"line":378},[156,6760,6761],{},"    \"fmt\"\n",[156,6763,6764],{"class":158,"line":395},[156,6765,6766],{},"    \"io\"\n",[156,6768,6769],{"class":158,"line":411},[156,6770,6771],{},"    \"mime\u002Fmultipart\"\n",[156,6773,6774],{"class":158,"line":13},[156,6775,6776],{},"    \"net\u002Fhttp\"\n",[156,6778,6779],{"class":158,"line":432},[156,6780,6781],{},"    \"os\"\n",[156,6783,6784],{"class":158,"line":438},[156,6785,6786],{},"    \"time\"\n",[156,6788,6789],{"class":158,"line":443},[156,6790,1718],{},[156,6792,6793],{"class":158,"line":487},[156,6794,279],{"emptyLinePlaceholder":278},[156,6796,6797],{"class":158,"line":492},[156,6798,6799],{},"func main() {\n",[156,6801,6802],{"class":158,"line":498},[156,6803,6804],{},"    api := \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[156,6806,6807],{"class":158,"line":549},[156,6808,6809],{},"    key := os.Getenv(\"SLIPBOLT_API_KEY\")\n",[156,6811,6812],{"class":158,"line":576},[156,6813,6814],{},"    data, err := os.ReadFile(\"slip.jpg\")\n",[156,6816,6817],{"class":158,"line":585},[156,6818,6819],{},"    if err != nil {\n",[156,6821,6822],{"class":158,"line":18},[156,6823,6824],{},"        panic(err)\n",[156,6826,6827],{"class":158,"line":619},[156,6828,758],{},[156,6830,6831],{"class":158,"line":631},[156,6832,6833],{},"    client := &http.Client{Timeout: 30 * time.Second}\n",[156,6835,6836],{"class":158,"line":659},[156,6837,279],{"emptyLinePlaceholder":278},[156,6839,6840],{"class":158,"line":665},[156,6841,6842],{},"    \u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n",[156,6844,6845],{"class":158,"line":22},[156,6846,6847],{},"    var form bytes.Buffer\n",[156,6849,6850],{"class":158,"line":687},[156,6851,6852],{},"    w := multipart.NewWriter(&form)\n",[156,6854,6855],{"class":158,"line":699},[156,6856,6857],{},"    part, err := w.CreateFormFile(\"file\", \"slip.jpg\")\n",[156,6859,6860],{"class":158,"line":723},[156,6861,6819],{},[156,6863,6864],{"class":158,"line":748},[156,6865,6824],{},[156,6867,6868],{"class":158,"line":26},[156,6869,758],{},[156,6871,6872],{"class":158,"line":761},[156,6873,6874],{},"    if _, err = part.Write(data); err != nil {\n",[156,6876,6877],{"class":158,"line":766},[156,6878,6824],{},[156,6880,6881],{"class":158,"line":805},[156,6882,758],{},[156,6884,6885],{"class":158,"line":849},[156,6886,6887],{},"    if err = w.Close(); err != nil {\n",[156,6889,6890],{"class":158,"line":30},[156,6891,6824],{},[156,6893,6894],{"class":158,"line":860},[156,6895,758],{},[156,6897,6898],{"class":158,"line":865},[156,6899,6900],{},"    viaForm := post(client, api, key, w.FormDataContentType(), form.Bytes())\n",[156,6902,6903],{"class":158,"line":896},[156,6904,279],{"emptyLinePlaceholder":278},[156,6906,6907],{"class":158,"line":918},[156,6908,6909],{},"    \u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n",[156,6911,6912],{"class":158,"line":35},[156,6913,6914],{},"    payload, _ := json.Marshal(map[string]string{\"image\": base64.StdEncoding.EncodeToString(data)})\n",[156,6916,6917],{"class":158,"line":934},[156,6918,6919],{},"    viaJSON := post(client, api, key, \"application\u002Fjson\", payload)\n",[156,6921,6922],{"class":158,"line":1504},[156,6923,279],{"emptyLinePlaceholder":278},[156,6925,6926],{"class":158,"line":1511},[156,6927,6928],{},"    for _, res := range []*http.Response{viaForm, viaJSON} {\n",[156,6930,6931],{"class":158,"line":1522},[156,6932,6933],{},"        show(res)\n",[156,6935,6936],{"class":158,"line":39},[156,6937,758],{},[156,6939,6940],{"class":158,"line":1541},[156,6941,435],{},[156,6943,6944],{"class":158,"line":1551},[156,6945,279],{"emptyLinePlaceholder":278},[156,6947,6948],{"class":158,"line":1560},[156,6949,6950],{},"func post(client *http.Client, api, key, contentType string, body []byte) *http.Response {\n",[156,6952,6953],{"class":158,"line":2208},[156,6954,6955],{},"    req, err := http.NewRequest(http.MethodPost, api, bytes.NewReader(body))\n",[156,6957,6958],{"class":158,"line":2224},[156,6959,6819],{},[156,6961,6962],{"class":158,"line":2236},[156,6963,6824],{},[156,6965,6966],{"class":158,"line":2241},[156,6967,758],{},[156,6969,6970],{"class":158,"line":2256},[156,6971,6972],{},"    req.Header.Set(\"Authorization\", \"Bearer \"+key)\n",[156,6974,6975],{"class":158,"line":2261},[156,6976,6977],{},"    req.Header.Set(\"Content-Type\", contentType)\n",[156,6979,6980],{"class":158,"line":3657},[156,6981,6982],{},"    res, err := client.Do(req)\n",[156,6984,6985],{"class":158,"line":3677},[156,6986,6819],{},[156,6988,6989],{"class":158,"line":3683},[156,6990,6824],{},[156,6992,6993],{"class":158,"line":3688},[156,6994,758],{},[156,6996,6997],{"class":158,"line":4461},[156,6998,6999],{},"    return res\n",[156,7001,7003],{"class":158,"line":7002},60,[156,7004,435],{},[156,7006,7008],{"class":158,"line":7007},61,[156,7009,279],{"emptyLinePlaceholder":278},[156,7011,7013],{"class":158,"line":7012},62,[156,7014,7015],{},"func show(res *http.Response) {\n",[156,7017,7019],{"class":158,"line":7018},63,[156,7020,7021],{},"    defer res.Body.Close()\n",[156,7023,7025],{"class":158,"line":7024},64,[156,7026,7027],{},"    raw, _ := io.ReadAll(res.Body)\n",[156,7029,7031],{"class":158,"line":7030},65,[156,7032,7033],{},"    var body struct {\n",[156,7035,7037],{"class":158,"line":7036},66,[156,7038,7039],{},"        Data    struct{ Status string } `json:\"data\"`\n",[156,7041,7043],{"class":158,"line":7042},67,[156,7044,7045],{},"        Message string                   `json:\"message\"`\n",[156,7047,7049],{"class":158,"line":7048},68,[156,7050,758],{},[156,7052,7054],{"class":158,"line":7053},69,[156,7055,7056],{},"    _ = json.Unmarshal(raw, &body)\n",[156,7058,7060],{"class":158,"line":7059},70,[156,7061,7062],{},"    status := body.Data.Status\n",[156,7064,7066],{"class":158,"line":7065},71,[156,7067,7068],{},"    if status == \"\" {\n",[156,7070,7072],{"class":158,"line":7071},72,[156,7073,7074],{},"        status = body.Message\n",[156,7076,7078],{"class":158,"line":7077},73,[156,7079,758],{},[156,7081,7083],{"class":158,"line":7082},74,[156,7084,7085],{},"    fmt.Println(res.StatusCode, status)\n",[156,7087,7089],{"class":158,"line":7088},75,[156,7090,435],{},[147,7092,7097],{"className":7093,"code":7094,"filename":7095,"language":7096,"meta":152,"style":152},"language-java shiki shiki-themes github-light github-dark","import java.net.URI;\nimport java.net.http.*;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.*;\nimport java.time.Duration;\nimport java.util.Base64;\n\nclass VerifyFormats {\n    public static void main(String[] args) throws Exception {\n        String api = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\";\n        String key = System.getenv(\"SLIPBOLT_API_KEY\");\n        byte[] data = Files.readAllBytes(Path.of(\"slip.jpg\"));\n        HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();\n\n        \u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n        show(send(client, api, key, \"multipart\u002Fform-data; boundary=slipbolt\", multipart(data)));\n\n        \u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n        String json = \"{\\\"image\\\":\\\"\" + Base64.getEncoder().encodeToString(data) + \"\\\"}\";\n        show(send(client, api, key, \"application\u002Fjson\", json.getBytes(StandardCharsets.UTF_8)));\n    }\n\n    static HttpResponse\u003CString> send(HttpClient client, String api, String key, String type, byte[] body) throws Exception {\n        HttpRequest req = HttpRequest.newBuilder(URI.create(api))\n                .timeout(Duration.ofSeconds(30))\n                .header(\"Authorization\", \"Bearer \" + key)\n                .header(\"Content-Type\", type)\n                .POST(HttpRequest.BodyPublishers.ofByteArray(body))\n                .build();\n        return client.send(req, HttpResponse.BodyHandlers.ofString());\n    }\n\n    static byte[] multipart(byte[] data) throws Exception {\n        String head = \"--slipbolt\\r\\nContent-Disposition: form-data; name=\\\"file\\\"; filename=\\\"slip.jpg\\\"\\r\\nContent-Type: image\u002Fjpeg\\r\\n\\r\\n\";\n        String tail = \"\\r\\n--slipbolt--\\r\\n\";\n        byte[] h = head.getBytes(StandardCharsets.UTF_8);\n        byte[] t = tail.getBytes(StandardCharsets.UTF_8);\n        byte[] out = new byte[h.length + data.length + t.length];\n        System.arraycopy(h, 0, out, 0, h.length);\n        System.arraycopy(data, 0, out, h.length, data.length);\n        System.arraycopy(t, 0, out, h.length + data.length, t.length);\n        return out;\n    }\n\n    static void show(HttpResponse\u003CString> res) {\n        String body = res.body();\n        String status = jsonString(body, \"status\");\n        if (status.isEmpty()) status = jsonString(body, \"message\");\n        System.out.println(res.statusCode() + \" \" + status);\n    }\n\n    static String jsonString(String json, String key) {\n        int i = json.indexOf(\"\\\"\" + key + \"\\\"\");\n        if (i \u003C 0) return \"\";\n        int q1 = json.indexOf('\"', json.indexOf(':', i) + 1);\n        int q2 = json.indexOf('\"', q1 + 1);\n        return q1 \u003C 0 || q2 \u003C 0 ? \"\" : json.substring(q1 + 1, q2);\n    }\n}\n","Java","java",[142,7098,7099,7106,7117,7124,7135,7142,7149,7153,7162,7194,7206,7224,7252,7288,7292,7297,7321,7325,7330,7381,7403,7407,7411,7463,7484,7501,7522,7535,7551,7559,7576,7580,7584,7610,7653,7673,7690,7706,7732,7753,7767,7786,7793,7797,7801,7821,7834,7851,7874,7901,7905,7909,7930,7969,7988,8024,8050,8091,8095],{"__ignoreMap":152},[156,7100,7101,7103],{"class":158,"line":9},[156,7102,954],{"class":161},[156,7104,7105],{"class":165}," java.net.URI;\n",[156,7107,7108,7110,7113,7115],{"class":158,"line":256},[156,7109,954],{"class":161},[156,7111,7112],{"class":165}," java.net.http.",[156,7114,841],{"class":262},[156,7116,272],{"class":165},[156,7118,7119,7121],{"class":158,"line":275},[156,7120,954],{"class":161},[156,7122,7123],{"class":165}," java.nio.charset.StandardCharsets;\n",[156,7125,7126,7128,7131,7133],{"class":158,"line":282},[156,7127,954],{"class":161},[156,7129,7130],{"class":165}," java.nio.file.",[156,7132,841],{"class":262},[156,7134,272],{"class":165},[156,7136,7137,7139],{"class":158,"line":303},[156,7138,954],{"class":161},[156,7140,7141],{"class":165}," java.time.Duration;\n",[156,7143,7144,7146],{"class":158,"line":324},[156,7145,954],{"class":161},[156,7147,7148],{"class":165}," java.util.Base64;\n",[156,7150,7151],{"class":158,"line":378},[156,7152,279],{"emptyLinePlaceholder":278},[156,7154,7155,7157,7160],{"class":158,"line":395},[156,7156,1001],{"class":161},[156,7158,7159],{"class":290}," VerifyFormats",[156,7161,300],{"class":165},[156,7163,7164,7166,7169,7172,7175,7177,7180,7183,7186,7188,7191],{"class":158,"line":411},[156,7165,1621],{"class":161},[156,7167,7168],{"class":161}," static",[156,7170,7171],{"class":161}," void",[156,7173,7174],{"class":290}," main",[156,7176,309],{"class":165},[156,7178,7179],{"class":161},"String",[156,7181,7182],{"class":165},"[] ",[156,7184,7185],{"class":312},"args",[156,7187,459],{"class":165},[156,7189,7190],{"class":161},"throws",[156,7192,7193],{"class":165}," Exception {\n",[156,7195,7196,7199,7201,7204],{"class":158,"line":13},[156,7197,7198],{"class":165},"        String api ",[156,7200,169],{"class":161},[156,7202,7203],{"class":172}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"",[156,7205,272],{"class":165},[156,7207,7208,7211,7213,7216,7218,7220,7222],{"class":158,"line":432},[156,7209,7210],{"class":165},"        String key ",[156,7212,169],{"class":161},[156,7214,7215],{"class":165}," System.",[156,7217,4703],{"class":290},[156,7219,309],{"class":165},[156,7221,1243],{"class":172},[156,7223,375],{"class":165},[156,7225,7226,7229,7232,7234,7237,7240,7243,7246,7248,7250],{"class":158,"line":438},[156,7227,7228],{"class":161},"        byte",[156,7230,7231],{"class":165},"[] data ",[156,7233,169],{"class":161},[156,7235,7236],{"class":165}," Files.",[156,7238,7239],{"class":290},"readAllBytes",[156,7241,7242],{"class":165},"(Path.",[156,7244,7245],{"class":290},"of",[156,7247,309],{"class":165},[156,7249,2379],{"class":172},[156,7251,2001],{"class":165},[156,7253,7254,7257,7259,7262,7265,7267,7270,7273,7276,7278,7280,7283,7286],{"class":158,"line":443},[156,7255,7256],{"class":165},"        HttpClient client ",[156,7258,169],{"class":161},[156,7260,7261],{"class":165}," HttpClient.",[156,7263,7264],{"class":290},"newBuilder",[156,7266,883],{"class":165},[156,7268,7269],{"class":290},"connectTimeout",[156,7271,7272],{"class":165},"(Duration.",[156,7274,7275],{"class":290},"ofSeconds",[156,7277,309],{"class":165},[156,7279,1379],{"class":262},[156,7281,7282],{"class":165},")).",[156,7284,7285],{"class":290},"build",[156,7287,2875],{"class":165},[156,7289,7290],{"class":158,"line":487},[156,7291,279],{"emptyLinePlaceholder":278},[156,7293,7294],{"class":158,"line":492},[156,7295,7296],{"class":252},"        \u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\n",[156,7298,7299,7302,7304,7307,7310,7313,7315,7318],{"class":158,"line":498},[156,7300,7301],{"class":290},"        show",[156,7303,309],{"class":165},[156,7305,7306],{"class":290},"send",[156,7308,7309],{"class":165},"(client, api, key, ",[156,7311,7312],{"class":172},"\"multipart\u002Fform-data; boundary=slipbolt\"",[156,7314,315],{"class":165},[156,7316,7317],{"class":290},"multipart",[156,7319,7320],{"class":165},"(data)));\n",[156,7322,7323],{"class":158,"line":549},[156,7324,279],{"emptyLinePlaceholder":278},[156,7326,7327],{"class":158,"line":576},[156,7328,7329],{"class":252},"        \u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\n",[156,7331,7332,7335,7337,7340,7343,7345,7347,7349,7351,7353,7356,7359,7362,7364,7367,7370,7372,7374,7376,7379],{"class":158,"line":585},[156,7333,7334],{"class":165},"        String json ",[156,7336,169],{"class":161},[156,7338,7339],{"class":172}," \"{",[156,7341,7342],{"class":262},"\\\"",[156,7344,514],{"class":172},[156,7346,7342],{"class":262},[156,7348,1771],{"class":172},[156,7350,7342],{"class":262},[156,7352,1054],{"class":172},[156,7354,7355],{"class":161}," +",[156,7357,7358],{"class":165}," Base64.",[156,7360,7361],{"class":290},"getEncoder",[156,7363,883],{"class":165},[156,7365,7366],{"class":290},"encodeToString",[156,7368,7369],{"class":165},"(data) ",[156,7371,1265],{"class":161},[156,7373,1671],{"class":172},[156,7375,7342],{"class":262},[156,7377,7378],{"class":172},"}\"",[156,7380,272],{"class":165},[156,7382,7383,7385,7387,7389,7391,7394,7397,7400],{"class":158,"line":18},[156,7384,7301],{"class":290},[156,7386,309],{"class":165},[156,7388,7306],{"class":290},[156,7390,7309],{"class":165},[156,7392,7393],{"class":172},"\"application\u002Fjson\"",[156,7395,7396],{"class":165},", json.",[156,7398,7399],{"class":290},"getBytes",[156,7401,7402],{"class":165},"(StandardCharsets.UTF_8)));\n",[156,7404,7405],{"class":158,"line":619},[156,7406,758],{"class":165},[156,7408,7409],{"class":158,"line":631},[156,7410,279],{"emptyLinePlaceholder":278},[156,7412,7413,7416,7419,7421,7424,7426,7429,7432,7435,7438,7440,7443,7445,7448,7450,7453,7455,7457,7459,7461],{"class":158,"line":659},[156,7414,7415],{"class":161},"    static",[156,7417,7418],{"class":165}," HttpResponse\u003C",[156,7420,7179],{"class":161},[156,7422,7423],{"class":165},"> ",[156,7425,7306],{"class":290},[156,7427,7428],{"class":165},"(HttpClient ",[156,7430,7431],{"class":312},"client",[156,7433,7434],{"class":165},", String ",[156,7436,7437],{"class":312},"api",[156,7439,7434],{"class":165},[156,7441,7442],{"class":312},"key",[156,7444,7434],{"class":165},[156,7446,7447],{"class":312},"type",[156,7449,315],{"class":165},[156,7451,7452],{"class":161},"byte",[156,7454,7182],{"class":165},[156,7456,318],{"class":312},[156,7458,459],{"class":165},[156,7460,7190],{"class":161},[156,7462,7193],{"class":165},[156,7464,7465,7468,7470,7473,7475,7478,7481],{"class":158,"line":665},[156,7466,7467],{"class":165},"        HttpRequest req ",[156,7469,169],{"class":161},[156,7471,7472],{"class":165}," HttpRequest.",[156,7474,7264],{"class":290},[156,7476,7477],{"class":165},"(URI.",[156,7479,7480],{"class":290},"create",[156,7482,7483],{"class":165},"(api))\n",[156,7485,7486,7489,7491,7493,7495,7497,7499],{"class":158,"line":22},[156,7487,7488],{"class":165},"                .",[156,7490,671],{"class":290},[156,7492,7272],{"class":165},[156,7494,7275],{"class":290},[156,7496,309],{"class":165},[156,7498,1379],{"class":262},[156,7500,4245],{"class":165},[156,7502,7503,7505,7508,7510,7512,7514,7517,7519],{"class":158,"line":687},[156,7504,7488],{"class":165},[156,7506,7507],{"class":290},"header",[156,7509,309],{"class":165},[156,7511,1329],{"class":172},[156,7513,315],{"class":165},[156,7515,7516],{"class":172},"\"Bearer \"",[156,7518,7355],{"class":161},[156,7520,7521],{"class":165}," key)\n",[156,7523,7524,7526,7528,7530,7532],{"class":158,"line":699},[156,7525,7488],{"class":165},[156,7527,7507],{"class":290},[156,7529,309],{"class":165},[156,7531,1351],{"class":172},[156,7533,7534],{"class":165},", type)\n",[156,7536,7537,7539,7542,7545,7548],{"class":158,"line":723},[156,7538,7488],{"class":165},[156,7540,7541],{"class":290},"POST",[156,7543,7544],{"class":165},"(HttpRequest.BodyPublishers.",[156,7546,7547],{"class":290},"ofByteArray",[156,7549,7550],{"class":165},"(body))\n",[156,7552,7553,7555,7557],{"class":158,"line":748},[156,7554,7488],{"class":165},[156,7556,7285],{"class":290},[156,7558,2875],{"class":165},[156,7560,7561,7563,7566,7568,7571,7574],{"class":158,"line":26},[156,7562,1563],{"class":161},[156,7564,7565],{"class":165}," client.",[156,7567,7306],{"class":290},[156,7569,7570],{"class":165},"(req, HttpResponse.BodyHandlers.",[156,7572,7573],{"class":290},"ofString",[156,7575,5059],{"class":165},[156,7577,7578],{"class":158,"line":761},[156,7579,758],{"class":165},[156,7581,7582],{"class":158,"line":766},[156,7583,279],{"emptyLinePlaceholder":278},[156,7585,7586,7588,7591,7593,7595,7597,7599,7601,7604,7606,7608],{"class":158,"line":805},[156,7587,7415],{"class":161},[156,7589,7590],{"class":161}," byte",[156,7592,7182],{"class":165},[156,7594,7317],{"class":290},[156,7596,309],{"class":165},[156,7598,7452],{"class":161},[156,7600,7182],{"class":165},[156,7602,7603],{"class":312},"data",[156,7605,459],{"class":165},[156,7607,7190],{"class":161},[156,7609,7193],{"class":165},[156,7611,7612,7615,7617,7620,7623,7626,7628,7630,7632,7635,7637,7640,7643,7646,7649,7651],{"class":158,"line":849},[156,7613,7614],{"class":165},"        String head ",[156,7616,169],{"class":161},[156,7618,7619],{"class":172}," \"--slipbolt",[156,7621,7622],{"class":262},"\\r\\n",[156,7624,7625],{"class":172},"Content-Disposition: form-data; name=",[156,7627,7342],{"class":262},[156,7629,5468],{"class":172},[156,7631,7342],{"class":262},[156,7633,7634],{"class":172},"; filename=",[156,7636,7342],{"class":262},[156,7638,7639],{"class":172},"slip.jpg",[156,7641,7642],{"class":262},"\\\"\\r\\n",[156,7644,7645],{"class":172},"Content-Type: image\u002Fjpeg",[156,7647,7648],{"class":262},"\\r\\n\\r\\n",[156,7650,1054],{"class":172},[156,7652,272],{"class":165},[156,7654,7655,7658,7660,7662,7664,7667,7669,7671],{"class":158,"line":30},[156,7656,7657],{"class":165},"        String tail ",[156,7659,169],{"class":161},[156,7661,1671],{"class":172},[156,7663,7622],{"class":262},[156,7665,7666],{"class":172},"--slipbolt--",[156,7668,7622],{"class":262},[156,7670,1054],{"class":172},[156,7672,272],{"class":165},[156,7674,7675,7677,7680,7682,7685,7687],{"class":158,"line":860},[156,7676,7228],{"class":161},[156,7678,7679],{"class":165},"[] h ",[156,7681,169],{"class":161},[156,7683,7684],{"class":165}," head.",[156,7686,7399],{"class":290},[156,7688,7689],{"class":165},"(StandardCharsets.UTF_8);\n",[156,7691,7692,7694,7697,7699,7702,7704],{"class":158,"line":865},[156,7693,7228],{"class":161},[156,7695,7696],{"class":165},"[] t ",[156,7698,169],{"class":161},[156,7700,7701],{"class":165}," tail.",[156,7703,7399],{"class":290},[156,7705,7689],{"class":165},[156,7707,7708,7710,7713,7715,7717,7719,7722,7724,7727,7729],{"class":158,"line":896},[156,7709,7228],{"class":161},[156,7711,7712],{"class":165},"[] out ",[156,7714,169],{"class":161},[156,7716,465],{"class":161},[156,7718,7590],{"class":161},[156,7720,7721],{"class":165},"[h.length ",[156,7723,1265],{"class":161},[156,7725,7726],{"class":165}," data.length ",[156,7728,1265],{"class":161},[156,7730,7731],{"class":165}," t.length];\n",[156,7733,7734,7737,7740,7743,7745,7748,7750],{"class":158,"line":918},[156,7735,7736],{"class":165},"        System.",[156,7738,7739],{"class":290},"arraycopy",[156,7741,7742],{"class":165},"(h, ",[156,7744,2780],{"class":262},[156,7746,7747],{"class":165},", out, ",[156,7749,2780],{"class":262},[156,7751,7752],{"class":165},", h.length);\n",[156,7754,7755,7757,7759,7762,7764],{"class":158,"line":35},[156,7756,7736],{"class":165},[156,7758,7739],{"class":290},[156,7760,7761],{"class":165},"(data, ",[156,7763,2780],{"class":262},[156,7765,7766],{"class":165},", out, h.length, data.length);\n",[156,7768,7769,7771,7773,7776,7778,7781,7783],{"class":158,"line":934},[156,7770,7736],{"class":165},[156,7772,7739],{"class":290},[156,7774,7775],{"class":165},"(t, ",[156,7777,2780],{"class":262},[156,7779,7780],{"class":165},", out, h.length ",[156,7782,1265],{"class":161},[156,7784,7785],{"class":165}," data.length, t.length);\n",[156,7787,7788,7790],{"class":158,"line":1504},[156,7789,1563],{"class":161},[156,7791,7792],{"class":165}," out;\n",[156,7794,7795],{"class":158,"line":1511},[156,7796,758],{"class":165},[156,7798,7799],{"class":158,"line":1522},[156,7800,279],{"emptyLinePlaceholder":278},[156,7802,7803,7805,7807,7810,7813,7815,7817,7819],{"class":158,"line":39},[156,7804,7415],{"class":161},[156,7806,7171],{"class":161},[156,7808,7809],{"class":290}," show",[156,7811,7812],{"class":165},"(HttpResponse\u003C",[156,7814,7179],{"class":161},[156,7816,7423],{"class":165},[156,7818,3161],{"class":312},[156,7820,321],{"class":165},[156,7822,7823,7826,7828,7830,7832],{"class":158,"line":1541},[156,7824,7825],{"class":165},"        String body ",[156,7827,169],{"class":161},[156,7829,877],{"class":165},[156,7831,318],{"class":290},[156,7833,2875],{"class":165},[156,7835,7836,7839,7841,7844,7847,7849],{"class":158,"line":1551},[156,7837,7838],{"class":165},"        String status ",[156,7840,169],{"class":161},[156,7842,7843],{"class":290}," jsonString",[156,7845,7846],{"class":165},"(body, ",[156,7848,2413],{"class":172},[156,7850,375],{"class":165},[156,7852,7853,7855,7858,7861,7864,7866,7868,7870,7872],{"class":158,"line":1560},[156,7854,1442],{"class":161},[156,7856,7857],{"class":165}," (status.",[156,7859,7860],{"class":290},"isEmpty",[156,7862,7863],{"class":165},"()) status ",[156,7865,169],{"class":161},[156,7867,7843],{"class":290},[156,7869,7846],{"class":165},[156,7871,6388],{"class":172},[156,7873,375],{"class":165},[156,7875,7876,7879,7882,7885,7888,7891,7893,7896,7898],{"class":158,"line":2208},[156,7877,7878],{"class":165},"        System.out.",[156,7880,7881],{"class":290},"println",[156,7883,7884],{"class":165},"(res.",[156,7886,7887],{"class":290},"statusCode",[156,7889,7890],{"class":165},"() ",[156,7892,1265],{"class":161},[156,7894,7895],{"class":172}," \" \"",[156,7897,7355],{"class":161},[156,7899,7900],{"class":165}," status);\n",[156,7902,7903],{"class":158,"line":2224},[156,7904,758],{"class":165},[156,7906,7907],{"class":158,"line":2236},[156,7908,279],{"emptyLinePlaceholder":278},[156,7910,7911,7913,7916,7919,7922,7924,7926,7928],{"class":158,"line":2241},[156,7912,7415],{"class":161},[156,7914,7915],{"class":165}," String ",[156,7917,7918],{"class":290},"jsonString",[156,7920,7921],{"class":165},"(String ",[156,7923,880],{"class":312},[156,7925,7434],{"class":165},[156,7927,7442],{"class":312},[156,7929,321],{"class":165},[156,7931,7932,7935,7938,7940,7943,7946,7948,7950,7952,7954,7956,7959,7961,7963,7965,7967],{"class":158,"line":2256},[156,7933,7934],{"class":161},"        int",[156,7936,7937],{"class":165}," i ",[156,7939,169],{"class":161},[156,7941,7942],{"class":165}," json.",[156,7944,7945],{"class":290},"indexOf",[156,7947,309],{"class":165},[156,7949,1054],{"class":172},[156,7951,7342],{"class":262},[156,7953,1054],{"class":172},[156,7955,7355],{"class":161},[156,7957,7958],{"class":165}," key ",[156,7960,1265],{"class":161},[156,7962,1671],{"class":172},[156,7964,7342],{"class":262},[156,7966,1054],{"class":172},[156,7968,375],{"class":165},[156,7970,7971,7973,7976,7978,7980,7982,7984,7986],{"class":158,"line":2261},[156,7972,1442],{"class":161},[156,7974,7975],{"class":165}," (i ",[156,7977,799],{"class":161},[156,7979,565],{"class":262},[156,7981,459],{"class":165},[156,7983,2797],{"class":161},[156,7985,1203],{"class":172},[156,7987,272],{"class":165},[156,7989,7990,7992,7995,7997,7999,8001,8003,8006,8008,8010,8012,8015,8018,8020,8022],{"class":158,"line":3657},[156,7991,7934],{"class":161},[156,7993,7994],{"class":165}," q1 ",[156,7996,169],{"class":161},[156,7998,7942],{"class":165},[156,8000,7945],{"class":290},[156,8002,309],{"class":165},[156,8004,8005],{"class":172},"'\"'",[156,8007,7396],{"class":165},[156,8009,7945],{"class":290},[156,8011,309],{"class":165},[156,8013,8014],{"class":172},"':'",[156,8016,8017],{"class":165},", i) ",[156,8019,1265],{"class":161},[156,8021,1268],{"class":262},[156,8023,375],{"class":165},[156,8025,8026,8028,8031,8033,8035,8037,8039,8041,8044,8046,8048],{"class":158,"line":3677},[156,8027,7934],{"class":161},[156,8029,8030],{"class":165}," q2 ",[156,8032,169],{"class":161},[156,8034,7942],{"class":165},[156,8036,7945],{"class":290},[156,8038,309],{"class":165},[156,8040,8005],{"class":172},[156,8042,8043],{"class":165},", q1 ",[156,8045,1265],{"class":161},[156,8047,1268],{"class":262},[156,8049,375],{"class":165},[156,8051,8052,8054,8056,8058,8060,8062,8064,8066,8068,8071,8073,8076,8078,8081,8084,8086,8088],{"class":158,"line":3683},[156,8053,1563],{"class":161},[156,8055,7994],{"class":165},[156,8057,799],{"class":161},[156,8059,565],{"class":262},[156,8061,781],{"class":161},[156,8063,8030],{"class":165},[156,8065,799],{"class":161},[156,8067,565],{"class":262},[156,8069,8070],{"class":161}," ?",[156,8072,1203],{"class":172},[156,8074,8075],{"class":161}," :",[156,8077,7942],{"class":165},[156,8079,8080],{"class":290},"substring",[156,8082,8083],{"class":165},"(q1 ",[156,8085,1265],{"class":161},[156,8087,1268],{"class":262},[156,8089,8090],{"class":165},", q2);\n",[156,8092,8093],{"class":158,"line":3688},[156,8094,758],{"class":165},[156,8096,8097],{"class":158,"line":4461},[156,8098,435],{"class":165},[147,8100,8105],{"className":8101,"code":8102,"filename":8103,"language":8104,"meta":152,"style":152},"language-csharp shiki shiki-themes github-light github-dark","using System.Net.Http.Headers;\nusing System.Text;\nusing System.Text.Json;\n\nvar api = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\";\nvar key = Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\")!;\nvar data = await File.ReadAllBytesAsync(\"slip.jpg\");\nusing var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n\n\u002F\u002F multipart\u002Fform-data — ฟิลด์ไฟล์ชื่อ file\nusing var form = new MultipartFormDataContent();\nvar file = new ByteArrayContent(data);\nfile.Headers.ContentType = new MediaTypeHeaderValue(\"image\u002Fjpeg\");\nform.Add(file, \"file\", \"slip.jpg\");\nusing var viaForm = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = form }));\n\n\u002F\u002F JSON base64 — รับทั้ง base64 ล้วนและ data:image\u002F...;base64,...\nvar json = new StringContent(\n    JsonSerializer.Serialize(new { image = Convert.ToBase64String(data) }),\n    Encoding.UTF8,\n    \"application\u002Fjson\");\nusing var viaJson = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = json }));\n\nforeach (var res in new[] { viaForm, viaJson })\n{\n    using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n    string? status = null;\n    if (body.RootElement.TryGetProperty(\"data\", out var d) && d.TryGetProperty(\"status\", out var s)) status = s.GetString();\n    else if (body.RootElement.TryGetProperty(\"message\", out var m)) status = m.GetString();\n    Console.WriteLine($\"{(int)res.StatusCode} {status}\");\n}\n\nHttpRequestMessage authed(HttpRequestMessage req)\n{\n    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\n    return req;\n}\n","C#","csharp",[142,8106,8107,8112,8117,8122,8126,8131,8136,8141,8146,8150,8154,8159,8164,8169,8174,8179,8183,8187,8192,8197,8202,8207,8212,8216,8221,8225,8230,8235,8240,8245,8250,8254,8258,8263,8267,8272,8277],{"__ignoreMap":152},[156,8108,8109],{"class":158,"line":9},[156,8110,8111],{},"using System.Net.Http.Headers;\n",[156,8113,8114],{"class":158,"line":256},[156,8115,8116],{},"using System.Text;\n",[156,8118,8119],{"class":158,"line":275},[156,8120,8121],{},"using System.Text.Json;\n",[156,8123,8124],{"class":158,"line":282},[156,8125,279],{"emptyLinePlaceholder":278},[156,8127,8128],{"class":158,"line":303},[156,8129,8130],{},"var api = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\";\n",[156,8132,8133],{"class":158,"line":324},[156,8134,8135],{},"var key = Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\")!;\n",[156,8137,8138],{"class":158,"line":378},[156,8139,8140],{},"var data = await File.ReadAllBytesAsync(\"slip.jpg\");\n",[156,8142,8143],{"class":158,"line":395},[156,8144,8145],{},"using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n",[156,8147,8148],{"class":158,"line":411},[156,8149,279],{"emptyLinePlaceholder":278},[156,8151,8152],{"class":158,"line":13},[156,8153,5910],{},[156,8155,8156],{"class":158,"line":432},[156,8157,8158],{},"using var form = new MultipartFormDataContent();\n",[156,8160,8161],{"class":158,"line":438},[156,8162,8163],{},"var file = new ByteArrayContent(data);\n",[156,8165,8166],{"class":158,"line":443},[156,8167,8168],{},"file.Headers.ContentType = new MediaTypeHeaderValue(\"image\u002Fjpeg\");\n",[156,8170,8171],{"class":158,"line":487},[156,8172,8173],{},"form.Add(file, \"file\", \"slip.jpg\");\n",[156,8175,8176],{"class":158,"line":492},[156,8177,8178],{},"using var viaForm = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = form }));\n",[156,8180,8181],{"class":158,"line":498},[156,8182,279],{"emptyLinePlaceholder":278},[156,8184,8185],{"class":158,"line":549},[156,8186,5988],{},[156,8188,8189],{"class":158,"line":576},[156,8190,8191],{},"var json = new StringContent(\n",[156,8193,8194],{"class":158,"line":585},[156,8195,8196],{},"    JsonSerializer.Serialize(new { image = Convert.ToBase64String(data) }),\n",[156,8198,8199],{"class":158,"line":18},[156,8200,8201],{},"    Encoding.UTF8,\n",[156,8203,8204],{"class":158,"line":619},[156,8205,8206],{},"    \"application\u002Fjson\");\n",[156,8208,8209],{"class":158,"line":631},[156,8210,8211],{},"using var viaJson = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = json }));\n",[156,8213,8214],{"class":158,"line":659},[156,8215,279],{"emptyLinePlaceholder":278},[156,8217,8218],{"class":158,"line":665},[156,8219,8220],{},"foreach (var res in new[] { viaForm, viaJson })\n",[156,8222,8223],{"class":158,"line":22},[156,8224,1616],{},[156,8226,8227],{"class":158,"line":687},[156,8228,8229],{},"    using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n",[156,8231,8232],{"class":158,"line":699},[156,8233,8234],{},"    string? status = null;\n",[156,8236,8237],{"class":158,"line":723},[156,8238,8239],{},"    if (body.RootElement.TryGetProperty(\"data\", out var d) && d.TryGetProperty(\"status\", out var s)) status = s.GetString();\n",[156,8241,8242],{"class":158,"line":748},[156,8243,8244],{},"    else if (body.RootElement.TryGetProperty(\"message\", out var m)) status = m.GetString();\n",[156,8246,8247],{"class":158,"line":26},[156,8248,8249],{},"    Console.WriteLine($\"{(int)res.StatusCode} {status}\");\n",[156,8251,8252],{"class":158,"line":761},[156,8253,435],{},[156,8255,8256],{"class":158,"line":766},[156,8257,279],{"emptyLinePlaceholder":278},[156,8259,8260],{"class":158,"line":805},[156,8261,8262],{},"HttpRequestMessage authed(HttpRequestMessage req)\n",[156,8264,8265],{"class":158,"line":849},[156,8266,1616],{},[156,8268,8269],{"class":158,"line":30},[156,8270,8271],{},"    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\n",[156,8273,8274],{"class":158,"line":860},[156,8275,8276],{},"    return req;\n",[156,8278,8279],{"class":158,"line":865},[156,8280,435],{},[2528,8282,8283],{"type":5376},[65,8284,8285,8288,8289,8292],{},[69,8286,8287],{},"ขนาดสูงสุด 5 MB ต่อคำขอ"," · JPEG หรือ PNG · ต้องเห็น QR บนสลิปครบ (รูปที่ครอปจน QR ขาดจะได้ ",[142,8290,8291],{},"INVALID",")\nbase64 ทำให้ข้อมูลโตขึ้นราว 33% ⇒ ส่งแบบ JSON ได้รูปใหญ่สุดประมาณ 3.7 MB — รูปใหญ่กว่านั้นใช้ raw bytes หรือ multipart",[2538,8294,8296],{"id":8295},"ส่งเป็น-url-หรือข้อความ-qr","ส่งเป็น URL หรือข้อความ QR",[65,8298,8299,8300,8303,8304,5393,8306,5393,8308,8310,8311,1768],{},"สองแบบนี้ส่งเป็น JSON เหมือน base64 — ใส่ ",[69,8301,8302],{},"อย่างใดอย่างหนึ่ง"," ใน ",[142,8305,514],{},[142,8307,5503],{},[142,8309,5520],{}," (ใส่เกินหนึ่งอย่างได้ ",[142,8312,3295],{},[65,8314,8315,8319],{},[69,8316,8317],{},[142,8318,5503],{}," — เราดาวน์โหลดรูปให้ แล้วตรวจเหมือนคุณส่งไฟล์นั้นมาเอง",[186,8321,8322,8329,8335],{},[189,8323,8324,8325,8328],{},"ต้องเป็น ",[142,8326,8327],{},"https:\u002F\u002F"," ที่เปิดได้จากอินเทอร์เน็ตโดยไม่ต้องล็อกอิน (เช่น pre-signed URL ของ S3) · localhost \u002F IP ภายในถูกปฏิเสธ",[189,8330,8331,8334],{},[69,8332,8333],{},"ไม่ตาม redirect"," — ใส่ลิงก์ปลายทางจริง · ไฟล์ไม่เกิน 5 MB · รอได้ไม่เกิน 10 วินาที",[189,8336,8337,8338,8340],{},"ดาวน์โหลดไม่ได้ → ",[142,8339,3295],{}," พร้อมเหตุผล (ไม่หักโควตา)",[65,8342,8343,8347],{},[69,8344,8345],{},[142,8346,5520],{}," — ข้อความที่อ่านได้จาก QR บนสลิป เหมาะกับแอปที่สแกน QR เองอยู่แล้ว ไม่ต้องอัปโหลดรูป",[186,8349,8350,8353],{},[189,8351,8352],{},"ส่งข้อความตามที่สแกนได้ทั้งก้อน ไม่ต้องตัดหรือแปลง",[189,8354,8355,8356,8358],{},"ข้อความเดิมส่งซ้ำใน 24 ชม. ได้ ",[142,8357,215],{}," เหมือนส่งรูปเดิมซ้ำ",[238,8360,8361,8636,8914,9254,9472,10134],{},[147,8362,8364],{"className":242,"code":8363,"filename":244,"language":245,"meta":152,"style":152},"const API = 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify';\n\nasync function verifyJson(payload) {\n  const res = await fetch(API, {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.SLIPBOLT_API_KEY}`,\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify(payload),\n    signal: AbortSignal.timeout(30_000),\n  });\n  const body = await res.json();\n  if (!res.ok) throw new Error(`${res.status} ${body.code ?? body.error}: ${body.message}`);\n  return body.data;\n}\n\nconst byUrl = await verifyJson({ url: process.env.SLIP_URL });\nconst byQr = await verifyJson({ qr: process.env.SLIP_QR });\nconsole.log(byUrl.status, byQr.status);\n",[142,8365,8366,8378,8382,8398,8416,8425,8430,8451,8462,8467,8481,8494,8498,8514,8569,8577,8581,8585,8606,8627],{"__ignoreMap":152},[156,8367,8368,8370,8372,8374,8376],{"class":158,"line":9},[156,8369,259],{"class":161},[156,8371,5844],{"class":262},[156,8373,266],{"class":161},[156,8375,5849],{"class":172},[156,8377,272],{"class":165},[156,8379,8380],{"class":158,"line":256},[156,8381,279],{"emptyLinePlaceholder":278},[156,8383,8384,8386,8388,8391,8393,8396],{"class":158,"line":275},[156,8385,2754],{"class":161},[156,8387,506],{"class":161},[156,8389,8390],{"class":290}," verifyJson",[156,8392,309],{"class":165},[156,8394,8395],{"class":312},"payload",[156,8397,321],{"class":165},[156,8399,8400,8402,8404,8406,8408,8410,8412,8414],{"class":158,"line":282},[156,8401,3172],{"class":161},[156,8403,2815],{"class":262},[156,8405,266],{"class":161},[156,8407,600],{"class":161},[156,8409,603],{"class":290},[156,8411,309],{"class":165},[156,8413,5537],{"class":262},[156,8415,616],{"class":165},[156,8417,8418,8421,8423],{"class":158,"line":303},[156,8419,8420],{"class":165},"    method: ",[156,8422,625],{"class":172},[156,8424,628],{"class":165},[156,8426,8427],{"class":158,"line":324},[156,8428,8429],{"class":165},"    headers: {\n",[156,8431,8432,8435,8437,8439,8441,8443,8445,8447,8449],{"class":158,"line":378},[156,8433,8434],{"class":165},"      Authorization: ",[156,8436,637],{"class":172},[156,8438,5868],{"class":165},[156,8440,342],{"class":172},[156,8442,5873],{"class":165},[156,8444,342],{"class":172},[156,8446,528],{"class":262},[156,8448,642],{"class":172},[156,8450,628],{"class":165},[156,8452,8453,8456,8458,8460],{"class":158,"line":395},[156,8454,8455],{"class":172},"      'Content-Type'",[156,8457,650],{"class":165},[156,8459,6034],{"class":172},[156,8461,628],{"class":165},[156,8463,8464],{"class":158,"line":411},[156,8465,8466],{"class":165},"    },\n",[156,8468,8469,8472,8474,8476,8478],{"class":158,"line":13},[156,8470,8471],{"class":165},"    body: ",[156,8473,6044],{"class":262},[156,8475,342],{"class":165},[156,8477,6049],{"class":290},[156,8479,8480],{"class":165},"(payload),\n",[156,8482,8483,8486,8488,8490,8492],{"class":158,"line":432},[156,8484,8485],{"class":165},"    signal: AbortSignal.",[156,8487,671],{"class":290},[156,8489,309],{"class":165},[156,8491,676],{"class":262},[156,8493,679],{"class":165},[156,8495,8496],{"class":158,"line":438},[156,8497,2900],{"class":165},[156,8499,8500,8502,8504,8506,8508,8510,8512],{"class":158,"line":443},[156,8501,3172],{"class":161},[156,8503,350],{"class":262},[156,8505,266],{"class":161},[156,8507,600],{"class":161},[156,8509,877],{"class":165},[156,8511,880],{"class":290},[156,8513,2875],{"class":165},[156,8515,8516,8518,8520,8522,8524,8526,8528,8530,8532,8534,8536,8538,8540,8542,8544,8546,8548,8550,8552,8554,8556,8559,8561,8563,8565,8567],{"class":158,"line":487},[156,8517,3190],{"class":161},[156,8519,453],{"class":165},[156,8521,903],{"class":161},[156,8523,906],{"class":165},[156,8525,714],{"class":161},[156,8527,465],{"class":161},[156,8529,297],{"class":290},[156,8531,309],{"class":165},[156,8533,332],{"class":172},[156,8535,3161],{"class":165},[156,8537,342],{"class":172},[156,8539,224],{"class":165},[156,8541,337],{"class":172},[156,8543,318],{"class":165},[156,8545,342],{"class":172},[156,8547,142],{"class":165},[156,8549,347],{"class":161},[156,8551,350],{"class":165},[156,8553,342],{"class":172},[156,8555,355],{"class":165},[156,8557,8558],{"class":172},"}: ${",[156,8560,318],{"class":165},[156,8562,342],{"class":172},[156,8564,367],{"class":165},[156,8566,642],{"class":172},[156,8568,375],{"class":165},[156,8570,8571,8574],{"class":158,"line":492},[156,8572,8573],{"class":161},"  return",[156,8575,8576],{"class":165}," body.data;\n",[156,8578,8579],{"class":158,"line":498},[156,8580,435],{"class":165},[156,8582,8583],{"class":158,"line":549},[156,8584,279],{"emptyLinePlaceholder":278},[156,8586,8587,8589,8592,8594,8596,8598,8601,8604],{"class":158,"line":576},[156,8588,259],{"class":161},[156,8590,8591],{"class":262}," byUrl",[156,8593,266],{"class":161},[156,8595,600],{"class":161},[156,8597,8390],{"class":290},[156,8599,8600],{"class":165},"({ url: process.env.",[156,8602,8603],{"class":262},"SLIP_URL",[156,8605,3226],{"class":165},[156,8607,8608,8610,8613,8615,8617,8619,8622,8625],{"class":158,"line":585},[156,8609,259],{"class":161},[156,8611,8612],{"class":262}," byQr",[156,8614,266],{"class":161},[156,8616,600],{"class":161},[156,8618,8390],{"class":290},[156,8620,8621],{"class":165},"({ qr: process.env.",[156,8623,8624],{"class":262},"SLIP_QR",[156,8626,3226],{"class":165},[156,8628,8629,8631,8633],{"class":158,"line":18},[156,8630,2339],{"class":165},[156,8632,2342],{"class":290},[156,8634,8635],{"class":165},"(byUrl.status, byQr.status);\n",[147,8637,8639],{"className":939,"code":8638,"filename":941,"language":942,"meta":152,"style":152},"import os\n\nimport requests\n\nAPI = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n\n\ndef verify_json(payload: dict) -> dict:\n    res = requests.post(\n        API,\n        headers={\"Authorization\": f\"Bearer {os.environ['SLIPBOLT_API_KEY']}\"},\n        json=payload,\n        timeout=30,\n    )\n    body = res.json()\n    if not res.ok:\n        raise RuntimeError(f\"{res.status_code} {body.get('code') or body.get('error')}: {body.get('message')}\")\n    return body[\"data\"]\n\n\nby_url = verify_json({\"url\": os.environ[\"SLIP_URL\"]})\nby_qr = verify_json({\"qr\": os.environ[\"SLIP_QR\"]})\nprint(by_url[\"status\"], by_qr[\"status\"])\n",[142,8640,8641,8647,8651,8657,8661,8669,8673,8677,8695,8704,8711,8742,8752,8763,8768,8776,8784,8839,8849,8853,8857,8879,8898],{"__ignoreMap":152},[156,8642,8643,8645],{"class":158,"line":9},[156,8644,954],{"class":161},[156,8646,957],{"class":165},[156,8648,8649],{"class":158,"line":256},[156,8650,279],{"emptyLinePlaceholder":278},[156,8652,8653,8655],{"class":158,"line":275},[156,8654,954],{"class":161},[156,8656,975],{"class":165},[156,8658,8659],{"class":158,"line":282},[156,8660,279],{"emptyLinePlaceholder":278},[156,8662,8663,8665,8667],{"class":158,"line":303},[156,8664,5537],{"class":262},[156,8666,266],{"class":161},[156,8668,6164],{"class":172},[156,8670,8671],{"class":158,"line":324},[156,8672,279],{"emptyLinePlaceholder":278},[156,8674,8675],{"class":158,"line":378},[156,8676,279],{"emptyLinePlaceholder":278},[156,8678,8679,8681,8684,8687,8689,8691,8693],{"class":158,"line":395},[156,8680,1183],{"class":161},[156,8682,8683],{"class":290}," verify_json",[156,8685,8686],{"class":165},"(payload: ",[156,8688,1031],{"class":262},[156,8690,1215],{"class":165},[156,8692,1031],{"class":262},[156,8694,1220],{"class":165},[156,8696,8697,8700,8702],{"class":158,"line":411},[156,8698,8699],{"class":165},"    res ",[156,8701,169],{"class":161},[156,8703,1302],{"class":165},[156,8705,8706,8709],{"class":158,"line":13},[156,8707,8708],{"class":262},"        API",[156,8710,628],{"class":165},[156,8712,8713,8716,8718,8720,8722,8724,8726,8728,8730,8732,8734,8736,8738,8740],{"class":158,"line":432},[156,8714,8715],{"class":312},"        headers",[156,8717,169],{"class":161},[156,8719,1057],{"class":165},[156,8721,1329],{"class":172},[156,8723,650],{"class":165},[156,8725,1334],{"class":161},[156,8727,1337],{"class":172},[156,8729,1057],{"class":262},[156,8731,6186],{"class":165},[156,8733,1871],{"class":172},[156,8735,4307],{"class":165},[156,8737,1062],{"class":262},[156,8739,1054],{"class":172},[156,8741,1359],{"class":165},[156,8743,8744,8747,8749],{"class":158,"line":438},[156,8745,8746],{"class":312},"        json",[156,8748,169],{"class":161},[156,8750,8751],{"class":165},"payload,\n",[156,8753,8754,8757,8759,8761],{"class":158,"line":443},[156,8755,8756],{"class":312},"        timeout",[156,8758,169],{"class":161},[156,8760,1379],{"class":262},[156,8762,628],{"class":165},[156,8764,8765],{"class":158,"line":487},[156,8766,8767],{"class":165},"    )\n",[156,8769,8770,8772,8774],{"class":158,"line":492},[156,8771,6354],{"class":165},[156,8773,169],{"class":161},[156,8775,1519],{"class":165},[156,8777,8778,8780,8782],{"class":158,"line":498},[156,8779,769],{"class":161},[156,8781,1467],{"class":161},[156,8783,1548],{"class":165},[156,8785,8786,8789,8792,8794,8796,8798,8800,8803,8805,8807,8809,8811,8813,8815,8817,8819,8821,8823,8825,8827,8829,8831,8833,8835,8837],{"class":158,"line":549},[156,8787,8788],{"class":161},"        raise",[156,8790,8791],{"class":262}," RuntimeError",[156,8793,309],{"class":165},[156,8795,1334],{"class":161},[156,8797,1054],{"class":172},[156,8799,1057],{"class":262},[156,8801,8802],{"class":165},"res.status_code",[156,8804,1062],{"class":262},[156,8806,1065],{"class":262},[156,8808,1068],{"class":165},[156,8810,1071],{"class":172},[156,8812,459],{"class":165},[156,8814,1076],{"class":161},[156,8816,1079],{"class":165},[156,8818,1082],{"class":172},[156,8820,1768],{"class":165},[156,8822,1062],{"class":262},[156,8824,650],{"class":172},[156,8826,1057],{"class":262},[156,8828,1068],{"class":165},[156,8830,1100],{"class":172},[156,8832,1768],{"class":165},[156,8834,1062],{"class":262},[156,8836,1054],{"class":172},[156,8838,1718],{"class":165},[156,8840,8841,8843,8845,8847],{"class":158,"line":576},[156,8842,921],{"class":161},[156,8844,1566],{"class":165},[156,8846,1569],{"class":172},[156,8848,1246],{"class":165},[156,8850,8851],{"class":158,"line":585},[156,8852,279],{"emptyLinePlaceholder":278},[156,8854,8855],{"class":158,"line":18},[156,8856,279],{"emptyLinePlaceholder":278},[156,8858,8859,8862,8864,8867,8870,8873,8876],{"class":158,"line":619},[156,8860,8861],{"class":165},"by_url ",[156,8863,169],{"class":161},[156,8865,8866],{"class":165}," verify_json({",[156,8868,8869],{"class":172},"\"url\"",[156,8871,8872],{"class":165},": os.environ[",[156,8874,8875],{"class":172},"\"SLIP_URL\"",[156,8877,8878],{"class":165},"]})\n",[156,8880,8881,8884,8886,8888,8891,8893,8896],{"class":158,"line":631},[156,8882,8883],{"class":165},"by_qr ",[156,8885,169],{"class":161},[156,8887,8866],{"class":165},[156,8889,8890],{"class":172},"\"qr\"",[156,8892,8872],{"class":165},[156,8894,8895],{"class":172},"\"SLIP_QR\"",[156,8897,8878],{"class":165},[156,8899,8900,8902,8905,8907,8910,8912],{"class":158,"line":659},[156,8901,2407],{"class":262},[156,8903,8904],{"class":165},"(by_url[",[156,8906,2413],{"class":172},[156,8908,8909],{"class":165},"], by_qr[",[156,8911,2413],{"class":172},[156,8913,2427],{"class":165},[147,8915,8917],{"className":1578,"code":8916,"filename":1580,"language":1581,"meta":152,"style":152},"\u003C?php\nfunction slipbolt_verify_json(array $payload): array\n{\n    $ch = curl_init('https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify');\n    curl_setopt_array($ch, [\n        CURLOPT_POST           => true,\n        CURLOPT_HTTPHEADER     => [\n            'Authorization: Bearer ' . getenv('SLIPBOLT_API_KEY'),\n            'Content-Type: application\u002Fjson',\n        ],\n        CURLOPT_POSTFIELDS     => json_encode($payload),\n        CURLOPT_RETURNTRANSFER => true,\n        CURLOPT_TIMEOUT        => 30,\n    ]);\n    $body   = json_decode(curl_exec($ch), true) ?? [];\n    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n    if ($status !== 200) {\n        throw new RuntimeException(\"$status \" . ($body['code'] ?? $body['error'] ?? '') . ': ' . ($body['message'] ?? ''));\n    }\n    return $body['data'];\n}\n\n$byUrl = slipbolt_verify_json(['url' => getenv('SLIP_URL')]);\n$byQr  = slipbolt_verify_json(['qr' => getenv('SLIP_QR')]);\necho $byUrl['status'], ' ', $byQr['status'], \"\\n\";\n",[142,8918,8919,8925,8943,8947,8961,8967,8977,8985,9000,9007,9012,9023,9033,9043,9047,9070,9085,9097,9154,9158,9168,9172,9176,9201,9226],{"__ignoreMap":152},[156,8920,8921,8923],{"class":158,"line":9},[156,8922,1588],{"class":161},[156,8924,1591],{"class":262},[156,8926,8927,8929,8932,8934,8936,8939,8941],{"class":158,"line":256},[156,8928,1745],{"class":161},[156,8930,8931],{"class":290}," slipbolt_verify_json",[156,8933,309],{"class":165},[156,8935,6413],{"class":161},[156,8937,8938],{"class":165}," $payload)",[156,8940,1771],{"class":161},[156,8942,1774],{"class":161},[156,8944,8945],{"class":158,"line":275},[156,8946,1616],{"class":165},[156,8948,8949,8951,8953,8955,8957,8959],{"class":158,"line":282},[156,8950,6429],{"class":165},[156,8952,169],{"class":161},[156,8954,1817],{"class":262},[156,8956,309],{"class":165},[156,8958,1822],{"class":172},[156,8960,375],{"class":165},[156,8962,8963,8965],{"class":158,"line":303},[156,8964,6444],{"class":262},[156,8966,1832],{"class":165},[156,8968,8969,8971,8973,8975],{"class":158,"line":324},[156,8970,6451],{"class":262},[156,8972,1840],{"class":161},[156,8974,1843],{"class":262},[156,8976,628],{"class":165},[156,8978,8979,8981,8983],{"class":158,"line":378},[156,8980,6462],{"class":262},[156,8982,1853],{"class":161},[156,8984,1856],{"class":165},[156,8986,8987,8990,8992,8994,8996,8998],{"class":158,"line":395},[156,8988,8989],{"class":172},"            'Authorization: Bearer '",[156,8991,1674],{"class":161},[156,8993,1866],{"class":262},[156,8995,309],{"class":165},[156,8997,1871],{"class":172},[156,8999,679],{"class":165},[156,9001,9002,9005],{"class":158,"line":411},[156,9003,9004],{"class":172},"            'Content-Type: application\u002Fjson'",[156,9006,628],{"class":165},[156,9008,9009],{"class":158,"line":13},[156,9010,9011],{"class":165},"        ],\n",[156,9013,9014,9016,9018,9020],{"class":158,"line":432},[156,9015,6490],{"class":262},[156,9017,1853],{"class":161},[156,9019,4564],{"class":262},[156,9021,9022],{"class":165},"($payload),\n",[156,9024,9025,9027,9029,9031],{"class":158,"line":438},[156,9026,6500],{"class":262},[156,9028,1903],{"class":161},[156,9030,1843],{"class":262},[156,9032,628],{"class":165},[156,9034,9035,9037,9039,9041],{"class":158,"line":443},[156,9036,6511],{"class":262},[156,9038,1915],{"class":161},[156,9040,1918],{"class":262},[156,9042,628],{"class":165},[156,9044,9045],{"class":158,"line":487},[156,9046,6522],{"class":165},[156,9048,9049,9052,9054,9056,9058,9060,9062,9064,9066,9068],{"class":158,"line":492},[156,9050,9051],{"class":165},"    $body   ",[156,9053,169],{"class":161},[156,9055,2192],{"class":262},[156,9057,309],{"class":165},[156,9059,6536],{"class":262},[156,9061,6539],{"class":165},[156,9063,2198],{"class":262},[156,9065,459],{"class":165},[156,9067,1685],{"class":161},[156,9069,2205],{"class":165},[156,9071,9072,9075,9077,9079,9081,9083],{"class":158,"line":498},[156,9073,9074],{"class":165},"    $status ",[156,9076,169],{"class":161},[156,9078,2050],{"class":262},[156,9080,2053],{"class":165},[156,9082,2056],{"class":262},[156,9084,375],{"class":165},[156,9086,9087,9089,9091,9093,9095],{"class":158,"line":549},[156,9088,769],{"class":161},[156,9090,2213],{"class":165},[156,9092,2216],{"class":161},[156,9094,2219],{"class":262},[156,9096,321],{"class":165},[156,9098,9099,9102,9104,9106,9108,9110,9112,9114,9116,9118,9120,9122,9124,9126,9128,9130,9132,9134,9136,9138,9140,9142,9144,9146,9148,9150,9152],{"class":158,"line":576},[156,9100,9101],{"class":161},"        throw",[156,9103,465],{"class":161},[156,9105,2161],{"class":262},[156,9107,309],{"class":165},[156,9109,1054],{"class":172},[156,9111,1668],{"class":165},[156,9113,1671],{"class":172},[156,9115,1674],{"class":161},[156,9117,1677],{"class":165},[156,9119,1071],{"class":172},[156,9121,1682],{"class":165},[156,9123,1685],{"class":161},[156,9125,1688],{"class":165},[156,9127,1082],{"class":172},[156,9129,1682],{"class":165},[156,9131,1685],{"class":161},[156,9133,1089],{"class":172},[156,9135,459],{"class":165},[156,9137,342],{"class":161},[156,9139,1703],{"class":172},[156,9141,1674],{"class":161},[156,9143,1677],{"class":165},[156,9145,1100],{"class":172},[156,9147,1682],{"class":165},[156,9149,1685],{"class":161},[156,9151,1089],{"class":172},[156,9153,2001],{"class":165},[156,9155,9156],{"class":158,"line":585},[156,9157,758],{"class":165},[156,9159,9160,9162,9164,9166],{"class":158,"line":18},[156,9161,921],{"class":161},[156,9163,1688],{"class":165},[156,9165,2248],{"class":172},[156,9167,2783],{"class":165},[156,9169,9170],{"class":158,"line":619},[156,9171,435],{"class":165},[156,9173,9174],{"class":158,"line":631},[156,9175,279],{"emptyLinePlaceholder":278},[156,9177,9178,9181,9183,9185,9187,9190,9192,9194,9196,9199],{"class":158,"line":659},[156,9179,9180],{"class":165},"$byUrl ",[156,9182,169],{"class":161},[156,9184,8931],{"class":290},[156,9186,4567],{"class":165},[156,9188,9189],{"class":172},"'url'",[156,9191,1903],{"class":161},[156,9193,1866],{"class":262},[156,9195,309],{"class":165},[156,9197,9198],{"class":172},"'SLIP_URL'",[156,9200,6603],{"class":165},[156,9202,9203,9206,9208,9210,9212,9215,9217,9219,9221,9224],{"class":158,"line":665},[156,9204,9205],{"class":165},"$byQr  ",[156,9207,169],{"class":161},[156,9209,8931],{"class":290},[156,9211,4567],{"class":165},[156,9213,9214],{"class":172},"'qr'",[156,9216,1903],{"class":161},[156,9218,1866],{"class":262},[156,9220,309],{"class":165},[156,9222,9223],{"class":172},"'SLIP_QR'",[156,9225,6603],{"class":165},[156,9227,9228,9230,9233,9235,9237,9239,9242,9244,9246,9248,9250,9252],{"class":158,"line":22},[156,9229,2482],{"class":262},[156,9231,9232],{"class":165}," $byUrl[",[156,9234,2488],{"class":172},[156,9236,2491],{"class":165},[156,9238,2494],{"class":172},[156,9240,9241],{"class":165},", $byQr[",[156,9243,2488],{"class":172},[156,9245,2491],{"class":165},[156,9247,1054],{"class":172},[156,9249,2516],{"class":262},[156,9251,1054],{"class":172},[156,9253,272],{"class":165},[147,9255,9257],{"className":6722,"code":9256,"filename":6724,"language":6725,"meta":152,"style":152},"package main\n\nimport (\n    \"bytes\"\n    \"encoding\u002Fjson\"\n    \"fmt\"\n    \"io\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"time\"\n)\n\nfunc main() {\n    byURL := verifyJSON(map[string]string{\"url\": os.Getenv(\"SLIP_URL\")})\n    byQR := verifyJSON(map[string]string{\"qr\": os.Getenv(\"SLIP_QR\")})\n    fmt.Println(byURL[\"status\"], byQR[\"status\"])\n}\n\nfunc verifyJSON(payload map[string]string) map[string]any {\n    body, _ := json.Marshal(payload)\n    req, err := http.NewRequest(http.MethodPost, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\", bytes.NewReader(body))\n    if err != nil {\n        panic(err)\n    }\n    req.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"SLIPBOLT_API_KEY\"))\n    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n    res, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer res.Body.Close()\n    raw, _ := io.ReadAll(res.Body)\n    var parsed struct {\n        Data    map[string]any `json:\"data\"`\n        Code    string         `json:\"code\"`\n        Error   string         `json:\"error\"`\n        Message string         `json:\"message\"`\n    }\n    _ = json.Unmarshal(raw, &parsed)\n    if res.StatusCode != 200 {\n        code := parsed.Code\n        if code == \"\" {\n            code = parsed.Error\n        }\n        panic(fmt.Sprintf(\"%d %s: %s\", res.StatusCode, code, parsed.Message))\n    }\n    return parsed.Data\n}\n",[142,9258,9259,9263,9267,9271,9275,9279,9283,9287,9291,9295,9299,9303,9307,9311,9316,9321,9326,9330,9334,9339,9344,9349,9353,9357,9361,9366,9371,9376,9380,9384,9388,9392,9396,9401,9406,9411,9416,9421,9425,9430,9435,9440,9445,9450,9454,9459,9463,9468],{"__ignoreMap":152},[156,9260,9261],{"class":158,"line":9},[156,9262,6732],{},[156,9264,9265],{"class":158,"line":256},[156,9266,279],{"emptyLinePlaceholder":278},[156,9268,9269],{"class":158,"line":275},[156,9270,6741],{},[156,9272,9273],{"class":158,"line":282},[156,9274,6746],{},[156,9276,9277],{"class":158,"line":303},[156,9278,6756],{},[156,9280,9281],{"class":158,"line":324},[156,9282,6761],{},[156,9284,9285],{"class":158,"line":378},[156,9286,6766],{},[156,9288,9289],{"class":158,"line":395},[156,9290,6776],{},[156,9292,9293],{"class":158,"line":411},[156,9294,6781],{},[156,9296,9297],{"class":158,"line":13},[156,9298,6786],{},[156,9300,9301],{"class":158,"line":432},[156,9302,1718],{},[156,9304,9305],{"class":158,"line":438},[156,9306,279],{"emptyLinePlaceholder":278},[156,9308,9309],{"class":158,"line":443},[156,9310,6799],{},[156,9312,9313],{"class":158,"line":487},[156,9314,9315],{},"    byURL := verifyJSON(map[string]string{\"url\": os.Getenv(\"SLIP_URL\")})\n",[156,9317,9318],{"class":158,"line":492},[156,9319,9320],{},"    byQR := verifyJSON(map[string]string{\"qr\": os.Getenv(\"SLIP_QR\")})\n",[156,9322,9323],{"class":158,"line":498},[156,9324,9325],{},"    fmt.Println(byURL[\"status\"], byQR[\"status\"])\n",[156,9327,9328],{"class":158,"line":549},[156,9329,435],{},[156,9331,9332],{"class":158,"line":576},[156,9333,279],{"emptyLinePlaceholder":278},[156,9335,9336],{"class":158,"line":585},[156,9337,9338],{},"func verifyJSON(payload map[string]string) map[string]any {\n",[156,9340,9341],{"class":158,"line":18},[156,9342,9343],{},"    body, _ := json.Marshal(payload)\n",[156,9345,9346],{"class":158,"line":619},[156,9347,9348],{},"    req, err := http.NewRequest(http.MethodPost, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\", bytes.NewReader(body))\n",[156,9350,9351],{"class":158,"line":631},[156,9352,6819],{},[156,9354,9355],{"class":158,"line":659},[156,9356,6824],{},[156,9358,9359],{"class":158,"line":665},[156,9360,758],{},[156,9362,9363],{"class":158,"line":22},[156,9364,9365],{},"    req.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"SLIPBOLT_API_KEY\"))\n",[156,9367,9368],{"class":158,"line":687},[156,9369,9370],{},"    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n",[156,9372,9373],{"class":158,"line":699},[156,9374,9375],{},"    res, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)\n",[156,9377,9378],{"class":158,"line":723},[156,9379,6819],{},[156,9381,9382],{"class":158,"line":748},[156,9383,6824],{},[156,9385,9386],{"class":158,"line":26},[156,9387,758],{},[156,9389,9390],{"class":158,"line":761},[156,9391,7021],{},[156,9393,9394],{"class":158,"line":766},[156,9395,7027],{},[156,9397,9398],{"class":158,"line":805},[156,9399,9400],{},"    var parsed struct {\n",[156,9402,9403],{"class":158,"line":849},[156,9404,9405],{},"        Data    map[string]any `json:\"data\"`\n",[156,9407,9408],{"class":158,"line":30},[156,9409,9410],{},"        Code    string         `json:\"code\"`\n",[156,9412,9413],{"class":158,"line":860},[156,9414,9415],{},"        Error   string         `json:\"error\"`\n",[156,9417,9418],{"class":158,"line":865},[156,9419,9420],{},"        Message string         `json:\"message\"`\n",[156,9422,9423],{"class":158,"line":896},[156,9424,758],{},[156,9426,9427],{"class":158,"line":918},[156,9428,9429],{},"    _ = json.Unmarshal(raw, &parsed)\n",[156,9431,9432],{"class":158,"line":35},[156,9433,9434],{},"    if res.StatusCode != 200 {\n",[156,9436,9437],{"class":158,"line":934},[156,9438,9439],{},"        code := parsed.Code\n",[156,9441,9442],{"class":158,"line":1504},[156,9443,9444],{},"        if code == \"\" {\n",[156,9446,9447],{"class":158,"line":1511},[156,9448,9449],{},"            code = parsed.Error\n",[156,9451,9452],{"class":158,"line":1522},[156,9453,2138],{},[156,9455,9456],{"class":158,"line":39},[156,9457,9458],{},"        panic(fmt.Sprintf(\"%d %s: %s\", res.StatusCode, code, parsed.Message))\n",[156,9460,9461],{"class":158,"line":1541},[156,9462,758],{},[156,9464,9465],{"class":158,"line":1551},[156,9466,9467],{},"    return parsed.Data\n",[156,9469,9470],{"class":158,"line":1560},[156,9471,435],{},[147,9473,9475],{"className":7093,"code":9474,"filename":7095,"language":7096,"meta":152,"style":152},"import java.net.URI;\nimport java.net.http.*;\nimport java.time.Duration;\n\nclass VerifyJson {\n    public static void main(String[] args) throws Exception {\n        String byUrl = verify(\"{\\\"url\\\":\\\"\" + System.getenv(\"SLIP_URL\") + \"\\\"}\");\n        String byQr = verify(\"{\\\"qr\\\":\\\"\" + System.getenv(\"SLIP_QR\") + \"\\\"}\");\n        System.out.println(byUrl + \" \" + byQr);\n    }\n\n    static String verify(String json) throws Exception {\n        HttpRequest req = HttpRequest.newBuilder(URI.create(\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"))\n                .timeout(Duration.ofSeconds(30))\n                .header(\"Authorization\", \"Bearer \" + System.getenv(\"SLIPBOLT_API_KEY\"))\n                .header(\"Content-Type\", \"application\u002Fjson\")\n                .POST(HttpRequest.BodyPublishers.ofString(json))\n                .build();\n        HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();\n        HttpResponse\u003CString> res = client.send(req, HttpResponse.BodyHandlers.ofString());\n        if (res.statusCode() != 200) {\n            String code = field(res.body(), \"code\");\n            if (code.isEmpty()) code = field(res.body(), \"error\");\n            throw new RuntimeException(res.statusCode() + \" \" + code + \": \" + field(res.body(), \"message\"));\n        }\n        return field(res.body(), \"status\");\n    }\n\n    static String field(String json, String key) {\n        int i = json.indexOf(\"\\\"\" + key + \"\\\"\");\n        if (i \u003C 0) return \"\";\n        int q1 = json.indexOf('\"', json.indexOf(':', i) + 1);\n        int q2 = json.indexOf('\"', q1 + 1);\n        return q1 \u003C 0 || q2 \u003C 0 ? \"\" : json.substring(q1 + 1, q2);\n    }\n}\n",[142,9476,9477,9483,9493,9499,9503,9512,9536,9585,9632,9650,9654,9658,9677,9698,9714,9740,9756,9769,9777,9805,9827,9845,9866,9893,9935,9939,9955,9959,9963,9982,10016,10034,10066,10090,10126,10130],{"__ignoreMap":152},[156,9478,9479,9481],{"class":158,"line":9},[156,9480,954],{"class":161},[156,9482,7105],{"class":165},[156,9484,9485,9487,9489,9491],{"class":158,"line":256},[156,9486,954],{"class":161},[156,9488,7112],{"class":165},[156,9490,841],{"class":262},[156,9492,272],{"class":165},[156,9494,9495,9497],{"class":158,"line":275},[156,9496,954],{"class":161},[156,9498,7141],{"class":165},[156,9500,9501],{"class":158,"line":282},[156,9502,279],{"emptyLinePlaceholder":278},[156,9504,9505,9507,9510],{"class":158,"line":303},[156,9506,1001],{"class":161},[156,9508,9509],{"class":290}," VerifyJson",[156,9511,300],{"class":165},[156,9513,9514,9516,9518,9520,9522,9524,9526,9528,9530,9532,9534],{"class":158,"line":324},[156,9515,1621],{"class":161},[156,9517,7168],{"class":161},[156,9519,7171],{"class":161},[156,9521,7174],{"class":290},[156,9523,309],{"class":165},[156,9525,7179],{"class":161},[156,9527,7182],{"class":165},[156,9529,7185],{"class":312},[156,9531,459],{"class":165},[156,9533,7190],{"class":161},[156,9535,7193],{"class":165},[156,9537,9538,9541,9543,9546,9548,9551,9553,9555,9557,9559,9561,9563,9565,9567,9569,9571,9573,9575,9577,9579,9581,9583],{"class":158,"line":378},[156,9539,9540],{"class":165},"        String byUrl ",[156,9542,169],{"class":161},[156,9544,9545],{"class":290}," verify",[156,9547,309],{"class":165},[156,9549,9550],{"class":172},"\"{",[156,9552,7342],{"class":262},[156,9554,5503],{"class":172},[156,9556,7342],{"class":262},[156,9558,1771],{"class":172},[156,9560,7342],{"class":262},[156,9562,1054],{"class":172},[156,9564,7355],{"class":161},[156,9566,7215],{"class":165},[156,9568,4703],{"class":290},[156,9570,309],{"class":165},[156,9572,8875],{"class":172},[156,9574,459],{"class":165},[156,9576,1265],{"class":161},[156,9578,1671],{"class":172},[156,9580,7342],{"class":262},[156,9582,7378],{"class":172},[156,9584,375],{"class":165},[156,9586,9587,9590,9592,9594,9596,9598,9600,9602,9604,9606,9608,9610,9612,9614,9616,9618,9620,9622,9624,9626,9628,9630],{"class":158,"line":395},[156,9588,9589],{"class":165},"        String byQr ",[156,9591,169],{"class":161},[156,9593,9545],{"class":290},[156,9595,309],{"class":165},[156,9597,9550],{"class":172},[156,9599,7342],{"class":262},[156,9601,5520],{"class":172},[156,9603,7342],{"class":262},[156,9605,1771],{"class":172},[156,9607,7342],{"class":262},[156,9609,1054],{"class":172},[156,9611,7355],{"class":161},[156,9613,7215],{"class":165},[156,9615,4703],{"class":290},[156,9617,309],{"class":165},[156,9619,8895],{"class":172},[156,9621,459],{"class":165},[156,9623,1265],{"class":161},[156,9625,1671],{"class":172},[156,9627,7342],{"class":262},[156,9629,7378],{"class":172},[156,9631,375],{"class":165},[156,9633,9634,9636,9638,9641,9643,9645,9647],{"class":158,"line":411},[156,9635,7878],{"class":165},[156,9637,7881],{"class":290},[156,9639,9640],{"class":165},"(byUrl ",[156,9642,1265],{"class":161},[156,9644,7895],{"class":172},[156,9646,7355],{"class":161},[156,9648,9649],{"class":165}," byQr);\n",[156,9651,9652],{"class":158,"line":13},[156,9653,758],{"class":165},[156,9655,9656],{"class":158,"line":432},[156,9657,279],{"emptyLinePlaceholder":278},[156,9659,9660,9662,9664,9667,9669,9671,9673,9675],{"class":158,"line":438},[156,9661,7415],{"class":161},[156,9663,7915],{"class":165},[156,9665,9666],{"class":290},"verify",[156,9668,7921],{"class":165},[156,9670,880],{"class":312},[156,9672,459],{"class":165},[156,9674,7190],{"class":161},[156,9676,7193],{"class":165},[156,9678,9679,9681,9683,9685,9687,9689,9691,9693,9696],{"class":158,"line":443},[156,9680,7467],{"class":165},[156,9682,169],{"class":161},[156,9684,7472],{"class":165},[156,9686,7264],{"class":290},[156,9688,7477],{"class":165},[156,9690,7480],{"class":290},[156,9692,309],{"class":165},[156,9694,9695],{"class":172},"\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"",[156,9697,4245],{"class":165},[156,9699,9700,9702,9704,9706,9708,9710,9712],{"class":158,"line":487},[156,9701,7488],{"class":165},[156,9703,671],{"class":290},[156,9705,7272],{"class":165},[156,9707,7275],{"class":290},[156,9709,309],{"class":165},[156,9711,1379],{"class":262},[156,9713,4245],{"class":165},[156,9715,9716,9718,9720,9722,9724,9726,9728,9730,9732,9734,9736,9738],{"class":158,"line":492},[156,9717,7488],{"class":165},[156,9719,7507],{"class":290},[156,9721,309],{"class":165},[156,9723,1329],{"class":172},[156,9725,315],{"class":165},[156,9727,7516],{"class":172},[156,9729,7355],{"class":161},[156,9731,7215],{"class":165},[156,9733,4703],{"class":290},[156,9735,309],{"class":165},[156,9737,1243],{"class":172},[156,9739,4245],{"class":165},[156,9741,9742,9744,9746,9748,9750,9752,9754],{"class":158,"line":498},[156,9743,7488],{"class":165},[156,9745,7507],{"class":290},[156,9747,309],{"class":165},[156,9749,1351],{"class":172},[156,9751,315],{"class":165},[156,9753,7393],{"class":172},[156,9755,1718],{"class":165},[156,9757,9758,9760,9762,9764,9766],{"class":158,"line":549},[156,9759,7488],{"class":165},[156,9761,7541],{"class":290},[156,9763,7544],{"class":165},[156,9765,7573],{"class":290},[156,9767,9768],{"class":165},"(json))\n",[156,9770,9771,9773,9775],{"class":158,"line":576},[156,9772,7488],{"class":165},[156,9774,7285],{"class":290},[156,9776,2875],{"class":165},[156,9778,9779,9781,9783,9785,9787,9789,9791,9793,9795,9797,9799,9801,9803],{"class":158,"line":585},[156,9780,7256],{"class":165},[156,9782,169],{"class":161},[156,9784,7261],{"class":165},[156,9786,7264],{"class":290},[156,9788,883],{"class":165},[156,9790,7269],{"class":290},[156,9792,7272],{"class":165},[156,9794,7275],{"class":290},[156,9796,309],{"class":165},[156,9798,1379],{"class":262},[156,9800,7282],{"class":165},[156,9802,7285],{"class":290},[156,9804,2875],{"class":165},[156,9806,9807,9810,9812,9815,9817,9819,9821,9823,9825],{"class":158,"line":18},[156,9808,9809],{"class":165},"        HttpResponse\u003C",[156,9811,7179],{"class":161},[156,9813,9814],{"class":165},"> res ",[156,9816,169],{"class":161},[156,9818,7565],{"class":165},[156,9820,7306],{"class":290},[156,9822,7570],{"class":165},[156,9824,7573],{"class":290},[156,9826,5059],{"class":165},[156,9828,9829,9831,9834,9836,9838,9841,9843],{"class":158,"line":619},[156,9830,1442],{"class":161},[156,9832,9833],{"class":165}," (res.",[156,9835,7887],{"class":290},[156,9837,7890],{"class":165},[156,9839,9840],{"class":161},"!=",[156,9842,2219],{"class":262},[156,9844,321],{"class":165},[156,9846,9847,9850,9852,9855,9857,9859,9862,9864],{"class":158,"line":631},[156,9848,9849],{"class":165},"            String code ",[156,9851,169],{"class":161},[156,9853,9854],{"class":290}," field",[156,9856,7884],{"class":165},[156,9858,318],{"class":290},[156,9860,9861],{"class":165},"(), ",[156,9863,1145],{"class":172},[156,9865,375],{"class":165},[156,9867,9868,9870,9873,9875,9878,9880,9882,9884,9886,9888,9891],{"class":158,"line":659},[156,9869,1399],{"class":161},[156,9871,9872],{"class":165}," (code.",[156,9874,7860],{"class":290},[156,9876,9877],{"class":165},"()) code ",[156,9879,169],{"class":161},[156,9881,9854],{"class":290},[156,9883,7884],{"class":165},[156,9885,318],{"class":290},[156,9887,9861],{"class":165},[156,9889,9890],{"class":172},"\"error\"",[156,9892,375],{"class":165},[156,9894,9895,9897,9899,9901,9903,9905,9907,9909,9911,9913,9916,9918,9921,9923,9925,9927,9929,9931,9933],{"class":158,"line":665},[156,9896,2156],{"class":161},[156,9898,465],{"class":161},[156,9900,2161],{"class":290},[156,9902,7884],{"class":165},[156,9904,7887],{"class":290},[156,9906,7890],{"class":165},[156,9908,1265],{"class":161},[156,9910,7895],{"class":172},[156,9912,7355],{"class":161},[156,9914,9915],{"class":165}," code ",[156,9917,1265],{"class":161},[156,9919,9920],{"class":172}," \": \"",[156,9922,7355],{"class":161},[156,9924,9854],{"class":290},[156,9926,7884],{"class":165},[156,9928,318],{"class":290},[156,9930,9861],{"class":165},[156,9932,6388],{"class":172},[156,9934,2001],{"class":165},[156,9936,9937],{"class":158,"line":22},[156,9938,2138],{"class":165},[156,9940,9941,9943,9945,9947,9949,9951,9953],{"class":158,"line":687},[156,9942,1563],{"class":161},[156,9944,9854],{"class":290},[156,9946,7884],{"class":165},[156,9948,318],{"class":290},[156,9950,9861],{"class":165},[156,9952,2413],{"class":172},[156,9954,375],{"class":165},[156,9956,9957],{"class":158,"line":699},[156,9958,758],{"class":165},[156,9960,9961],{"class":158,"line":723},[156,9962,279],{"emptyLinePlaceholder":278},[156,9964,9965,9967,9969,9972,9974,9976,9978,9980],{"class":158,"line":748},[156,9966,7415],{"class":161},[156,9968,7915],{"class":165},[156,9970,9971],{"class":290},"field",[156,9973,7921],{"class":165},[156,9975,880],{"class":312},[156,9977,7434],{"class":165},[156,9979,7442],{"class":312},[156,9981,321],{"class":165},[156,9983,9984,9986,9988,9990,9992,9994,9996,9998,10000,10002,10004,10006,10008,10010,10012,10014],{"class":158,"line":26},[156,9985,7934],{"class":161},[156,9987,7937],{"class":165},[156,9989,169],{"class":161},[156,9991,7942],{"class":165},[156,9993,7945],{"class":290},[156,9995,309],{"class":165},[156,9997,1054],{"class":172},[156,9999,7342],{"class":262},[156,10001,1054],{"class":172},[156,10003,7355],{"class":161},[156,10005,7958],{"class":165},[156,10007,1265],{"class":161},[156,10009,1671],{"class":172},[156,10011,7342],{"class":262},[156,10013,1054],{"class":172},[156,10015,375],{"class":165},[156,10017,10018,10020,10022,10024,10026,10028,10030,10032],{"class":158,"line":761},[156,10019,1442],{"class":161},[156,10021,7975],{"class":165},[156,10023,799],{"class":161},[156,10025,565],{"class":262},[156,10027,459],{"class":165},[156,10029,2797],{"class":161},[156,10031,1203],{"class":172},[156,10033,272],{"class":165},[156,10035,10036,10038,10040,10042,10044,10046,10048,10050,10052,10054,10056,10058,10060,10062,10064],{"class":158,"line":766},[156,10037,7934],{"class":161},[156,10039,7994],{"class":165},[156,10041,169],{"class":161},[156,10043,7942],{"class":165},[156,10045,7945],{"class":290},[156,10047,309],{"class":165},[156,10049,8005],{"class":172},[156,10051,7396],{"class":165},[156,10053,7945],{"class":290},[156,10055,309],{"class":165},[156,10057,8014],{"class":172},[156,10059,8017],{"class":165},[156,10061,1265],{"class":161},[156,10063,1268],{"class":262},[156,10065,375],{"class":165},[156,10067,10068,10070,10072,10074,10076,10078,10080,10082,10084,10086,10088],{"class":158,"line":805},[156,10069,7934],{"class":161},[156,10071,8030],{"class":165},[156,10073,169],{"class":161},[156,10075,7942],{"class":165},[156,10077,7945],{"class":290},[156,10079,309],{"class":165},[156,10081,8005],{"class":172},[156,10083,8043],{"class":165},[156,10085,1265],{"class":161},[156,10087,1268],{"class":262},[156,10089,375],{"class":165},[156,10091,10092,10094,10096,10098,10100,10102,10104,10106,10108,10110,10112,10114,10116,10118,10120,10122,10124],{"class":158,"line":849},[156,10093,1563],{"class":161},[156,10095,7994],{"class":165},[156,10097,799],{"class":161},[156,10099,565],{"class":262},[156,10101,781],{"class":161},[156,10103,8030],{"class":165},[156,10105,799],{"class":161},[156,10107,565],{"class":262},[156,10109,8070],{"class":161},[156,10111,1203],{"class":172},[156,10113,8075],{"class":161},[156,10115,7942],{"class":165},[156,10117,8080],{"class":290},[156,10119,8083],{"class":165},[156,10121,1265],{"class":161},[156,10123,1268],{"class":262},[156,10125,8090],{"class":165},[156,10127,10128],{"class":158,"line":30},[156,10129,758],{"class":165},[156,10131,10132],{"class":158,"line":860},[156,10133,435],{"class":165},[147,10135,10137],{"className":8101,"code":10136,"filename":8103,"language":8104,"meta":152,"style":152},"using System.Net.Http.Headers;\nusing System.Text;\nusing System.Text.Json;\n\nvar byUrl = await VerifyJson(new { url = Environment.GetEnvironmentVariable(\"SLIP_URL\") });\nvar byQr = await VerifyJson(new { qr = Environment.GetEnvironmentVariable(\"SLIP_QR\") });\nConsole.WriteLine($\"{byUrl} {byQr}\");\n\nstatic async Task\u003Cstring> VerifyJson(object payload)\n{\n    using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n    using var req = new HttpRequestMessage(HttpMethod.Post, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\");\n    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\"));\n    req.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, \"application\u002Fjson\");\n    using var res = await http.SendAsync(req);\n    var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n    if (!res.IsSuccessStatusCode)\n    {\n        string code = body.RootElement.TryGetProperty(\"code\", out var c) ? c.GetString() ?? \"\" : \"\";\n        if (code == \"\" && body.RootElement.TryGetProperty(\"error\", out var e)) code = e.GetString() ?? \"\";\n        string message = body.RootElement.TryGetProperty(\"message\", out var m) ? m.GetString() ?? \"\" : \"\";\n        throw new Exception($\"{(int)res.StatusCode} {code}: {message}\");\n    }\n    return body.RootElement.GetProperty(\"data\").GetProperty(\"status\").GetString()!;\n}\n",[142,10138,10139,10143,10147,10151,10155,10160,10165,10170,10174,10179,10183,10188,10193,10198,10203,10208,10213,10218,10222,10227,10232,10237,10242,10246,10251],{"__ignoreMap":152},[156,10140,10141],{"class":158,"line":9},[156,10142,8111],{},[156,10144,10145],{"class":158,"line":256},[156,10146,8116],{},[156,10148,10149],{"class":158,"line":275},[156,10150,8121],{},[156,10152,10153],{"class":158,"line":282},[156,10154,279],{"emptyLinePlaceholder":278},[156,10156,10157],{"class":158,"line":303},[156,10158,10159],{},"var byUrl = await VerifyJson(new { url = Environment.GetEnvironmentVariable(\"SLIP_URL\") });\n",[156,10161,10162],{"class":158,"line":324},[156,10163,10164],{},"var byQr = await VerifyJson(new { qr = Environment.GetEnvironmentVariable(\"SLIP_QR\") });\n",[156,10166,10167],{"class":158,"line":378},[156,10168,10169],{},"Console.WriteLine($\"{byUrl} {byQr}\");\n",[156,10171,10172],{"class":158,"line":395},[156,10173,279],{"emptyLinePlaceholder":278},[156,10175,10176],{"class":158,"line":411},[156,10177,10178],{},"static async Task\u003Cstring> VerifyJson(object payload)\n",[156,10180,10181],{"class":158,"line":13},[156,10182,1616],{},[156,10184,10185],{"class":158,"line":432},[156,10186,10187],{},"    using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n",[156,10189,10190],{"class":158,"line":438},[156,10191,10192],{},"    using var req = new HttpRequestMessage(HttpMethod.Post, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\");\n",[156,10194,10195],{"class":158,"line":443},[156,10196,10197],{},"    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\"));\n",[156,10199,10200],{"class":158,"line":487},[156,10201,10202],{},"    req.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, \"application\u002Fjson\");\n",[156,10204,10205],{"class":158,"line":492},[156,10206,10207],{},"    using var res = await http.SendAsync(req);\n",[156,10209,10210],{"class":158,"line":498},[156,10211,10212],{},"    var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n",[156,10214,10215],{"class":158,"line":549},[156,10216,10217],{},"    if (!res.IsSuccessStatusCode)\n",[156,10219,10220],{"class":158,"line":576},[156,10221,1650],{},[156,10223,10224],{"class":158,"line":585},[156,10225,10226],{},"        string code = body.RootElement.TryGetProperty(\"code\", out var c) ? c.GetString() ?? \"\" : \"\";\n",[156,10228,10229],{"class":158,"line":18},[156,10230,10231],{},"        if (code == \"\" && body.RootElement.TryGetProperty(\"error\", out var e)) code = e.GetString() ?? \"\";\n",[156,10233,10234],{"class":158,"line":619},[156,10235,10236],{},"        string message = body.RootElement.TryGetProperty(\"message\", out var m) ? m.GetString() ?? \"\" : \"\";\n",[156,10238,10239],{"class":158,"line":631},[156,10240,10241],{},"        throw new Exception($\"{(int)res.StatusCode} {code}: {message}\");\n",[156,10243,10244],{"class":158,"line":659},[156,10245,758],{},[156,10247,10248],{"class":158,"line":665},[156,10249,10250],{},"    return body.RootElement.GetProperty(\"data\").GetProperty(\"status\").GetString()!;\n",[156,10252,10253],{"class":158,"line":22},[156,10254,435],{},[175,10256,137],{"id":10257},"_4-ทดสอบ-webhook-ในเครื่อง",[65,10259,10260,10261,10263,10264,10267],{},"SlipBolt ส่ง webhook ไปได้เฉพาะ ",[142,10262,8327],{}," ที่เป็นที่อยู่สาธารณะ จึงยิงเข้า ",[142,10265,10266],{},"localhost"," ตรง ๆ ไม่ได้ — มีสองทาง:",[2538,10269,10271],{"id":10270},"ทางที่-1-เซ็น-event-เองแล้วยิงเข้า-localhost","ทางที่ 1 — เซ็น event เองแล้วยิงเข้า localhost",[65,10273,10274,10275,1768],{},"เร็วที่สุด ไม่ต้องเปิดอะไรออกอินเทอร์เน็ต · สคริปต์นี้เซ็นแบบเดียวกับที่ระบบจริงเซ็นทุกประการ\nใช้ secret เดียวกับที่ตั้งไว้ใน handler ของคุณ (",[101,10276,10278],{"href":10277},"\u002Fdocs\u002Fwebhooks#verify-signature","ตัวอย่าง handler",[147,10280,10282],{"className":149,"code":10281,"language":151,"meta":152,"style":152},"SECRET=\"whsec_ใส่ของคุณ\"\nURL=\"http:\u002F\u002Flocalhost:3000\u002Fwebhooks\u002Fslipbolt\"\n\nTS=$(date +%s)\nBODY='{\"event\":\"slip.verified\",\"id\":\"evt_local_'$TS'\",\"created\":'$TS',\"data\":{\"transactionId\":\"txn_local_1\",\"transRef\":\"TEST'$TS'\",\"amount\":250,\"status\":\"SUCCESS\",\"bankCode\":\"004\",\"bankName\":\"ธนาคารกสิกรไทย\",\"sender\":\"นาย ทดสอบ ระบบ\",\"receiver\":\"ร้านของคุณ\",\"verifiedAt\":\"2026-06-17T03:21:06.412Z\",\"latencyMs\":480}}'\nSIG=$(printf '%s.%s' \"$TS\" \"$BODY\" | openssl dgst -sha256 -hmac \"$SECRET\" | sed 's\u002F^.*= \u002F\u002F')\n\ncurl -i -X POST \"$URL\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"X-Slipbolt-Event: slip.verified\" \\\n  -H \"X-Slipbolt-Signature: t=$TS,v1=$SIG\" \\\n  --data-binary \"$BODY\"\n",[142,10283,10284,10294,10304,10308,10326,10352,10410,10414,10434,10442,10451,10470],{"__ignoreMap":152},[156,10285,10286,10289,10291],{"class":158,"line":9},[156,10287,10288],{"class":165},"SECRET",[156,10290,169],{"class":161},[156,10292,10293],{"class":172},"\"whsec_ใส่ของคุณ\"\n",[156,10295,10296,10299,10301],{"class":158,"line":256},[156,10297,10298],{"class":165},"URL",[156,10300,169],{"class":161},[156,10302,10303],{"class":172},"\"http:\u002F\u002Flocalhost:3000\u002Fwebhooks\u002Fslipbolt\"\n",[156,10305,10306],{"class":158,"line":275},[156,10307,279],{"emptyLinePlaceholder":278},[156,10309,10310,10313,10315,10318,10321,10324],{"class":158,"line":282},[156,10311,10312],{"class":165},"TS",[156,10314,169],{"class":161},[156,10316,10317],{"class":165},"$(",[156,10319,10320],{"class":290},"date",[156,10322,10323],{"class":172}," +%s",[156,10325,1718],{"class":165},[156,10327,10328,10331,10333,10336,10339,10342,10344,10347,10349],{"class":158,"line":303},[156,10329,10330],{"class":165},"BODY",[156,10332,169],{"class":161},[156,10334,10335],{"class":172},"'{\"event\":\"slip.verified\",\"id\":\"evt_local_'",[156,10337,10338],{"class":165},"$TS",[156,10340,10341],{"class":172},"'\",\"created\":'",[156,10343,10338],{"class":165},[156,10345,10346],{"class":172},"',\"data\":{\"transactionId\":\"txn_local_1\",\"transRef\":\"TEST'",[156,10348,10338],{"class":165},[156,10350,10351],{"class":172},"'\",\"amount\":250,\"status\":\"SUCCESS\",\"bankCode\":\"004\",\"bankName\":\"ธนาคารกสิกรไทย\",\"sender\":\"นาย ทดสอบ ระบบ\",\"receiver\":\"ร้านของคุณ\",\"verifiedAt\":\"2026-06-17T03:21:06.412Z\",\"latencyMs\":480}}'\n",[156,10353,10354,10357,10359,10361,10364,10367,10369,10371,10373,10375,10378,10380,10382,10385,10388,10391,10394,10396,10399,10401,10403,10405,10408],{"class":158,"line":324},[156,10355,10356],{"class":165},"SIG",[156,10358,169],{"class":161},[156,10360,10317],{"class":165},[156,10362,10363],{"class":262},"printf",[156,10365,10366],{"class":172}," '%s.%s'",[156,10368,1671],{"class":172},[156,10370,10338],{"class":165},[156,10372,1054],{"class":172},[156,10374,1671],{"class":172},[156,10376,10377],{"class":165},"$BODY",[156,10379,1054],{"class":172},[156,10381,5661],{"class":161},[156,10383,10384],{"class":290}," openssl",[156,10386,10387],{"class":172}," dgst",[156,10389,10390],{"class":262}," -sha256",[156,10392,10393],{"class":262}," -hmac",[156,10395,1671],{"class":172},[156,10397,10398],{"class":165},"$SECRET",[156,10400,1054],{"class":172},[156,10402,5661],{"class":161},[156,10404,5675],{"class":290},[156,10406,10407],{"class":172}," 's\u002F^.*= \u002F\u002F'",[156,10409,1718],{"class":165},[156,10411,10412],{"class":158,"line":378},[156,10413,279],{"emptyLinePlaceholder":278},[156,10415,10416,10418,10421,10423,10425,10427,10430,10432],{"class":158,"line":395},[156,10417,5556],{"class":290},[156,10419,10420],{"class":262}," -i",[156,10422,5559],{"class":262},[156,10424,5562],{"class":172},[156,10426,1671],{"class":172},[156,10428,10429],{"class":165},"$URL",[156,10431,1054],{"class":172},[156,10433,5583],{"class":262},[156,10435,10436,10438,10440],{"class":158,"line":411},[156,10437,5588],{"class":262},[156,10439,5714],{"class":172},[156,10441,5583],{"class":262},[156,10443,10444,10446,10449],{"class":158,"line":13},[156,10445,5588],{"class":262},[156,10447,10448],{"class":172}," \"X-Slipbolt-Event: slip.verified\"",[156,10450,5583],{"class":262},[156,10452,10453,10455,10458,10460,10463,10466,10468],{"class":158,"line":432},[156,10454,5588],{"class":262},[156,10456,10457],{"class":172}," \"X-Slipbolt-Signature: t=",[156,10459,10338],{"class":165},[156,10461,10462],{"class":172},",v1=",[156,10464,10465],{"class":165},"$SIG",[156,10467,1054],{"class":172},[156,10469,5583],{"class":262},[156,10471,10472,10475,10477,10479],{"class":158,"line":438},[156,10473,10474],{"class":262},"  --data-binary",[156,10476,1671],{"class":172},[156,10478,10377],{"class":165},[156,10480,1112],{"class":172},[65,10482,10483,10484,10486,10487,10489,10490,10492,10493,10495],{},"ได้ ",[142,10485,4062],{}," = handler ตรวจ signature ผ่าน · ลองแก้ ",[142,10488,10288],{}," ให้ผิดแล้วยิงอีกรอบ ต้องได้ ",[142,10491,3295],{},"\n(ถ้ายังได้ ",[142,10494,4062],{}," แปลว่า handler ไม่ได้ตรวจ signature จริง)",[2538,10497,10499],{"id":10498},"ทางที่-2-เปิดอุโมงค์แล้วให้ระบบจริงยิงมา","ทางที่ 2 — เปิดอุโมงค์แล้วให้ระบบจริงยิงมา",[65,10501,10502],{},"ใช้เมื่ออยากเห็น event จากสลิปจริง — เปิดอุโมงค์ด้วยเครื่องมือที่ถนัด (cloudflared, ngrok ฯลฯ) เช่น",[147,10504,10506],{"className":149,"code":10505,"language":151,"meta":152,"style":152},"cloudflared tunnel --url http:\u002F\u002Flocalhost:3000\n",[142,10507,10508],{"__ignoreMap":152},[156,10509,10510,10513,10516,10519],{"class":158,"line":9},[156,10511,10512],{"class":290},"cloudflared",[156,10514,10515],{"class":172}," tunnel",[156,10517,10518],{"class":262}," --url",[156,10520,10521],{"class":172}," http:\u002F\u002Flocalhost:3000\n",[65,10523,10524,10525,10528,10529,10532,10533,10536],{},"เอา URL ",[142,10526,10527],{},"https:\u002F\u002F….trycloudflare.com"," ที่ได้ ต่อด้วย path ของ handler ไปใส่ที่ ",[69,10530,10531],{},"Settings → Webhooks","\nแล้วกด ",[69,10534,10535],{},"ส่ง event ตัวอย่าง"," — ไม่กินโควตา",[175,10538,10540],{"id":10539},"เช็กลิสต์ก่อนขึ้น-production","เช็กลิสต์ก่อนขึ้น production",[186,10542,10543,10550,10561,10575,10581,10592],{},[189,10544,10545,10546,10549],{},"เปลี่ยนคีย์เป็น ",[142,10547,10548],{},"sk_live_"," และเก็บใน environment variable ของเซิร์ฟเวอร์ ไม่อยู่ในโค้ดหรือ repo",[189,10551,10552,10553,10557,10558,10560],{},"เช็คครบ ",[101,10554,10556],{"href":10555},"#%E0%B8%9B%E0%B8%A5%E0%B9%88%E0%B8%AD%E0%B8%A2%E0%B8%82%E0%B8%AD%E0%B8%87%E0%B9%84%E0%B8%94%E0%B9%89%E0%B9%80%E0%B8%A1%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%9C%E0%B9%88%E0%B8%B2%E0%B8%99%E0%B8%84%E0%B8%A3%E0%B8%9A-4-%E0%B8%82%E0%B9%89%E0%B8%AD","4 ข้อ"," ก่อนปล่อยของ และ ",[142,10559,2608],{}," ติด UNIQUE ในฐานข้อมูล",[189,10562,10563,10564,10570,10571,10574],{},"เรียก ",[101,10565,10567],{"href":10566},"\u002Fdocs\u002Fapi#get-apiv1me",[142,10568,10569],{},"GET \u002Fme"," ตอนบูตระบบ — ยืนยันว่าคีย์ถูกร้าน และ ",[142,10572,10573],{},"payeeAccounts"," มีบัญชีที่ลูกค้าโอนเข้า",[189,10576,10577,10578,10580],{},"จัดการ ",[142,10579,231],{}," (โควตาหมด) ให้แจ้งเตือนทีมคุณ ไม่ใช่เงียบ — ลูกค้าจะจ่ายเงินแล้วออเดอร์ไม่ปิด",[189,10582,10583,10584,10587,10588,10591],{},"ถ้าใช้ webhook: ตรวจ signature จาก raw body · ตอบ ",[142,10585,10586],{},"2xx"," ภายใน 10 วินาที · กันประมวลผล ",[142,10589,10590],{},"id"," ซ้ำ",[189,10593,10594,10595,10598,10599,10601],{},"เก็บ ",[142,10596,10597],{},"requestId"," (จาก ",[142,10600,43],{}," หรือ error) ลง log — ส่งมาให้ทีมงานแล้วเราไล่ให้ได้ทันที",[10603,10604,10605],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":152,"searchDepth":275,"depth":275,"links":10607},[10608,10609,10614,10617,10621],{"id":177,"depth":256,"text":104},{"id":2523,"depth":256,"text":115,"children":10610},[10611,10612,10613],{"id":2540,"depth":275,"text":2541},{"id":2642,"depth":275,"text":2643},{"id":2912,"depth":275,"text":2912},{"id":5400,"depth":256,"text":126,"children":10615},[10616],{"id":8295,"depth":275,"text":8296},{"id":10257,"depth":256,"text":137,"children":10618},[10619,10620],{"id":10270,"depth":275,"text":10271},{"id":10498,"depth":275,"text":10499},{"id":10539,"depth":256,"text":10540},"โค้ดก๊อปไปวางแล้วใช้ได้จริง — ไคลเอนต์ที่ retry เอง, รับสลิปจากลูกค้าแล้วปิดออเดอร์, ส่งสลิปแบบ multipart\u002Fbase64\u002FURL\u002FQR, ทดสอบ webhook ในเครื่อง","md",{},{"title":33,"description":10622},"docs\u002Frecipes",null,"-7ezIHYjcDAJV5jF2GAkL4L5kQIyUqcG1ySx0RY0igU",1793286720330]