[{"data":1,"prerenderedAt":611},["ShallowReactive",2],{"navigation-en":3,"en:\u002Fsandbox\u002Foverview":193,"en:\u002Fsandbox\u002Foverview:surround":606},[4,20,51,77,95,110,133,158,172],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting Started",false,"\u002Fgetting-started","1.getting-started",[10,15],{"title":11,"path":12,"stem":13,"icon":14},"Portal Preparation","\u002Fgetting-started\u002Fportal-setup","1.getting-started\u002F1.portal-setup","i-lucide-rocket",{"title":16,"path":17,"stem":18,"icon":19},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F2.quickstart","i-lucide-zap",{"title":21,"icon":22,"path":23,"stem":24,"children":25,"page":6},"Core Concepts","i-lucide-key-round","\u002Fconcepts","2.concepts",[26,31,36,41,46],{"title":27,"path":28,"stem":29,"icon":30},"Authentication","\u002Fconcepts\u002Fauthentication","2.concepts\u002F1.authentication","i-lucide-fingerprint",{"title":32,"path":33,"stem":34,"icon":35},"IP Allowlist","\u002Fconcepts\u002Fip-allowlist","2.concepts\u002F2.ip-allowlist","i-lucide-shield-check",{"title":37,"path":38,"stem":39,"icon":40},"Money Format","\u002Fconcepts\u002Fmoney","2.concepts\u002F3.money","i-lucide-banknote",{"title":42,"path":43,"stem":44,"icon":45},"Idempotency","\u002Fconcepts\u002Fidempotency","2.concepts\u002F4.idempotency","i-lucide-repeat",{"title":47,"path":48,"stem":49,"icon":50},"Error envelope & codes","\u002Fconcepts\u002Ferrors","2.concepts\u002F5.errors","i-lucide-octagon-alert",{"title":52,"icon":53,"path":54,"stem":55,"children":56,"page":6},"Deposits","i-lucide-arrow-down-to-line","\u002Fdeposits","3.deposits",[57,62,67,72],{"title":58,"path":59,"stem":60,"icon":61},"Deposit Overview & State Machine","\u002Fdeposits\u002Foverview","3.deposits\u002F1.overview","i-lucide-info",{"title":63,"path":64,"stem":65,"icon":66},"Create a Deposit","\u002Fdeposits\u002Fcreate","3.deposits\u002F2.create","i-lucide-plus",{"title":68,"path":69,"stem":70,"icon":71},"Get a Deposit","\u002Fdeposits\u002Fretrieve","3.deposits\u002F3.retrieve","i-lucide-search",{"title":73,"path":74,"stem":75,"icon":76},"Cancel a Deposit","\u002Fdeposits\u002Fcancel","3.deposits\u002F4.cancel","i-lucide-x",{"title":78,"icon":79,"path":80,"stem":81,"children":82,"page":6},"Withdrawals","i-lucide-arrow-up-from-line","\u002Fwithdrawals","4.withdrawals",[83,87,91],{"title":84,"path":85,"stem":86,"icon":61},"Withdrawal Overview","\u002Fwithdrawals\u002Foverview","4.withdrawals\u002F1.overview",{"title":88,"path":89,"stem":90,"icon":66},"Create a Withdrawal","\u002Fwithdrawals\u002Fcreate","4.withdrawals\u002F2.create",{"title":92,"path":93,"stem":94,"icon":71},"Get & List Withdrawals","\u002Fwithdrawals\u002Fretrieve","4.withdrawals\u002F3.retrieve",{"title":96,"icon":97,"path":98,"stem":99,"children":100,"page":6},"Balance & Banks","i-lucide-wallet","\u002Fbalance","5.balance",[101,105],{"title":102,"path":103,"stem":104,"icon":97},"Get Balance","\u002Fbalance\u002Fget-balance","5.balance\u002F1.get-balance",{"title":106,"path":107,"stem":108,"icon":109},"Bank List","\u002Fbalance\u002Fbanks","5.balance\u002F2.banks","i-lucide-landmark",{"title":111,"icon":112,"path":113,"stem":114,"children":115,"page":6},"Webhooks","i-lucide-webhook","\u002Fwebhooks","6.webhooks",[116,120,125,129],{"title":117,"path":118,"stem":119,"icon":61},"Webhook Overview","\u002Fwebhooks\u002Foverview","6.webhooks\u002F1.overview",{"title":121,"path":122,"stem":123,"icon":124},"Event Catalog & Payloads","\u002Fwebhooks\u002Fevents","6.webhooks\u002F2.events","i-lucide-list",{"title":126,"path":127,"stem":128,"icon":35},"Signature Verification","\u002Fwebhooks\u002Fsignature-verification","6.webhooks\u002F3.signature-verification",{"title":130,"path":131,"stem":132,"icon":45},"Endpoint Requirements, Retries & SSRF","\u002Fwebhooks\u002Fdelivery-and-retries","6.webhooks\u002F4.delivery-and-retries",{"title":134,"icon":135,"path":136,"stem":137,"children":138,"page":6},"Sandbox","i-lucide-flask-conical","\u002Fsandbox","7.sandbox",[139,143,148,153],{"title":140,"path":141,"stem":142,"icon":61},"Test Mode Overview","\u002Fsandbox\u002Foverview","7.sandbox\u002F1.overview",{"title":144,"path":145,"stem":146,"icon":147},"Simulate Transfer","\u002Fsandbox\u002Fsimulate-transfer","7.sandbox\u002F2.simulate-transfer","i-lucide-banknote-arrow-down",{"title":149,"path":150,"stem":151,"icon":152},"Top-up & Reset","\u002Fsandbox\u002Ftop-up-and-reset","7.sandbox\u002F3.top-up-and-reset","i-lucide-rotate-ccw",{"title":154,"path":155,"stem":156,"icon":157},"End-to-End Test Flow","\u002Fsandbox\u002Fe2e-test-flow","7.sandbox\u002F4.e2e-test-flow","i-lucide-list-checks",{"title":159,"icon":14,"path":160,"stem":161,"children":162,"page":6},"Go-live","\u002Fgo-live","8.go-live",[163,167],{"title":164,"path":165,"stem":166,"icon":157},"Go-live Checklist","\u002Fgo-live\u002Fchecklist","8.go-live\u002F1.checklist",{"title":168,"path":169,"stem":170,"icon":171},"Contact & Support","\u002Fgo-live\u002Fsupport","8.go-live\u002F2.support","i-lucide-life-buoy",{"title":173,"icon":174,"path":175,"stem":176,"children":177,"page":6},"Reference","i-lucide-book-marked","\u002Freference","9.reference",[178,183,188],{"title":179,"path":180,"stem":181,"icon":182},"Endpoint Catalog","\u002Freference\u002Fendpoints","9.reference\u002F1.endpoints","i-lucide-table",{"title":184,"path":185,"stem":186,"icon":187},"Code Samples (Node.js & PHP)","\u002Freference\u002Fcode-samples","9.reference\u002F2.code-samples","i-lucide-code",{"title":189,"path":190,"stem":191,"icon":192},"Status Values & Glossary","\u002Freference\u002Fglossary-states","9.reference\u002F3.glossary-states","i-lucide-book-a",{"id":194,"title":140,"badge":195,"body":196,"description":600,"extension":601,"links":195,"meta":602,"method":195,"navigation":603,"path":141,"seo":604,"stem":142,"__hash__":605},"docs_en\u002F7.sandbox\u002F1.overview.md",null,{"type":197,"value":198,"toc":592},"minimark",[199,225,239,244,251,318,329,356,360,364,368,380,448,455,465,485,489,564,567,571],[200,201,202,203,207,208,211,212,216,217,220,221,224],"p",{},"UnknownPay provides a ",[204,205,206],"strong",{},"Test Mode (Sandbox)"," that works Stripe-style: you call the ",[204,209,210],{},"same"," business endpoints (e.g. ",[213,214,215],"code",{},"POST \u002Fv1\u002Fdeposits","), but sign them with a ",[204,218,219],{},"test key"," instead of your live key. The system keeps test money and test data ",[204,222,223],{},"completely"," separate from live (the test ledger is a different namespace; test balances never mix with real balances), so you can rehearse the full end-to-end integration without touching real money.",[226,227,228],"warning",{},[200,229,230,231,234,235,238],{},"Every money field on the wire is always a ",[204,232,233],{},"baht string with 2 decimals",", e.g. ",[213,236,237],{},"\"100.50\""," — never a number, never satang — on both the request and the response side.",[240,241,243],"h2",{"id":242},"how-test-mode-is-enabled","How test mode is enabled",[200,245,246,247,250],{},"The mode is determined by the ",[204,248,249],{},"API key prefix"," that signs the request — not by the URL or host:",[252,253,254,273],"table",{},[255,256,257],"thead",{},[258,259,260,267,270],"tr",{},[261,262,263,264],"th",{},"Prefix of ",[213,265,266],{},"X-Api-Key",[261,268,269],{},"Mode",[261,271,272],{},"Effect",[274,275,276,296],"tbody",{},[258,277,278,284,289],{},[279,280,281],"td",{},[213,282,283],{},"unk_test_...",[279,285,286],{},[204,287,288],{},"test",[279,290,291,292,295],{},"Every request runs in test mode, money\u002Fledger isolated from live, and the ",[213,293,294],{},"\u002Fv1\u002Ftest\u002F*"," endpoints are unlocked.",[258,297,298,303,308],{},[279,299,300],{},[213,301,302],{},"unk_live_...",[279,304,305],{},[204,306,307],{},"live",[279,309,310,311,313,314,317],{},"Real money; calling ",[213,312,294],{}," returns ",[204,315,316],{},"404",".",[200,319,320,321,324,325,328],{},"The mode is always ",[204,322,323],{},"derived server-side"," from the key that verifies successfully. You ",[204,326,327],{},"do not"," (and cannot) send a mode flag yourself in the request.",[200,330,331,332,335,336,339,340,343,344,347,348,351,352,355],{},"Test keys are issued through the Portal\u002Fadmin (rotate-secret with ",[213,333,334],{},"?mode=test",") — you receive a ",[213,337,338],{},"key_id"," pair (prefixed ",[213,341,342],{},"unk_test_",") plus a ",[204,345,346],{},"show-once"," ",[213,349,350],{},"secret"," (see the steps in ",[353,354,11],"a",{"href":12},").",[357,358],"placeholder-image",{"subject":359},"Portal screen issuing\u002Frotating a Test API key, with a key_id prefixed unk_test_",[361,362],"placeholder-note",{"value":363},"the exact Portal UI steps for issuing a Test key (which menu, which role)",[240,365,367],{"id":366},"request-signing-s2s-identical-to-live","Request signing (S2S) — identical to live",[200,369,370,372,373,376,377,379],{},[213,371,294],{}," uses the ",[204,374,375],{},"same S2S HMAC"," as the live money POSTs. You must send these headers (signing details are in ",[353,378,27],{"href":28},"):",[252,381,382,392],{},[255,383,384],{},[258,385,386,389],{},[261,387,388],{},"Header",[261,390,391],{},"Description",[274,393,394,405,419,432],{},[258,395,396,400],{},[279,397,398],{},[213,399,266],{},[279,401,402,403,355],{},"Your key id (in test mode, prefixed ",[213,404,342],{},[258,406,407,412],{},[279,408,409],{},[213,410,411],{},"X-Timestamp",[279,413,414,415,418],{},"Unix epoch seconds; must be within ",[204,416,417],{},"±300 seconds"," or it is rejected (replay reject).",[258,420,421,426],{},[279,422,423],{},[213,424,425],{},"X-Signature",[279,427,428,431],{},[213,429,430],{},"HMAC-SHA256(secret, base)"," as hex.",[258,433,434,439],{},[279,435,436],{},[213,437,438],{},"Idempotency-Key",[279,440,441,444,445,447],{},[204,442,443],{},"Required"," for all three ",[213,446,294],{}," endpoints (replaying the same key returns the same result).",[200,449,450,451,454],{},"The ",[213,452,453],{},"base"," (canonical string) is:",[456,457,462],"pre",{"className":458,"code":460,"language":461},[459],"language-text","\u003CMETHOD>\\n\u003Cpath+query>\\n\u003CX-Timestamp>\\nSHA256_hex(\u003Craw body bytes>)\n","text",[213,463,460],{"__ignoreMap":464},"",[466,467,468],"note",{},[200,469,470,471,474,475,477,478,481,482,484],{},"If any header is missing, or the signature\u002Ftimestamp does not pass, you get ",[213,472,473],{},"401 UNAUTHORIZED",". If ",[213,476,438],{}," is missing, you get ",[213,479,480],{},"400 IDEMPOTENCY_KEY_REQUIRED",". If you reuse the same ",[213,483,438],{}," with a different body, you get an error that the key was reused with a different request.",[240,486,488],{"id":487},"key-limits-and-behavior","Key limits and behavior",[490,491,492,508,517,548],"ul",{},[493,494,495,500,501,504,505,507],"li",{},[204,496,497,498],{},"Using a test endpoint with a live key → ",[213,499,316],{}," (the ",[213,502,503],{},"RequireTestMode"," gate) — ",[213,506,294],{}," is deliberately \"invisible\" to live keys.",[493,509,510,513,514,355],{},[204,511,512],{},"Top-up cap:"," 1,000,000 baht per call (over → ",[213,515,516],{},"422 AMOUNT_TOO_LARGE",[493,518,519,347,522,525,526,529,530,533,534,539,540,543,544,547],{},[204,520,521],{},"Rate cap on data-creating triggers:",[213,523,524],{},"simulate-transfer"," and ",[213,527,528],{},"top-up"," are capped at ",[204,531,532],{},"60 calls\u002Fminute per merchant","; over the limit → ",[204,535,536],{},[213,537,538],{},"429 RATE_LIMITED"," (",[213,541,542],{},"\"too many sandbox requests; slow down\"","). ",[213,545,546],{},"reset"," is not capped.",[493,549,550,553,554,556,557,560,561,317],{},[204,551,552],{},"Idempotency:"," all three endpoints require an ",[213,555,438],{},"; replaying the same key with the same body returns the same result (24-hour window), scoped per ",[213,558,559],{},"(mode, merchant)"," → ",[213,562,563],{},"test:\u003Cmerchant_id>",[361,565],{"value":566},"whether the sandbox base URL is the same domain as production or a separate domain (the mode comes from the key, not the host)",[240,568,570],{"id":569},"next-steps","Next steps",[490,572,573,578,583],{},[493,574,575,577],{},[353,576,144],{"href":145}," — inject a bank transfer into a PENDING test deposit.",[493,579,580,582],{},[353,581,149],{"href":150}," — credit your test balance and wipe your test data.",[493,584,585,587,588,591],{},[353,586,154],{"href":155}," — the recommended full rehearsal that drives a ",[213,589,590],{},"deposit.success"," webhook.",{"title":464,"searchDepth":593,"depth":594,"links":595},1,2,[596,597,598,599],{"id":242,"depth":594,"text":243},{"id":366,"depth":594,"text":367},{"id":487,"depth":594,"text":488},{"id":569,"depth":594,"text":570},"Sandbox \u002F Test Mode works Stripe-style — same business endpoints, signed with a test key, on a fully isolated test ledger","md",{},{"icon":61},{"title":140,"description":600},"7dqf6skgoCxJ2JfSw_Rr4ZaqqGmi1q18sAJ5ViJ21S4",[607,609],{"title":130,"path":131,"stem":132,"description":608,"icon":45,"children":-1},"What your webhook endpoint must do, the retry\u002Fbackoff schedule, replay, and the HTTPS\u002FSSRF rules that reject an INVALID_URL",{"title":144,"path":145,"stem":146,"description":610,"icon":147,"children":-1},"Inject a simulated bank transfer into a PENDING test deposit to drive the real matcher and a deposit.success webhook",1781891157166]