[{"data":1,"prerenderedAt":10628},["ShallowReactive",2],{"docs-nav":3,"docs-en-\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":55,"badge":60,"body":61,"category":34,"description":10621,"extension":10622,"meta":10623,"navigation":277,"order":35,"path":32,"seo":10624,"stem":10625,"updatedAt":10626,"__hash__":10627,"translated":277},"docs_en\u002Fdocs\u002Frecipes.md","Copy & paste",{"type":62,"value":63,"toc":10605},"minimark",[64,72,137,145,173,177,184,236,2263,2266,2520,2523,2526,2536,2541,2615,2639,2643,2650,2909,2913,2920,5374,5398,5401,5414,5525,8281,8293,8297,8313,8320,8341,8348,8359,10255,10258,10268,10272,10279,10481,10495,10499,10502,10521,10536,10540,10601],[65,66,67,71],"p",{},[68,69,70],"strong",{},"Every block on this page runs as-is."," Paste it in and change only the database part.\nPick your language on a tab once and every block follows.",[73,74,75,88],"table",{},[76,77,78],"thead",{},[79,80,81,85],"tr",{},[82,83,84],"th",{},"You want",[82,86,87],{},"Go to",[89,90,91,104,115,126],"tbody",{},[79,92,93,97],{},[94,95,96],"td",{},"A verify function that handles retries and timeouts",[94,98,99],{},[100,101,103],"a",{"href":102},"#_1-ready-made-client","1. Ready-made client",[79,105,106,109],{},[94,107,108],{},"Customer uploads a slip → verify → close the order",[94,110,111],{},[100,112,114],{"href":113},"#_2-take-a-slip-close-the-order","2. Take a slip, close the order",[79,116,117,120],{},[94,118,119],{},"Send a form upload \u002F base64 \u002F a URL \u002F the QR text",[94,121,122],{},[100,123,125],{"href":124},"#_3-the-image-is-in-another-format","3. The image is in another format",[79,127,128,131],{},[94,129,130],{},"Try webhooks before you have a real server",[94,132,133],{},[100,134,136],{"href":135},"#_4-test-webhooks-locally","4. Test webhooks locally",[65,138,139,140,144],{},"Every example reads the key from an environment variable — use ",[141,142,143],"code",{},"sk_test_"," while developing; it does not consume the shop's quota.",[146,147,152],"pre",{"className":148,"code":149,"language":150,"meta":151,"style":151},"language-bash shiki shiki-themes github-light github-dark","export SLIPBOLT_API_KEY=\"sk_test_...\"\n","bash","",[141,153,154],{"__ignoreMap":151},[155,156,158,162,166,169],"span",{"class":157,"line":9},"line",[155,159,161],{"class":160},"szBVR","export",[155,163,165],{"class":164},"sVt8B"," SLIPBOLT_API_KEY",[155,167,168],{"class":160},"=",[155,170,172],{"class":171},"sZZnC","\"sk_test_...\"\n",[174,175,103],"h2",{"id":176},"_1-ready-made-client",[65,178,179,180,183],{},"One file, no extra dependencies (Python uses ",[141,181,182],{},"requests","). It covers the three things every real system needs:",[185,186,187,194,216],"ul",{},[188,189,190,193],"li",{},[68,191,192],{},"30-second timeout"," — a network problem does not hang your customer's whole request",[188,195,196,199,200,203,204,207,208,211,212,215],{},[68,197,198],{},"Automatic retries"," on network failure · ",[141,201,202],{},"429"," (waits for ",[141,205,206],{},"Retry-After",") · ",[141,209,210],{},"5xx"," — safe, because resending the same\nimage within 24 hours returns the original result (",[141,213,214],{},"cached: true","): no second check, no second quota charge",[188,217,218,227,228,231,232,235],{},[68,219,220,221,224,225],{},"Errors with ",[141,222,223],{},"status"," + ",[141,226,141],{}," — tell \"quota used up\" (",[141,229,230],{},"402",") from \"bad key\" (",[141,233,234],{},"401",") without parsing the message",[237,238,239,936,1575],"code-group",{},[146,240,245],{"className":241,"code":242,"filename":243,"language":244,"meta":151,"style":151},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F slipbolt.js — Node.js 18+ · no packages to install\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, e.g. 402\n    this.code = body.code; \u002F\u002F e.g. QUOTA_EXCEEDED\n    this.requestId = body.requestId; \u002F\u002F include it when you contact support\n  }\n}\n\nconst sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\n\u002F** Verify one slip — returns the `data` block · throws SlipBoltError when the API returns an 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 network failure \u002F timeout, out of attempts\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 the result is always under data\n  }\n}\n","Node.js","js",[141,246,247,253,272,279,300,321,375,392,408,424,429,435,440,484,489,495,546,573,582,590,616,628,656,662,679,684,696,720,745,753,758,763,802,846,853,857,862,893,915,927,931],{"__ignoreMap":151},[155,248,249],{"class":157,"line":9},[155,250,252],{"class":251},"sJ8bj","\u002F\u002F slipbolt.js — Node.js 18+ · no packages to install\n",[155,254,256,259,263,266,269],{"class":157,"line":255},2,[155,257,258],{"class":160},"const",[155,260,262],{"class":261},"sj4cs"," BASE",[155,264,265],{"class":160}," =",[155,267,268],{"class":171}," 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1'",[155,270,271],{"class":164},";\n",[155,273,275],{"class":157,"line":274},3,[155,276,278],{"emptyLinePlaceholder":277},true,"\n",[155,280,282,284,287,291,294,297],{"class":157,"line":281},4,[155,283,161],{"class":160},[155,285,286],{"class":160}," class",[155,288,290],{"class":289},"sScJk"," SlipBoltError",[155,292,293],{"class":160}," extends",[155,295,296],{"class":289}," Error",[155,298,299],{"class":164}," {\n",[155,301,303,306,309,312,315,318],{"class":157,"line":302},5,[155,304,305],{"class":160},"  constructor",[155,307,308],{"class":164},"(",[155,310,223],{"class":311},"s4XuR",[155,313,314],{"class":164},", ",[155,316,317],{"class":311},"body",[155,319,320],{"class":164},") {\n",[155,322,324,327,329,332,334,337,339,342,344,347,350,352,355,357,360,362,364,367,369,372],{"class":157,"line":323},6,[155,325,326],{"class":261},"    super",[155,328,308],{"class":164},[155,330,331],{"class":171},"`${",[155,333,223],{"class":164},[155,335,336],{"class":171},"} ${",[155,338,317],{"class":164},[155,340,341],{"class":171},".",[155,343,141],{"class":164},[155,345,346],{"class":160}," ??",[155,348,349],{"class":164}," body",[155,351,341],{"class":171},[155,353,354],{"class":164},"error",[155,356,346],{"class":160},[155,358,359],{"class":171}," ''}: ${",[155,361,317],{"class":164},[155,363,341],{"class":171},[155,365,366],{"class":164},"message",[155,368,346],{"class":160},[155,370,371],{"class":171}," 'request failed'}`",[155,373,374],{"class":164},");\n",[155,376,378,381,384,386,389],{"class":157,"line":377},7,[155,379,380],{"class":261},"    this",[155,382,383],{"class":164},".status ",[155,385,168],{"class":160},[155,387,388],{"class":164}," status; ",[155,390,391],{"class":251},"\u002F\u002F HTTP status, e.g. 402\n",[155,393,395,397,400,402,405],{"class":157,"line":394},8,[155,396,380],{"class":261},[155,398,399],{"class":164},".code ",[155,401,168],{"class":160},[155,403,404],{"class":164}," body.code; ",[155,406,407],{"class":251},"\u002F\u002F e.g. QUOTA_EXCEEDED\n",[155,409,411,413,416,418,421],{"class":157,"line":410},9,[155,412,380],{"class":261},[155,414,415],{"class":164},".requestId ",[155,417,168],{"class":160},[155,419,420],{"class":164}," body.requestId; ",[155,422,423],{"class":251},"\u002F\u002F include it when you contact support\n",[155,425,426],{"class":157,"line":13},[155,427,428],{"class":164},"  }\n",[155,430,432],{"class":157,"line":431},11,[155,433,434],{"class":164},"}\n",[155,436,438],{"class":157,"line":437},12,[155,439,278],{"emptyLinePlaceholder":277},[155,441,443,445,448,450,453,456,459,462,465,468,471,474,476,478,481],{"class":157,"line":442},13,[155,444,258],{"class":160},[155,446,447],{"class":289}," sleep",[155,449,265],{"class":160},[155,451,452],{"class":164}," (",[155,454,455],{"class":311},"ms",[155,457,458],{"class":164},") ",[155,460,461],{"class":160},"=>",[155,463,464],{"class":160}," new",[155,466,467],{"class":261}," Promise",[155,469,470],{"class":164},"((",[155,472,473],{"class":311},"resolve",[155,475,458],{"class":164},[155,477,461],{"class":160},[155,479,480],{"class":289}," setTimeout",[155,482,483],{"class":164},"(resolve, ms));\n",[155,485,487],{"class":157,"line":486},14,[155,488,278],{"emptyLinePlaceholder":277},[155,490,492],{"class":157,"line":491},15,[155,493,494],{"class":251},"\u002F** Verify one slip — returns the `data` block · throws SlipBoltError when the API returns an error *\u002F\n",[155,496,498,500,503,506,509,511,514,517,520,522,525,528,530,533,535,538,541,543],{"class":157,"line":497},16,[155,499,161],{"class":160},[155,501,502],{"class":160}," async",[155,504,505],{"class":160}," function",[155,507,508],{"class":289}," verifySlip",[155,510,308],{"class":164},[155,512,513],{"class":311},"image",[155,515,516],{"class":164},", { ",[155,518,519],{"class":311},"apiKey",[155,521,265],{"class":160},[155,523,524],{"class":164}," process.env.",[155,526,527],{"class":261},"SLIPBOLT_API_KEY",[155,529,314],{"class":164},[155,531,532],{"class":311},"retries",[155,534,265],{"class":160},[155,536,537],{"class":261}," 3",[155,539,540],{"class":164}," } ",[155,542,168],{"class":160},[155,544,545],{"class":164}," {}) {\n",[155,547,549,552,554,557,560,562,565,568,571],{"class":157,"line":548},17,[155,550,551],{"class":160},"  for",[155,553,452],{"class":164},[155,555,556],{"class":160},"let",[155,558,559],{"class":164}," attempt ",[155,561,168],{"class":160},[155,563,564],{"class":261}," 0",[155,566,567],{"class":164},"; ; attempt",[155,569,570],{"class":160},"++",[155,572,320],{"class":164},[155,574,576,579],{"class":157,"line":575},18,[155,577,578],{"class":160},"    let",[155,580,581],{"class":164}," res;\n",[155,583,585,588],{"class":157,"line":584},19,[155,586,587],{"class":160},"    try",[155,589,299],{"class":164},[155,591,592,595,597,600,603,605,607,610,613],{"class":157,"line":18},[155,593,594],{"class":164},"      res ",[155,596,168],{"class":160},[155,598,599],{"class":160}," await",[155,601,602],{"class":289}," fetch",[155,604,308],{"class":164},[155,606,331],{"class":171},[155,608,609],{"class":261},"BASE",[155,611,612],{"class":171},"}\u002Fverify`",[155,614,615],{"class":164},", {\n",[155,617,619,622,625],{"class":157,"line":618},21,[155,620,621],{"class":164},"        method: ",[155,623,624],{"class":171},"'POST'",[155,626,627],{"class":164},",\n",[155,629,631,634,637,639,642,644,647,650,653],{"class":157,"line":630},22,[155,632,633],{"class":164},"        headers: { Authorization: ",[155,635,636],{"class":171},"`Bearer ${",[155,638,519],{"class":164},[155,640,641],{"class":171},"}`",[155,643,314],{"class":164},[155,645,646],{"class":171},"'Content-Type'",[155,648,649],{"class":164},": ",[155,651,652],{"class":171},"'application\u002Foctet-stream'",[155,654,655],{"class":164}," },\n",[155,657,659],{"class":157,"line":658},23,[155,660,661],{"class":164},"        body: image,\n",[155,663,665,668,671,673,676],{"class":157,"line":664},24,[155,666,667],{"class":164},"        signal: AbortSignal.",[155,669,670],{"class":289},"timeout",[155,672,308],{"class":164},[155,674,675],{"class":261},"30_000",[155,677,678],{"class":164},"),\n",[155,680,681],{"class":157,"line":22},[155,682,683],{"class":164},"      });\n",[155,685,687,690,693],{"class":157,"line":686},26,[155,688,689],{"class":164},"    } ",[155,691,692],{"class":160},"catch",[155,694,695],{"class":164}," (err) {\n",[155,697,699,702,705,708,711,714,717],{"class":157,"line":698},27,[155,700,701],{"class":160},"      if",[155,703,704],{"class":164}," (attempt ",[155,706,707],{"class":160},">=",[155,709,710],{"class":164}," retries) ",[155,712,713],{"class":160},"throw",[155,715,716],{"class":164}," err; ",[155,718,719],{"class":251},"\u002F\u002F network failure \u002F timeout, out of attempts\n",[155,721,723,726,728,730,733,736,739,742],{"class":157,"line":722},28,[155,724,725],{"class":160},"      await",[155,727,447],{"class":289},[155,729,308],{"class":164},[155,731,732],{"class":261},"500",[155,734,735],{"class":160}," *",[155,737,738],{"class":261}," 2",[155,740,741],{"class":160}," **",[155,743,744],{"class":164}," attempt);\n",[155,746,748,751],{"class":157,"line":747},29,[155,749,750],{"class":160},"      continue",[155,752,271],{"class":164},[155,754,755],{"class":157,"line":26},[155,756,757],{"class":164},"    }\n",[155,759,761],{"class":157,"line":760},31,[155,762,278],{"emptyLinePlaceholder":277},[155,764,766,769,772,775,778,781,784,786,789,791,794,796,799],{"class":157,"line":765},32,[155,767,768],{"class":160},"    if",[155,770,771],{"class":164}," ((res.status ",[155,773,774],{"class":160},"===",[155,776,777],{"class":261}," 429",[155,779,780],{"class":160}," ||",[155,782,783],{"class":164}," res.status ",[155,785,707],{"class":160},[155,787,788],{"class":261}," 500",[155,790,458],{"class":164},[155,792,793],{"class":160},"&&",[155,795,559],{"class":164},[155,797,798],{"class":160},"\u003C",[155,800,801],{"class":164}," retries) {\n",[155,803,805,807,809,811,814,817,820,822,825,828,831,833,835,838,841,844],{"class":157,"line":804},33,[155,806,725],{"class":160},[155,808,447],{"class":289},[155,810,470],{"class":164},[155,812,813],{"class":289},"Number",[155,815,816],{"class":164},"(res.headers.",[155,818,819],{"class":289},"get",[155,821,308],{"class":164},[155,823,824],{"class":171},"'retry-after'",[155,826,827],{"class":164},")) ",[155,829,830],{"class":160},"||",[155,832,738],{"class":261},[155,834,741],{"class":160},[155,836,837],{"class":164}," attempt) ",[155,839,840],{"class":160},"*",[155,842,843],{"class":261}," 1000",[155,845,374],{"class":164},[155,847,849,851],{"class":157,"line":848},34,[155,850,750],{"class":160},[155,852,271],{"class":164},[155,854,855],{"class":157,"line":30},[155,856,757],{"class":164},[155,858,860],{"class":157,"line":859},36,[155,861,278],{"emptyLinePlaceholder":277},[155,863,865,868,870,872,874,877,880,883,885,888,890],{"class":157,"line":864},37,[155,866,867],{"class":160},"    const",[155,869,349],{"class":261},[155,871,265],{"class":160},[155,873,599],{"class":160},[155,875,876],{"class":164}," res.",[155,878,879],{"class":289},"json",[155,881,882],{"class":164},"().",[155,884,692],{"class":289},[155,886,887],{"class":164},"(() ",[155,889,461],{"class":160},[155,891,892],{"class":164}," ({}));\n",[155,894,896,898,900,903,906,908,910,912],{"class":157,"line":895},38,[155,897,768],{"class":160},[155,899,452],{"class":164},[155,901,902],{"class":160},"!",[155,904,905],{"class":164},"res.ok) ",[155,907,713],{"class":160},[155,909,464],{"class":160},[155,911,290],{"class":289},[155,913,914],{"class":164},"(res.status, body);\n",[155,916,918,921,924],{"class":157,"line":917},39,[155,919,920],{"class":160},"    return",[155,922,923],{"class":164}," body.data; ",[155,925,926],{"class":251},"\u002F\u002F the result is always under data\n",[155,928,929],{"class":157,"line":35},[155,930,428],{"class":164},[155,932,934],{"class":157,"line":933},41,[155,935,434],{"class":164},[146,937,942],{"className":938,"code":939,"filename":940,"language":941,"meta":151,"style":151},"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, e.g. 402\n        self.code = body.get(\"code\")  # e.g. QUOTA_EXCEEDED\n        self.request_id = body.get(\"requestId\")  # include it when you contact support\n\n\ndef verify_slip(image: bytes, api_key: str = \"\", retries: int = 3) -> dict:\n    \"\"\"Verify one slip — returns the data block · raises SlipBoltError when the API returns an 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  # network failure \u002F timeout, out of attempts\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\"]  # the result is always under data\n","Python","python",[141,943,944,949,957,964,968,975,979,988,992,996,1011,1033,1046,1112,1117,1132,1151,1170,1174,1178,1220,1225,1246,1270,1285,1292,1302,1317,1359,1369,1381,1386,1394,1402,1410,1428,1433,1437,1469,1493,1497,1501,1508,1519,1529,1538,1548,1557],{"__ignoreMap":151},[155,945,946],{"class":157,"line":9},[155,947,948],{"class":251},"# slipbolt.py — pip install requests\n",[155,950,951,954],{"class":157,"line":255},[155,952,953],{"class":160},"import",[155,955,956],{"class":164}," os\n",[155,958,959,961],{"class":157,"line":274},[155,960,953],{"class":160},[155,962,963],{"class":164}," time\n",[155,965,966],{"class":157,"line":281},[155,967,278],{"emptyLinePlaceholder":277},[155,969,970,972],{"class":157,"line":302},[155,971,953],{"class":160},[155,973,974],{"class":164}," requests\n",[155,976,977],{"class":157,"line":323},[155,978,278],{"emptyLinePlaceholder":277},[155,980,981,983,985],{"class":157,"line":377},[155,982,609],{"class":261},[155,984,265],{"class":160},[155,986,987],{"class":171}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\"\n",[155,989,990],{"class":157,"line":394},[155,991,278],{"emptyLinePlaceholder":277},[155,993,994],{"class":157,"line":410},[155,995,278],{"emptyLinePlaceholder":277},[155,997,998,1001,1003,1005,1008],{"class":157,"line":13},[155,999,1000],{"class":160},"class",[155,1002,290],{"class":289},[155,1004,308],{"class":164},[155,1006,1007],{"class":261},"Exception",[155,1009,1010],{"class":164},"):\n",[155,1012,1013,1016,1019,1022,1025,1028,1031],{"class":157,"line":431},[155,1014,1015],{"class":160},"    def",[155,1017,1018],{"class":261}," __init__",[155,1020,1021],{"class":164},"(self, status: ",[155,1023,1024],{"class":261},"int",[155,1026,1027],{"class":164},", body: ",[155,1029,1030],{"class":261},"dict",[155,1032,1010],{"class":164},[155,1034,1035,1038,1040,1043],{"class":157,"line":437},[155,1036,1037],{"class":261},"        super",[155,1039,882],{"class":164},[155,1041,1042],{"class":261},"__init__",[155,1044,1045],{"class":164},"(\n",[155,1047,1048,1051,1054,1057,1059,1062,1065,1068,1071,1073,1076,1079,1082,1084,1086,1089,1091,1093,1095,1097,1100,1102,1104,1107,1109],{"class":157,"line":442},[155,1049,1050],{"class":160},"            f",[155,1052,1053],{"class":171},"\"",[155,1055,1056],{"class":261},"{",[155,1058,223],{"class":164},[155,1060,1061],{"class":261},"}",[155,1063,1064],{"class":261}," {",[155,1066,1067],{"class":164},"body.get(",[155,1069,1070],{"class":171},"'code'",[155,1072,458],{"class":164},[155,1074,1075],{"class":160},"or",[155,1077,1078],{"class":164}," body.get(",[155,1080,1081],{"class":171},"'error'",[155,1083,458],{"class":164},[155,1085,1075],{"class":160},[155,1087,1088],{"class":171}," ''",[155,1090,1061],{"class":261},[155,1092,649],{"class":171},[155,1094,1056],{"class":261},[155,1096,1067],{"class":164},[155,1098,1099],{"class":171},"'message'",[155,1101,458],{"class":164},[155,1103,1075],{"class":160},[155,1105,1106],{"class":171}," 'request failed'",[155,1108,1061],{"class":261},[155,1110,1111],{"class":171},"\"\n",[155,1113,1114],{"class":157,"line":486},[155,1115,1116],{"class":164},"        )\n",[155,1118,1119,1122,1124,1126,1129],{"class":157,"line":491},[155,1120,1121],{"class":261},"        self",[155,1123,383],{"class":164},[155,1125,168],{"class":160},[155,1127,1128],{"class":164}," status  ",[155,1130,1131],{"class":251},"# HTTP status, e.g. 402\n",[155,1133,1134,1136,1138,1140,1142,1145,1148],{"class":157,"line":497},[155,1135,1121],{"class":261},[155,1137,399],{"class":164},[155,1139,168],{"class":160},[155,1141,1078],{"class":164},[155,1143,1144],{"class":171},"\"code\"",[155,1146,1147],{"class":164},")  ",[155,1149,1150],{"class":251},"# e.g. QUOTA_EXCEEDED\n",[155,1152,1153,1155,1158,1160,1162,1165,1167],{"class":157,"line":548},[155,1154,1121],{"class":261},[155,1156,1157],{"class":164},".request_id ",[155,1159,168],{"class":160},[155,1161,1078],{"class":164},[155,1163,1164],{"class":171},"\"requestId\"",[155,1166,1147],{"class":164},[155,1168,1169],{"class":251},"# include it when you contact support\n",[155,1171,1172],{"class":157,"line":575},[155,1173,278],{"emptyLinePlaceholder":277},[155,1175,1176],{"class":157,"line":584},[155,1177,278],{"emptyLinePlaceholder":277},[155,1179,1180,1183,1186,1189,1192,1195,1198,1200,1203,1206,1208,1210,1212,1215,1217],{"class":157,"line":18},[155,1181,1182],{"class":160},"def",[155,1184,1185],{"class":289}," verify_slip",[155,1187,1188],{"class":164},"(image: ",[155,1190,1191],{"class":261},"bytes",[155,1193,1194],{"class":164},", api_key: ",[155,1196,1197],{"class":261},"str",[155,1199,265],{"class":160},[155,1201,1202],{"class":171}," \"\"",[155,1204,1205],{"class":164},", retries: ",[155,1207,1024],{"class":261},[155,1209,265],{"class":160},[155,1211,537],{"class":261},[155,1213,1214],{"class":164},") -> ",[155,1216,1030],{"class":261},[155,1218,1219],{"class":164},":\n",[155,1221,1222],{"class":157,"line":618},[155,1223,1224],{"class":171},"    \"\"\"Verify one slip — returns the data block · raises SlipBoltError when the API returns an error\"\"\"\n",[155,1226,1227,1230,1232,1235,1237,1240,1243],{"class":157,"line":630},[155,1228,1229],{"class":164},"    api_key ",[155,1231,168],{"class":160},[155,1233,1234],{"class":164}," api_key ",[155,1236,1075],{"class":160},[155,1238,1239],{"class":164}," os.environ[",[155,1241,1242],{"class":171},"\"SLIPBOLT_API_KEY\"",[155,1244,1245],{"class":164},"]\n",[155,1247,1248,1251,1253,1256,1259,1262,1265,1268],{"class":157,"line":658},[155,1249,1250],{"class":160},"    for",[155,1252,559],{"class":164},[155,1254,1255],{"class":160},"in",[155,1257,1258],{"class":261}," range",[155,1260,1261],{"class":164},"(retries ",[155,1263,1264],{"class":160},"+",[155,1266,1267],{"class":261}," 1",[155,1269,1010],{"class":164},[155,1271,1272,1275,1277,1279,1282],{"class":157,"line":664},[155,1273,1274],{"class":164},"        last ",[155,1276,168],{"class":160},[155,1278,559],{"class":164},[155,1280,1281],{"class":160},"==",[155,1283,1284],{"class":164}," retries\n",[155,1286,1287,1290],{"class":157,"line":22},[155,1288,1289],{"class":160},"        try",[155,1291,1219],{"class":164},[155,1293,1294,1297,1299],{"class":157,"line":686},[155,1295,1296],{"class":164},"            res ",[155,1298,168],{"class":160},[155,1300,1301],{"class":164}," requests.post(\n",[155,1303,1304,1307,1309,1312,1315],{"class":157,"line":698},[155,1305,1306],{"class":160},"                f",[155,1308,1053],{"class":171},[155,1310,1311],{"class":261},"{BASE}",[155,1313,1314],{"class":171},"\u002Fverify\"",[155,1316,627],{"class":164},[155,1318,1319,1322,1324,1326,1329,1331,1334,1337,1339,1342,1344,1346,1348,1351,1353,1356],{"class":157,"line":722},[155,1320,1321],{"class":311},"                headers",[155,1323,168],{"class":160},[155,1325,1056],{"class":164},[155,1327,1328],{"class":171},"\"Authorization\"",[155,1330,649],{"class":164},[155,1332,1333],{"class":160},"f",[155,1335,1336],{"class":171},"\"Bearer ",[155,1338,1056],{"class":261},[155,1340,1341],{"class":164},"api_key",[155,1343,1061],{"class":261},[155,1345,1053],{"class":171},[155,1347,314],{"class":164},[155,1349,1350],{"class":171},"\"Content-Type\"",[155,1352,649],{"class":164},[155,1354,1355],{"class":171},"\"application\u002Foctet-stream\"",[155,1357,1358],{"class":164},"},\n",[155,1360,1361,1364,1366],{"class":157,"line":747},[155,1362,1363],{"class":311},"                data",[155,1365,168],{"class":160},[155,1367,1368],{"class":164},"image,\n",[155,1370,1371,1374,1376,1379],{"class":157,"line":26},[155,1372,1373],{"class":311},"                timeout",[155,1375,168],{"class":160},[155,1377,1378],{"class":261},"30",[155,1380,627],{"class":164},[155,1382,1383],{"class":157,"line":760},[155,1384,1385],{"class":164},"            )\n",[155,1387,1388,1391],{"class":157,"line":765},[155,1389,1390],{"class":160},"        except",[155,1392,1393],{"class":164}," requests.RequestException:\n",[155,1395,1396,1399],{"class":157,"line":804},[155,1397,1398],{"class":160},"            if",[155,1400,1401],{"class":164}," last:\n",[155,1403,1404,1407],{"class":157,"line":848},[155,1405,1406],{"class":160},"                raise",[155,1408,1409],{"class":251},"  # network failure \u002F timeout, out of attempts\n",[155,1411,1412,1415,1418,1420,1422,1425],{"class":157,"line":30},[155,1413,1414],{"class":164},"            time.sleep(",[155,1416,1417],{"class":261},"0.5",[155,1419,735],{"class":160},[155,1421,738],{"class":261},[155,1423,1424],{"class":160},"**",[155,1426,1427],{"class":164},"attempt)\n",[155,1429,1430],{"class":157,"line":859},[155,1431,1432],{"class":160},"            continue\n",[155,1434,1435],{"class":157,"line":864},[155,1436,278],{"emptyLinePlaceholder":277},[155,1438,1439,1442,1445,1447,1449,1452,1455,1457,1459,1461,1464,1467],{"class":157,"line":895},[155,1440,1441],{"class":160},"        if",[155,1443,1444],{"class":164}," (res.status_code ",[155,1446,1281],{"class":160},[155,1448,777],{"class":261},[155,1450,1451],{"class":160}," or",[155,1453,1454],{"class":164}," res.status_code ",[155,1456,707],{"class":160},[155,1458,788],{"class":261},[155,1460,458],{"class":164},[155,1462,1463],{"class":160},"and",[155,1465,1466],{"class":160}," not",[155,1468,1401],{"class":164},[155,1470,1471,1473,1476,1479,1482,1484,1486,1488,1490],{"class":157,"line":917},[155,1472,1414],{"class":164},[155,1474,1475],{"class":261},"float",[155,1477,1478],{"class":164},"(res.headers.get(",[155,1480,1481],{"class":171},"\"Retry-After\"",[155,1483,458],{"class":164},[155,1485,1075],{"class":160},[155,1487,738],{"class":261},[155,1489,1424],{"class":160},[155,1491,1492],{"class":164},"attempt))\n",[155,1494,1495],{"class":157,"line":35},[155,1496,1432],{"class":160},[155,1498,1499],{"class":157,"line":933},[155,1500,278],{"emptyLinePlaceholder":277},[155,1502,1504,1506],{"class":157,"line":1503},42,[155,1505,1289],{"class":160},[155,1507,1219],{"class":164},[155,1509,1511,1514,1516],{"class":157,"line":1510},43,[155,1512,1513],{"class":164},"            body ",[155,1515,168],{"class":160},[155,1517,1518],{"class":164}," res.json()\n",[155,1520,1522,1524,1527],{"class":157,"line":1521},44,[155,1523,1390],{"class":160},[155,1525,1526],{"class":261}," ValueError",[155,1528,1219],{"class":164},[155,1530,1531,1533,1535],{"class":157,"line":39},[155,1532,1513],{"class":164},[155,1534,168],{"class":160},[155,1536,1537],{"class":164}," {}\n",[155,1539,1541,1543,1545],{"class":157,"line":1540},46,[155,1542,1441],{"class":160},[155,1544,1466],{"class":160},[155,1546,1547],{"class":164}," res.ok:\n",[155,1549,1551,1554],{"class":157,"line":1550},47,[155,1552,1553],{"class":160},"            raise",[155,1555,1556],{"class":164}," SlipBoltError(res.status_code, body)\n",[155,1558,1560,1563,1566,1569,1572],{"class":157,"line":1559},48,[155,1561,1562],{"class":160},"        return",[155,1564,1565],{"class":164}," body[",[155,1567,1568],{"class":171},"\"data\"",[155,1570,1571],{"class":164},"]  ",[155,1573,1574],{"class":251},"# the result is always under data\n",[146,1576,1581],{"className":1577,"code":1578,"filename":1579,"language":1580,"meta":151,"style":151},"language-php shiki shiki-themes github-light github-dark","\u003C?php\n\u002F\u002F slipbolt.php — PHP 8.1+ · uses ext-curl, no Composer needed\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** Verify one slip — returns the data block · throws SlipBoltError when the API returns an 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 network failure \u002F timeout \u002F 429 \u002F 5xx → wait, then try again\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('Connection failed: ' . 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 the result is always under data\n    }\n}\n","PHP","php",[141,1582,1583,1591,1596,1600,1611,1616,1645,1650,1660,1718,1723,1727,1731,1735,1740,1774,1778,1796,1807,1824,1832,1845,1856,1873,1880,1885,1895,1907,1920,1948,1972,2001,2006,2017,2022,2027,2040,2058,2062,2067,2108,2126,2133,2138,2151,2174,2178,2182,2205,2221,2233,2238,2253,2258],{"__ignoreMap":151},[155,1584,1585,1588],{"class":157,"line":9},[155,1586,1587],{"class":160},"\u003C?",[155,1589,1590],{"class":261},"php\n",[155,1592,1593],{"class":157,"line":255},[155,1594,1595],{"class":251},"\u002F\u002F slipbolt.php — PHP 8.1+ · uses ext-curl, no Composer needed\n",[155,1597,1598],{"class":157,"line":274},[155,1599,278],{"emptyLinePlaceholder":277},[155,1601,1602,1604,1606,1608],{"class":157,"line":281},[155,1603,1000],{"class":160},[155,1605,290],{"class":289},[155,1607,293],{"class":160},[155,1609,1610],{"class":261}," RuntimeException\n",[155,1612,1613],{"class":157,"line":302},[155,1614,1615],{"class":164},"{\n",[155,1617,1618,1621,1623,1626,1628,1631,1634,1637,1639,1642],{"class":157,"line":323},[155,1619,1620],{"class":160},"    public",[155,1622,505],{"class":160},[155,1624,1625],{"class":261}," __construct",[155,1627,308],{"class":164},[155,1629,1630],{"class":160},"public",[155,1632,1633],{"class":160}," int",[155,1635,1636],{"class":164}," $status, ",[155,1638,1630],{"class":160},[155,1640,1641],{"class":160}," array",[155,1643,1644],{"class":164}," $body)\n",[155,1646,1647],{"class":157,"line":377},[155,1648,1649],{"class":164},"    {\n",[155,1651,1652,1655,1658],{"class":157,"line":394},[155,1653,1654],{"class":160},"        parent::",[155,1656,1657],{"class":289},"__construct",[155,1659,1045],{"class":164},[155,1661,1662,1665,1668,1671,1674,1677,1679,1682,1685,1688,1690,1692,1694,1696,1698,1700,1703,1705,1707,1709,1711,1713,1715],{"class":157,"line":410},[155,1663,1664],{"class":171},"            \"",[155,1666,1667],{"class":164},"$status",[155,1669,1670],{"class":171}," \"",[155,1672,1673],{"class":160}," .",[155,1675,1676],{"class":164}," ($body[",[155,1678,1070],{"class":171},[155,1680,1681],{"class":164},"] ",[155,1683,1684],{"class":160},"??",[155,1686,1687],{"class":164}," $body[",[155,1689,1081],{"class":171},[155,1691,1681],{"class":164},[155,1693,1684],{"class":160},[155,1695,1088],{"class":171},[155,1697,458],{"class":164},[155,1699,341],{"class":160},[155,1701,1702],{"class":171}," ': '",[155,1704,1673],{"class":160},[155,1706,1676],{"class":164},[155,1708,1099],{"class":171},[155,1710,1681],{"class":164},[155,1712,1684],{"class":160},[155,1714,1106],{"class":171},[155,1716,1717],{"class":164},")\n",[155,1719,1720],{"class":157,"line":13},[155,1721,1722],{"class":164},"        );\n",[155,1724,1725],{"class":157,"line":431},[155,1726,757],{"class":164},[155,1728,1729],{"class":157,"line":437},[155,1730,434],{"class":164},[155,1732,1733],{"class":157,"line":442},[155,1734,278],{"emptyLinePlaceholder":277},[155,1736,1737],{"class":157,"line":486},[155,1738,1739],{"class":251},"\u002F** Verify one slip — returns the data block · throws SlipBoltError when the API returns an error *\u002F\n",[155,1741,1742,1745,1748,1750,1753,1756,1758,1761,1763,1765,1768,1771],{"class":157,"line":491},[155,1743,1744],{"class":160},"function",[155,1746,1747],{"class":289}," slipbolt_verify",[155,1749,308],{"class":164},[155,1751,1752],{"class":160},"string",[155,1754,1755],{"class":164}," $image, ",[155,1757,1024],{"class":160},[155,1759,1760],{"class":164}," $retries ",[155,1762,168],{"class":160},[155,1764,537],{"class":261},[155,1766,1767],{"class":164},")",[155,1769,1770],{"class":160},":",[155,1772,1773],{"class":160}," array\n",[155,1775,1776],{"class":157,"line":497},[155,1777,1615],{"class":164},[155,1779,1780,1782,1785,1787,1789,1792,1794],{"class":157,"line":548},[155,1781,1250],{"class":160},[155,1783,1784],{"class":164}," ($attempt ",[155,1786,168],{"class":160},[155,1788,564],{"class":261},[155,1790,1791],{"class":164},"; ; $attempt",[155,1793,570],{"class":160},[155,1795,320],{"class":164},[155,1797,1798,1801,1803,1805],{"class":157,"line":575},[155,1799,1800],{"class":164},"        $retryAfter ",[155,1802,168],{"class":160},[155,1804,564],{"class":261},[155,1806,271],{"class":164},[155,1808,1809,1812,1814,1817,1819,1822],{"class":157,"line":584},[155,1810,1811],{"class":164},"        $ch ",[155,1813,168],{"class":160},[155,1815,1816],{"class":261}," curl_init",[155,1818,308],{"class":164},[155,1820,1821],{"class":171},"'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify'",[155,1823,374],{"class":164},[155,1825,1826,1829],{"class":157,"line":18},[155,1827,1828],{"class":261},"        curl_setopt_array",[155,1830,1831],{"class":164},"($ch, [\n",[155,1833,1834,1837,1840,1843],{"class":157,"line":618},[155,1835,1836],{"class":261},"            CURLOPT_POST",[155,1838,1839],{"class":160},"           =>",[155,1841,1842],{"class":261}," true",[155,1844,627],{"class":164},[155,1846,1847,1850,1853],{"class":157,"line":630},[155,1848,1849],{"class":261},"            CURLOPT_HTTPHEADER",[155,1851,1852],{"class":160},"     =>",[155,1854,1855],{"class":164}," [\n",[155,1857,1858,1861,1863,1866,1868,1871],{"class":157,"line":658},[155,1859,1860],{"class":171},"                'Authorization: Bearer '",[155,1862,1673],{"class":160},[155,1864,1865],{"class":261}," getenv",[155,1867,308],{"class":164},[155,1869,1870],{"class":171},"'SLIPBOLT_API_KEY'",[155,1872,678],{"class":164},[155,1874,1875,1878],{"class":157,"line":664},[155,1876,1877],{"class":171},"                'Content-Type: application\u002Foctet-stream'",[155,1879,627],{"class":164},[155,1881,1882],{"class":157,"line":22},[155,1883,1884],{"class":164},"            ],\n",[155,1886,1887,1890,1892],{"class":157,"line":686},[155,1888,1889],{"class":261},"            CURLOPT_POSTFIELDS",[155,1891,1852],{"class":160},[155,1893,1894],{"class":164}," $image,\n",[155,1896,1897,1900,1903,1905],{"class":157,"line":698},[155,1898,1899],{"class":261},"            CURLOPT_RETURNTRANSFER",[155,1901,1902],{"class":160}," =>",[155,1904,1842],{"class":261},[155,1906,627],{"class":164},[155,1908,1909,1912,1915,1918],{"class":157,"line":722},[155,1910,1911],{"class":261},"            CURLOPT_TIMEOUT",[155,1913,1914],{"class":160},"        =>",[155,1916,1917],{"class":261}," 30",[155,1919,627],{"class":164},[155,1921,1922,1925,1927,1929,1932,1934,1937,1940,1942,1945],{"class":157,"line":747},[155,1923,1924],{"class":261},"            CURLOPT_HEADERFUNCTION",[155,1926,1902],{"class":160},[155,1928,505],{"class":160},[155,1930,1931],{"class":164}," ($ch, ",[155,1933,1752],{"class":160},[155,1935,1936],{"class":164}," $line) ",[155,1938,1939],{"class":160},"use",[155,1941,452],{"class":164},[155,1943,1944],{"class":160},"&",[155,1946,1947],{"class":164},"$retryAfter) {\n",[155,1949,1950,1953,1955,1958,1961,1964,1966,1968,1970],{"class":157,"line":26},[155,1951,1952],{"class":160},"                if",[155,1954,452],{"class":164},[155,1956,1957],{"class":261},"stripos",[155,1959,1960],{"class":164},"($line, ",[155,1962,1963],{"class":171},"'retry-after:'",[155,1965,458],{"class":164},[155,1967,774],{"class":160},[155,1969,564],{"class":261},[155,1971,320],{"class":164},[155,1973,1974,1977,1979,1981,1983,1985,1988,1990,1993,1995,1998],{"class":157,"line":760},[155,1975,1976],{"class":164},"                    $retryAfter ",[155,1978,168],{"class":160},[155,1980,452],{"class":164},[155,1982,1024],{"class":160},[155,1984,458],{"class":164},[155,1986,1987],{"class":261},"trim",[155,1989,308],{"class":164},[155,1991,1992],{"class":261},"substr",[155,1994,1960],{"class":164},[155,1996,1997],{"class":261},"12",[155,1999,2000],{"class":164},"));\n",[155,2002,2003],{"class":157,"line":765},[155,2004,2005],{"class":164},"                }\n",[155,2007,2008,2011,2014],{"class":157,"line":804},[155,2009,2010],{"class":160},"                return",[155,2012,2013],{"class":261}," strlen",[155,2015,2016],{"class":164},"($line);\n",[155,2018,2019],{"class":157,"line":848},[155,2020,2021],{"class":164},"            },\n",[155,2023,2024],{"class":157,"line":30},[155,2025,2026],{"class":164},"        ]);\n",[155,2028,2029,2032,2034,2037],{"class":157,"line":859},[155,2030,2031],{"class":164},"        $raw    ",[155,2033,168],{"class":160},[155,2035,2036],{"class":261}," curl_exec",[155,2038,2039],{"class":164},"($ch);\n",[155,2041,2042,2045,2047,2050,2053,2056],{"class":157,"line":864},[155,2043,2044],{"class":164},"        $status ",[155,2046,168],{"class":160},[155,2048,2049],{"class":261}," curl_getinfo",[155,2051,2052],{"class":164},"($ch, ",[155,2054,2055],{"class":261},"CURLINFO_HTTP_CODE",[155,2057,374],{"class":164},[155,2059,2060],{"class":157,"line":895},[155,2061,278],{"emptyLinePlaceholder":277},[155,2063,2064],{"class":157,"line":917},[155,2065,2066],{"class":251},"        \u002F\u002F network failure \u002F timeout \u002F 429 \u002F 5xx → wait, then try again\n",[155,2068,2069,2071,2074,2076,2079,2081,2084,2086,2088,2090,2092,2094,2096,2098,2100,2103,2105],{"class":157,"line":35},[155,2070,1441],{"class":160},[155,2072,2073],{"class":164}," (($raw ",[155,2075,774],{"class":160},[155,2077,2078],{"class":261}," false",[155,2080,780],{"class":160},[155,2082,2083],{"class":164}," $status ",[155,2085,774],{"class":160},[155,2087,777],{"class":261},[155,2089,780],{"class":160},[155,2091,2083],{"class":164},[155,2093,707],{"class":160},[155,2095,788],{"class":261},[155,2097,458],{"class":164},[155,2099,793],{"class":160},[155,2101,2102],{"class":164}," $attempt ",[155,2104,798],{"class":160},[155,2106,2107],{"class":164}," $retries) {\n",[155,2109,2110,2113,2116,2119,2121,2123],{"class":157,"line":933},[155,2111,2112],{"class":261},"            sleep",[155,2114,2115],{"class":164},"($retryAfter ",[155,2117,2118],{"class":160},"?:",[155,2120,738],{"class":261},[155,2122,741],{"class":160},[155,2124,2125],{"class":164}," $attempt);\n",[155,2127,2128,2131],{"class":157,"line":1503},[155,2129,2130],{"class":160},"            continue",[155,2132,271],{"class":164},[155,2134,2135],{"class":157,"line":1510},[155,2136,2137],{"class":164},"        }\n",[155,2139,2140,2142,2145,2147,2149],{"class":157,"line":1521},[155,2141,1441],{"class":160},[155,2143,2144],{"class":164}," ($raw ",[155,2146,774],{"class":160},[155,2148,2078],{"class":261},[155,2150,320],{"class":164},[155,2152,2153,2156,2158,2161,2163,2166,2168,2171],{"class":157,"line":39},[155,2154,2155],{"class":160},"            throw",[155,2157,464],{"class":160},[155,2159,2160],{"class":261}," RuntimeException",[155,2162,308],{"class":164},[155,2164,2165],{"class":171},"'Connection failed: '",[155,2167,1673],{"class":160},[155,2169,2170],{"class":261}," curl_error",[155,2172,2173],{"class":164},"($ch));\n",[155,2175,2176],{"class":157,"line":1540},[155,2177,2137],{"class":164},[155,2179,2180],{"class":157,"line":1550},[155,2181,278],{"emptyLinePlaceholder":277},[155,2183,2184,2187,2189,2192,2195,2198,2200,2202],{"class":157,"line":1559},[155,2185,2186],{"class":164},"        $body ",[155,2188,168],{"class":160},[155,2190,2191],{"class":261}," json_decode",[155,2193,2194],{"class":164},"($raw, ",[155,2196,2197],{"class":261},"true",[155,2199,458],{"class":164},[155,2201,1684],{"class":160},[155,2203,2204],{"class":164}," [];\n",[155,2206,2208,2210,2213,2216,2219],{"class":157,"line":2207},49,[155,2209,1441],{"class":160},[155,2211,2212],{"class":164}," ($status ",[155,2214,2215],{"class":160},"!==",[155,2217,2218],{"class":261}," 200",[155,2220,320],{"class":164},[155,2222,2224,2226,2228,2230],{"class":157,"line":2223},50,[155,2225,2155],{"class":160},[155,2227,464],{"class":160},[155,2229,290],{"class":261},[155,2231,2232],{"class":164},"($status, $body);\n",[155,2234,2236],{"class":157,"line":2235},51,[155,2237,2137],{"class":164},[155,2239,2241,2243,2245,2248,2251],{"class":157,"line":2240},52,[155,2242,1562],{"class":160},[155,2244,1687],{"class":164},[155,2246,2247],{"class":171},"'data'",[155,2249,2250],{"class":164},"]; ",[155,2252,926],{"class":251},[155,2254,2256],{"class":157,"line":2255},53,[155,2257,757],{"class":164},[155,2259,2261],{"class":157,"line":2260},54,[155,2262,434],{"class":164},[65,2264,2265],{},"Using it:",[237,2267,2268,2345,2427],{},[146,2269,2271],{"className":241,"code":2270,"filename":243,"language":244,"meta":151,"style":151},"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",[141,2272,2273,2288,2302,2306,2334],{"__ignoreMap":151},[155,2274,2275,2277,2280,2283,2286],{"class":157,"line":9},[155,2276,953],{"class":160},[155,2278,2279],{"class":164}," { readFile } ",[155,2281,2282],{"class":160},"from",[155,2284,2285],{"class":171}," 'node:fs\u002Fpromises'",[155,2287,271],{"class":164},[155,2289,2290,2292,2295,2297,2300],{"class":157,"line":255},[155,2291,953],{"class":160},[155,2293,2294],{"class":164}," { verifySlip } ",[155,2296,2282],{"class":160},[155,2298,2299],{"class":171}," '.\u002Fslipbolt.js'",[155,2301,271],{"class":164},[155,2303,2304],{"class":157,"line":274},[155,2305,278],{"emptyLinePlaceholder":277},[155,2307,2308,2310,2313,2315,2317,2319,2321,2324,2327,2329,2332],{"class":157,"line":281},[155,2309,258],{"class":160},[155,2311,2312],{"class":261}," slip",[155,2314,265],{"class":160},[155,2316,599],{"class":160},[155,2318,508],{"class":289},[155,2320,308],{"class":164},[155,2322,2323],{"class":160},"await",[155,2325,2326],{"class":289}," readFile",[155,2328,308],{"class":164},[155,2330,2331],{"class":171},"'slip.jpg'",[155,2333,2000],{"class":164},[155,2335,2336,2339,2342],{"class":157,"line":302},[155,2337,2338],{"class":164},"console.",[155,2340,2341],{"class":289},"log",[155,2343,2344],{"class":164},"(slip.status, slip.amount, slip.transRef);\n",[146,2346,2348],{"className":938,"code":2347,"filename":940,"language":941,"meta":151,"style":151},"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",[141,2349,2350,2362,2366,2392,2402],{"__ignoreMap":151},[155,2351,2352,2354,2357,2359],{"class":157,"line":9},[155,2353,2282],{"class":160},[155,2355,2356],{"class":164}," slipbolt ",[155,2358,953],{"class":160},[155,2360,2361],{"class":164}," verify_slip\n",[155,2363,2364],{"class":157,"line":255},[155,2365,278],{"emptyLinePlaceholder":277},[155,2367,2368,2371,2374,2376,2379,2381,2384,2386,2389],{"class":157,"line":274},[155,2369,2370],{"class":160},"with",[155,2372,2373],{"class":261}," open",[155,2375,308],{"class":164},[155,2377,2378],{"class":171},"\"slip.jpg\"",[155,2380,314],{"class":164},[155,2382,2383],{"class":171},"\"rb\"",[155,2385,458],{"class":164},[155,2387,2388],{"class":160},"as",[155,2390,2391],{"class":164}," f:\n",[155,2393,2394,2397,2399],{"class":157,"line":281},[155,2395,2396],{"class":164},"    slip ",[155,2398,168],{"class":160},[155,2400,2401],{"class":164}," verify_slip(f.read())\n",[155,2403,2404,2407,2410,2413,2416,2419,2421,2424],{"class":157,"line":302},[155,2405,2406],{"class":261},"print",[155,2408,2409],{"class":164},"(slip[",[155,2411,2412],{"class":171},"\"status\"",[155,2414,2415],{"class":164},"], slip[",[155,2417,2418],{"class":171},"\"amount\"",[155,2420,2415],{"class":164},[155,2422,2423],{"class":171},"\"transRef\"",[155,2425,2426],{"class":164},"])\n",[146,2428,2430],{"className":1577,"code":2429,"filename":1579,"language":1580,"meta":151,"style":151},"\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",[141,2431,2432,2438,2453,2457,2477],{"__ignoreMap":151},[155,2433,2434,2436],{"class":157,"line":9},[155,2435,1587],{"class":160},[155,2437,1590],{"class":261},[155,2439,2440,2443,2446,2448,2451],{"class":157,"line":255},[155,2441,2442],{"class":160},"require",[155,2444,2445],{"class":261}," __DIR__",[155,2447,1673],{"class":160},[155,2449,2450],{"class":171}," '\u002Fslipbolt.php'",[155,2452,271],{"class":164},[155,2454,2455],{"class":157,"line":274},[155,2456,278],{"emptyLinePlaceholder":277},[155,2458,2459,2462,2464,2466,2468,2471,2473,2475],{"class":157,"line":281},[155,2460,2461],{"class":164},"$slip ",[155,2463,168],{"class":160},[155,2465,1747],{"class":289},[155,2467,308],{"class":164},[155,2469,2470],{"class":261},"file_get_contents",[155,2472,308],{"class":164},[155,2474,2331],{"class":171},[155,2476,2000],{"class":164},[155,2478,2479,2482,2485,2488,2491,2494,2497,2500,2502,2504,2506,2509,2511,2513,2516,2518],{"class":157,"line":302},[155,2480,2481],{"class":261},"echo",[155,2483,2484],{"class":164}," $slip[",[155,2486,2487],{"class":171},"'status'",[155,2489,2490],{"class":164},"], ",[155,2492,2493],{"class":171},"' '",[155,2495,2496],{"class":164},", $slip[",[155,2498,2499],{"class":171},"'amount'",[155,2501,2490],{"class":164},[155,2503,2493],{"class":171},[155,2505,2496],{"class":164},[155,2507,2508],{"class":171},"'transRef'",[155,2510,2490],{"class":164},[155,2512,1053],{"class":171},[155,2514,2515],{"class":261},"\\n",[155,2517,1053],{"class":171},[155,2519,271],{"class":164},[174,2521,114],{"id":2522},"_2-take-a-slip-close-the-order",[65,2524,2525],{},"The most common job: a customer uploads a slip on your checkout page → your server verifies it → the order closes automatically.",[2527,2528,2530],"callout",{"type":2529},"warning",[65,2531,2532,2535],{},[68,2533,2534],{},"Call SlipBolt from your server only"," — never straight from browser JavaScript or a mobile app,\nbecause the API key ships with client-side code. The browser sends the image to your server; your server forwards it.",[2537,2538,2540],"h3",{"id":2539},"release-the-order-only-when-all-4-checks-pass","Release the order only when all 4 checks pass",[73,2542,2543,2556],{},[76,2544,2545],{},[79,2546,2547,2550,2553],{},[82,2548,2549],{},"#",[82,2551,2552],{},"Check",[82,2554,2555],{},"If you skip it",[89,2557,2558,2571,2584,2598],{},[79,2559,2560,2563,2568],{},[94,2561,2562],{},"1",[94,2564,2565],{},[141,2566,2567],{},"verified === true",[94,2569,2570],{},"You accept fake slips, or slips paid into someone else's account",[79,2572,2573,2576,2581],{},[94,2574,2575],{},"2",[94,2577,2578],{},[141,2579,2580],{},"duplicate === false",[94,2582,2583],{},"A customer resends an old slip that was already used",[79,2585,2586,2589,2595],{},[94,2587,2588],{},"3",[94,2590,2591,2594],{},[141,2592,2593],{},"amount"," matches the order total",[94,2596,2597],{},"A customer transfers 1 THB and sends that slip — it is still \"genuine\"",[79,2599,2600,2603,2612],{},[94,2601,2602],{},"4",[94,2604,2605,2608,2609],{},[141,2606,2607],{},"transRef"," is not yet attached to another order ",[68,2610,2611],{},"in your system",[94,2613,2614],{},"One slip closes two orders",[2527,2616,2617],{"type":2529},[65,2618,2619,2622,2623,2625,2626,2625,2629,2632,2633,341],{},[68,2620,2621],{},"Check 4 is not optional"," — resending the same image within 24 hours returns the original result\n(",[141,2624,214],{}," · ",[141,2627,2628],{},"verified: true",[141,2630,2631],{},"duplicate: false",") so that retries are safe ⇒ if a customer uploads the same\nimage against a second order, checks 1–3 all pass. The real guard is ",[68,2634,2635,2636,2638],{},"a UNIQUE ",[141,2637,2607],{}," column in your orders table",[2537,2640,2642],{"id":2641},"web-page-customer-side","Web page (customer side)",[65,2644,2645,2646,2649],{},"Send the file as the request body, no ",[141,2647,2648],{},"FormData"," needed — it works with all three servers below.",[146,2651,2655],{"className":2652,"code":2653,"language":2654,"meta":151,"style":151},"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 for PHP use '\u002Fpay.php?order=1001' instead\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",[141,2656,2657,2692,2712,2716,2725,2765,2783,2799,2803,2808,2828,2837,2847,2852,2857,2875,2895,2900],{"__ignoreMap":151},[155,2658,2659,2661,2665,2668,2670,2673,2676,2678,2681,2684,2686,2689],{"class":157,"line":9},[155,2660,798],{"class":164},[155,2662,2664],{"class":2663},"s9eBZ","input",[155,2666,2667],{"class":289}," type",[155,2669,168],{"class":164},[155,2671,2672],{"class":171},"\"file\"",[155,2674,2675],{"class":289}," id",[155,2677,168],{"class":164},[155,2679,2680],{"class":171},"\"slip\"",[155,2682,2683],{"class":289}," accept",[155,2685,168],{"class":164},[155,2687,2688],{"class":171},"\"image\u002F*\"",[155,2690,2691],{"class":164},">\n",[155,2693,2694,2696,2698,2700,2702,2705,2708,2710],{"class":157,"line":255},[155,2695,798],{"class":164},[155,2697,65],{"class":2663},[155,2699,2675],{"class":289},[155,2701,168],{"class":164},[155,2703,2704],{"class":171},"\"result\"",[155,2706,2707],{"class":164},">\u003C\u002F",[155,2709,65],{"class":2663},[155,2711,2691],{"class":164},[155,2713,2714],{"class":157,"line":274},[155,2715,278],{"emptyLinePlaceholder":277},[155,2717,2718,2720,2723],{"class":157,"line":281},[155,2719,798],{"class":164},[155,2721,2722],{"class":2663},"script",[155,2724,2691],{"class":164},[155,2726,2727,2730,2733,2735,2738,2741,2744,2746,2749,2751,2754,2756,2759,2761,2763],{"class":157,"line":302},[155,2728,2729],{"class":164},"  document.",[155,2731,2732],{"class":289},"getElementById",[155,2734,308],{"class":164},[155,2736,2737],{"class":171},"'slip'",[155,2739,2740],{"class":164},").",[155,2742,2743],{"class":289},"addEventListener",[155,2745,308],{"class":164},[155,2747,2748],{"class":171},"'change'",[155,2750,314],{"class":164},[155,2752,2753],{"class":160},"async",[155,2755,452],{"class":164},[155,2757,2758],{"class":311},"e",[155,2760,458],{"class":164},[155,2762,461],{"class":160},[155,2764,299],{"class":164},[155,2766,2767,2769,2772,2774,2777,2780],{"class":157,"line":323},[155,2768,867],{"class":160},[155,2770,2771],{"class":261}," file",[155,2773,265],{"class":160},[155,2775,2776],{"class":164}," e.target.files[",[155,2778,2779],{"class":261},"0",[155,2781,2782],{"class":164},"];\n",[155,2784,2785,2787,2789,2791,2794,2797],{"class":157,"line":377},[155,2786,768],{"class":160},[155,2788,452],{"class":164},[155,2790,902],{"class":160},[155,2792,2793],{"class":164},"file) ",[155,2795,2796],{"class":160},"return",[155,2798,271],{"class":164},[155,2800,2801],{"class":157,"line":394},[155,2802,278],{"emptyLinePlaceholder":277},[155,2804,2805],{"class":157,"line":410},[155,2806,2807],{"class":251},"    \u002F\u002F for PHP use '\u002Fpay.php?order=1001' instead\n",[155,2809,2810,2812,2815,2817,2819,2821,2823,2826],{"class":157,"line":13},[155,2811,867],{"class":160},[155,2813,2814],{"class":261}," res",[155,2816,265],{"class":160},[155,2818,599],{"class":160},[155,2820,602],{"class":289},[155,2822,308],{"class":164},[155,2824,2825],{"class":171},"'\u002Forders\u002F1001\u002Fslip'",[155,2827,615],{"class":164},[155,2829,2830,2833,2835],{"class":157,"line":431},[155,2831,2832],{"class":164},"      method: ",[155,2834,624],{"class":171},[155,2836,627],{"class":164},[155,2838,2839,2842,2844],{"class":157,"line":437},[155,2840,2841],{"class":164},"      headers: { ",[155,2843,646],{"class":171},[155,2845,2846],{"class":164},": file.type },\n",[155,2848,2849],{"class":157,"line":442},[155,2850,2851],{"class":164},"      body: file,\n",[155,2853,2854],{"class":157,"line":486},[155,2855,2856],{"class":164},"    });\n",[155,2858,2859,2861,2864,2866,2868,2870,2872],{"class":157,"line":491},[155,2860,867],{"class":160},[155,2862,2863],{"class":261}," out",[155,2865,265],{"class":160},[155,2867,599],{"class":160},[155,2869,876],{"class":164},[155,2871,879],{"class":289},[155,2873,2874],{"class":164},"();\n",[155,2876,2877,2880,2882,2884,2887,2890,2892],{"class":157,"line":497},[155,2878,2879],{"class":164},"    document.",[155,2881,2732],{"class":289},[155,2883,308],{"class":164},[155,2885,2886],{"class":171},"'result'",[155,2888,2889],{"class":164},").textContent ",[155,2891,168],{"class":160},[155,2893,2894],{"class":164}," out.message;\n",[155,2896,2897],{"class":157,"line":548},[155,2898,2899],{"class":164},"  });\n",[155,2901,2902,2905,2907],{"class":157,"line":575},[155,2903,2904],{"class":164},"\u003C\u002F",[155,2906,2722],{"class":2663},[155,2908,2691],{"class":164},[2537,2910,2912],{"id":2911},"server","Server",[65,2914,2915,2916,2919],{},"Uses the client file from ",[100,2917,2918],{"href":102},"step 1"," · the Node.js \u002F Python examples keep orders in memory so they run\nimmediately — in production that is a table in your database (the PHP example uses PDO to show the shape).",[237,2921,2922,3701,4474],{},[146,2923,2926],{"className":241,"code":2924,"filename":2925,"language":244,"meta":151,"style":151},"\u002F\u002F server.js — npm install express\nimport express from 'express';\nimport { verifySlip } from '.\u002Fslipbolt.js';\n\nconst app = express();\n\n\u002F\u002F in production = a database table · usedRefs = a UNIQUE transRef column\nconst orders = new Map([['1001', { total: 250, paid: false }]]);\nconst usedRefs = new Set();\n\n\u002F\u002F what to tell the customer when a slip is rejected\nconst REJECT = {\n  DUPLICATE: 'This slip has already been used',\n  FRAUD: 'This slip is not valid. Please contact the shop',\n  RECEIVER_MISMATCH: 'This slip was not paid into the shop account',\n  INVALID: 'We could not read the slip. Upload an image with the QR code clearly visible',\n  PROVIDER_ERROR: 'Slip verification is temporarily unavailable. Please try again',\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: 'Order not found' });\n  if (order.paid) return res.json({ ok: true, message: 'This order is already paid' });\n  if (!Buffer.isBuffer(req.body) || req.body.length === 0) {\n    return res.status(400).json({ ok: false, message: 'Please attach a slip image' });\n  }\n\n  let slip;\n  try {\n    slip = await verifySlip(req.body);\n  } catch (err) {\n    console.error('SlipBolt:', err); \u002F\u002F 402 = shop quota used up · 401\u002F403 = key or plan → alert your team\n    return res.status(503).json({ ok: false, message: 'Automatic verification is unavailable. Try again or contact the shop' });\n  }\n\n  \u002F\u002F 1) genuine and paid into the shop account  2) not a slip that was already checked\n  if (!slip.verified || slip.duplicate) {\n    return res.status(422).json({ ok: false, message: REJECT[slip.status] ?? 'The slip did not pass verification' });\n  }\n  \u002F\u002F 3) the amount matches the order — the API does not know what this order costs\n  if (Math.abs(slip.amount - order.total) > 0.001) {\n    return res.status(422).json({\n      ok: false,\n      message: `Transferred ${slip.amount} THB, but the order total is ${order.total} THB`,\n    });\n  }\n  \u002F\u002F 4) one slip closes one order\n  if (usedRefs.has(slip.transRef)) {\n    return res.status(422).json({ ok: false, message: 'This slip was already used for another order' });\n  }\n\n  usedRefs.add(slip.transRef);\n  order.paid = true;\n  order.transRef = slip.transRef;\n  res.json({ ok: true, message: 'Payment received. Thank you!', transRef: slip.transRef });\n});\n\napp.listen(3000);\n","Node.js (Express)",[141,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":151},[155,2929,2930],{"class":157,"line":9},[155,2931,2932],{"class":251},"\u002F\u002F server.js — npm install express\n",[155,2934,2935,2937,2940,2942,2945],{"class":157,"line":255},[155,2936,953],{"class":160},[155,2938,2939],{"class":164}," express ",[155,2941,2282],{"class":160},[155,2943,2944],{"class":171}," 'express'",[155,2946,271],{"class":164},[155,2948,2949,2951,2953,2955,2957],{"class":157,"line":274},[155,2950,953],{"class":160},[155,2952,2294],{"class":164},[155,2954,2282],{"class":160},[155,2956,2299],{"class":171},[155,2958,271],{"class":164},[155,2960,2961],{"class":157,"line":281},[155,2962,278],{"emptyLinePlaceholder":277},[155,2964,2965,2967,2970,2972,2975],{"class":157,"line":302},[155,2966,258],{"class":160},[155,2968,2969],{"class":261}," app",[155,2971,265],{"class":160},[155,2973,2974],{"class":289}," express",[155,2976,2874],{"class":164},[155,2978,2979],{"class":157,"line":323},[155,2980,278],{"emptyLinePlaceholder":277},[155,2982,2983],{"class":157,"line":377},[155,2984,2985],{"class":251},"\u002F\u002F in production = a database table · usedRefs = a UNIQUE transRef column\n",[155,2987,2988,2990,2993,2995,2997,3000,3003,3006,3009,3012,3015,3018],{"class":157,"line":394},[155,2989,258],{"class":160},[155,2991,2992],{"class":261}," orders",[155,2994,265],{"class":160},[155,2996,464],{"class":160},[155,2998,2999],{"class":289}," Map",[155,3001,3002],{"class":164},"([[",[155,3004,3005],{"class":171},"'1001'",[155,3007,3008],{"class":164},", { total: ",[155,3010,3011],{"class":261},"250",[155,3013,3014],{"class":164},", paid: ",[155,3016,3017],{"class":261},"false",[155,3019,3020],{"class":164}," }]]);\n",[155,3022,3023,3025,3028,3030,3032,3035],{"class":157,"line":410},[155,3024,258],{"class":160},[155,3026,3027],{"class":261}," usedRefs",[155,3029,265],{"class":160},[155,3031,464],{"class":160},[155,3033,3034],{"class":289}," Set",[155,3036,2874],{"class":164},[155,3038,3039],{"class":157,"line":13},[155,3040,278],{"emptyLinePlaceholder":277},[155,3042,3043],{"class":157,"line":431},[155,3044,3045],{"class":251},"\u002F\u002F what to tell the customer when a slip is rejected\n",[155,3047,3048,3050,3053,3055],{"class":157,"line":437},[155,3049,258],{"class":160},[155,3051,3052],{"class":261}," REJECT",[155,3054,265],{"class":160},[155,3056,299],{"class":164},[155,3058,3059,3062,3065],{"class":157,"line":442},[155,3060,3061],{"class":164},"  DUPLICATE: ",[155,3063,3064],{"class":171},"'This slip has already been used'",[155,3066,627],{"class":164},[155,3068,3069,3072,3075],{"class":157,"line":486},[155,3070,3071],{"class":164},"  FRAUD: ",[155,3073,3074],{"class":171},"'This slip is not valid. Please contact the shop'",[155,3076,627],{"class":164},[155,3078,3079,3082,3085],{"class":157,"line":491},[155,3080,3081],{"class":164},"  RECEIVER_MISMATCH: ",[155,3083,3084],{"class":171},"'This slip was not paid into the shop account'",[155,3086,627],{"class":164},[155,3088,3089,3092,3095],{"class":157,"line":497},[155,3090,3091],{"class":164},"  INVALID: ",[155,3093,3094],{"class":171},"'We could not read the slip. Upload an image with the QR code clearly visible'",[155,3096,627],{"class":164},[155,3098,3099,3102,3105],{"class":157,"line":548},[155,3100,3101],{"class":164},"  PROVIDER_ERROR: ",[155,3103,3104],{"class":171},"'Slip verification is temporarily unavailable. Please try again'",[155,3106,627],{"class":164},[155,3108,3109],{"class":157,"line":575},[155,3110,3111],{"class":164},"};\n",[155,3113,3114],{"class":157,"line":584},[155,3115,278],{"emptyLinePlaceholder":277},[155,3117,3118,3121,3124,3126,3129,3132,3135,3138,3141,3144,3147,3150,3152,3154,3157,3159,3162,3164,3166],{"class":157,"line":18},[155,3119,3120],{"class":164},"app.",[155,3122,3123],{"class":289},"post",[155,3125,308],{"class":164},[155,3127,3128],{"class":171},"'\u002Forders\u002F:id\u002Fslip'",[155,3130,3131],{"class":164},", express.",[155,3133,3134],{"class":289},"raw",[155,3136,3137],{"class":164},"({ type: ",[155,3139,3140],{"class":171},"'image\u002F*'",[155,3142,3143],{"class":164},", limit: ",[155,3145,3146],{"class":171},"'5mb'",[155,3148,3149],{"class":164}," }), ",[155,3151,2753],{"class":160},[155,3153,452],{"class":164},[155,3155,3156],{"class":311},"req",[155,3158,314],{"class":164},[155,3160,3161],{"class":311},"res",[155,3163,458],{"class":164},[155,3165,461],{"class":160},[155,3167,299],{"class":164},[155,3169,3170,3173,3176,3178,3181,3183],{"class":157,"line":618},[155,3171,3172],{"class":160},"  const",[155,3174,3175],{"class":261}," order",[155,3177,265],{"class":160},[155,3179,3180],{"class":164}," orders.",[155,3182,819],{"class":289},[155,3184,3185],{"class":164},"(req.params.id);\n",[155,3187,3188,3191,3193,3195,3198,3200,3202,3204,3206,3209,3211,3213,3216,3218,3221,3224],{"class":157,"line":630},[155,3189,3190],{"class":160},"  if",[155,3192,452],{"class":164},[155,3194,902],{"class":160},[155,3196,3197],{"class":164},"order) ",[155,3199,2796],{"class":160},[155,3201,876],{"class":164},[155,3203,223],{"class":289},[155,3205,308],{"class":164},[155,3207,3208],{"class":261},"404",[155,3210,2740],{"class":164},[155,3212,879],{"class":289},[155,3214,3215],{"class":164},"({ ok: ",[155,3217,3017],{"class":261},[155,3219,3220],{"class":164},", message: ",[155,3222,3223],{"class":171},"'Order not found'",[155,3225,3226],{"class":164}," });\n",[155,3228,3229,3231,3234,3236,3238,3240,3242,3244,3246,3249],{"class":157,"line":658},[155,3230,3190],{"class":160},[155,3232,3233],{"class":164}," (order.paid) ",[155,3235,2796],{"class":160},[155,3237,876],{"class":164},[155,3239,879],{"class":289},[155,3241,3215],{"class":164},[155,3243,2197],{"class":261},[155,3245,3220],{"class":164},[155,3247,3248],{"class":171},"'This order is already paid'",[155,3250,3226],{"class":164},[155,3252,3253,3255,3257,3259,3262,3265,3268,3270,3273,3276,3279,3281],{"class":157,"line":664},[155,3254,3190],{"class":160},[155,3256,452],{"class":164},[155,3258,902],{"class":160},[155,3260,3261],{"class":164},"Buffer.",[155,3263,3264],{"class":289},"isBuffer",[155,3266,3267],{"class":164},"(req.body) ",[155,3269,830],{"class":160},[155,3271,3272],{"class":164}," req.body.",[155,3274,3275],{"class":261},"length",[155,3277,3278],{"class":160}," ===",[155,3280,564],{"class":261},[155,3282,320],{"class":164},[155,3284,3285,3287,3289,3291,3293,3296,3298,3300,3302,3304,3306,3309],{"class":157,"line":22},[155,3286,920],{"class":160},[155,3288,876],{"class":164},[155,3290,223],{"class":289},[155,3292,308],{"class":164},[155,3294,3295],{"class":261},"400",[155,3297,2740],{"class":164},[155,3299,879],{"class":289},[155,3301,3215],{"class":164},[155,3303,3017],{"class":261},[155,3305,3220],{"class":164},[155,3307,3308],{"class":171},"'Please attach a slip image'",[155,3310,3226],{"class":164},[155,3312,3313],{"class":157,"line":686},[155,3314,428],{"class":164},[155,3316,3317],{"class":157,"line":698},[155,3318,278],{"emptyLinePlaceholder":277},[155,3320,3321,3324],{"class":157,"line":722},[155,3322,3323],{"class":160},"  let",[155,3325,3326],{"class":164}," slip;\n",[155,3328,3329,3332],{"class":157,"line":747},[155,3330,3331],{"class":160},"  try",[155,3333,299],{"class":164},[155,3335,3336,3338,3340,3342,3344],{"class":157,"line":26},[155,3337,2396],{"class":164},[155,3339,168],{"class":160},[155,3341,599],{"class":160},[155,3343,508],{"class":289},[155,3345,3346],{"class":164},"(req.body);\n",[155,3348,3349,3352,3354],{"class":157,"line":760},[155,3350,3351],{"class":164},"  } ",[155,3353,692],{"class":160},[155,3355,695],{"class":164},[155,3357,3358,3361,3363,3365,3368,3371],{"class":157,"line":765},[155,3359,3360],{"class":164},"    console.",[155,3362,354],{"class":289},[155,3364,308],{"class":164},[155,3366,3367],{"class":171},"'SlipBolt:'",[155,3369,3370],{"class":164},", err); ",[155,3372,3373],{"class":251},"\u002F\u002F 402 = shop quota used up · 401\u002F403 = key or plan → alert your team\n",[155,3375,3376,3378,3380,3382,3384,3387,3389,3391,3393,3395,3397,3400],{"class":157,"line":804},[155,3377,920],{"class":160},[155,3379,876],{"class":164},[155,3381,223],{"class":289},[155,3383,308],{"class":164},[155,3385,3386],{"class":261},"503",[155,3388,2740],{"class":164},[155,3390,879],{"class":289},[155,3392,3215],{"class":164},[155,3394,3017],{"class":261},[155,3396,3220],{"class":164},[155,3398,3399],{"class":171},"'Automatic verification is unavailable. Try again or contact the shop'",[155,3401,3226],{"class":164},[155,3403,3404],{"class":157,"line":848},[155,3405,428],{"class":164},[155,3407,3408],{"class":157,"line":30},[155,3409,278],{"emptyLinePlaceholder":277},[155,3411,3412],{"class":157,"line":859},[155,3413,3414],{"class":251},"  \u002F\u002F 1) genuine and paid into the shop account  2) not a slip that was already checked\n",[155,3416,3417,3419,3421,3423,3426,3428],{"class":157,"line":864},[155,3418,3190],{"class":160},[155,3420,452],{"class":164},[155,3422,902],{"class":160},[155,3424,3425],{"class":164},"slip.verified ",[155,3427,830],{"class":160},[155,3429,3430],{"class":164}," slip.duplicate) {\n",[155,3432,3433,3435,3437,3439,3441,3444,3446,3448,3450,3452,3454,3457,3460,3462,3465],{"class":157,"line":895},[155,3434,920],{"class":160},[155,3436,876],{"class":164},[155,3438,223],{"class":289},[155,3440,308],{"class":164},[155,3442,3443],{"class":261},"422",[155,3445,2740],{"class":164},[155,3447,879],{"class":289},[155,3449,3215],{"class":164},[155,3451,3017],{"class":261},[155,3453,3220],{"class":164},[155,3455,3456],{"class":261},"REJECT",[155,3458,3459],{"class":164},"[slip.status] ",[155,3461,1684],{"class":160},[155,3463,3464],{"class":171}," 'The slip did not pass verification'",[155,3466,3226],{"class":164},[155,3468,3469],{"class":157,"line":917},[155,3470,428],{"class":164},[155,3472,3473],{"class":157,"line":35},[155,3474,3475],{"class":251},"  \u002F\u002F 3) the amount matches the order — the API does not know what this order costs\n",[155,3477,3478,3480,3483,3486,3489,3492,3495,3498,3501],{"class":157,"line":933},[155,3479,3190],{"class":160},[155,3481,3482],{"class":164}," (Math.",[155,3484,3485],{"class":289},"abs",[155,3487,3488],{"class":164},"(slip.amount ",[155,3490,3491],{"class":160},"-",[155,3493,3494],{"class":164}," order.total) ",[155,3496,3497],{"class":160},">",[155,3499,3500],{"class":261}," 0.001",[155,3502,320],{"class":164},[155,3504,3505,3507,3509,3511,3513,3515,3517,3519],{"class":157,"line":1503},[155,3506,920],{"class":160},[155,3508,876],{"class":164},[155,3510,223],{"class":289},[155,3512,308],{"class":164},[155,3514,3443],{"class":261},[155,3516,2740],{"class":164},[155,3518,879],{"class":289},[155,3520,3521],{"class":164},"({\n",[155,3523,3524,3527,3529],{"class":157,"line":1510},[155,3525,3526],{"class":164},"      ok: ",[155,3528,3017],{"class":261},[155,3530,627],{"class":164},[155,3532,3533,3536,3539,3542,3544,3546,3549,3552,3554,3557,3560],{"class":157,"line":1521},[155,3534,3535],{"class":164},"      message: ",[155,3537,3538],{"class":171},"`Transferred ${",[155,3540,3541],{"class":164},"slip",[155,3543,341],{"class":171},[155,3545,2593],{"class":164},[155,3547,3548],{"class":171},"} THB, but the order total is ${",[155,3550,3551],{"class":164},"order",[155,3553,341],{"class":171},[155,3555,3556],{"class":164},"total",[155,3558,3559],{"class":171},"} THB`",[155,3561,627],{"class":164},[155,3563,3564],{"class":157,"line":39},[155,3565,2856],{"class":164},[155,3567,3568],{"class":157,"line":1540},[155,3569,428],{"class":164},[155,3571,3572],{"class":157,"line":1550},[155,3573,3574],{"class":251},"  \u002F\u002F 4) one slip closes one order\n",[155,3576,3577,3579,3582,3585],{"class":157,"line":1559},[155,3578,3190],{"class":160},[155,3580,3581],{"class":164}," (usedRefs.",[155,3583,3584],{"class":289},"has",[155,3586,3587],{"class":164},"(slip.transRef)) {\n",[155,3589,3590,3592,3594,3596,3598,3600,3602,3604,3606,3608,3610,3613],{"class":157,"line":2207},[155,3591,920],{"class":160},[155,3593,876],{"class":164},[155,3595,223],{"class":289},[155,3597,308],{"class":164},[155,3599,3443],{"class":261},[155,3601,2740],{"class":164},[155,3603,879],{"class":289},[155,3605,3215],{"class":164},[155,3607,3017],{"class":261},[155,3609,3220],{"class":164},[155,3611,3612],{"class":171},"'This slip was already used for another order'",[155,3614,3226],{"class":164},[155,3616,3617],{"class":157,"line":2223},[155,3618,428],{"class":164},[155,3620,3621],{"class":157,"line":2235},[155,3622,278],{"emptyLinePlaceholder":277},[155,3624,3625,3628,3631],{"class":157,"line":2240},[155,3626,3627],{"class":164},"  usedRefs.",[155,3629,3630],{"class":289},"add",[155,3632,3633],{"class":164},"(slip.transRef);\n",[155,3635,3636,3639,3641,3643],{"class":157,"line":2255},[155,3637,3638],{"class":164},"  order.paid ",[155,3640,168],{"class":160},[155,3642,1842],{"class":261},[155,3644,271],{"class":164},[155,3646,3647,3650,3652],{"class":157,"line":2260},[155,3648,3649],{"class":164},"  order.transRef ",[155,3651,168],{"class":160},[155,3653,3654],{"class":164}," slip.transRef;\n",[155,3656,3658,3661,3663,3665,3667,3669,3672],{"class":157,"line":3657},55,[155,3659,3660],{"class":164},"  res.",[155,3662,879],{"class":289},[155,3664,3215],{"class":164},[155,3666,2197],{"class":261},[155,3668,3220],{"class":164},[155,3670,3671],{"class":171},"'Payment received. Thank you!'",[155,3673,3674],{"class":164},", transRef: slip.transRef });\n",[155,3676,3678],{"class":157,"line":3677},56,[155,3679,3680],{"class":164},"});\n",[155,3682,3684],{"class":157,"line":3683},57,[155,3685,278],{"emptyLinePlaceholder":277},[155,3687,3689,3691,3694,3696,3699],{"class":157,"line":3688},58,[155,3690,3120],{"class":164},[155,3692,3693],{"class":289},"listen",[155,3695,308],{"class":164},[155,3697,3698],{"class":261},"3000",[155,3700,374],{"class":164},[146,3702,3705],{"className":938,"code":3703,"filename":3704,"language":941,"meta":151,"style":151},"# app.py — pip install flask requests\nfrom flask import Flask, jsonify, request\n\nfrom slipbolt import verify_slip\n\napp = Flask(__name__)\n\n# in production = a database table · used_refs = a UNIQUE transRef column\norders = {\"1001\": {\"total\": 250, \"paid\": False}}\nused_refs: set[str] = set()\n\n# what to tell the customer when a slip is rejected\nREJECT = {\n    \"DUPLICATE\": \"This slip has already been used\",\n    \"FRAUD\": \"This slip is not valid. Please contact the shop\",\n    \"RECEIVER_MISMATCH\": \"This slip was not paid into the shop account\",\n    \"INVALID\": \"We could not read the slip. Upload an image with the QR code clearly visible\",\n    \"PROVIDER_ERROR\": \"Slip verification is temporarily unavailable. Please try again\",\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, \"Order not found\")\n    if order[\"paid\"]:\n        return reply(200, True, \"This order is already paid\")\n    image = request.get_data()\n    if not image:\n        return reply(400, False, \"Please attach a slip image\")\n\n    try:\n        slip = verify_slip(image)\n    except Exception as err:  # 402 = shop quota used up · 401\u002F403 = key or plan → alert your team\n        app.logger.error(\"SlipBolt: %s\", err)\n        return reply(503, False, \"Automatic verification is unavailable. Try again or contact the shop\")\n\n    # 1) genuine and paid into the shop account  2) not a slip that was already checked\n    if not slip[\"verified\"] or slip[\"duplicate\"]:\n        return reply(422, False, REJECT.get(slip[\"status\"], \"The slip did not pass verification\"))\n    # 3) the amount matches the order — the API does not know what this order costs\n    if abs(slip[\"amount\"] - order[\"total\"]) > 0.001:\n        return reply(422, False, f\"Transferred {slip['amount']} THB, but the order total is {order['total']} THB\")\n    # 4) one slip closes one order\n    if slip[\"transRef\"] in used_refs:\n        return reply(422, False, \"This slip was already used for another order\")\n\n    used_refs.add(slip[\"transRef\"])\n    order.update(paid=True, transRef=slip[\"transRef\"])\n    return reply(200, True, \"Payment received. Thank you!\", transRef=slip[\"transRef\"])\n\n\nif __name__ == \"__main__\":\n    app.run(port=3000)\n","Python (Flask)",[141,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":151},[155,3708,3709],{"class":157,"line":9},[155,3710,3711],{"class":251},"# app.py — pip install flask requests\n",[155,3713,3714,3716,3719,3721],{"class":157,"line":255},[155,3715,2282],{"class":160},[155,3717,3718],{"class":164}," flask ",[155,3720,953],{"class":160},[155,3722,3723],{"class":164}," Flask, jsonify, request\n",[155,3725,3726],{"class":157,"line":274},[155,3727,278],{"emptyLinePlaceholder":277},[155,3729,3730,3732,3734,3736],{"class":157,"line":281},[155,3731,2282],{"class":160},[155,3733,2356],{"class":164},[155,3735,953],{"class":160},[155,3737,2361],{"class":164},[155,3739,3740],{"class":157,"line":302},[155,3741,278],{"emptyLinePlaceholder":277},[155,3743,3744,3747,3749,3752,3755],{"class":157,"line":323},[155,3745,3746],{"class":164},"app ",[155,3748,168],{"class":160},[155,3750,3751],{"class":164}," Flask(",[155,3753,3754],{"class":261},"__name__",[155,3756,1717],{"class":164},[155,3758,3759],{"class":157,"line":377},[155,3760,278],{"emptyLinePlaceholder":277},[155,3762,3763],{"class":157,"line":394},[155,3764,3765],{"class":251},"# in production = a database table · used_refs = a UNIQUE transRef column\n",[155,3767,3768,3771,3773,3775,3778,3781,3784,3786,3788,3790,3793,3795,3798],{"class":157,"line":410},[155,3769,3770],{"class":164},"orders ",[155,3772,168],{"class":160},[155,3774,1064],{"class":164},[155,3776,3777],{"class":171},"\"1001\"",[155,3779,3780],{"class":164},": {",[155,3782,3783],{"class":171},"\"total\"",[155,3785,649],{"class":164},[155,3787,3011],{"class":261},[155,3789,314],{"class":164},[155,3791,3792],{"class":171},"\"paid\"",[155,3794,649],{"class":164},[155,3796,3797],{"class":261},"False",[155,3799,3800],{"class":164},"}}\n",[155,3802,3803,3806,3808,3810,3812,3815],{"class":157,"line":13},[155,3804,3805],{"class":164},"used_refs: set[",[155,3807,1197],{"class":261},[155,3809,1681],{"class":164},[155,3811,168],{"class":160},[155,3813,3814],{"class":261}," set",[155,3816,3817],{"class":164},"()\n",[155,3819,3820],{"class":157,"line":431},[155,3821,278],{"emptyLinePlaceholder":277},[155,3823,3824],{"class":157,"line":437},[155,3825,3826],{"class":251},"# what to tell the customer when a slip is rejected\n",[155,3828,3829,3831,3833],{"class":157,"line":442},[155,3830,3456],{"class":261},[155,3832,265],{"class":160},[155,3834,299],{"class":164},[155,3836,3837,3840,3842,3845],{"class":157,"line":486},[155,3838,3839],{"class":171},"    \"DUPLICATE\"",[155,3841,649],{"class":164},[155,3843,3844],{"class":171},"\"This slip has already been used\"",[155,3846,627],{"class":164},[155,3848,3849,3852,3854,3857],{"class":157,"line":491},[155,3850,3851],{"class":171},"    \"FRAUD\"",[155,3853,649],{"class":164},[155,3855,3856],{"class":171},"\"This slip is not valid. Please contact the shop\"",[155,3858,627],{"class":164},[155,3860,3861,3864,3866,3869],{"class":157,"line":497},[155,3862,3863],{"class":171},"    \"RECEIVER_MISMATCH\"",[155,3865,649],{"class":164},[155,3867,3868],{"class":171},"\"This slip was not paid into the shop account\"",[155,3870,627],{"class":164},[155,3872,3873,3876,3878,3881],{"class":157,"line":548},[155,3874,3875],{"class":171},"    \"INVALID\"",[155,3877,649],{"class":164},[155,3879,3880],{"class":171},"\"We could not read the slip. Upload an image with the QR code clearly visible\"",[155,3882,627],{"class":164},[155,3884,3885,3888,3890,3893],{"class":157,"line":575},[155,3886,3887],{"class":171},"    \"PROVIDER_ERROR\"",[155,3889,649],{"class":164},[155,3891,3892],{"class":171},"\"Slip verification is temporarily unavailable. Please try again\"",[155,3894,627],{"class":164},[155,3896,3897],{"class":157,"line":584},[155,3898,434],{"class":164},[155,3900,3901],{"class":157,"line":18},[155,3902,278],{"emptyLinePlaceholder":277},[155,3904,3905],{"class":157,"line":618},[155,3906,278],{"emptyLinePlaceholder":277},[155,3908,3909,3911,3914,3917,3919,3922,3925,3927,3929,3931,3933],{"class":157,"line":630},[155,3910,1182],{"class":160},[155,3912,3913],{"class":289}," reply",[155,3915,3916],{"class":164},"(status: ",[155,3918,1024],{"class":261},[155,3920,3921],{"class":164},", ok: ",[155,3923,3924],{"class":261},"bool",[155,3926,3220],{"class":164},[155,3928,1197],{"class":261},[155,3930,314],{"class":164},[155,3932,1424],{"class":160},[155,3934,3935],{"class":164},"extra):\n",[155,3937,3938,3940,3943,3946,3948,3951,3953,3955,3958,3960],{"class":157,"line":658},[155,3939,920],{"class":160},[155,3941,3942],{"class":164}," jsonify(",[155,3944,3945],{"class":311},"ok",[155,3947,168],{"class":160},[155,3949,3950],{"class":164},"ok, ",[155,3952,366],{"class":311},[155,3954,168],{"class":160},[155,3956,3957],{"class":164},"message, ",[155,3959,1424],{"class":160},[155,3961,3962],{"class":164},"extra), status\n",[155,3964,3965],{"class":157,"line":664},[155,3966,278],{"emptyLinePlaceholder":277},[155,3968,3969],{"class":157,"line":22},[155,3970,278],{"emptyLinePlaceholder":277},[155,3972,3973,3976,3978,3981],{"class":157,"line":686},[155,3974,3975],{"class":289},"@app.post",[155,3977,308],{"class":164},[155,3979,3980],{"class":171},"\"\u002Forders\u002F\u003Corder_id>\u002Fslip\"",[155,3982,1717],{"class":164},[155,3984,3985,3987,3990,3993,3995],{"class":157,"line":698},[155,3986,1182],{"class":160},[155,3988,3989],{"class":289}," pay_with_slip",[155,3991,3992],{"class":164},"(order_id: ",[155,3994,1197],{"class":261},[155,3996,1010],{"class":164},[155,3998,3999,4002,4004],{"class":157,"line":722},[155,4000,4001],{"class":164},"    order ",[155,4003,168],{"class":160},[155,4005,4006],{"class":164}," orders.get(order_id)\n",[155,4008,4009,4011,4014,4017,4020],{"class":157,"line":747},[155,4010,768],{"class":160},[155,4012,4013],{"class":164}," order ",[155,4015,4016],{"class":160},"is",[155,4018,4019],{"class":261}," None",[155,4021,1219],{"class":164},[155,4023,4024,4026,4029,4031,4033,4035,4037,4040],{"class":157,"line":26},[155,4025,1562],{"class":160},[155,4027,4028],{"class":164}," reply(",[155,4030,3208],{"class":261},[155,4032,314],{"class":164},[155,4034,3797],{"class":261},[155,4036,314],{"class":164},[155,4038,4039],{"class":171},"\"Order not found\"",[155,4041,1717],{"class":164},[155,4043,4044,4046,4049,4051],{"class":157,"line":760},[155,4045,768],{"class":160},[155,4047,4048],{"class":164}," order[",[155,4050,3792],{"class":171},[155,4052,4053],{"class":164},"]:\n",[155,4055,4056,4058,4060,4063,4065,4068,4070,4073],{"class":157,"line":765},[155,4057,1562],{"class":160},[155,4059,4028],{"class":164},[155,4061,4062],{"class":261},"200",[155,4064,314],{"class":164},[155,4066,4067],{"class":261},"True",[155,4069,314],{"class":164},[155,4071,4072],{"class":171},"\"This order is already paid\"",[155,4074,1717],{"class":164},[155,4076,4077,4080,4082],{"class":157,"line":804},[155,4078,4079],{"class":164},"    image ",[155,4081,168],{"class":160},[155,4083,4084],{"class":164}," request.get_data()\n",[155,4086,4087,4089,4091],{"class":157,"line":848},[155,4088,768],{"class":160},[155,4090,1466],{"class":160},[155,4092,4093],{"class":164}," image:\n",[155,4095,4096,4098,4100,4102,4104,4106,4108,4111],{"class":157,"line":30},[155,4097,1562],{"class":160},[155,4099,4028],{"class":164},[155,4101,3295],{"class":261},[155,4103,314],{"class":164},[155,4105,3797],{"class":261},[155,4107,314],{"class":164},[155,4109,4110],{"class":171},"\"Please attach a slip image\"",[155,4112,1717],{"class":164},[155,4114,4115],{"class":157,"line":859},[155,4116,278],{"emptyLinePlaceholder":277},[155,4118,4119,4121],{"class":157,"line":864},[155,4120,587],{"class":160},[155,4122,1219],{"class":164},[155,4124,4125,4128,4130],{"class":157,"line":895},[155,4126,4127],{"class":164},"        slip ",[155,4129,168],{"class":160},[155,4131,4132],{"class":164}," verify_slip(image)\n",[155,4134,4135,4138,4141,4144,4147],{"class":157,"line":917},[155,4136,4137],{"class":160},"    except",[155,4139,4140],{"class":261}," Exception",[155,4142,4143],{"class":160}," as",[155,4145,4146],{"class":164}," err:  ",[155,4148,4149],{"class":251},"# 402 = shop quota used up · 401\u002F403 = key or plan → alert your team\n",[155,4151,4152,4155,4158,4161,4163],{"class":157,"line":35},[155,4153,4154],{"class":164},"        app.logger.error(",[155,4156,4157],{"class":171},"\"SlipBolt: ",[155,4159,4160],{"class":261},"%s",[155,4162,1053],{"class":171},[155,4164,4165],{"class":164},", err)\n",[155,4167,4168,4170,4172,4174,4176,4178,4180,4183],{"class":157,"line":933},[155,4169,1562],{"class":160},[155,4171,4028],{"class":164},[155,4173,3386],{"class":261},[155,4175,314],{"class":164},[155,4177,3797],{"class":261},[155,4179,314],{"class":164},[155,4181,4182],{"class":171},"\"Automatic verification is unavailable. Try again or contact the shop\"",[155,4184,1717],{"class":164},[155,4186,4187],{"class":157,"line":1503},[155,4188,278],{"emptyLinePlaceholder":277},[155,4190,4191],{"class":157,"line":1510},[155,4192,4193],{"class":251},"    # 1) genuine and paid into the shop account  2) not a slip that was already checked\n",[155,4195,4196,4198,4200,4203,4206,4208,4210,4212,4215],{"class":157,"line":1521},[155,4197,768],{"class":160},[155,4199,1466],{"class":160},[155,4201,4202],{"class":164}," slip[",[155,4204,4205],{"class":171},"\"verified\"",[155,4207,1681],{"class":164},[155,4209,1075],{"class":160},[155,4211,4202],{"class":164},[155,4213,4214],{"class":171},"\"duplicate\"",[155,4216,4053],{"class":164},[155,4218,4219,4221,4223,4225,4227,4229,4231,4233,4236,4238,4240,4243],{"class":157,"line":39},[155,4220,1562],{"class":160},[155,4222,4028],{"class":164},[155,4224,3443],{"class":261},[155,4226,314],{"class":164},[155,4228,3797],{"class":261},[155,4230,314],{"class":164},[155,4232,3456],{"class":261},[155,4234,4235],{"class":164},".get(slip[",[155,4237,2412],{"class":171},[155,4239,2490],{"class":164},[155,4241,4242],{"class":171},"\"The slip did not pass verification\"",[155,4244,4245],{"class":164},"))\n",[155,4247,4248],{"class":157,"line":1540},[155,4249,4250],{"class":251},"    # 3) the amount matches the order — the API does not know what this order costs\n",[155,4252,4253,4255,4258,4260,4262,4264,4266,4268,4270,4273,4275,4277],{"class":157,"line":1550},[155,4254,768],{"class":160},[155,4256,4257],{"class":261}," abs",[155,4259,2409],{"class":164},[155,4261,2418],{"class":171},[155,4263,1681],{"class":164},[155,4265,3491],{"class":160},[155,4267,4048],{"class":164},[155,4269,3783],{"class":171},[155,4271,4272],{"class":164},"]) ",[155,4274,3497],{"class":160},[155,4276,3500],{"class":261},[155,4278,1219],{"class":164},[155,4280,4281,4283,4285,4287,4289,4291,4293,4295,4298,4300,4303,4305,4308,4310,4313,4315,4318,4321,4323,4325,4328],{"class":157,"line":1559},[155,4282,1562],{"class":160},[155,4284,4028],{"class":164},[155,4286,3443],{"class":261},[155,4288,314],{"class":164},[155,4290,3797],{"class":261},[155,4292,314],{"class":164},[155,4294,1333],{"class":160},[155,4296,4297],{"class":171},"\"Transferred ",[155,4299,1056],{"class":261},[155,4301,4302],{"class":164},"slip[",[155,4304,2499],{"class":171},[155,4306,4307],{"class":164},"]",[155,4309,1061],{"class":261},[155,4311,4312],{"class":171}," THB, but the order total is ",[155,4314,1056],{"class":261},[155,4316,4317],{"class":164},"order[",[155,4319,4320],{"class":171},"'total'",[155,4322,4307],{"class":164},[155,4324,1061],{"class":261},[155,4326,4327],{"class":171}," THB\"",[155,4329,1717],{"class":164},[155,4331,4332],{"class":157,"line":2207},[155,4333,4334],{"class":251},"    # 4) one slip closes one order\n",[155,4336,4337,4339,4341,4343,4345,4347],{"class":157,"line":2223},[155,4338,768],{"class":160},[155,4340,4202],{"class":164},[155,4342,2423],{"class":171},[155,4344,1681],{"class":164},[155,4346,1255],{"class":160},[155,4348,4349],{"class":164}," used_refs:\n",[155,4351,4352,4354,4356,4358,4360,4362,4364,4367],{"class":157,"line":2235},[155,4353,1562],{"class":160},[155,4355,4028],{"class":164},[155,4357,3443],{"class":261},[155,4359,314],{"class":164},[155,4361,3797],{"class":261},[155,4363,314],{"class":164},[155,4365,4366],{"class":171},"\"This slip was already used for another order\"",[155,4368,1717],{"class":164},[155,4370,4371],{"class":157,"line":2240},[155,4372,278],{"emptyLinePlaceholder":277},[155,4374,4375,4378,4380],{"class":157,"line":2255},[155,4376,4377],{"class":164},"    used_refs.add(slip[",[155,4379,2423],{"class":171},[155,4381,2426],{"class":164},[155,4383,4384,4387,4390,4392,4394,4396,4398,4400,4402,4404],{"class":157,"line":2260},[155,4385,4386],{"class":164},"    order.update(",[155,4388,4389],{"class":311},"paid",[155,4391,168],{"class":160},[155,4393,4067],{"class":261},[155,4395,314],{"class":164},[155,4397,2607],{"class":311},[155,4399,168],{"class":160},[155,4401,4302],{"class":164},[155,4403,2423],{"class":171},[155,4405,2426],{"class":164},[155,4407,4408,4410,4412,4414,4416,4418,4420,4423,4425,4427,4429,4431,4433],{"class":157,"line":3657},[155,4409,920],{"class":160},[155,4411,4028],{"class":164},[155,4413,4062],{"class":261},[155,4415,314],{"class":164},[155,4417,4067],{"class":261},[155,4419,314],{"class":164},[155,4421,4422],{"class":171},"\"Payment received. Thank you!\"",[155,4424,314],{"class":164},[155,4426,2607],{"class":311},[155,4428,168],{"class":160},[155,4430,4302],{"class":164},[155,4432,2423],{"class":171},[155,4434,2426],{"class":164},[155,4436,4437],{"class":157,"line":3677},[155,4438,278],{"emptyLinePlaceholder":277},[155,4440,4441],{"class":157,"line":3683},[155,4442,278],{"emptyLinePlaceholder":277},[155,4444,4445,4448,4451,4454,4457],{"class":157,"line":3688},[155,4446,4447],{"class":160},"if",[155,4449,4450],{"class":261}," __name__",[155,4452,4453],{"class":160}," ==",[155,4455,4456],{"class":171}," \"__main__\"",[155,4458,1219],{"class":164},[155,4460,4462,4465,4468,4470,4472],{"class":157,"line":4461},59,[155,4463,4464],{"class":164},"    app.run(",[155,4466,4467],{"class":311},"port",[155,4469,168],{"class":160},[155,4471,3698],{"class":261},[155,4473,1717],{"class":164},[146,4475,4477],{"className":1577,"code":4476,"filename":1579,"language":1580,"meta":151,"style":151},"\u003C?php\n\u002F\u002F pay.php?order=1001 — table: 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 what to tell the customer when a slip is rejected\nconst REJECT = [\n    'DUPLICATE'         => 'This slip has already been used',\n    'FRAUD'             => 'This slip is not valid. Please contact the shop',\n    'RECEIVER_MISMATCH' => 'This slip was not paid into the shop account',\n    'INVALID'           => 'We could not read the slip. Upload an image with the QR code clearly visible',\n    'PROVIDER_ERROR'    => 'Slip verification is temporarily unavailable. Please try again',\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, 'Order not found');\nif ($order['trans_ref'] !== null) reply(200, true, 'This order is already paid');\n\n$image = file_get_contents('php:\u002F\u002Finput'); \u002F\u002F the slip image the browser sent as the body\nif ($image === '' || $image === false) reply(400, false, 'Please attach a slip image');\n\ntry {\n    $slip = slipbolt_verify($image);\n} catch (Throwable $err) { \u002F\u002F 402 = shop quota used up · 401\u002F403 = key or plan → alert your team\n    error_log('SlipBolt: ' . $err->getMessage());\n    reply(503, false, 'Automatic verification is unavailable. Try again or contact the shop');\n}\n\n\u002F\u002F 1) genuine and paid into the shop account  2) not a slip that was already checked\nif (!$slip['verified'] || $slip['duplicate']) {\n    reply(422, false, REJECT[$slip['status']] ?? 'The slip did not pass verification');\n}\n\u002F\u002F 3) the amount matches the order — the API does not know what this order costs\nif (abs($slip['amount'] - (float) $order['total']) > 0.001) {\n    reply(422, false, \"Transferred {$slip['amount']} THB, but the order total is {$order['total']} THB\");\n}\n\u002F\u002F 4) one slip closes one order — let the database UNIQUE decide (it also covers two requests racing)\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, 'This slip was already used for another order');\n}\n\nreply(200, true, 'Payment received. Thank you!');\n",[141,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":151},[155,4480,4481,4483],{"class":157,"line":9},[155,4482,1587],{"class":160},[155,4484,1590],{"class":261},[155,4486,4487],{"class":157,"line":255},[155,4488,4489],{"class":251},"\u002F\u002F pay.php?order=1001 — table: orders(id, total, trans_ref UNIQUE NULL)\n",[155,4491,4492,4494,4496,4498,4500],{"class":157,"line":274},[155,4493,2442],{"class":160},[155,4495,2445],{"class":261},[155,4497,1673],{"class":160},[155,4499,2450],{"class":171},[155,4501,271],{"class":164},[155,4503,4504],{"class":157,"line":281},[155,4505,278],{"emptyLinePlaceholder":277},[155,4507,4508,4510,4512,4514,4516,4518,4520,4523,4525,4528,4530],{"class":157,"line":302},[155,4509,1744],{"class":160},[155,4511,3913],{"class":289},[155,4513,308],{"class":164},[155,4515,1024],{"class":160},[155,4517,1636],{"class":164},[155,4519,3924],{"class":160},[155,4521,4522],{"class":164}," $ok, ",[155,4524,1752],{"class":160},[155,4526,4527],{"class":164}," $message)",[155,4529,1770],{"class":160},[155,4531,4532],{"class":160}," never\n",[155,4534,4535],{"class":157,"line":323},[155,4536,1615],{"class":164},[155,4538,4539,4542],{"class":157,"line":377},[155,4540,4541],{"class":261},"    http_response_code",[155,4543,4544],{"class":164},"($status);\n",[155,4546,4547,4550,4552,4555],{"class":157,"line":394},[155,4548,4549],{"class":261},"    header",[155,4551,308],{"class":164},[155,4553,4554],{"class":171},"'Content-Type: application\u002Fjson; charset=utf-8'",[155,4556,374],{"class":164},[155,4558,4559,4562,4565,4568,4571,4573,4575,4577,4579,4582,4585],{"class":157,"line":410},[155,4560,4561],{"class":261},"    echo",[155,4563,4564],{"class":261}," json_encode",[155,4566,4567],{"class":164},"([",[155,4569,4570],{"class":171},"'ok'",[155,4572,1902],{"class":160},[155,4574,4522],{"class":164},[155,4576,1099],{"class":171},[155,4578,1902],{"class":160},[155,4580,4581],{"class":164}," $message], ",[155,4583,4584],{"class":261},"JSON_UNESCAPED_UNICODE",[155,4586,374],{"class":164},[155,4588,4589,4592],{"class":157,"line":13},[155,4590,4591],{"class":160},"    exit",[155,4593,271],{"class":164},[155,4595,4596],{"class":157,"line":431},[155,4597,434],{"class":164},[155,4599,4600],{"class":157,"line":437},[155,4601,278],{"emptyLinePlaceholder":277},[155,4603,4604],{"class":157,"line":442},[155,4605,3045],{"class":251},[155,4607,4608,4610,4612,4614],{"class":157,"line":486},[155,4609,258],{"class":160},[155,4611,3052],{"class":261},[155,4613,265],{"class":160},[155,4615,1855],{"class":164},[155,4617,4618,4621,4624,4627],{"class":157,"line":491},[155,4619,4620],{"class":171},"    'DUPLICATE'",[155,4622,4623],{"class":160},"         =>",[155,4625,4626],{"class":171}," 'This slip has already been used'",[155,4628,627],{"class":164},[155,4630,4631,4634,4637,4640],{"class":157,"line":497},[155,4632,4633],{"class":171},"    'FRAUD'",[155,4635,4636],{"class":160},"             =>",[155,4638,4639],{"class":171}," 'This slip is not valid. Please contact the shop'",[155,4641,627],{"class":164},[155,4643,4644,4647,4649,4652],{"class":157,"line":548},[155,4645,4646],{"class":171},"    'RECEIVER_MISMATCH'",[155,4648,1902],{"class":160},[155,4650,4651],{"class":171}," 'This slip was not paid into the shop account'",[155,4653,627],{"class":164},[155,4655,4656,4659,4661,4664],{"class":157,"line":575},[155,4657,4658],{"class":171},"    'INVALID'",[155,4660,1839],{"class":160},[155,4662,4663],{"class":171}," 'We could not read the slip. Upload an image with the QR code clearly visible'",[155,4665,627],{"class":164},[155,4667,4668,4671,4674,4677],{"class":157,"line":584},[155,4669,4670],{"class":171},"    'PROVIDER_ERROR'",[155,4672,4673],{"class":160},"    =>",[155,4675,4676],{"class":171}," 'Slip verification is temporarily unavailable. Please try again'",[155,4678,627],{"class":164},[155,4680,4681],{"class":157,"line":18},[155,4682,2782],{"class":164},[155,4684,4685],{"class":157,"line":618},[155,4686,278],{"emptyLinePlaceholder":277},[155,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":157,"line":630},[155,4690,4691],{"class":164},"$pdo ",[155,4693,168],{"class":160},[155,4695,464],{"class":160},[155,4697,4698],{"class":261}," PDO",[155,4700,308],{"class":164},[155,4702,4703],{"class":261},"getenv",[155,4705,308],{"class":164},[155,4707,4708],{"class":171},"'DB_DSN'",[155,4710,4711],{"class":164},"), ",[155,4713,4703],{"class":261},[155,4715,308],{"class":164},[155,4717,4718],{"class":171},"'DB_USER'",[155,4720,458],{"class":164},[155,4722,2118],{"class":160},[155,4724,4725],{"class":261}," null",[155,4727,314],{"class":164},[155,4729,4703],{"class":261},[155,4731,308],{"class":164},[155,4733,4734],{"class":171},"'DB_PASS'",[155,4736,458],{"class":164},[155,4738,2118],{"class":160},[155,4740,4725],{"class":261},[155,4742,4743],{"class":164},", [\n",[155,4745,4746,4749,4752,4755,4757,4759,4761,4764],{"class":157,"line":658},[155,4747,4748],{"class":261},"    PDO",[155,4750,4751],{"class":160},"::",[155,4753,4754],{"class":261},"ATTR_ERRMODE",[155,4756,1902],{"class":160},[155,4758,4698],{"class":261},[155,4760,4751],{"class":160},[155,4762,4763],{"class":261},"ERRMODE_EXCEPTION",[155,4765,627],{"class":164},[155,4767,4768],{"class":157,"line":664},[155,4769,4770],{"class":164},"]);\n",[155,4772,4773],{"class":157,"line":22},[155,4774,278],{"emptyLinePlaceholder":277},[155,4776,4777,4780,4782,4785,4788,4791,4793,4796,4799,4802,4805,4808,4811,4814,4816,4819],{"class":157,"line":686},[155,4778,4779],{"class":164},"$find ",[155,4781,168],{"class":160},[155,4783,4784],{"class":164}," $pdo",[155,4786,4787],{"class":160},"->",[155,4789,4790],{"class":289},"prepare",[155,4792,308],{"class":164},[155,4794,4795],{"class":171},"'",[155,4797,4798],{"class":160},"SELECT",[155,4800,4801],{"class":171}," id, total, trans_ref ",[155,4803,4804],{"class":160},"FROM",[155,4806,4807],{"class":171}," orders ",[155,4809,4810],{"class":160},"WHERE",[155,4812,4813],{"class":171}," id ",[155,4815,168],{"class":160},[155,4817,4818],{"class":171}," ?'",[155,4820,374],{"class":164},[155,4822,4823,4826,4828,4831,4834,4837,4839,4841,4843],{"class":157,"line":698},[155,4824,4825],{"class":164},"$find",[155,4827,4787],{"class":160},[155,4829,4830],{"class":289},"execute",[155,4832,4833],{"class":164},"([$_GET[",[155,4835,4836],{"class":171},"'order'",[155,4838,1681],{"class":164},[155,4840,1684],{"class":160},[155,4842,1088],{"class":171},[155,4844,4770],{"class":164},[155,4846,4847,4850,4852,4855,4857,4860,4862,4865,4867,4870],{"class":157,"line":722},[155,4848,4849],{"class":164},"$order ",[155,4851,168],{"class":160},[155,4853,4854],{"class":164}," $find",[155,4856,4787],{"class":160},[155,4858,4859],{"class":289},"fetch",[155,4861,308],{"class":164},[155,4863,4864],{"class":261},"PDO",[155,4866,4751],{"class":160},[155,4868,4869],{"class":261},"FETCH_ASSOC",[155,4871,374],{"class":164},[155,4873,4874,4876,4878,4880,4883,4886,4888,4890,4892,4894,4896,4898],{"class":157,"line":747},[155,4875,4447],{"class":160},[155,4877,452],{"class":164},[155,4879,902],{"class":160},[155,4881,4882],{"class":164},"$order) ",[155,4884,4885],{"class":289},"reply",[155,4887,308],{"class":164},[155,4889,3208],{"class":261},[155,4891,314],{"class":164},[155,4893,3017],{"class":261},[155,4895,314],{"class":164},[155,4897,3223],{"class":171},[155,4899,374],{"class":164},[155,4901,4902,4904,4907,4910,4912,4914,4916,4918,4920,4922,4924,4926,4928,4930,4932],{"class":157,"line":26},[155,4903,4447],{"class":160},[155,4905,4906],{"class":164}," ($order[",[155,4908,4909],{"class":171},"'trans_ref'",[155,4911,1681],{"class":164},[155,4913,2215],{"class":160},[155,4915,4725],{"class":261},[155,4917,458],{"class":164},[155,4919,4885],{"class":289},[155,4921,308],{"class":164},[155,4923,4062],{"class":261},[155,4925,314],{"class":164},[155,4927,2197],{"class":261},[155,4929,314],{"class":164},[155,4931,3248],{"class":171},[155,4933,374],{"class":164},[155,4935,4936],{"class":157,"line":760},[155,4937,278],{"emptyLinePlaceholder":277},[155,4939,4940,4943,4945,4948,4950,4953,4956],{"class":157,"line":765},[155,4941,4942],{"class":164},"$image ",[155,4944,168],{"class":160},[155,4946,4947],{"class":261}," file_get_contents",[155,4949,308],{"class":164},[155,4951,4952],{"class":171},"'php:\u002F\u002Finput'",[155,4954,4955],{"class":164},"); ",[155,4957,4958],{"class":251},"\u002F\u002F the slip image the browser sent as the body\n",[155,4960,4961,4963,4966,4968,4970,4972,4975,4977,4979,4981,4983,4985,4987,4989,4991,4993,4995],{"class":157,"line":804},[155,4962,4447],{"class":160},[155,4964,4965],{"class":164}," ($image ",[155,4967,774],{"class":160},[155,4969,1088],{"class":171},[155,4971,780],{"class":160},[155,4973,4974],{"class":164}," $image ",[155,4976,774],{"class":160},[155,4978,2078],{"class":261},[155,4980,458],{"class":164},[155,4982,4885],{"class":289},[155,4984,308],{"class":164},[155,4986,3295],{"class":261},[155,4988,314],{"class":164},[155,4990,3017],{"class":261},[155,4992,314],{"class":164},[155,4994,3308],{"class":171},[155,4996,374],{"class":164},[155,4998,4999],{"class":157,"line":848},[155,5000,278],{"emptyLinePlaceholder":277},[155,5002,5003,5006],{"class":157,"line":30},[155,5004,5005],{"class":160},"try",[155,5007,299],{"class":164},[155,5009,5010,5013,5015,5017],{"class":157,"line":859},[155,5011,5012],{"class":164},"    $slip ",[155,5014,168],{"class":160},[155,5016,1747],{"class":289},[155,5018,5019],{"class":164},"($image);\n",[155,5021,5022,5025,5027,5029,5032,5035],{"class":157,"line":864},[155,5023,5024],{"class":164},"} ",[155,5026,692],{"class":160},[155,5028,452],{"class":164},[155,5030,5031],{"class":261},"Throwable",[155,5033,5034],{"class":164}," $err) { ",[155,5036,3373],{"class":251},[155,5038,5039,5042,5044,5047,5049,5052,5054,5057],{"class":157,"line":895},[155,5040,5041],{"class":261},"    error_log",[155,5043,308],{"class":164},[155,5045,5046],{"class":171},"'SlipBolt: '",[155,5048,1673],{"class":160},[155,5050,5051],{"class":164}," $err",[155,5053,4787],{"class":160},[155,5055,5056],{"class":289},"getMessage",[155,5058,5059],{"class":164},"());\n",[155,5061,5062,5065,5067,5069,5071,5073,5075,5077],{"class":157,"line":917},[155,5063,5064],{"class":289},"    reply",[155,5066,308],{"class":164},[155,5068,3386],{"class":261},[155,5070,314],{"class":164},[155,5072,3017],{"class":261},[155,5074,314],{"class":164},[155,5076,3399],{"class":171},[155,5078,374],{"class":164},[155,5080,5081],{"class":157,"line":35},[155,5082,434],{"class":164},[155,5084,5085],{"class":157,"line":933},[155,5086,278],{"emptyLinePlaceholder":277},[155,5088,5089],{"class":157,"line":1503},[155,5090,5091],{"class":251},"\u002F\u002F 1) genuine and paid into the shop account  2) not a slip that was already checked\n",[155,5093,5094,5096,5098,5100,5103,5106,5108,5110,5112,5115],{"class":157,"line":1510},[155,5095,4447],{"class":160},[155,5097,452],{"class":164},[155,5099,902],{"class":160},[155,5101,5102],{"class":164},"$slip[",[155,5104,5105],{"class":171},"'verified'",[155,5107,1681],{"class":164},[155,5109,830],{"class":160},[155,5111,2484],{"class":164},[155,5113,5114],{"class":171},"'duplicate'",[155,5116,5117],{"class":164},"]) {\n",[155,5119,5120,5122,5124,5126,5128,5130,5132,5134,5137,5139,5142,5144,5146],{"class":157,"line":1521},[155,5121,5064],{"class":289},[155,5123,308],{"class":164},[155,5125,3443],{"class":261},[155,5127,314],{"class":164},[155,5129,3017],{"class":261},[155,5131,314],{"class":164},[155,5133,3456],{"class":261},[155,5135,5136],{"class":164},"[$slip[",[155,5138,2487],{"class":171},[155,5140,5141],{"class":164},"]] ",[155,5143,1684],{"class":160},[155,5145,3464],{"class":171},[155,5147,374],{"class":164},[155,5149,5150],{"class":157,"line":39},[155,5151,434],{"class":164},[155,5153,5154],{"class":157,"line":1540},[155,5155,5156],{"class":251},"\u002F\u002F 3) the amount matches the order — the API does not know what this order costs\n",[155,5158,5159,5161,5163,5165,5168,5170,5172,5174,5176,5178,5181,5183,5185,5187,5189],{"class":157,"line":1550},[155,5160,4447],{"class":160},[155,5162,452],{"class":164},[155,5164,3485],{"class":261},[155,5166,5167],{"class":164},"($slip[",[155,5169,2499],{"class":171},[155,5171,1681],{"class":164},[155,5173,3491],{"class":160},[155,5175,452],{"class":164},[155,5177,1475],{"class":160},[155,5179,5180],{"class":164},") $order[",[155,5182,4320],{"class":171},[155,5184,4272],{"class":164},[155,5186,3497],{"class":160},[155,5188,3500],{"class":261},[155,5190,320],{"class":164},[155,5192,5193,5195,5197,5199,5201,5203,5205,5208,5211,5214,5217,5220],{"class":157,"line":1559},[155,5194,5064],{"class":289},[155,5196,308],{"class":164},[155,5198,3443],{"class":261},[155,5200,314],{"class":164},[155,5202,3017],{"class":261},[155,5204,314],{"class":164},[155,5206,5207],{"class":171},"\"Transferred {",[155,5209,5210],{"class":164},"$slip",[155,5212,5213],{"class":171},"['amount']} THB, but the order total is {",[155,5215,5216],{"class":164},"$order",[155,5218,5219],{"class":171},"['total']} THB\"",[155,5221,374],{"class":164},[155,5223,5224],{"class":157,"line":2207},[155,5225,434],{"class":164},[155,5227,5228],{"class":157,"line":2223},[155,5229,5230],{"class":251},"\u002F\u002F 4) one slip closes one order — let the database UNIQUE decide (it also covers two requests racing)\n",[155,5232,5233,5235],{"class":157,"line":2235},[155,5234,5005],{"class":160},[155,5236,299],{"class":164},[155,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":157,"line":2240},[155,5240,5241],{"class":164},"    $pay ",[155,5243,168],{"class":160},[155,5245,4784],{"class":164},[155,5247,4787],{"class":160},[155,5249,4790],{"class":289},[155,5251,308],{"class":164},[155,5253,4795],{"class":171},[155,5255,5256],{"class":160},"UPDATE",[155,5258,4807],{"class":171},[155,5260,5261],{"class":160},"SET",[155,5263,5264],{"class":171}," trans_ref ",[155,5266,168],{"class":160},[155,5268,5269],{"class":171}," ? ",[155,5271,4810],{"class":160},[155,5273,4813],{"class":171},[155,5275,168],{"class":160},[155,5277,5269],{"class":171},[155,5279,5280],{"class":160},"AND",[155,5282,5264],{"class":171},[155,5284,5285],{"class":160},"IS",[155,5287,5288],{"class":160}," NULL",[155,5290,4795],{"class":171},[155,5292,374],{"class":164},[155,5294,5295,5298,5300,5302,5305,5307,5310,5313],{"class":157,"line":2255},[155,5296,5297],{"class":164},"    $pay",[155,5299,4787],{"class":160},[155,5301,4830],{"class":289},[155,5303,5304],{"class":164},"([$slip[",[155,5306,2508],{"class":171},[155,5308,5309],{"class":164},"], $order[",[155,5311,5312],{"class":171},"'id'",[155,5314,5315],{"class":164},"]]);\n",[155,5317,5318,5320,5322,5324,5327],{"class":157,"line":2260},[155,5319,5024],{"class":164},[155,5321,692],{"class":160},[155,5323,452],{"class":164},[155,5325,5326],{"class":261},"PDOException",[155,5328,5329],{"class":164}," $err) {\n",[155,5331,5332,5334,5336,5338,5340,5342,5344,5346],{"class":157,"line":3657},[155,5333,5064],{"class":289},[155,5335,308],{"class":164},[155,5337,3443],{"class":261},[155,5339,314],{"class":164},[155,5341,3017],{"class":261},[155,5343,314],{"class":164},[155,5345,3612],{"class":171},[155,5347,374],{"class":164},[155,5349,5350],{"class":157,"line":3677},[155,5351,434],{"class":164},[155,5353,5354],{"class":157,"line":3683},[155,5355,278],{"emptyLinePlaceholder":277},[155,5357,5358,5360,5362,5364,5366,5368,5370,5372],{"class":157,"line":3688},[155,5359,4885],{"class":289},[155,5361,308],{"class":164},[155,5363,4062],{"class":261},[155,5365,314],{"class":164},[155,5367,2197],{"class":261},[155,5369,314],{"class":164},[155,5371,3671],{"class":171},[155,5373,374],{"class":164},[2527,5375,5377],{"type":5376},"info",[65,5378,5379,5382,5383,5386,5387,5390,5391,5394,5395,341],{},[68,5380,5381],{},"Don't want the customer to wait?"," Let them send the slip in the shop's LINE OA and have the\n",[100,5384,5385],{"href":24},"Webhook"," ",[141,5388,5389],{},"slip.verified"," hit your server instead — the same 4 checks work from ",[141,5392,5393],{},"data.amount"," \u002F ",[141,5396,5397],{},"data.transRef",[174,5399,125],{"id":5400},"_3-the-image-is-in-another-format",[65,5402,5403,5406,5407,5410,5411,5413],{},[141,5404,5405],{},"POST \u002Fverify"," accepts the slip in ",[68,5408,5409],{},"5 ways"," — the result, the quota and the 24-hour cache are identical for all of them\n(resending the same image in a different format still returns ",[141,5412,214],{},", with no second quota charge)",[73,5415,5416,5431],{},[76,5417,5418],{},[79,5419,5420,5423,5426],{},[82,5421,5422],{},"What you have",[82,5424,5425],{},"How to send it",[82,5427,5428],{},[141,5429,5430],{},"Content-Type",[89,5432,5433,5456,5474,5492,5509],{},[79,5434,5435,5438,5444],{},[94,5436,5437],{},"An image file \u002F Buffer \u002F bytes",[94,5439,5440,5441],{},"As the request body — smallest and fastest, ",[68,5442,5443],{},"recommended",[94,5445,5446,5449,5450,2625,5453,1767],{},[141,5447,5448],{},"application\u002Foctet-stream"," (or ",[141,5451,5452],{},"image\u002Fjpeg",[141,5454,5455],{},"image\u002Fpng",[79,5457,5458,5461,5469],{},[94,5459,5460],{},"A file from an upload form",[94,5462,5463,5464],{},"Forward it as multipart, in a file field named ",[68,5465,5466],{},[141,5467,5468],{},"file",[94,5470,5471],{},[141,5472,5473],{},"multipart\u002Fform-data",[79,5475,5476,5479,5487],{},[94,5477,5478],{},"base64 or a data URL",[94,5480,5481,5482,5486],{},"Put it in the ",[68,5483,5484],{},[141,5485,513],{}," field of a JSON body",[94,5488,5489],{},[141,5490,5491],{},"application\u002Fjson",[79,5493,5494,5497,5505],{},[94,5495,5496],{},"An image URL (S3, CDN)",[94,5498,5481,5499,5504],{},[68,5500,5501],{},[141,5502,5503],{},"url"," field of a JSON body — we download it",[94,5506,5507],{},[141,5508,5491],{},[79,5510,5511,5514,5521],{},[94,5512,5513],{},"The text inside the slip's QR code (no image)",[94,5515,5481,5516,5486],{},[68,5517,5518],{},[141,5519,5520],{},"qr",[94,5522,5523],{},[141,5524,5491],{},[237,5526,5527,5817,6124,6391,6720,7091,8099],{},[146,5528,5531],{"className":148,"code":5529,"filename":5530,"language":150,"meta":151,"style":151},"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 field named 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 — an https link to the image, reachable from the internet\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 — the text scanned from the QR code on the slip\ncurl -X POST \"$API\" -H \"Authorization: Bearer $SLIPBOLT_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"qr\":\"0046000600000101030140225202610075020019535816MIR5102TH9104A1B2\"}'\n","cURL",[141,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":151},[155,5534,5535,5538,5540],{"class":157,"line":9},[155,5536,5537],{"class":164},"API",[155,5539,168],{"class":160},[155,5541,5542],{"class":171},"\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[155,5544,5545],{"class":157,"line":255},[155,5546,278],{"emptyLinePlaceholder":277},[155,5548,5549],{"class":157,"line":274},[155,5550,5551],{"class":251},"# 1) raw bytes\n",[155,5553,5554,5557,5560,5563,5565,5568,5570,5573,5576,5579,5581],{"class":157,"line":281},[155,5555,5556],{"class":289},"curl",[155,5558,5559],{"class":261}," -X",[155,5561,5562],{"class":171}," POST",[155,5564,1670],{"class":171},[155,5566,5567],{"class":164},"$API",[155,5569,1053],{"class":171},[155,5571,5572],{"class":261}," -H",[155,5574,5575],{"class":171}," \"Authorization: Bearer ",[155,5577,5578],{"class":164},"$SLIPBOLT_API_KEY",[155,5580,1053],{"class":171},[155,5582,5583],{"class":261}," \\\n",[155,5585,5586,5589,5592,5595],{"class":157,"line":302},[155,5587,5588],{"class":261},"  -H",[155,5590,5591],{"class":171}," \"Content-Type: application\u002Foctet-stream\"",[155,5593,5594],{"class":261}," --data-binary",[155,5596,5597],{"class":171}," \"@slip.jpg\"\n",[155,5599,5600],{"class":157,"line":323},[155,5601,278],{"emptyLinePlaceholder":277},[155,5603,5604],{"class":157,"line":377},[155,5605,5606],{"class":251},"# 2) multipart\u002Fform-data — file field named file\n",[155,5608,5609,5611,5613,5615,5617,5619,5621,5623,5625,5627,5629],{"class":157,"line":394},[155,5610,5556],{"class":289},[155,5612,5559],{"class":261},[155,5614,5562],{"class":171},[155,5616,1670],{"class":171},[155,5618,5567],{"class":164},[155,5620,1053],{"class":171},[155,5622,5572],{"class":261},[155,5624,5575],{"class":171},[155,5626,5578],{"class":164},[155,5628,1053],{"class":171},[155,5630,5583],{"class":261},[155,5632,5633,5636],{"class":157,"line":410},[155,5634,5635],{"class":261},"  -F",[155,5637,5638],{"class":171}," \"file=@slip.jpg\"\n",[155,5640,5641],{"class":157,"line":13},[155,5642,278],{"emptyLinePlaceholder":277},[155,5644,5645],{"class":157,"line":431},[155,5646,5647],{"class":251},"# 3) JSON base64\n",[155,5649,5650,5653,5656,5659,5662,5665,5668,5671,5673,5676,5679],{"class":157,"line":437},[155,5651,5652],{"class":289},"base64",[155,5654,5655],{"class":160}," \u003C",[155,5657,5658],{"class":171}," slip.jpg",[155,5660,5661],{"class":160}," |",[155,5663,5664],{"class":289}," tr",[155,5666,5667],{"class":261}," -d",[155,5669,5670],{"class":171}," '\\n'",[155,5672,5661],{"class":160},[155,5674,5675],{"class":289}," sed",[155,5677,5678],{"class":171}," 's\u002F.*\u002F{\"image\":\"&\"}\u002F'",[155,5680,5681],{"class":160}," |\n",[155,5683,5684,5687,5689,5691,5693,5695,5697,5699,5701,5703,5705],{"class":157,"line":442},[155,5685,5686],{"class":289},"  curl",[155,5688,5559],{"class":261},[155,5690,5562],{"class":171},[155,5692,1670],{"class":171},[155,5694,5567],{"class":164},[155,5696,1053],{"class":171},[155,5698,5572],{"class":261},[155,5700,5575],{"class":171},[155,5702,5578],{"class":164},[155,5704,1053],{"class":171},[155,5706,5583],{"class":261},[155,5708,5709,5712,5715,5717],{"class":157,"line":486},[155,5710,5711],{"class":261},"    -H",[155,5713,5714],{"class":171}," \"Content-Type: application\u002Fjson\"",[155,5716,5594],{"class":261},[155,5718,5719],{"class":171}," @-\n",[155,5721,5722],{"class":157,"line":491},[155,5723,278],{"emptyLinePlaceholder":277},[155,5725,5726],{"class":157,"line":497},[155,5727,5728],{"class":251},"# 4) JSON url — an https link to the image, reachable from the internet\n",[155,5730,5731,5733,5735,5737,5739,5741,5743,5745,5747,5749,5751],{"class":157,"line":548},[155,5732,5556],{"class":289},[155,5734,5559],{"class":261},[155,5736,5562],{"class":171},[155,5738,1670],{"class":171},[155,5740,5567],{"class":164},[155,5742,1053],{"class":171},[155,5744,5572],{"class":261},[155,5746,5575],{"class":171},[155,5748,5578],{"class":164},[155,5750,1053],{"class":171},[155,5752,5583],{"class":261},[155,5754,5755,5757,5759],{"class":157,"line":575},[155,5756,5588],{"class":261},[155,5758,5714],{"class":171},[155,5760,5583],{"class":261},[155,5762,5763,5766],{"class":157,"line":584},[155,5764,5765],{"class":261},"  -d",[155,5767,5768],{"class":171}," '{\"url\":\"https:\u002F\u002Fcdn.example.com\u002Fslips\u002F1001.jpg\"}'\n",[155,5770,5771],{"class":157,"line":18},[155,5772,278],{"emptyLinePlaceholder":277},[155,5774,5775],{"class":157,"line":618},[155,5776,5777],{"class":251},"# 5) JSON qr — the text scanned from the QR code on the slip\n",[155,5779,5780,5782,5784,5786,5788,5790,5792,5794,5796,5798,5800],{"class":157,"line":630},[155,5781,5556],{"class":289},[155,5783,5559],{"class":261},[155,5785,5562],{"class":171},[155,5787,1670],{"class":171},[155,5789,5567],{"class":164},[155,5791,1053],{"class":171},[155,5793,5572],{"class":261},[155,5795,5575],{"class":171},[155,5797,5578],{"class":164},[155,5799,1053],{"class":171},[155,5801,5583],{"class":261},[155,5803,5804,5806,5808],{"class":157,"line":658},[155,5805,5588],{"class":261},[155,5807,5714],{"class":171},[155,5809,5583],{"class":261},[155,5811,5812,5814],{"class":157,"line":664},[155,5813,5765],{"class":261},[155,5815,5816],{"class":171}," '{\"qr\":\"0046000600000101030140225202610075020019535816MIR5102TH9104A1B2\"}'\n",[146,5818,5820],{"className":241,"code":5819,"filename":243,"language":244,"meta":151,"style":151},"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 field named 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 — plain base64 or data:image\u002F...;base64,... both work\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",[141,5821,5822,5834,5838,5852,5883,5902,5906,5911,5927,5955,5980,5984,5989,6008,6017,6037,6064,6068,6072,6089,6105,6120],{"__ignoreMap":151},[155,5823,5824,5826,5828,5830,5832],{"class":157,"line":9},[155,5825,953],{"class":160},[155,5827,2279],{"class":164},[155,5829,2282],{"class":160},[155,5831,2285],{"class":171},[155,5833,271],{"class":164},[155,5835,5836],{"class":157,"line":255},[155,5837,278],{"emptyLinePlaceholder":277},[155,5839,5840,5842,5845,5847,5850],{"class":157,"line":274},[155,5841,258],{"class":160},[155,5843,5844],{"class":261}," API",[155,5846,265],{"class":160},[155,5848,5849],{"class":171}," 'https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify'",[155,5851,271],{"class":164},[155,5853,5854,5856,5859,5861,5864,5866,5869,5871,5874,5876,5878,5880],{"class":157,"line":281},[155,5855,258],{"class":160},[155,5857,5858],{"class":261}," auth",[155,5860,265],{"class":160},[155,5862,5863],{"class":164}," { Authorization: ",[155,5865,636],{"class":171},[155,5867,5868],{"class":164},"process",[155,5870,341],{"class":171},[155,5872,5873],{"class":164},"env",[155,5875,341],{"class":171},[155,5877,527],{"class":261},[155,5879,641],{"class":171},[155,5881,5882],{"class":164}," };\n",[155,5884,5885,5887,5890,5892,5894,5896,5898,5900],{"class":157,"line":302},[155,5886,258],{"class":160},[155,5888,5889],{"class":261}," bytes",[155,5891,265],{"class":160},[155,5893,599],{"class":160},[155,5895,2326],{"class":289},[155,5897,308],{"class":164},[155,5899,2331],{"class":171},[155,5901,374],{"class":164},[155,5903,5904],{"class":157,"line":323},[155,5905,278],{"emptyLinePlaceholder":277},[155,5907,5908],{"class":157,"line":377},[155,5909,5910],{"class":251},"\u002F\u002F multipart\u002Fform-data — file field named file\n",[155,5912,5913,5915,5918,5920,5922,5925],{"class":157,"line":394},[155,5914,258],{"class":160},[155,5916,5917],{"class":261}," form",[155,5919,265],{"class":160},[155,5921,464],{"class":160},[155,5923,5924],{"class":289}," FormData",[155,5926,2874],{"class":164},[155,5928,5929,5932,5935,5937,5940,5942,5945,5948,5951,5953],{"class":157,"line":410},[155,5930,5931],{"class":164},"form.",[155,5933,5934],{"class":289},"append",[155,5936,308],{"class":164},[155,5938,5939],{"class":171},"'file'",[155,5941,314],{"class":164},[155,5943,5944],{"class":160},"new",[155,5946,5947],{"class":289}," Blob",[155,5949,5950],{"class":164},"([bytes]), ",[155,5952,2331],{"class":171},[155,5954,374],{"class":164},[155,5956,5957,5959,5962,5964,5966,5968,5970,5972,5975,5977],{"class":157,"line":13},[155,5958,258],{"class":160},[155,5960,5961],{"class":261}," viaForm",[155,5963,265],{"class":160},[155,5965,599],{"class":160},[155,5967,602],{"class":289},[155,5969,308],{"class":164},[155,5971,5537],{"class":261},[155,5973,5974],{"class":164},", { method: ",[155,5976,624],{"class":171},[155,5978,5979],{"class":164},", headers: auth, body: form });\n",[155,5981,5982],{"class":157,"line":431},[155,5983,278],{"emptyLinePlaceholder":277},[155,5985,5986],{"class":157,"line":437},[155,5987,5988],{"class":251},"\u002F\u002F JSON base64 — plain base64 or data:image\u002F...;base64,... both work\n",[155,5990,5991,5993,5996,5998,6000,6002,6004,6006],{"class":157,"line":442},[155,5992,258],{"class":160},[155,5994,5995],{"class":261}," viaJson",[155,5997,265],{"class":160},[155,5999,599],{"class":160},[155,6001,602],{"class":289},[155,6003,308],{"class":164},[155,6005,5537],{"class":261},[155,6007,615],{"class":164},[155,6009,6010,6013,6015],{"class":157,"line":486},[155,6011,6012],{"class":164},"  method: ",[155,6014,624],{"class":171},[155,6016,627],{"class":164},[155,6018,6019,6022,6025,6028,6030,6032,6035],{"class":157,"line":491},[155,6020,6021],{"class":164},"  headers: { ",[155,6023,6024],{"class":160},"...",[155,6026,6027],{"class":164},"auth, ",[155,6029,646],{"class":171},[155,6031,649],{"class":164},[155,6033,6034],{"class":171},"'application\u002Fjson'",[155,6036,655],{"class":164},[155,6038,6039,6042,6045,6047,6050,6053,6056,6058,6061],{"class":157,"line":497},[155,6040,6041],{"class":164},"  body: ",[155,6043,6044],{"class":261},"JSON",[155,6046,341],{"class":164},[155,6048,6049],{"class":289},"stringify",[155,6051,6052],{"class":164},"({ image: bytes.",[155,6054,6055],{"class":289},"toString",[155,6057,308],{"class":164},[155,6059,6060],{"class":171},"'base64'",[155,6062,6063],{"class":164},") }),\n",[155,6065,6066],{"class":157,"line":548},[155,6067,3680],{"class":164},[155,6069,6070],{"class":157,"line":575},[155,6071,278],{"emptyLinePlaceholder":277},[155,6073,6074,6077,6079,6081,6083,6086],{"class":157,"line":584},[155,6075,6076],{"class":160},"for",[155,6078,452],{"class":164},[155,6080,258],{"class":160},[155,6082,2814],{"class":261},[155,6084,6085],{"class":160}," of",[155,6087,6088],{"class":164}," [viaForm, viaJson]) {\n",[155,6090,6091,6093,6095,6097,6099,6101,6103],{"class":157,"line":18},[155,6092,3172],{"class":160},[155,6094,349],{"class":261},[155,6096,265],{"class":160},[155,6098,599],{"class":160},[155,6100,876],{"class":164},[155,6102,879],{"class":289},[155,6104,2874],{"class":164},[155,6106,6107,6110,6112,6115,6117],{"class":157,"line":618},[155,6108,6109],{"class":164},"  console.",[155,6111,2341],{"class":289},[155,6113,6114],{"class":164},"(res.status, body.data?.status ",[155,6116,1684],{"class":160},[155,6118,6119],{"class":164}," body.message);\n",[155,6121,6122],{"class":157,"line":630},[155,6123,434],{"class":164},[146,6125,6127],{"className":938,"code":6126,"filename":940,"language":941,"meta":151,"style":151},"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 field named file\nvia_form = requests.post(API, headers=auth, files={\"file\": (\"slip.jpg\", data)}, timeout=30)\n\n# JSON base64 — plain base64 or data:image\u002F...;base64,... both work\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",[141,6128,6129,6136,6142,6146,6152,6156,6165,6197,6201,6221,6231,6235,6240,6286,6290,6295,6334,6338,6350,6359],{"__ignoreMap":151},[155,6130,6131,6133],{"class":157,"line":9},[155,6132,953],{"class":160},[155,6134,6135],{"class":164}," base64\n",[155,6137,6138,6140],{"class":157,"line":255},[155,6139,953],{"class":160},[155,6141,956],{"class":164},[155,6143,6144],{"class":157,"line":274},[155,6145,278],{"emptyLinePlaceholder":277},[155,6147,6148,6150],{"class":157,"line":281},[155,6149,953],{"class":160},[155,6151,974],{"class":164},[155,6153,6154],{"class":157,"line":302},[155,6155,278],{"emptyLinePlaceholder":277},[155,6157,6158,6160,6162],{"class":157,"line":323},[155,6159,5537],{"class":261},[155,6161,265],{"class":160},[155,6163,6164],{"class":171}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[155,6166,6167,6170,6172,6174,6176,6178,6180,6182,6184,6187,6189,6191,6193,6195],{"class":157,"line":377},[155,6168,6169],{"class":164},"auth ",[155,6171,168],{"class":160},[155,6173,1064],{"class":164},[155,6175,1328],{"class":171},[155,6177,649],{"class":164},[155,6179,1333],{"class":160},[155,6181,1336],{"class":171},[155,6183,1056],{"class":261},[155,6185,6186],{"class":164},"os.environ[",[155,6188,1870],{"class":171},[155,6190,4307],{"class":164},[155,6192,1061],{"class":261},[155,6194,1053],{"class":171},[155,6196,434],{"class":164},[155,6198,6199],{"class":157,"line":394},[155,6200,278],{"emptyLinePlaceholder":277},[155,6202,6203,6205,6207,6209,6211,6213,6215,6217,6219],{"class":157,"line":410},[155,6204,2370],{"class":160},[155,6206,2373],{"class":261},[155,6208,308],{"class":164},[155,6210,2378],{"class":171},[155,6212,314],{"class":164},[155,6214,2383],{"class":171},[155,6216,458],{"class":164},[155,6218,2388],{"class":160},[155,6220,2391],{"class":164},[155,6222,6223,6226,6228],{"class":157,"line":13},[155,6224,6225],{"class":164},"    data ",[155,6227,168],{"class":160},[155,6229,6230],{"class":164}," f.read()\n",[155,6232,6233],{"class":157,"line":431},[155,6234,278],{"emptyLinePlaceholder":277},[155,6236,6237],{"class":157,"line":437},[155,6238,6239],{"class":251},"# multipart\u002Fform-data — file field named file\n",[155,6241,6242,6245,6247,6250,6252,6254,6257,6259,6261,6264,6266,6268,6270,6273,6275,6278,6280,6282,6284],{"class":157,"line":442},[155,6243,6244],{"class":164},"via_form ",[155,6246,168],{"class":160},[155,6248,6249],{"class":164}," requests.post(",[155,6251,5537],{"class":261},[155,6253,314],{"class":164},[155,6255,6256],{"class":311},"headers",[155,6258,168],{"class":160},[155,6260,6027],{"class":164},[155,6262,6263],{"class":311},"files",[155,6265,168],{"class":160},[155,6267,1056],{"class":164},[155,6269,2672],{"class":171},[155,6271,6272],{"class":164},": (",[155,6274,2378],{"class":171},[155,6276,6277],{"class":164},", data)}, ",[155,6279,670],{"class":311},[155,6281,168],{"class":160},[155,6283,1378],{"class":261},[155,6285,1717],{"class":164},[155,6287,6288],{"class":157,"line":486},[155,6289,278],{"emptyLinePlaceholder":277},[155,6291,6292],{"class":157,"line":491},[155,6293,6294],{"class":251},"# JSON base64 — plain base64 or data:image\u002F...;base64,... both work\n",[155,6296,6297,6300,6302,6304,6306,6308,6310,6312,6314,6316,6318,6320,6323,6326,6328,6330,6332],{"class":157,"line":497},[155,6298,6299],{"class":164},"via_json ",[155,6301,168],{"class":160},[155,6303,6249],{"class":164},[155,6305,5537],{"class":261},[155,6307,314],{"class":164},[155,6309,6256],{"class":311},[155,6311,168],{"class":160},[155,6313,6027],{"class":164},[155,6315,879],{"class":311},[155,6317,168],{"class":160},[155,6319,1056],{"class":164},[155,6321,6322],{"class":171},"\"image\"",[155,6324,6325],{"class":164},": base64.b64encode(data).decode()}, ",[155,6327,670],{"class":311},[155,6329,168],{"class":160},[155,6331,1378],{"class":261},[155,6333,1717],{"class":164},[155,6335,6336],{"class":157,"line":548},[155,6337,278],{"emptyLinePlaceholder":277},[155,6339,6340,6342,6345,6347],{"class":157,"line":575},[155,6341,6076],{"class":160},[155,6343,6344],{"class":164}," res ",[155,6346,1255],{"class":160},[155,6348,6349],{"class":164}," (via_form, via_json):\n",[155,6351,6352,6355,6357],{"class":157,"line":584},[155,6353,6354],{"class":164},"    body ",[155,6356,168],{"class":160},[155,6358,1518],{"class":164},[155,6360,6361,6364,6367,6369,6372,6374,6376,6378,6381,6384,6386,6389],{"class":157,"line":18},[155,6362,6363],{"class":261},"    print",[155,6365,6366],{"class":164},"(res.status_code, body[",[155,6368,1568],{"class":171},[155,6370,6371],{"class":164},"][",[155,6373,2412],{"class":171},[155,6375,1681],{"class":164},[155,6377,4447],{"class":160},[155,6379,6380],{"class":164}," res.ok ",[155,6382,6383],{"class":160},"else",[155,6385,1565],{"class":164},[155,6387,6388],{"class":171},"\"message\"",[155,6390,2426],{"class":164},[146,6392,6394],{"className":1577,"code":6393,"filename":1579,"language":1580,"meta":151,"style":151},"\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 field named file\n$viaForm = slipbolt_post([], ['file' => new CURLFile('slip.jpg')]);\n\n\u002F\u002F JSON base64 — plain base64 or data:image\u002F...;base64,... both work\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",[141,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":151},[155,6397,6398,6400],{"class":157,"line":9},[155,6399,1587],{"class":160},[155,6401,1590],{"class":261},[155,6403,6404,6406,6409,6411,6414,6417,6419],{"class":157,"line":255},[155,6405,1744],{"class":160},[155,6407,6408],{"class":289}," slipbolt_post",[155,6410,308],{"class":164},[155,6412,6413],{"class":160},"array",[155,6415,6416],{"class":164}," $headers, $payload)",[155,6418,1770],{"class":160},[155,6420,1773],{"class":160},[155,6422,6423],{"class":157,"line":274},[155,6424,1615],{"class":164},[155,6426,6427,6430,6432,6434,6436,6438],{"class":157,"line":281},[155,6428,6429],{"class":164},"    $ch ",[155,6431,168],{"class":160},[155,6433,1816],{"class":261},[155,6435,308],{"class":164},[155,6437,1821],{"class":171},[155,6439,374],{"class":164},[155,6441,6442,6445],{"class":157,"line":302},[155,6443,6444],{"class":261},"    curl_setopt_array",[155,6446,1831],{"class":164},[155,6448,6449,6452,6454,6456],{"class":157,"line":323},[155,6450,6451],{"class":261},"        CURLOPT_POST",[155,6453,1839],{"class":160},[155,6455,1842],{"class":261},[155,6457,627],{"class":164},[155,6459,6460,6463,6465,6468,6471,6473,6475,6477,6479,6481,6483],{"class":157,"line":377},[155,6461,6462],{"class":261},"        CURLOPT_HTTPHEADER",[155,6464,1852],{"class":160},[155,6466,6467],{"class":164}," [",[155,6469,6470],{"class":171},"'Authorization: Bearer '",[155,6472,1673],{"class":160},[155,6474,1865],{"class":261},[155,6476,308],{"class":164},[155,6478,1870],{"class":171},[155,6480,4711],{"class":164},[155,6482,6024],{"class":160},[155,6484,6485],{"class":164},"$headers],\n",[155,6487,6488,6491,6493],{"class":157,"line":394},[155,6489,6490],{"class":261},"        CURLOPT_POSTFIELDS",[155,6492,1852],{"class":160},[155,6494,6495],{"class":164}," $payload,\n",[155,6497,6498,6501,6503,6505],{"class":157,"line":410},[155,6499,6500],{"class":261},"        CURLOPT_RETURNTRANSFER",[155,6502,1902],{"class":160},[155,6504,1842],{"class":261},[155,6506,627],{"class":164},[155,6508,6509,6512,6514,6516],{"class":157,"line":13},[155,6510,6511],{"class":261},"        CURLOPT_TIMEOUT",[155,6513,1914],{"class":160},[155,6515,1917],{"class":261},[155,6517,627],{"class":164},[155,6519,6520],{"class":157,"line":431},[155,6521,6522],{"class":164},"    ]);\n",[155,6524,6525,6528,6530,6532,6534,6537,6540,6542,6544,6546],{"class":157,"line":437},[155,6526,6527],{"class":164},"    $body ",[155,6529,168],{"class":160},[155,6531,2191],{"class":261},[155,6533,308],{"class":164},[155,6535,6536],{"class":261},"curl_exec",[155,6538,6539],{"class":164},"($ch), ",[155,6541,2197],{"class":261},[155,6543,458],{"class":164},[155,6545,1684],{"class":160},[155,6547,2204],{"class":164},[155,6549,6550,6552,6554,6557,6559,6561],{"class":157,"line":442},[155,6551,920],{"class":160},[155,6553,6467],{"class":164},[155,6555,6556],{"class":261},"curl_getinfo",[155,6558,2052],{"class":164},[155,6560,2055],{"class":261},[155,6562,6563],{"class":164},"), $body];\n",[155,6565,6566],{"class":157,"line":486},[155,6567,434],{"class":164},[155,6569,6570],{"class":157,"line":491},[155,6571,278],{"emptyLinePlaceholder":277},[155,6573,6574],{"class":157,"line":497},[155,6575,5910],{"class":251},[155,6577,6578,6581,6583,6585,6588,6590,6592,6594,6597,6599,6601],{"class":157,"line":548},[155,6579,6580],{"class":164},"$viaForm ",[155,6582,168],{"class":160},[155,6584,6408],{"class":289},[155,6586,6587],{"class":164},"([], [",[155,6589,5939],{"class":171},[155,6591,1902],{"class":160},[155,6593,464],{"class":160},[155,6595,6596],{"class":261}," CURLFile",[155,6598,308],{"class":164},[155,6600,2331],{"class":171},[155,6602,6603],{"class":164},")]);\n",[155,6605,6606],{"class":157,"line":575},[155,6607,278],{"emptyLinePlaceholder":277},[155,6609,6610],{"class":157,"line":584},[155,6611,5988],{"class":251},[155,6613,6614,6617,6619,6621],{"class":157,"line":18},[155,6615,6616],{"class":164},"$viaJson ",[155,6618,168],{"class":160},[155,6620,6408],{"class":289},[155,6622,1045],{"class":164},[155,6624,6625,6628,6631],{"class":157,"line":618},[155,6626,6627],{"class":164},"    [",[155,6629,6630],{"class":171},"'Content-Type: application\u002Fjson'",[155,6632,6633],{"class":164},"],\n",[155,6635,6636,6639,6641,6644,6646,6649,6651,6653,6655,6657],{"class":157,"line":630},[155,6637,6638],{"class":261},"    json_encode",[155,6640,4567],{"class":164},[155,6642,6643],{"class":171},"'image'",[155,6645,1902],{"class":160},[155,6647,6648],{"class":261}," base64_encode",[155,6650,308],{"class":164},[155,6652,2470],{"class":261},[155,6654,308],{"class":164},[155,6656,2331],{"class":171},[155,6658,6659],{"class":164},"))])\n",[155,6661,6662],{"class":157,"line":658},[155,6663,374],{"class":164},[155,6665,6666],{"class":157,"line":664},[155,6667,278],{"emptyLinePlaceholder":277},[155,6669,6670,6673,6676,6678],{"class":157,"line":22},[155,6671,6672],{"class":160},"foreach",[155,6674,6675],{"class":164}," ([$viaForm, $viaJson] ",[155,6677,2388],{"class":160},[155,6679,6680],{"class":164}," [$status, $body]) {\n",[155,6682,6683,6685,6687,6689,6692,6694,6696,6698,6700,6702,6704,6706,6708,6710,6712,6714],{"class":157,"line":686},[155,6684,4561],{"class":261},[155,6686,1636],{"class":164},[155,6688,2493],{"class":171},[155,6690,6691],{"class":164},", $body[",[155,6693,2247],{"class":171},[155,6695,6371],{"class":164},[155,6697,2487],{"class":171},[155,6699,1681],{"class":164},[155,6701,1684],{"class":160},[155,6703,1687],{"class":164},[155,6705,1099],{"class":171},[155,6707,2490],{"class":164},[155,6709,1053],{"class":171},[155,6711,2515],{"class":261},[155,6713,1053],{"class":171},[155,6715,271],{"class":164},[155,6717,6718],{"class":157,"line":698},[155,6719,434],{"class":164},[146,6721,6726],{"className":6722,"code":6723,"filename":6724,"language":6725,"meta":151,"style":151},"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 field named 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 — plain base64 or data:image\u002F...;base64,... both work\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",[141,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":151},[155,6729,6730],{"class":157,"line":9},[155,6731,6732],{},"package main\n",[155,6734,6735],{"class":157,"line":255},[155,6736,278],{"emptyLinePlaceholder":277},[155,6738,6739],{"class":157,"line":274},[155,6740,6741],{},"import (\n",[155,6743,6744],{"class":157,"line":281},[155,6745,6746],{},"    \"bytes\"\n",[155,6748,6749],{"class":157,"line":302},[155,6750,6751],{},"    \"encoding\u002Fbase64\"\n",[155,6753,6754],{"class":157,"line":323},[155,6755,6756],{},"    \"encoding\u002Fjson\"\n",[155,6758,6759],{"class":157,"line":377},[155,6760,6761],{},"    \"fmt\"\n",[155,6763,6764],{"class":157,"line":394},[155,6765,6766],{},"    \"io\"\n",[155,6768,6769],{"class":157,"line":410},[155,6770,6771],{},"    \"mime\u002Fmultipart\"\n",[155,6773,6774],{"class":157,"line":13},[155,6775,6776],{},"    \"net\u002Fhttp\"\n",[155,6778,6779],{"class":157,"line":431},[155,6780,6781],{},"    \"os\"\n",[155,6783,6784],{"class":157,"line":437},[155,6785,6786],{},"    \"time\"\n",[155,6788,6789],{"class":157,"line":442},[155,6790,1717],{},[155,6792,6793],{"class":157,"line":486},[155,6794,278],{"emptyLinePlaceholder":277},[155,6796,6797],{"class":157,"line":491},[155,6798,6799],{},"func main() {\n",[155,6801,6802],{"class":157,"line":497},[155,6803,6804],{},"    api := \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"\n",[155,6806,6807],{"class":157,"line":548},[155,6808,6809],{},"    key := os.Getenv(\"SLIPBOLT_API_KEY\")\n",[155,6811,6812],{"class":157,"line":575},[155,6813,6814],{},"    data, err := os.ReadFile(\"slip.jpg\")\n",[155,6816,6817],{"class":157,"line":584},[155,6818,6819],{},"    if err != nil {\n",[155,6821,6822],{"class":157,"line":18},[155,6823,6824],{},"        panic(err)\n",[155,6826,6827],{"class":157,"line":618},[155,6828,757],{},[155,6830,6831],{"class":157,"line":630},[155,6832,6833],{},"    client := &http.Client{Timeout: 30 * time.Second}\n",[155,6835,6836],{"class":157,"line":658},[155,6837,278],{"emptyLinePlaceholder":277},[155,6839,6840],{"class":157,"line":664},[155,6841,6842],{},"    \u002F\u002F multipart\u002Fform-data — file field named file\n",[155,6844,6845],{"class":157,"line":22},[155,6846,6847],{},"    var form bytes.Buffer\n",[155,6849,6850],{"class":157,"line":686},[155,6851,6852],{},"    w := multipart.NewWriter(&form)\n",[155,6854,6855],{"class":157,"line":698},[155,6856,6857],{},"    part, err := w.CreateFormFile(\"file\", \"slip.jpg\")\n",[155,6859,6860],{"class":157,"line":722},[155,6861,6819],{},[155,6863,6864],{"class":157,"line":747},[155,6865,6824],{},[155,6867,6868],{"class":157,"line":26},[155,6869,757],{},[155,6871,6872],{"class":157,"line":760},[155,6873,6874],{},"    if _, err = part.Write(data); err != nil {\n",[155,6876,6877],{"class":157,"line":765},[155,6878,6824],{},[155,6880,6881],{"class":157,"line":804},[155,6882,757],{},[155,6884,6885],{"class":157,"line":848},[155,6886,6887],{},"    if err = w.Close(); err != nil {\n",[155,6889,6890],{"class":157,"line":30},[155,6891,6824],{},[155,6893,6894],{"class":157,"line":859},[155,6895,757],{},[155,6897,6898],{"class":157,"line":864},[155,6899,6900],{},"    viaForm := post(client, api, key, w.FormDataContentType(), form.Bytes())\n",[155,6902,6903],{"class":157,"line":895},[155,6904,278],{"emptyLinePlaceholder":277},[155,6906,6907],{"class":157,"line":917},[155,6908,6909],{},"    \u002F\u002F JSON base64 — plain base64 or data:image\u002F...;base64,... both work\n",[155,6911,6912],{"class":157,"line":35},[155,6913,6914],{},"    payload, _ := json.Marshal(map[string]string{\"image\": base64.StdEncoding.EncodeToString(data)})\n",[155,6916,6917],{"class":157,"line":933},[155,6918,6919],{},"    viaJSON := post(client, api, key, \"application\u002Fjson\", payload)\n",[155,6921,6922],{"class":157,"line":1503},[155,6923,278],{"emptyLinePlaceholder":277},[155,6925,6926],{"class":157,"line":1510},[155,6927,6928],{},"    for _, res := range []*http.Response{viaForm, viaJSON} {\n",[155,6930,6931],{"class":157,"line":1521},[155,6932,6933],{},"        show(res)\n",[155,6935,6936],{"class":157,"line":39},[155,6937,757],{},[155,6939,6940],{"class":157,"line":1540},[155,6941,434],{},[155,6943,6944],{"class":157,"line":1550},[155,6945,278],{"emptyLinePlaceholder":277},[155,6947,6948],{"class":157,"line":1559},[155,6949,6950],{},"func post(client *http.Client, api, key, contentType string, body []byte) *http.Response {\n",[155,6952,6953],{"class":157,"line":2207},[155,6954,6955],{},"    req, err := http.NewRequest(http.MethodPost, api, bytes.NewReader(body))\n",[155,6957,6958],{"class":157,"line":2223},[155,6959,6819],{},[155,6961,6962],{"class":157,"line":2235},[155,6963,6824],{},[155,6965,6966],{"class":157,"line":2240},[155,6967,757],{},[155,6969,6970],{"class":157,"line":2255},[155,6971,6972],{},"    req.Header.Set(\"Authorization\", \"Bearer \"+key)\n",[155,6974,6975],{"class":157,"line":2260},[155,6976,6977],{},"    req.Header.Set(\"Content-Type\", contentType)\n",[155,6979,6980],{"class":157,"line":3657},[155,6981,6982],{},"    res, err := client.Do(req)\n",[155,6984,6985],{"class":157,"line":3677},[155,6986,6819],{},[155,6988,6989],{"class":157,"line":3683},[155,6990,6824],{},[155,6992,6993],{"class":157,"line":3688},[155,6994,757],{},[155,6996,6997],{"class":157,"line":4461},[155,6998,6999],{},"    return res\n",[155,7001,7003],{"class":157,"line":7002},60,[155,7004,434],{},[155,7006,7008],{"class":157,"line":7007},61,[155,7009,278],{"emptyLinePlaceholder":277},[155,7011,7013],{"class":157,"line":7012},62,[155,7014,7015],{},"func show(res *http.Response) {\n",[155,7017,7019],{"class":157,"line":7018},63,[155,7020,7021],{},"    defer res.Body.Close()\n",[155,7023,7025],{"class":157,"line":7024},64,[155,7026,7027],{},"    raw, _ := io.ReadAll(res.Body)\n",[155,7029,7031],{"class":157,"line":7030},65,[155,7032,7033],{},"    var body struct {\n",[155,7035,7037],{"class":157,"line":7036},66,[155,7038,7039],{},"        Data    struct{ Status string } `json:\"data\"`\n",[155,7041,7043],{"class":157,"line":7042},67,[155,7044,7045],{},"        Message string                   `json:\"message\"`\n",[155,7047,7049],{"class":157,"line":7048},68,[155,7050,757],{},[155,7052,7054],{"class":157,"line":7053},69,[155,7055,7056],{},"    _ = json.Unmarshal(raw, &body)\n",[155,7058,7060],{"class":157,"line":7059},70,[155,7061,7062],{},"    status := body.Data.Status\n",[155,7064,7066],{"class":157,"line":7065},71,[155,7067,7068],{},"    if status == \"\" {\n",[155,7070,7072],{"class":157,"line":7071},72,[155,7073,7074],{},"        status = body.Message\n",[155,7076,7078],{"class":157,"line":7077},73,[155,7079,757],{},[155,7081,7083],{"class":157,"line":7082},74,[155,7084,7085],{},"    fmt.Println(res.StatusCode, status)\n",[155,7087,7089],{"class":157,"line":7088},75,[155,7090,434],{},[146,7092,7097],{"className":7093,"code":7094,"filename":7095,"language":7096,"meta":151,"style":151},"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 field named file\n        show(send(client, api, key, \"multipart\u002Fform-data; boundary=slipbolt\", multipart(data)));\n\n        \u002F\u002F JSON base64 — plain base64 or data:image\u002F...;base64,... both work\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",[141,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":151},[155,7100,7101,7103],{"class":157,"line":9},[155,7102,953],{"class":160},[155,7104,7105],{"class":164}," java.net.URI;\n",[155,7107,7108,7110,7113,7115],{"class":157,"line":255},[155,7109,953],{"class":160},[155,7111,7112],{"class":164}," java.net.http.",[155,7114,840],{"class":261},[155,7116,271],{"class":164},[155,7118,7119,7121],{"class":157,"line":274},[155,7120,953],{"class":160},[155,7122,7123],{"class":164}," java.nio.charset.StandardCharsets;\n",[155,7125,7126,7128,7131,7133],{"class":157,"line":281},[155,7127,953],{"class":160},[155,7129,7130],{"class":164}," java.nio.file.",[155,7132,840],{"class":261},[155,7134,271],{"class":164},[155,7136,7137,7139],{"class":157,"line":302},[155,7138,953],{"class":160},[155,7140,7141],{"class":164}," java.time.Duration;\n",[155,7143,7144,7146],{"class":157,"line":323},[155,7145,953],{"class":160},[155,7147,7148],{"class":164}," java.util.Base64;\n",[155,7150,7151],{"class":157,"line":377},[155,7152,278],{"emptyLinePlaceholder":277},[155,7154,7155,7157,7160],{"class":157,"line":394},[155,7156,1000],{"class":160},[155,7158,7159],{"class":289}," VerifyFormats",[155,7161,299],{"class":164},[155,7163,7164,7166,7169,7172,7175,7177,7180,7183,7186,7188,7191],{"class":157,"line":410},[155,7165,1620],{"class":160},[155,7167,7168],{"class":160}," static",[155,7170,7171],{"class":160}," void",[155,7173,7174],{"class":289}," main",[155,7176,308],{"class":164},[155,7178,7179],{"class":160},"String",[155,7181,7182],{"class":164},"[] ",[155,7184,7185],{"class":311},"args",[155,7187,458],{"class":164},[155,7189,7190],{"class":160},"throws",[155,7192,7193],{"class":164}," Exception {\n",[155,7195,7196,7199,7201,7204],{"class":157,"line":13},[155,7197,7198],{"class":164},"        String api ",[155,7200,168],{"class":160},[155,7202,7203],{"class":171}," \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"",[155,7205,271],{"class":164},[155,7207,7208,7211,7213,7216,7218,7220,7222],{"class":157,"line":431},[155,7209,7210],{"class":164},"        String key ",[155,7212,168],{"class":160},[155,7214,7215],{"class":164}," System.",[155,7217,4703],{"class":289},[155,7219,308],{"class":164},[155,7221,1242],{"class":171},[155,7223,374],{"class":164},[155,7225,7226,7229,7232,7234,7237,7240,7243,7246,7248,7250],{"class":157,"line":437},[155,7227,7228],{"class":160},"        byte",[155,7230,7231],{"class":164},"[] data ",[155,7233,168],{"class":160},[155,7235,7236],{"class":164}," Files.",[155,7238,7239],{"class":289},"readAllBytes",[155,7241,7242],{"class":164},"(Path.",[155,7244,7245],{"class":289},"of",[155,7247,308],{"class":164},[155,7249,2378],{"class":171},[155,7251,2000],{"class":164},[155,7253,7254,7257,7259,7262,7265,7267,7270,7273,7276,7278,7280,7283,7286],{"class":157,"line":442},[155,7255,7256],{"class":164},"        HttpClient client ",[155,7258,168],{"class":160},[155,7260,7261],{"class":164}," HttpClient.",[155,7263,7264],{"class":289},"newBuilder",[155,7266,882],{"class":164},[155,7268,7269],{"class":289},"connectTimeout",[155,7271,7272],{"class":164},"(Duration.",[155,7274,7275],{"class":289},"ofSeconds",[155,7277,308],{"class":164},[155,7279,1378],{"class":261},[155,7281,7282],{"class":164},")).",[155,7284,7285],{"class":289},"build",[155,7287,2874],{"class":164},[155,7289,7290],{"class":157,"line":486},[155,7291,278],{"emptyLinePlaceholder":277},[155,7293,7294],{"class":157,"line":491},[155,7295,7296],{"class":251},"        \u002F\u002F multipart\u002Fform-data — file field named file\n",[155,7298,7299,7302,7304,7307,7310,7313,7315,7318],{"class":157,"line":497},[155,7300,7301],{"class":289},"        show",[155,7303,308],{"class":164},[155,7305,7306],{"class":289},"send",[155,7308,7309],{"class":164},"(client, api, key, ",[155,7311,7312],{"class":171},"\"multipart\u002Fform-data; boundary=slipbolt\"",[155,7314,314],{"class":164},[155,7316,7317],{"class":289},"multipart",[155,7319,7320],{"class":164},"(data)));\n",[155,7322,7323],{"class":157,"line":548},[155,7324,278],{"emptyLinePlaceholder":277},[155,7326,7327],{"class":157,"line":575},[155,7328,7329],{"class":251},"        \u002F\u002F JSON base64 — plain base64 or data:image\u002F...;base64,... both work\n",[155,7331,7332,7335,7337,7340,7343,7345,7347,7349,7351,7353,7356,7359,7362,7364,7367,7370,7372,7374,7376,7379],{"class":157,"line":584},[155,7333,7334],{"class":164},"        String json ",[155,7336,168],{"class":160},[155,7338,7339],{"class":171}," \"{",[155,7341,7342],{"class":261},"\\\"",[155,7344,513],{"class":171},[155,7346,7342],{"class":261},[155,7348,1770],{"class":171},[155,7350,7342],{"class":261},[155,7352,1053],{"class":171},[155,7354,7355],{"class":160}," +",[155,7357,7358],{"class":164}," Base64.",[155,7360,7361],{"class":289},"getEncoder",[155,7363,882],{"class":164},[155,7365,7366],{"class":289},"encodeToString",[155,7368,7369],{"class":164},"(data) ",[155,7371,1264],{"class":160},[155,7373,1670],{"class":171},[155,7375,7342],{"class":261},[155,7377,7378],{"class":171},"}\"",[155,7380,271],{"class":164},[155,7382,7383,7385,7387,7389,7391,7394,7397,7400],{"class":157,"line":18},[155,7384,7301],{"class":289},[155,7386,308],{"class":164},[155,7388,7306],{"class":289},[155,7390,7309],{"class":164},[155,7392,7393],{"class":171},"\"application\u002Fjson\"",[155,7395,7396],{"class":164},", json.",[155,7398,7399],{"class":289},"getBytes",[155,7401,7402],{"class":164},"(StandardCharsets.UTF_8)));\n",[155,7404,7405],{"class":157,"line":618},[155,7406,757],{"class":164},[155,7408,7409],{"class":157,"line":630},[155,7410,278],{"emptyLinePlaceholder":277},[155,7412,7413,7416,7419,7421,7424,7426,7429,7432,7435,7438,7440,7443,7445,7448,7450,7453,7455,7457,7459,7461],{"class":157,"line":658},[155,7414,7415],{"class":160},"    static",[155,7417,7418],{"class":164}," HttpResponse\u003C",[155,7420,7179],{"class":160},[155,7422,7423],{"class":164},"> ",[155,7425,7306],{"class":289},[155,7427,7428],{"class":164},"(HttpClient ",[155,7430,7431],{"class":311},"client",[155,7433,7434],{"class":164},", String ",[155,7436,7437],{"class":311},"api",[155,7439,7434],{"class":164},[155,7441,7442],{"class":311},"key",[155,7444,7434],{"class":164},[155,7446,7447],{"class":311},"type",[155,7449,314],{"class":164},[155,7451,7452],{"class":160},"byte",[155,7454,7182],{"class":164},[155,7456,317],{"class":311},[155,7458,458],{"class":164},[155,7460,7190],{"class":160},[155,7462,7193],{"class":164},[155,7464,7465,7468,7470,7473,7475,7478,7481],{"class":157,"line":664},[155,7466,7467],{"class":164},"        HttpRequest req ",[155,7469,168],{"class":160},[155,7471,7472],{"class":164}," HttpRequest.",[155,7474,7264],{"class":289},[155,7476,7477],{"class":164},"(URI.",[155,7479,7480],{"class":289},"create",[155,7482,7483],{"class":164},"(api))\n",[155,7485,7486,7489,7491,7493,7495,7497,7499],{"class":157,"line":22},[155,7487,7488],{"class":164},"                .",[155,7490,670],{"class":289},[155,7492,7272],{"class":164},[155,7494,7275],{"class":289},[155,7496,308],{"class":164},[155,7498,1378],{"class":261},[155,7500,4245],{"class":164},[155,7502,7503,7505,7508,7510,7512,7514,7517,7519],{"class":157,"line":686},[155,7504,7488],{"class":164},[155,7506,7507],{"class":289},"header",[155,7509,308],{"class":164},[155,7511,1328],{"class":171},[155,7513,314],{"class":164},[155,7515,7516],{"class":171},"\"Bearer \"",[155,7518,7355],{"class":160},[155,7520,7521],{"class":164}," key)\n",[155,7523,7524,7526,7528,7530,7532],{"class":157,"line":698},[155,7525,7488],{"class":164},[155,7527,7507],{"class":289},[155,7529,308],{"class":164},[155,7531,1350],{"class":171},[155,7533,7534],{"class":164},", type)\n",[155,7536,7537,7539,7542,7545,7548],{"class":157,"line":722},[155,7538,7488],{"class":164},[155,7540,7541],{"class":289},"POST",[155,7543,7544],{"class":164},"(HttpRequest.BodyPublishers.",[155,7546,7547],{"class":289},"ofByteArray",[155,7549,7550],{"class":164},"(body))\n",[155,7552,7553,7555,7557],{"class":157,"line":747},[155,7554,7488],{"class":164},[155,7556,7285],{"class":289},[155,7558,2874],{"class":164},[155,7560,7561,7563,7566,7568,7571,7574],{"class":157,"line":26},[155,7562,1562],{"class":160},[155,7564,7565],{"class":164}," client.",[155,7567,7306],{"class":289},[155,7569,7570],{"class":164},"(req, HttpResponse.BodyHandlers.",[155,7572,7573],{"class":289},"ofString",[155,7575,5059],{"class":164},[155,7577,7578],{"class":157,"line":760},[155,7579,757],{"class":164},[155,7581,7582],{"class":157,"line":765},[155,7583,278],{"emptyLinePlaceholder":277},[155,7585,7586,7588,7591,7593,7595,7597,7599,7601,7604,7606,7608],{"class":157,"line":804},[155,7587,7415],{"class":160},[155,7589,7590],{"class":160}," byte",[155,7592,7182],{"class":164},[155,7594,7317],{"class":289},[155,7596,308],{"class":164},[155,7598,7452],{"class":160},[155,7600,7182],{"class":164},[155,7602,7603],{"class":311},"data",[155,7605,458],{"class":164},[155,7607,7190],{"class":160},[155,7609,7193],{"class":164},[155,7611,7612,7615,7617,7620,7623,7626,7628,7630,7632,7635,7637,7640,7643,7646,7649,7651],{"class":157,"line":848},[155,7613,7614],{"class":164},"        String head ",[155,7616,168],{"class":160},[155,7618,7619],{"class":171}," \"--slipbolt",[155,7621,7622],{"class":261},"\\r\\n",[155,7624,7625],{"class":171},"Content-Disposition: form-data; name=",[155,7627,7342],{"class":261},[155,7629,5468],{"class":171},[155,7631,7342],{"class":261},[155,7633,7634],{"class":171},"; filename=",[155,7636,7342],{"class":261},[155,7638,7639],{"class":171},"slip.jpg",[155,7641,7642],{"class":261},"\\\"\\r\\n",[155,7644,7645],{"class":171},"Content-Type: image\u002Fjpeg",[155,7647,7648],{"class":261},"\\r\\n\\r\\n",[155,7650,1053],{"class":171},[155,7652,271],{"class":164},[155,7654,7655,7658,7660,7662,7664,7667,7669,7671],{"class":157,"line":30},[155,7656,7657],{"class":164},"        String tail ",[155,7659,168],{"class":160},[155,7661,1670],{"class":171},[155,7663,7622],{"class":261},[155,7665,7666],{"class":171},"--slipbolt--",[155,7668,7622],{"class":261},[155,7670,1053],{"class":171},[155,7672,271],{"class":164},[155,7674,7675,7677,7680,7682,7685,7687],{"class":157,"line":859},[155,7676,7228],{"class":160},[155,7678,7679],{"class":164},"[] h ",[155,7681,168],{"class":160},[155,7683,7684],{"class":164}," head.",[155,7686,7399],{"class":289},[155,7688,7689],{"class":164},"(StandardCharsets.UTF_8);\n",[155,7691,7692,7694,7697,7699,7702,7704],{"class":157,"line":864},[155,7693,7228],{"class":160},[155,7695,7696],{"class":164},"[] t ",[155,7698,168],{"class":160},[155,7700,7701],{"class":164}," tail.",[155,7703,7399],{"class":289},[155,7705,7689],{"class":164},[155,7707,7708,7710,7713,7715,7717,7719,7722,7724,7727,7729],{"class":157,"line":895},[155,7709,7228],{"class":160},[155,7711,7712],{"class":164},"[] out ",[155,7714,168],{"class":160},[155,7716,464],{"class":160},[155,7718,7590],{"class":160},[155,7720,7721],{"class":164},"[h.length ",[155,7723,1264],{"class":160},[155,7725,7726],{"class":164}," data.length ",[155,7728,1264],{"class":160},[155,7730,7731],{"class":164}," t.length];\n",[155,7733,7734,7737,7740,7743,7745,7748,7750],{"class":157,"line":917},[155,7735,7736],{"class":164},"        System.",[155,7738,7739],{"class":289},"arraycopy",[155,7741,7742],{"class":164},"(h, ",[155,7744,2779],{"class":261},[155,7746,7747],{"class":164},", out, ",[155,7749,2779],{"class":261},[155,7751,7752],{"class":164},", h.length);\n",[155,7754,7755,7757,7759,7762,7764],{"class":157,"line":35},[155,7756,7736],{"class":164},[155,7758,7739],{"class":289},[155,7760,7761],{"class":164},"(data, ",[155,7763,2779],{"class":261},[155,7765,7766],{"class":164},", out, h.length, data.length);\n",[155,7768,7769,7771,7773,7776,7778,7781,7783],{"class":157,"line":933},[155,7770,7736],{"class":164},[155,7772,7739],{"class":289},[155,7774,7775],{"class":164},"(t, ",[155,7777,2779],{"class":261},[155,7779,7780],{"class":164},", out, h.length ",[155,7782,1264],{"class":160},[155,7784,7785],{"class":164}," data.length, t.length);\n",[155,7787,7788,7790],{"class":157,"line":1503},[155,7789,1562],{"class":160},[155,7791,7792],{"class":164}," out;\n",[155,7794,7795],{"class":157,"line":1510},[155,7796,757],{"class":164},[155,7798,7799],{"class":157,"line":1521},[155,7800,278],{"emptyLinePlaceholder":277},[155,7802,7803,7805,7807,7810,7813,7815,7817,7819],{"class":157,"line":39},[155,7804,7415],{"class":160},[155,7806,7171],{"class":160},[155,7808,7809],{"class":289}," show",[155,7811,7812],{"class":164},"(HttpResponse\u003C",[155,7814,7179],{"class":160},[155,7816,7423],{"class":164},[155,7818,3161],{"class":311},[155,7820,320],{"class":164},[155,7822,7823,7826,7828,7830,7832],{"class":157,"line":1540},[155,7824,7825],{"class":164},"        String body ",[155,7827,168],{"class":160},[155,7829,876],{"class":164},[155,7831,317],{"class":289},[155,7833,2874],{"class":164},[155,7835,7836,7839,7841,7844,7847,7849],{"class":157,"line":1550},[155,7837,7838],{"class":164},"        String status ",[155,7840,168],{"class":160},[155,7842,7843],{"class":289}," jsonString",[155,7845,7846],{"class":164},"(body, ",[155,7848,2412],{"class":171},[155,7850,374],{"class":164},[155,7852,7853,7855,7858,7861,7864,7866,7868,7870,7872],{"class":157,"line":1559},[155,7854,1441],{"class":160},[155,7856,7857],{"class":164}," (status.",[155,7859,7860],{"class":289},"isEmpty",[155,7862,7863],{"class":164},"()) status ",[155,7865,168],{"class":160},[155,7867,7843],{"class":289},[155,7869,7846],{"class":164},[155,7871,6388],{"class":171},[155,7873,374],{"class":164},[155,7875,7876,7879,7882,7885,7888,7891,7893,7896,7898],{"class":157,"line":2207},[155,7877,7878],{"class":164},"        System.out.",[155,7880,7881],{"class":289},"println",[155,7883,7884],{"class":164},"(res.",[155,7886,7887],{"class":289},"statusCode",[155,7889,7890],{"class":164},"() ",[155,7892,1264],{"class":160},[155,7894,7895],{"class":171}," \" \"",[155,7897,7355],{"class":160},[155,7899,7900],{"class":164}," status);\n",[155,7902,7903],{"class":157,"line":2223},[155,7904,757],{"class":164},[155,7906,7907],{"class":157,"line":2235},[155,7908,278],{"emptyLinePlaceholder":277},[155,7910,7911,7913,7916,7919,7922,7924,7926,7928],{"class":157,"line":2240},[155,7912,7415],{"class":160},[155,7914,7915],{"class":164}," String ",[155,7917,7918],{"class":289},"jsonString",[155,7920,7921],{"class":164},"(String ",[155,7923,879],{"class":311},[155,7925,7434],{"class":164},[155,7927,7442],{"class":311},[155,7929,320],{"class":164},[155,7931,7932,7935,7938,7940,7943,7946,7948,7950,7952,7954,7956,7959,7961,7963,7965,7967],{"class":157,"line":2255},[155,7933,7934],{"class":160},"        int",[155,7936,7937],{"class":164}," i ",[155,7939,168],{"class":160},[155,7941,7942],{"class":164}," json.",[155,7944,7945],{"class":289},"indexOf",[155,7947,308],{"class":164},[155,7949,1053],{"class":171},[155,7951,7342],{"class":261},[155,7953,1053],{"class":171},[155,7955,7355],{"class":160},[155,7957,7958],{"class":164}," key ",[155,7960,1264],{"class":160},[155,7962,1670],{"class":171},[155,7964,7342],{"class":261},[155,7966,1053],{"class":171},[155,7968,374],{"class":164},[155,7970,7971,7973,7976,7978,7980,7982,7984,7986],{"class":157,"line":2260},[155,7972,1441],{"class":160},[155,7974,7975],{"class":164}," (i ",[155,7977,798],{"class":160},[155,7979,564],{"class":261},[155,7981,458],{"class":164},[155,7983,2796],{"class":160},[155,7985,1202],{"class":171},[155,7987,271],{"class":164},[155,7989,7990,7992,7995,7997,7999,8001,8003,8006,8008,8010,8012,8015,8018,8020,8022],{"class":157,"line":3657},[155,7991,7934],{"class":160},[155,7993,7994],{"class":164}," q1 ",[155,7996,168],{"class":160},[155,7998,7942],{"class":164},[155,8000,7945],{"class":289},[155,8002,308],{"class":164},[155,8004,8005],{"class":171},"'\"'",[155,8007,7396],{"class":164},[155,8009,7945],{"class":289},[155,8011,308],{"class":164},[155,8013,8014],{"class":171},"':'",[155,8016,8017],{"class":164},", i) ",[155,8019,1264],{"class":160},[155,8021,1267],{"class":261},[155,8023,374],{"class":164},[155,8025,8026,8028,8031,8033,8035,8037,8039,8041,8044,8046,8048],{"class":157,"line":3677},[155,8027,7934],{"class":160},[155,8029,8030],{"class":164}," q2 ",[155,8032,168],{"class":160},[155,8034,7942],{"class":164},[155,8036,7945],{"class":289},[155,8038,308],{"class":164},[155,8040,8005],{"class":171},[155,8042,8043],{"class":164},", q1 ",[155,8045,1264],{"class":160},[155,8047,1267],{"class":261},[155,8049,374],{"class":164},[155,8051,8052,8054,8056,8058,8060,8062,8064,8066,8068,8071,8073,8076,8078,8081,8084,8086,8088],{"class":157,"line":3683},[155,8053,1562],{"class":160},[155,8055,7994],{"class":164},[155,8057,798],{"class":160},[155,8059,564],{"class":261},[155,8061,780],{"class":160},[155,8063,8030],{"class":164},[155,8065,798],{"class":160},[155,8067,564],{"class":261},[155,8069,8070],{"class":160}," ?",[155,8072,1202],{"class":171},[155,8074,8075],{"class":160}," :",[155,8077,7942],{"class":164},[155,8079,8080],{"class":289},"substring",[155,8082,8083],{"class":164},"(q1 ",[155,8085,1264],{"class":160},[155,8087,1267],{"class":261},[155,8089,8090],{"class":164},", q2);\n",[155,8092,8093],{"class":157,"line":3688},[155,8094,757],{"class":164},[155,8096,8097],{"class":157,"line":4461},[155,8098,434],{"class":164},[146,8100,8105],{"className":8101,"code":8102,"filename":8103,"language":8104,"meta":151,"style":151},"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 field named 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 — plain base64 or data:image\u002F...;base64,... both work\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",[141,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":151},[155,8108,8109],{"class":157,"line":9},[155,8110,8111],{},"using System.Net.Http.Headers;\n",[155,8113,8114],{"class":157,"line":255},[155,8115,8116],{},"using System.Text;\n",[155,8118,8119],{"class":157,"line":274},[155,8120,8121],{},"using System.Text.Json;\n",[155,8123,8124],{"class":157,"line":281},[155,8125,278],{"emptyLinePlaceholder":277},[155,8127,8128],{"class":157,"line":302},[155,8129,8130],{},"var api = \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\";\n",[155,8132,8133],{"class":157,"line":323},[155,8134,8135],{},"var key = Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\")!;\n",[155,8137,8138],{"class":157,"line":377},[155,8139,8140],{},"var data = await File.ReadAllBytesAsync(\"slip.jpg\");\n",[155,8142,8143],{"class":157,"line":394},[155,8144,8145],{},"using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n",[155,8147,8148],{"class":157,"line":410},[155,8149,278],{"emptyLinePlaceholder":277},[155,8151,8152],{"class":157,"line":13},[155,8153,5910],{},[155,8155,8156],{"class":157,"line":431},[155,8157,8158],{},"using var form = new MultipartFormDataContent();\n",[155,8160,8161],{"class":157,"line":437},[155,8162,8163],{},"var file = new ByteArrayContent(data);\n",[155,8165,8166],{"class":157,"line":442},[155,8167,8168],{},"file.Headers.ContentType = new MediaTypeHeaderValue(\"image\u002Fjpeg\");\n",[155,8170,8171],{"class":157,"line":486},[155,8172,8173],{},"form.Add(file, \"file\", \"slip.jpg\");\n",[155,8175,8176],{"class":157,"line":491},[155,8177,8178],{},"using var viaForm = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = form }));\n",[155,8180,8181],{"class":157,"line":497},[155,8182,278],{"emptyLinePlaceholder":277},[155,8184,8185],{"class":157,"line":548},[155,8186,5988],{},[155,8188,8189],{"class":157,"line":575},[155,8190,8191],{},"var json = new StringContent(\n",[155,8193,8194],{"class":157,"line":584},[155,8195,8196],{},"    JsonSerializer.Serialize(new { image = Convert.ToBase64String(data) }),\n",[155,8198,8199],{"class":157,"line":18},[155,8200,8201],{},"    Encoding.UTF8,\n",[155,8203,8204],{"class":157,"line":618},[155,8205,8206],{},"    \"application\u002Fjson\");\n",[155,8208,8209],{"class":157,"line":630},[155,8210,8211],{},"using var viaJson = await http.SendAsync(authed(new HttpRequestMessage(HttpMethod.Post, api) { Content = json }));\n",[155,8213,8214],{"class":157,"line":658},[155,8215,278],{"emptyLinePlaceholder":277},[155,8217,8218],{"class":157,"line":664},[155,8219,8220],{},"foreach (var res in new[] { viaForm, viaJson })\n",[155,8222,8223],{"class":157,"line":22},[155,8224,1615],{},[155,8226,8227],{"class":157,"line":686},[155,8228,8229],{},"    using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n",[155,8231,8232],{"class":157,"line":698},[155,8233,8234],{},"    string? status = null;\n",[155,8236,8237],{"class":157,"line":722},[155,8238,8239],{},"    if (body.RootElement.TryGetProperty(\"data\", out var d) && d.TryGetProperty(\"status\", out var s)) status = s.GetString();\n",[155,8241,8242],{"class":157,"line":747},[155,8243,8244],{},"    else if (body.RootElement.TryGetProperty(\"message\", out var m)) status = m.GetString();\n",[155,8246,8247],{"class":157,"line":26},[155,8248,8249],{},"    Console.WriteLine($\"{(int)res.StatusCode} {status}\");\n",[155,8251,8252],{"class":157,"line":760},[155,8253,434],{},[155,8255,8256],{"class":157,"line":765},[155,8257,278],{"emptyLinePlaceholder":277},[155,8259,8260],{"class":157,"line":804},[155,8261,8262],{},"HttpRequestMessage authed(HttpRequestMessage req)\n",[155,8264,8265],{"class":157,"line":848},[155,8266,1615],{},[155,8268,8269],{"class":157,"line":30},[155,8270,8271],{},"    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", key);\n",[155,8273,8274],{"class":157,"line":859},[155,8275,8276],{},"    return req;\n",[155,8278,8279],{"class":157,"line":864},[155,8280,434],{},[2527,8282,8283],{"type":5376},[65,8284,8285,8288,8289,8292],{},[68,8286,8287],{},"Maximum 5 MB per request"," · JPEG or PNG · the slip's QR code must be fully visible (an image cropped through the QR returns ",[141,8290,8291],{},"INVALID",").\nbase64 grows the data by about 33% ⇒ the largest image you can send as JSON is roughly 3.7 MB — for anything bigger use raw bytes or multipart",[2537,8294,8296],{"id":8295},"send-a-url-or-the-qr-text","Send a URL or the QR text",[65,8298,8299,8300,8303,8304,5394,8306,5394,8308,8310,8311,1767],{},"Both go in a JSON body, like base64 — put ",[68,8301,8302],{},"exactly one"," of ",[141,8305,513],{},[141,8307,5503],{},[141,8309,5520],{}," (more than one returns ",[141,8312,3295],{},[65,8314,8315,8319],{},[68,8316,8317],{},[141,8318,5503],{}," — we download the image and verify it exactly as if you had sent that file yourself",[185,8321,8322,8329,8335],{},[188,8323,8324,8325,8328],{},"Must be ",[141,8326,8327],{},"https:\u002F\u002F"," and reachable from the internet without signing in (e.g. an S3 pre-signed URL) · localhost \u002F internal IPs are rejected",[188,8330,8331,8334],{},[68,8332,8333],{},"Redirects are not followed"," — give the final link · file up to 5 MB · we wait at most 10 seconds",[188,8336,8337,8338,8340],{},"If the download fails → ",[141,8339,3295],{}," with the reason (no quota used)",[65,8342,8343,8347],{},[68,8344,8345],{},[141,8346,5520],{}," — the text decoded from the QR code on the slip; ideal for apps that already scan the QR, no image upload needed",[185,8349,8350,8353],{},[188,8351,8352],{},"Send the scanned text as-is, in full — do not trim or convert it",[188,8354,8355,8356,8358],{},"The same text sent again within 24 hours returns ",[141,8357,214],{},", just like resending the same image",[237,8360,8361,8636,8914,9254,9472,10134],{},[146,8362,8364],{"className":241,"code":8363,"filename":243,"language":244,"meta":151,"style":151},"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",[141,8365,8366,8378,8382,8398,8416,8425,8430,8451,8462,8467,8481,8494,8498,8514,8569,8577,8581,8585,8606,8627],{"__ignoreMap":151},[155,8367,8368,8370,8372,8374,8376],{"class":157,"line":9},[155,8369,258],{"class":160},[155,8371,5844],{"class":261},[155,8373,265],{"class":160},[155,8375,5849],{"class":171},[155,8377,271],{"class":164},[155,8379,8380],{"class":157,"line":255},[155,8381,278],{"emptyLinePlaceholder":277},[155,8383,8384,8386,8388,8391,8393,8396],{"class":157,"line":274},[155,8385,2753],{"class":160},[155,8387,505],{"class":160},[155,8389,8390],{"class":289}," verifyJson",[155,8392,308],{"class":164},[155,8394,8395],{"class":311},"payload",[155,8397,320],{"class":164},[155,8399,8400,8402,8404,8406,8408,8410,8412,8414],{"class":157,"line":281},[155,8401,3172],{"class":160},[155,8403,2814],{"class":261},[155,8405,265],{"class":160},[155,8407,599],{"class":160},[155,8409,602],{"class":289},[155,8411,308],{"class":164},[155,8413,5537],{"class":261},[155,8415,615],{"class":164},[155,8417,8418,8421,8423],{"class":157,"line":302},[155,8419,8420],{"class":164},"    method: ",[155,8422,624],{"class":171},[155,8424,627],{"class":164},[155,8426,8427],{"class":157,"line":323},[155,8428,8429],{"class":164},"    headers: {\n",[155,8431,8432,8435,8437,8439,8441,8443,8445,8447,8449],{"class":157,"line":377},[155,8433,8434],{"class":164},"      Authorization: ",[155,8436,636],{"class":171},[155,8438,5868],{"class":164},[155,8440,341],{"class":171},[155,8442,5873],{"class":164},[155,8444,341],{"class":171},[155,8446,527],{"class":261},[155,8448,641],{"class":171},[155,8450,627],{"class":164},[155,8452,8453,8456,8458,8460],{"class":157,"line":394},[155,8454,8455],{"class":171},"      'Content-Type'",[155,8457,649],{"class":164},[155,8459,6034],{"class":171},[155,8461,627],{"class":164},[155,8463,8464],{"class":157,"line":410},[155,8465,8466],{"class":164},"    },\n",[155,8468,8469,8472,8474,8476,8478],{"class":157,"line":13},[155,8470,8471],{"class":164},"    body: ",[155,8473,6044],{"class":261},[155,8475,341],{"class":164},[155,8477,6049],{"class":289},[155,8479,8480],{"class":164},"(payload),\n",[155,8482,8483,8486,8488,8490,8492],{"class":157,"line":431},[155,8484,8485],{"class":164},"    signal: AbortSignal.",[155,8487,670],{"class":289},[155,8489,308],{"class":164},[155,8491,675],{"class":261},[155,8493,678],{"class":164},[155,8495,8496],{"class":157,"line":437},[155,8497,2899],{"class":164},[155,8499,8500,8502,8504,8506,8508,8510,8512],{"class":157,"line":442},[155,8501,3172],{"class":160},[155,8503,349],{"class":261},[155,8505,265],{"class":160},[155,8507,599],{"class":160},[155,8509,876],{"class":164},[155,8511,879],{"class":289},[155,8513,2874],{"class":164},[155,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":157,"line":486},[155,8517,3190],{"class":160},[155,8519,452],{"class":164},[155,8521,902],{"class":160},[155,8523,905],{"class":164},[155,8525,713],{"class":160},[155,8527,464],{"class":160},[155,8529,296],{"class":289},[155,8531,308],{"class":164},[155,8533,331],{"class":171},[155,8535,3161],{"class":164},[155,8537,341],{"class":171},[155,8539,223],{"class":164},[155,8541,336],{"class":171},[155,8543,317],{"class":164},[155,8545,341],{"class":171},[155,8547,141],{"class":164},[155,8549,346],{"class":160},[155,8551,349],{"class":164},[155,8553,341],{"class":171},[155,8555,354],{"class":164},[155,8557,8558],{"class":171},"}: ${",[155,8560,317],{"class":164},[155,8562,341],{"class":171},[155,8564,366],{"class":164},[155,8566,641],{"class":171},[155,8568,374],{"class":164},[155,8570,8571,8574],{"class":157,"line":491},[155,8572,8573],{"class":160},"  return",[155,8575,8576],{"class":164}," body.data;\n",[155,8578,8579],{"class":157,"line":497},[155,8580,434],{"class":164},[155,8582,8583],{"class":157,"line":548},[155,8584,278],{"emptyLinePlaceholder":277},[155,8586,8587,8589,8592,8594,8596,8598,8601,8604],{"class":157,"line":575},[155,8588,258],{"class":160},[155,8590,8591],{"class":261}," byUrl",[155,8593,265],{"class":160},[155,8595,599],{"class":160},[155,8597,8390],{"class":289},[155,8599,8600],{"class":164},"({ url: process.env.",[155,8602,8603],{"class":261},"SLIP_URL",[155,8605,3226],{"class":164},[155,8607,8608,8610,8613,8615,8617,8619,8622,8625],{"class":157,"line":584},[155,8609,258],{"class":160},[155,8611,8612],{"class":261}," byQr",[155,8614,265],{"class":160},[155,8616,599],{"class":160},[155,8618,8390],{"class":289},[155,8620,8621],{"class":164},"({ qr: process.env.",[155,8623,8624],{"class":261},"SLIP_QR",[155,8626,3226],{"class":164},[155,8628,8629,8631,8633],{"class":157,"line":18},[155,8630,2338],{"class":164},[155,8632,2341],{"class":289},[155,8634,8635],{"class":164},"(byUrl.status, byQr.status);\n",[146,8637,8639],{"className":938,"code":8638,"filename":940,"language":941,"meta":151,"style":151},"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",[141,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":151},[155,8642,8643,8645],{"class":157,"line":9},[155,8644,953],{"class":160},[155,8646,956],{"class":164},[155,8648,8649],{"class":157,"line":255},[155,8650,278],{"emptyLinePlaceholder":277},[155,8652,8653,8655],{"class":157,"line":274},[155,8654,953],{"class":160},[155,8656,974],{"class":164},[155,8658,8659],{"class":157,"line":281},[155,8660,278],{"emptyLinePlaceholder":277},[155,8662,8663,8665,8667],{"class":157,"line":302},[155,8664,5537],{"class":261},[155,8666,265],{"class":160},[155,8668,6164],{"class":171},[155,8670,8671],{"class":157,"line":323},[155,8672,278],{"emptyLinePlaceholder":277},[155,8674,8675],{"class":157,"line":377},[155,8676,278],{"emptyLinePlaceholder":277},[155,8678,8679,8681,8684,8687,8689,8691,8693],{"class":157,"line":394},[155,8680,1182],{"class":160},[155,8682,8683],{"class":289}," verify_json",[155,8685,8686],{"class":164},"(payload: ",[155,8688,1030],{"class":261},[155,8690,1214],{"class":164},[155,8692,1030],{"class":261},[155,8694,1219],{"class":164},[155,8696,8697,8700,8702],{"class":157,"line":410},[155,8698,8699],{"class":164},"    res ",[155,8701,168],{"class":160},[155,8703,1301],{"class":164},[155,8705,8706,8709],{"class":157,"line":13},[155,8707,8708],{"class":261},"        API",[155,8710,627],{"class":164},[155,8712,8713,8716,8718,8720,8722,8724,8726,8728,8730,8732,8734,8736,8738,8740],{"class":157,"line":431},[155,8714,8715],{"class":311},"        headers",[155,8717,168],{"class":160},[155,8719,1056],{"class":164},[155,8721,1328],{"class":171},[155,8723,649],{"class":164},[155,8725,1333],{"class":160},[155,8727,1336],{"class":171},[155,8729,1056],{"class":261},[155,8731,6186],{"class":164},[155,8733,1870],{"class":171},[155,8735,4307],{"class":164},[155,8737,1061],{"class":261},[155,8739,1053],{"class":171},[155,8741,1358],{"class":164},[155,8743,8744,8747,8749],{"class":157,"line":437},[155,8745,8746],{"class":311},"        json",[155,8748,168],{"class":160},[155,8750,8751],{"class":164},"payload,\n",[155,8753,8754,8757,8759,8761],{"class":157,"line":442},[155,8755,8756],{"class":311},"        timeout",[155,8758,168],{"class":160},[155,8760,1378],{"class":261},[155,8762,627],{"class":164},[155,8764,8765],{"class":157,"line":486},[155,8766,8767],{"class":164},"    )\n",[155,8769,8770,8772,8774],{"class":157,"line":491},[155,8771,6354],{"class":164},[155,8773,168],{"class":160},[155,8775,1518],{"class":164},[155,8777,8778,8780,8782],{"class":157,"line":497},[155,8779,768],{"class":160},[155,8781,1466],{"class":160},[155,8783,1547],{"class":164},[155,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":157,"line":548},[155,8787,8788],{"class":160},"        raise",[155,8790,8791],{"class":261}," RuntimeError",[155,8793,308],{"class":164},[155,8795,1333],{"class":160},[155,8797,1053],{"class":171},[155,8799,1056],{"class":261},[155,8801,8802],{"class":164},"res.status_code",[155,8804,1061],{"class":261},[155,8806,1064],{"class":261},[155,8808,1067],{"class":164},[155,8810,1070],{"class":171},[155,8812,458],{"class":164},[155,8814,1075],{"class":160},[155,8816,1078],{"class":164},[155,8818,1081],{"class":171},[155,8820,1767],{"class":164},[155,8822,1061],{"class":261},[155,8824,649],{"class":171},[155,8826,1056],{"class":261},[155,8828,1067],{"class":164},[155,8830,1099],{"class":171},[155,8832,1767],{"class":164},[155,8834,1061],{"class":261},[155,8836,1053],{"class":171},[155,8838,1717],{"class":164},[155,8840,8841,8843,8845,8847],{"class":157,"line":575},[155,8842,920],{"class":160},[155,8844,1565],{"class":164},[155,8846,1568],{"class":171},[155,8848,1245],{"class":164},[155,8850,8851],{"class":157,"line":584},[155,8852,278],{"emptyLinePlaceholder":277},[155,8854,8855],{"class":157,"line":18},[155,8856,278],{"emptyLinePlaceholder":277},[155,8858,8859,8862,8864,8867,8870,8873,8876],{"class":157,"line":618},[155,8860,8861],{"class":164},"by_url ",[155,8863,168],{"class":160},[155,8865,8866],{"class":164}," verify_json({",[155,8868,8869],{"class":171},"\"url\"",[155,8871,8872],{"class":164},": os.environ[",[155,8874,8875],{"class":171},"\"SLIP_URL\"",[155,8877,8878],{"class":164},"]})\n",[155,8880,8881,8884,8886,8888,8891,8893,8896],{"class":157,"line":630},[155,8882,8883],{"class":164},"by_qr ",[155,8885,168],{"class":160},[155,8887,8866],{"class":164},[155,8889,8890],{"class":171},"\"qr\"",[155,8892,8872],{"class":164},[155,8894,8895],{"class":171},"\"SLIP_QR\"",[155,8897,8878],{"class":164},[155,8899,8900,8902,8905,8907,8910,8912],{"class":157,"line":658},[155,8901,2406],{"class":261},[155,8903,8904],{"class":164},"(by_url[",[155,8906,2412],{"class":171},[155,8908,8909],{"class":164},"], by_qr[",[155,8911,2412],{"class":171},[155,8913,2426],{"class":164},[146,8915,8917],{"className":1577,"code":8916,"filename":1579,"language":1580,"meta":151,"style":151},"\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",[141,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":151},[155,8920,8921,8923],{"class":157,"line":9},[155,8922,1587],{"class":160},[155,8924,1590],{"class":261},[155,8926,8927,8929,8932,8934,8936,8939,8941],{"class":157,"line":255},[155,8928,1744],{"class":160},[155,8930,8931],{"class":289}," slipbolt_verify_json",[155,8933,308],{"class":164},[155,8935,6413],{"class":160},[155,8937,8938],{"class":164}," $payload)",[155,8940,1770],{"class":160},[155,8942,1773],{"class":160},[155,8944,8945],{"class":157,"line":274},[155,8946,1615],{"class":164},[155,8948,8949,8951,8953,8955,8957,8959],{"class":157,"line":281},[155,8950,6429],{"class":164},[155,8952,168],{"class":160},[155,8954,1816],{"class":261},[155,8956,308],{"class":164},[155,8958,1821],{"class":171},[155,8960,374],{"class":164},[155,8962,8963,8965],{"class":157,"line":302},[155,8964,6444],{"class":261},[155,8966,1831],{"class":164},[155,8968,8969,8971,8973,8975],{"class":157,"line":323},[155,8970,6451],{"class":261},[155,8972,1839],{"class":160},[155,8974,1842],{"class":261},[155,8976,627],{"class":164},[155,8978,8979,8981,8983],{"class":157,"line":377},[155,8980,6462],{"class":261},[155,8982,1852],{"class":160},[155,8984,1855],{"class":164},[155,8986,8987,8990,8992,8994,8996,8998],{"class":157,"line":394},[155,8988,8989],{"class":171},"            'Authorization: Bearer '",[155,8991,1673],{"class":160},[155,8993,1865],{"class":261},[155,8995,308],{"class":164},[155,8997,1870],{"class":171},[155,8999,678],{"class":164},[155,9001,9002,9005],{"class":157,"line":410},[155,9003,9004],{"class":171},"            'Content-Type: application\u002Fjson'",[155,9006,627],{"class":164},[155,9008,9009],{"class":157,"line":13},[155,9010,9011],{"class":164},"        ],\n",[155,9013,9014,9016,9018,9020],{"class":157,"line":431},[155,9015,6490],{"class":261},[155,9017,1852],{"class":160},[155,9019,4564],{"class":261},[155,9021,9022],{"class":164},"($payload),\n",[155,9024,9025,9027,9029,9031],{"class":157,"line":437},[155,9026,6500],{"class":261},[155,9028,1902],{"class":160},[155,9030,1842],{"class":261},[155,9032,627],{"class":164},[155,9034,9035,9037,9039,9041],{"class":157,"line":442},[155,9036,6511],{"class":261},[155,9038,1914],{"class":160},[155,9040,1917],{"class":261},[155,9042,627],{"class":164},[155,9044,9045],{"class":157,"line":486},[155,9046,6522],{"class":164},[155,9048,9049,9052,9054,9056,9058,9060,9062,9064,9066,9068],{"class":157,"line":491},[155,9050,9051],{"class":164},"    $body   ",[155,9053,168],{"class":160},[155,9055,2191],{"class":261},[155,9057,308],{"class":164},[155,9059,6536],{"class":261},[155,9061,6539],{"class":164},[155,9063,2197],{"class":261},[155,9065,458],{"class":164},[155,9067,1684],{"class":160},[155,9069,2204],{"class":164},[155,9071,9072,9075,9077,9079,9081,9083],{"class":157,"line":497},[155,9073,9074],{"class":164},"    $status ",[155,9076,168],{"class":160},[155,9078,2049],{"class":261},[155,9080,2052],{"class":164},[155,9082,2055],{"class":261},[155,9084,374],{"class":164},[155,9086,9087,9089,9091,9093,9095],{"class":157,"line":548},[155,9088,768],{"class":160},[155,9090,2212],{"class":164},[155,9092,2215],{"class":160},[155,9094,2218],{"class":261},[155,9096,320],{"class":164},[155,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":157,"line":575},[155,9100,9101],{"class":160},"        throw",[155,9103,464],{"class":160},[155,9105,2160],{"class":261},[155,9107,308],{"class":164},[155,9109,1053],{"class":171},[155,9111,1667],{"class":164},[155,9113,1670],{"class":171},[155,9115,1673],{"class":160},[155,9117,1676],{"class":164},[155,9119,1070],{"class":171},[155,9121,1681],{"class":164},[155,9123,1684],{"class":160},[155,9125,1687],{"class":164},[155,9127,1081],{"class":171},[155,9129,1681],{"class":164},[155,9131,1684],{"class":160},[155,9133,1088],{"class":171},[155,9135,458],{"class":164},[155,9137,341],{"class":160},[155,9139,1702],{"class":171},[155,9141,1673],{"class":160},[155,9143,1676],{"class":164},[155,9145,1099],{"class":171},[155,9147,1681],{"class":164},[155,9149,1684],{"class":160},[155,9151,1088],{"class":171},[155,9153,2000],{"class":164},[155,9155,9156],{"class":157,"line":584},[155,9157,757],{"class":164},[155,9159,9160,9162,9164,9166],{"class":157,"line":18},[155,9161,920],{"class":160},[155,9163,1687],{"class":164},[155,9165,2247],{"class":171},[155,9167,2782],{"class":164},[155,9169,9170],{"class":157,"line":618},[155,9171,434],{"class":164},[155,9173,9174],{"class":157,"line":630},[155,9175,278],{"emptyLinePlaceholder":277},[155,9177,9178,9181,9183,9185,9187,9190,9192,9194,9196,9199],{"class":157,"line":658},[155,9179,9180],{"class":164},"$byUrl ",[155,9182,168],{"class":160},[155,9184,8931],{"class":289},[155,9186,4567],{"class":164},[155,9188,9189],{"class":171},"'url'",[155,9191,1902],{"class":160},[155,9193,1865],{"class":261},[155,9195,308],{"class":164},[155,9197,9198],{"class":171},"'SLIP_URL'",[155,9200,6603],{"class":164},[155,9202,9203,9206,9208,9210,9212,9215,9217,9219,9221,9224],{"class":157,"line":664},[155,9204,9205],{"class":164},"$byQr  ",[155,9207,168],{"class":160},[155,9209,8931],{"class":289},[155,9211,4567],{"class":164},[155,9213,9214],{"class":171},"'qr'",[155,9216,1902],{"class":160},[155,9218,1865],{"class":261},[155,9220,308],{"class":164},[155,9222,9223],{"class":171},"'SLIP_QR'",[155,9225,6603],{"class":164},[155,9227,9228,9230,9233,9235,9237,9239,9242,9244,9246,9248,9250,9252],{"class":157,"line":22},[155,9229,2481],{"class":261},[155,9231,9232],{"class":164}," $byUrl[",[155,9234,2487],{"class":171},[155,9236,2490],{"class":164},[155,9238,2493],{"class":171},[155,9240,9241],{"class":164},", $byQr[",[155,9243,2487],{"class":171},[155,9245,2490],{"class":164},[155,9247,1053],{"class":171},[155,9249,2515],{"class":261},[155,9251,1053],{"class":171},[155,9253,271],{"class":164},[146,9255,9257],{"className":6722,"code":9256,"filename":6724,"language":6725,"meta":151,"style":151},"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",[141,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":151},[155,9260,9261],{"class":157,"line":9},[155,9262,6732],{},[155,9264,9265],{"class":157,"line":255},[155,9266,278],{"emptyLinePlaceholder":277},[155,9268,9269],{"class":157,"line":274},[155,9270,6741],{},[155,9272,9273],{"class":157,"line":281},[155,9274,6746],{},[155,9276,9277],{"class":157,"line":302},[155,9278,6756],{},[155,9280,9281],{"class":157,"line":323},[155,9282,6761],{},[155,9284,9285],{"class":157,"line":377},[155,9286,6766],{},[155,9288,9289],{"class":157,"line":394},[155,9290,6776],{},[155,9292,9293],{"class":157,"line":410},[155,9294,6781],{},[155,9296,9297],{"class":157,"line":13},[155,9298,6786],{},[155,9300,9301],{"class":157,"line":431},[155,9302,1717],{},[155,9304,9305],{"class":157,"line":437},[155,9306,278],{"emptyLinePlaceholder":277},[155,9308,9309],{"class":157,"line":442},[155,9310,6799],{},[155,9312,9313],{"class":157,"line":486},[155,9314,9315],{},"    byURL := verifyJSON(map[string]string{\"url\": os.Getenv(\"SLIP_URL\")})\n",[155,9317,9318],{"class":157,"line":491},[155,9319,9320],{},"    byQR := verifyJSON(map[string]string{\"qr\": os.Getenv(\"SLIP_QR\")})\n",[155,9322,9323],{"class":157,"line":497},[155,9324,9325],{},"    fmt.Println(byURL[\"status\"], byQR[\"status\"])\n",[155,9327,9328],{"class":157,"line":548},[155,9329,434],{},[155,9331,9332],{"class":157,"line":575},[155,9333,278],{"emptyLinePlaceholder":277},[155,9335,9336],{"class":157,"line":584},[155,9337,9338],{},"func verifyJSON(payload map[string]string) map[string]any {\n",[155,9340,9341],{"class":157,"line":18},[155,9342,9343],{},"    body, _ := json.Marshal(payload)\n",[155,9345,9346],{"class":157,"line":618},[155,9347,9348],{},"    req, err := http.NewRequest(http.MethodPost, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\", bytes.NewReader(body))\n",[155,9350,9351],{"class":157,"line":630},[155,9352,6819],{},[155,9354,9355],{"class":157,"line":658},[155,9356,6824],{},[155,9358,9359],{"class":157,"line":664},[155,9360,757],{},[155,9362,9363],{"class":157,"line":22},[155,9364,9365],{},"    req.Header.Set(\"Authorization\", \"Bearer \"+os.Getenv(\"SLIPBOLT_API_KEY\"))\n",[155,9367,9368],{"class":157,"line":686},[155,9369,9370],{},"    req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n",[155,9372,9373],{"class":157,"line":698},[155,9374,9375],{},"    res, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)\n",[155,9377,9378],{"class":157,"line":722},[155,9379,6819],{},[155,9381,9382],{"class":157,"line":747},[155,9383,6824],{},[155,9385,9386],{"class":157,"line":26},[155,9387,757],{},[155,9389,9390],{"class":157,"line":760},[155,9391,7021],{},[155,9393,9394],{"class":157,"line":765},[155,9395,7027],{},[155,9397,9398],{"class":157,"line":804},[155,9399,9400],{},"    var parsed struct {\n",[155,9402,9403],{"class":157,"line":848},[155,9404,9405],{},"        Data    map[string]any `json:\"data\"`\n",[155,9407,9408],{"class":157,"line":30},[155,9409,9410],{},"        Code    string         `json:\"code\"`\n",[155,9412,9413],{"class":157,"line":859},[155,9414,9415],{},"        Error   string         `json:\"error\"`\n",[155,9417,9418],{"class":157,"line":864},[155,9419,9420],{},"        Message string         `json:\"message\"`\n",[155,9422,9423],{"class":157,"line":895},[155,9424,757],{},[155,9426,9427],{"class":157,"line":917},[155,9428,9429],{},"    _ = json.Unmarshal(raw, &parsed)\n",[155,9431,9432],{"class":157,"line":35},[155,9433,9434],{},"    if res.StatusCode != 200 {\n",[155,9436,9437],{"class":157,"line":933},[155,9438,9439],{},"        code := parsed.Code\n",[155,9441,9442],{"class":157,"line":1503},[155,9443,9444],{},"        if code == \"\" {\n",[155,9446,9447],{"class":157,"line":1510},[155,9448,9449],{},"            code = parsed.Error\n",[155,9451,9452],{"class":157,"line":1521},[155,9453,2137],{},[155,9455,9456],{"class":157,"line":39},[155,9457,9458],{},"        panic(fmt.Sprintf(\"%d %s: %s\", res.StatusCode, code, parsed.Message))\n",[155,9460,9461],{"class":157,"line":1540},[155,9462,757],{},[155,9464,9465],{"class":157,"line":1550},[155,9466,9467],{},"    return parsed.Data\n",[155,9469,9470],{"class":157,"line":1559},[155,9471,434],{},[146,9473,9475],{"className":7093,"code":9474,"filename":7095,"language":7096,"meta":151,"style":151},"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",[141,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":151},[155,9478,9479,9481],{"class":157,"line":9},[155,9480,953],{"class":160},[155,9482,7105],{"class":164},[155,9484,9485,9487,9489,9491],{"class":157,"line":255},[155,9486,953],{"class":160},[155,9488,7112],{"class":164},[155,9490,840],{"class":261},[155,9492,271],{"class":164},[155,9494,9495,9497],{"class":157,"line":274},[155,9496,953],{"class":160},[155,9498,7141],{"class":164},[155,9500,9501],{"class":157,"line":281},[155,9502,278],{"emptyLinePlaceholder":277},[155,9504,9505,9507,9510],{"class":157,"line":302},[155,9506,1000],{"class":160},[155,9508,9509],{"class":289}," VerifyJson",[155,9511,299],{"class":164},[155,9513,9514,9516,9518,9520,9522,9524,9526,9528,9530,9532,9534],{"class":157,"line":323},[155,9515,1620],{"class":160},[155,9517,7168],{"class":160},[155,9519,7171],{"class":160},[155,9521,7174],{"class":289},[155,9523,308],{"class":164},[155,9525,7179],{"class":160},[155,9527,7182],{"class":164},[155,9529,7185],{"class":311},[155,9531,458],{"class":164},[155,9533,7190],{"class":160},[155,9535,7193],{"class":164},[155,9537,9538,9541,9543,9546,9548,9551,9553,9555,9557,9559,9561,9563,9565,9567,9569,9571,9573,9575,9577,9579,9581,9583],{"class":157,"line":377},[155,9539,9540],{"class":164},"        String byUrl ",[155,9542,168],{"class":160},[155,9544,9545],{"class":289}," verify",[155,9547,308],{"class":164},[155,9549,9550],{"class":171},"\"{",[155,9552,7342],{"class":261},[155,9554,5503],{"class":171},[155,9556,7342],{"class":261},[155,9558,1770],{"class":171},[155,9560,7342],{"class":261},[155,9562,1053],{"class":171},[155,9564,7355],{"class":160},[155,9566,7215],{"class":164},[155,9568,4703],{"class":289},[155,9570,308],{"class":164},[155,9572,8875],{"class":171},[155,9574,458],{"class":164},[155,9576,1264],{"class":160},[155,9578,1670],{"class":171},[155,9580,7342],{"class":261},[155,9582,7378],{"class":171},[155,9584,374],{"class":164},[155,9586,9587,9590,9592,9594,9596,9598,9600,9602,9604,9606,9608,9610,9612,9614,9616,9618,9620,9622,9624,9626,9628,9630],{"class":157,"line":394},[155,9588,9589],{"class":164},"        String byQr ",[155,9591,168],{"class":160},[155,9593,9545],{"class":289},[155,9595,308],{"class":164},[155,9597,9550],{"class":171},[155,9599,7342],{"class":261},[155,9601,5520],{"class":171},[155,9603,7342],{"class":261},[155,9605,1770],{"class":171},[155,9607,7342],{"class":261},[155,9609,1053],{"class":171},[155,9611,7355],{"class":160},[155,9613,7215],{"class":164},[155,9615,4703],{"class":289},[155,9617,308],{"class":164},[155,9619,8895],{"class":171},[155,9621,458],{"class":164},[155,9623,1264],{"class":160},[155,9625,1670],{"class":171},[155,9627,7342],{"class":261},[155,9629,7378],{"class":171},[155,9631,374],{"class":164},[155,9633,9634,9636,9638,9641,9643,9645,9647],{"class":157,"line":410},[155,9635,7878],{"class":164},[155,9637,7881],{"class":289},[155,9639,9640],{"class":164},"(byUrl ",[155,9642,1264],{"class":160},[155,9644,7895],{"class":171},[155,9646,7355],{"class":160},[155,9648,9649],{"class":164}," byQr);\n",[155,9651,9652],{"class":157,"line":13},[155,9653,757],{"class":164},[155,9655,9656],{"class":157,"line":431},[155,9657,278],{"emptyLinePlaceholder":277},[155,9659,9660,9662,9664,9667,9669,9671,9673,9675],{"class":157,"line":437},[155,9661,7415],{"class":160},[155,9663,7915],{"class":164},[155,9665,9666],{"class":289},"verify",[155,9668,7921],{"class":164},[155,9670,879],{"class":311},[155,9672,458],{"class":164},[155,9674,7190],{"class":160},[155,9676,7193],{"class":164},[155,9678,9679,9681,9683,9685,9687,9689,9691,9693,9696],{"class":157,"line":442},[155,9680,7467],{"class":164},[155,9682,168],{"class":160},[155,9684,7472],{"class":164},[155,9686,7264],{"class":289},[155,9688,7477],{"class":164},[155,9690,7480],{"class":289},[155,9692,308],{"class":164},[155,9694,9695],{"class":171},"\"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\"",[155,9697,4245],{"class":164},[155,9699,9700,9702,9704,9706,9708,9710,9712],{"class":157,"line":486},[155,9701,7488],{"class":164},[155,9703,670],{"class":289},[155,9705,7272],{"class":164},[155,9707,7275],{"class":289},[155,9709,308],{"class":164},[155,9711,1378],{"class":261},[155,9713,4245],{"class":164},[155,9715,9716,9718,9720,9722,9724,9726,9728,9730,9732,9734,9736,9738],{"class":157,"line":491},[155,9717,7488],{"class":164},[155,9719,7507],{"class":289},[155,9721,308],{"class":164},[155,9723,1328],{"class":171},[155,9725,314],{"class":164},[155,9727,7516],{"class":171},[155,9729,7355],{"class":160},[155,9731,7215],{"class":164},[155,9733,4703],{"class":289},[155,9735,308],{"class":164},[155,9737,1242],{"class":171},[155,9739,4245],{"class":164},[155,9741,9742,9744,9746,9748,9750,9752,9754],{"class":157,"line":497},[155,9743,7488],{"class":164},[155,9745,7507],{"class":289},[155,9747,308],{"class":164},[155,9749,1350],{"class":171},[155,9751,314],{"class":164},[155,9753,7393],{"class":171},[155,9755,1717],{"class":164},[155,9757,9758,9760,9762,9764,9766],{"class":157,"line":548},[155,9759,7488],{"class":164},[155,9761,7541],{"class":289},[155,9763,7544],{"class":164},[155,9765,7573],{"class":289},[155,9767,9768],{"class":164},"(json))\n",[155,9770,9771,9773,9775],{"class":157,"line":575},[155,9772,7488],{"class":164},[155,9774,7285],{"class":289},[155,9776,2874],{"class":164},[155,9778,9779,9781,9783,9785,9787,9789,9791,9793,9795,9797,9799,9801,9803],{"class":157,"line":584},[155,9780,7256],{"class":164},[155,9782,168],{"class":160},[155,9784,7261],{"class":164},[155,9786,7264],{"class":289},[155,9788,882],{"class":164},[155,9790,7269],{"class":289},[155,9792,7272],{"class":164},[155,9794,7275],{"class":289},[155,9796,308],{"class":164},[155,9798,1378],{"class":261},[155,9800,7282],{"class":164},[155,9802,7285],{"class":289},[155,9804,2874],{"class":164},[155,9806,9807,9810,9812,9815,9817,9819,9821,9823,9825],{"class":157,"line":18},[155,9808,9809],{"class":164},"        HttpResponse\u003C",[155,9811,7179],{"class":160},[155,9813,9814],{"class":164},"> res ",[155,9816,168],{"class":160},[155,9818,7565],{"class":164},[155,9820,7306],{"class":289},[155,9822,7570],{"class":164},[155,9824,7573],{"class":289},[155,9826,5059],{"class":164},[155,9828,9829,9831,9834,9836,9838,9841,9843],{"class":157,"line":618},[155,9830,1441],{"class":160},[155,9832,9833],{"class":164}," (res.",[155,9835,7887],{"class":289},[155,9837,7890],{"class":164},[155,9839,9840],{"class":160},"!=",[155,9842,2218],{"class":261},[155,9844,320],{"class":164},[155,9846,9847,9850,9852,9855,9857,9859,9862,9864],{"class":157,"line":630},[155,9848,9849],{"class":164},"            String code ",[155,9851,168],{"class":160},[155,9853,9854],{"class":289}," field",[155,9856,7884],{"class":164},[155,9858,317],{"class":289},[155,9860,9861],{"class":164},"(), ",[155,9863,1144],{"class":171},[155,9865,374],{"class":164},[155,9867,9868,9870,9873,9875,9878,9880,9882,9884,9886,9888,9891],{"class":157,"line":658},[155,9869,1398],{"class":160},[155,9871,9872],{"class":164}," (code.",[155,9874,7860],{"class":289},[155,9876,9877],{"class":164},"()) code ",[155,9879,168],{"class":160},[155,9881,9854],{"class":289},[155,9883,7884],{"class":164},[155,9885,317],{"class":289},[155,9887,9861],{"class":164},[155,9889,9890],{"class":171},"\"error\"",[155,9892,374],{"class":164},[155,9894,9895,9897,9899,9901,9903,9905,9907,9909,9911,9913,9916,9918,9921,9923,9925,9927,9929,9931,9933],{"class":157,"line":664},[155,9896,2155],{"class":160},[155,9898,464],{"class":160},[155,9900,2160],{"class":289},[155,9902,7884],{"class":164},[155,9904,7887],{"class":289},[155,9906,7890],{"class":164},[155,9908,1264],{"class":160},[155,9910,7895],{"class":171},[155,9912,7355],{"class":160},[155,9914,9915],{"class":164}," code ",[155,9917,1264],{"class":160},[155,9919,9920],{"class":171}," \": \"",[155,9922,7355],{"class":160},[155,9924,9854],{"class":289},[155,9926,7884],{"class":164},[155,9928,317],{"class":289},[155,9930,9861],{"class":164},[155,9932,6388],{"class":171},[155,9934,2000],{"class":164},[155,9936,9937],{"class":157,"line":22},[155,9938,2137],{"class":164},[155,9940,9941,9943,9945,9947,9949,9951,9953],{"class":157,"line":686},[155,9942,1562],{"class":160},[155,9944,9854],{"class":289},[155,9946,7884],{"class":164},[155,9948,317],{"class":289},[155,9950,9861],{"class":164},[155,9952,2412],{"class":171},[155,9954,374],{"class":164},[155,9956,9957],{"class":157,"line":698},[155,9958,757],{"class":164},[155,9960,9961],{"class":157,"line":722},[155,9962,278],{"emptyLinePlaceholder":277},[155,9964,9965,9967,9969,9972,9974,9976,9978,9980],{"class":157,"line":747},[155,9966,7415],{"class":160},[155,9968,7915],{"class":164},[155,9970,9971],{"class":289},"field",[155,9973,7921],{"class":164},[155,9975,879],{"class":311},[155,9977,7434],{"class":164},[155,9979,7442],{"class":311},[155,9981,320],{"class":164},[155,9983,9984,9986,9988,9990,9992,9994,9996,9998,10000,10002,10004,10006,10008,10010,10012,10014],{"class":157,"line":26},[155,9985,7934],{"class":160},[155,9987,7937],{"class":164},[155,9989,168],{"class":160},[155,9991,7942],{"class":164},[155,9993,7945],{"class":289},[155,9995,308],{"class":164},[155,9997,1053],{"class":171},[155,9999,7342],{"class":261},[155,10001,1053],{"class":171},[155,10003,7355],{"class":160},[155,10005,7958],{"class":164},[155,10007,1264],{"class":160},[155,10009,1670],{"class":171},[155,10011,7342],{"class":261},[155,10013,1053],{"class":171},[155,10015,374],{"class":164},[155,10017,10018,10020,10022,10024,10026,10028,10030,10032],{"class":157,"line":760},[155,10019,1441],{"class":160},[155,10021,7975],{"class":164},[155,10023,798],{"class":160},[155,10025,564],{"class":261},[155,10027,458],{"class":164},[155,10029,2796],{"class":160},[155,10031,1202],{"class":171},[155,10033,271],{"class":164},[155,10035,10036,10038,10040,10042,10044,10046,10048,10050,10052,10054,10056,10058,10060,10062,10064],{"class":157,"line":765},[155,10037,7934],{"class":160},[155,10039,7994],{"class":164},[155,10041,168],{"class":160},[155,10043,7942],{"class":164},[155,10045,7945],{"class":289},[155,10047,308],{"class":164},[155,10049,8005],{"class":171},[155,10051,7396],{"class":164},[155,10053,7945],{"class":289},[155,10055,308],{"class":164},[155,10057,8014],{"class":171},[155,10059,8017],{"class":164},[155,10061,1264],{"class":160},[155,10063,1267],{"class":261},[155,10065,374],{"class":164},[155,10067,10068,10070,10072,10074,10076,10078,10080,10082,10084,10086,10088],{"class":157,"line":804},[155,10069,7934],{"class":160},[155,10071,8030],{"class":164},[155,10073,168],{"class":160},[155,10075,7942],{"class":164},[155,10077,7945],{"class":289},[155,10079,308],{"class":164},[155,10081,8005],{"class":171},[155,10083,8043],{"class":164},[155,10085,1264],{"class":160},[155,10087,1267],{"class":261},[155,10089,374],{"class":164},[155,10091,10092,10094,10096,10098,10100,10102,10104,10106,10108,10110,10112,10114,10116,10118,10120,10122,10124],{"class":157,"line":848},[155,10093,1562],{"class":160},[155,10095,7994],{"class":164},[155,10097,798],{"class":160},[155,10099,564],{"class":261},[155,10101,780],{"class":160},[155,10103,8030],{"class":164},[155,10105,798],{"class":160},[155,10107,564],{"class":261},[155,10109,8070],{"class":160},[155,10111,1202],{"class":171},[155,10113,8075],{"class":160},[155,10115,7942],{"class":164},[155,10117,8080],{"class":289},[155,10119,8083],{"class":164},[155,10121,1264],{"class":160},[155,10123,1267],{"class":261},[155,10125,8090],{"class":164},[155,10127,10128],{"class":157,"line":30},[155,10129,757],{"class":164},[155,10131,10132],{"class":157,"line":859},[155,10133,434],{"class":164},[146,10135,10137],{"className":8101,"code":10136,"filename":8103,"language":8104,"meta":151,"style":151},"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",[141,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":151},[155,10140,10141],{"class":157,"line":9},[155,10142,8111],{},[155,10144,10145],{"class":157,"line":255},[155,10146,8116],{},[155,10148,10149],{"class":157,"line":274},[155,10150,8121],{},[155,10152,10153],{"class":157,"line":281},[155,10154,278],{"emptyLinePlaceholder":277},[155,10156,10157],{"class":157,"line":302},[155,10158,10159],{},"var byUrl = await VerifyJson(new { url = Environment.GetEnvironmentVariable(\"SLIP_URL\") });\n",[155,10161,10162],{"class":157,"line":323},[155,10163,10164],{},"var byQr = await VerifyJson(new { qr = Environment.GetEnvironmentVariable(\"SLIP_QR\") });\n",[155,10166,10167],{"class":157,"line":377},[155,10168,10169],{},"Console.WriteLine($\"{byUrl} {byQr}\");\n",[155,10171,10172],{"class":157,"line":394},[155,10173,278],{"emptyLinePlaceholder":277},[155,10175,10176],{"class":157,"line":410},[155,10177,10178],{},"static async Task\u003Cstring> VerifyJson(object payload)\n",[155,10180,10181],{"class":157,"line":13},[155,10182,1615],{},[155,10184,10185],{"class":157,"line":431},[155,10186,10187],{},"    using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };\n",[155,10189,10190],{"class":157,"line":437},[155,10191,10192],{},"    using var req = new HttpRequestMessage(HttpMethod.Post, \"https:\u002F\u002Fapi.slip-bolt.com\u002Fapi\u002Fv1\u002Fverify\");\n",[155,10194,10195],{"class":157,"line":442},[155,10196,10197],{},"    req.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", Environment.GetEnvironmentVariable(\"SLIPBOLT_API_KEY\"));\n",[155,10199,10200],{"class":157,"line":486},[155,10201,10202],{},"    req.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, \"application\u002Fjson\");\n",[155,10204,10205],{"class":157,"line":491},[155,10206,10207],{},"    using var res = await http.SendAsync(req);\n",[155,10209,10210],{"class":157,"line":497},[155,10211,10212],{},"    var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());\n",[155,10214,10215],{"class":157,"line":548},[155,10216,10217],{},"    if (!res.IsSuccessStatusCode)\n",[155,10219,10220],{"class":157,"line":575},[155,10221,1649],{},[155,10223,10224],{"class":157,"line":584},[155,10225,10226],{},"        string code = body.RootElement.TryGetProperty(\"code\", out var c) ? c.GetString() ?? \"\" : \"\";\n",[155,10228,10229],{"class":157,"line":18},[155,10230,10231],{},"        if (code == \"\" && body.RootElement.TryGetProperty(\"error\", out var e)) code = e.GetString() ?? \"\";\n",[155,10233,10234],{"class":157,"line":618},[155,10235,10236],{},"        string message = body.RootElement.TryGetProperty(\"message\", out var m) ? m.GetString() ?? \"\" : \"\";\n",[155,10238,10239],{"class":157,"line":630},[155,10240,10241],{},"        throw new Exception($\"{(int)res.StatusCode} {code}: {message}\");\n",[155,10243,10244],{"class":157,"line":658},[155,10245,757],{},[155,10247,10248],{"class":157,"line":664},[155,10249,10250],{},"    return body.RootElement.GetProperty(\"data\").GetProperty(\"status\").GetString()!;\n",[155,10252,10253],{"class":157,"line":22},[155,10254,434],{},[174,10256,136],{"id":10257},"_4-test-webhooks-locally",[65,10259,10260,10261,10263,10264,10267],{},"SlipBolt only delivers webhooks to public ",[141,10262,8327],{}," addresses, so it cannot reach ",[141,10265,10266],{},"localhost"," directly. Two options:",[2537,10269,10271],{"id":10270},"option-1-sign-an-event-yourself-and-post-it-to-localhost","Option 1 — sign an event yourself and post it to localhost",[65,10273,10274,10275,2740],{},"The fastest way, nothing exposed to the internet. This script signs exactly the way the real system does.\nUse the same secret your handler is configured with (",[100,10276,10278],{"href":10277},"\u002Fdocs\u002Fwebhooks#verify-signature","example handler",[146,10280,10282],{"className":148,"code":10281,"language":150,"meta":151,"style":151},"SECRET=\"whsec_your_secret\"\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\":\"Your shop\",\"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",[141,10283,10284,10294,10304,10308,10326,10352,10410,10414,10434,10442,10451,10470],{"__ignoreMap":151},[155,10285,10286,10289,10291],{"class":157,"line":9},[155,10287,10288],{"class":164},"SECRET",[155,10290,168],{"class":160},[155,10292,10293],{"class":171},"\"whsec_your_secret\"\n",[155,10295,10296,10299,10301],{"class":157,"line":255},[155,10297,10298],{"class":164},"URL",[155,10300,168],{"class":160},[155,10302,10303],{"class":171},"\"http:\u002F\u002Flocalhost:3000\u002Fwebhooks\u002Fslipbolt\"\n",[155,10305,10306],{"class":157,"line":274},[155,10307,278],{"emptyLinePlaceholder":277},[155,10309,10310,10313,10315,10318,10321,10324],{"class":157,"line":281},[155,10311,10312],{"class":164},"TS",[155,10314,168],{"class":160},[155,10316,10317],{"class":164},"$(",[155,10319,10320],{"class":289},"date",[155,10322,10323],{"class":171}," +%s",[155,10325,1717],{"class":164},[155,10327,10328,10331,10333,10336,10339,10342,10344,10347,10349],{"class":157,"line":302},[155,10329,10330],{"class":164},"BODY",[155,10332,168],{"class":160},[155,10334,10335],{"class":171},"'{\"event\":\"slip.verified\",\"id\":\"evt_local_'",[155,10337,10338],{"class":164},"$TS",[155,10340,10341],{"class":171},"'\",\"created\":'",[155,10343,10338],{"class":164},[155,10345,10346],{"class":171},"',\"data\":{\"transactionId\":\"txn_local_1\",\"transRef\":\"TEST'",[155,10348,10338],{"class":164},[155,10350,10351],{"class":171},"'\",\"amount\":250,\"status\":\"SUCCESS\",\"bankCode\":\"004\",\"bankName\":\"ธนาคารกสิกรไทย\",\"sender\":\"นาย ทดสอบ ระบบ\",\"receiver\":\"Your shop\",\"verifiedAt\":\"2026-06-17T03:21:06.412Z\",\"latencyMs\":480}}'\n",[155,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":157,"line":323},[155,10355,10356],{"class":164},"SIG",[155,10358,168],{"class":160},[155,10360,10317],{"class":164},[155,10362,10363],{"class":261},"printf",[155,10365,10366],{"class":171}," '%s.%s'",[155,10368,1670],{"class":171},[155,10370,10338],{"class":164},[155,10372,1053],{"class":171},[155,10374,1670],{"class":171},[155,10376,10377],{"class":164},"$BODY",[155,10379,1053],{"class":171},[155,10381,5661],{"class":160},[155,10383,10384],{"class":289}," openssl",[155,10386,10387],{"class":171}," dgst",[155,10389,10390],{"class":261}," -sha256",[155,10392,10393],{"class":261}," -hmac",[155,10395,1670],{"class":171},[155,10397,10398],{"class":164},"$SECRET",[155,10400,1053],{"class":171},[155,10402,5661],{"class":160},[155,10404,5675],{"class":289},[155,10406,10407],{"class":171}," 's\u002F^.*= \u002F\u002F'",[155,10409,1717],{"class":164},[155,10411,10412],{"class":157,"line":377},[155,10413,278],{"emptyLinePlaceholder":277},[155,10415,10416,10418,10421,10423,10425,10427,10430,10432],{"class":157,"line":394},[155,10417,5556],{"class":289},[155,10419,10420],{"class":261}," -i",[155,10422,5559],{"class":261},[155,10424,5562],{"class":171},[155,10426,1670],{"class":171},[155,10428,10429],{"class":164},"$URL",[155,10431,1053],{"class":171},[155,10433,5583],{"class":261},[155,10435,10436,10438,10440],{"class":157,"line":410},[155,10437,5588],{"class":261},[155,10439,5714],{"class":171},[155,10441,5583],{"class":261},[155,10443,10444,10446,10449],{"class":157,"line":13},[155,10445,5588],{"class":261},[155,10447,10448],{"class":171}," \"X-Slipbolt-Event: slip.verified\"",[155,10450,5583],{"class":261},[155,10452,10453,10455,10458,10460,10463,10466,10468],{"class":157,"line":431},[155,10454,5588],{"class":261},[155,10456,10457],{"class":171}," \"X-Slipbolt-Signature: t=",[155,10459,10338],{"class":164},[155,10461,10462],{"class":171},",v1=",[155,10464,10465],{"class":164},"$SIG",[155,10467,1053],{"class":171},[155,10469,5583],{"class":261},[155,10471,10472,10475,10477,10479],{"class":157,"line":437},[155,10473,10474],{"class":261},"  --data-binary",[155,10476,1670],{"class":171},[155,10478,10377],{"class":164},[155,10480,1111],{"class":171},[65,10482,10483,10485,10486,10488,10489,10491,10492,10494],{},[141,10484,4062],{}," = your handler verified the signature. Now change ",[141,10487,10288],{}," to something wrong and run it again — you must get ",[141,10490,3295],{},"\n(if you still get ",[141,10493,4062],{},", the handler is not really checking the signature). The Thai text in the body is deliberate:\nreal slips carry Thai names, and that is where a re-serialised body breaks the signature.",[2537,10496,10498],{"id":10497},"option-2-open-a-tunnel-and-let-the-real-system-call-you","Option 2 — open a tunnel and let the real system call you",[65,10500,10501],{},"Use this when you want events from real slips — open a tunnel with the tool you prefer (cloudflared, ngrok, …), for example",[146,10503,10505],{"className":148,"code":10504,"language":150,"meta":151,"style":151},"cloudflared tunnel --url http:\u002F\u002Flocalhost:3000\n",[141,10506,10507],{"__ignoreMap":151},[155,10508,10509,10512,10515,10518],{"class":157,"line":9},[155,10510,10511],{"class":289},"cloudflared",[155,10513,10514],{"class":171}," tunnel",[155,10516,10517],{"class":261}," --url",[155,10519,10520],{"class":171}," http:\u002F\u002Flocalhost:3000\n",[65,10522,10523,10524,10527,10528,10531,10532,10535],{},"Take the ",[141,10525,10526],{},"https:\u002F\u002F….trycloudflare.com"," URL it prints, append your handler's path, save it under ",[68,10529,10530],{},"Settings → Webhooks",",\nthen press ",[68,10533,10534],{},"Send test event"," — it uses no quota.",[174,10537,10539],{"id":10538},"pre-production-checklist","Pre-production checklist",[185,10541,10542,10549,10560,10574,10580,10591],{},[188,10543,10544,10545,10548],{},"Switch to an ",[141,10546,10547],{},"sk_live_"," key, kept in a server environment variable — not in code or in the repo",[188,10550,10551,10552,10556,10557,10559],{},"Run all ",[100,10553,10555],{"href":10554},"#release-the-order-only-when-all-4-checks-pass","4 checks"," before releasing an order, with ",[141,10558,2607],{}," UNIQUE in your database",[188,10561,10562,10563,10569,10570,10573],{},"Call ",[100,10564,10566],{"href":10565},"\u002Fdocs\u002Fapi#get-apiv1me",[141,10567,10568],{},"GET \u002Fme"," at boot — confirm the key belongs to the right shop and ",[141,10571,10572],{},"payeeAccounts"," lists the account customers pay into",[188,10575,10576,10577,10579],{},"Handle ",[141,10578,230],{}," (quota used up) by alerting your team, not silently — otherwise customers pay and their orders never close",[188,10581,10582,10583,10586,10587,10590],{},"If you use webhooks: verify the signature from the raw body · answer ",[141,10584,10585],{},"2xx"," within 10 seconds · skip an ",[141,10588,10589],{},"id"," you have already processed",[188,10592,10593,10594,10597,10598,10600],{},"Log the ",[141,10595,10596],{},"requestId"," (from ",[141,10599,43],{}," or from an error) — send it to us and we can trace the call straight away",[10602,10603,10604],"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":151,"searchDepth":274,"depth":274,"links":10606},[10607,10608,10613,10616,10620],{"id":176,"depth":255,"text":103},{"id":2522,"depth":255,"text":114,"children":10609},[10610,10611,10612],{"id":2539,"depth":274,"text":2540},{"id":2641,"depth":274,"text":2642},{"id":2911,"depth":274,"text":2912},{"id":5400,"depth":255,"text":125,"children":10614},[10615],{"id":8295,"depth":274,"text":8296},{"id":10257,"depth":255,"text":136,"children":10617},[10618,10619],{"id":10270,"depth":274,"text":10271},{"id":10497,"depth":274,"text":10498},{"id":10538,"depth":255,"text":10539},"Copy-paste code that actually runs — a client with retries, taking a slip from a customer and closing the order, sending the slip as multipart\u002Fbase64\u002FURL\u002FQR, testing webhooks locally","md",{},{"title":55,"description":10621},"docs\u002Frecipes",null,"revdaxtvVWs1na8Uyt3jbZUw2RVcEgY8xY85ZrGeVBo",1793286719468]