[{"data":1,"prerenderedAt":693},["ShallowReactive",2],{"navigation-en":3,"en:\u002Fconcepts\u002Fidempotency":193,"en:\u002Fconcepts\u002Fidempotency:surround":688},[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":42,"badge":195,"body":196,"description":682,"extension":683,"links":195,"meta":684,"method":195,"navigation":685,"path":43,"seo":686,"stem":44,"__hash__":687},"docs_en\u002F2.concepts\u002F4.idempotency.md",null,{"type":197,"value":198,"toc":676},"minimark",[199,212,217,275,279,313,358,362,366,387,390,450,473,477,509,512,651,669,672],[200,201,202,203,207,208,211],"p",{},"Every endpoint that ",[204,205,206],"strong",{},"creates\u002Fmoves money"," (a money-moving POST) must send a header to prevent duplication. If the network times out and the merchant retries, the system returns the ",[204,209,210],{},"original result"," instead of creating a duplicate record.",[213,214,216],"h2",{"id":215},"_1-header","1. Header",[218,219,220,236],"table",{},[221,222,223],"thead",{},[224,225,226,230,233],"tr",{},[227,228,229],"th",{},"Header",[227,231,232],{},"Direction",[227,234,235],{},"Meaning",[237,238,239,254],"tbody",{},[224,240,241,248,251],{},[242,243,244],"td",{},[245,246,247],"code",{},"Idempotency-Key",[242,249,250],{},"request (merchant sends)",[242,252,253],{},"A merchant-defined key bound to a single transaction attempt",[224,255,256,261,264],{},[242,257,258],{},[245,259,260],{},"Idempotent-Replay",[242,262,263],{},"response (system returns)",[242,265,266,267,270,271,274],{},"If set to ",[245,268,269],{},"true",", this response is a ",[204,272,273],{},"replay"," from cache — no new record was created",[213,276,278],{"id":277},"_2-endpoints-that-require-it-money-moving-post-on-the-s2s-side","2. Endpoints that require it (money-moving POST on the S2S side)",[218,280,281,291],{},[221,282,283],{},[224,284,285,288],{},[227,286,287],{},"Method + Path",[227,289,290],{},"Description",[237,292,293,303],{},[224,294,295,300],{},[242,296,297],{},[245,298,299],{},"POST \u002Fv1\u002Fdeposits",[242,301,302],{},"Create a deposit",[224,304,305,310],{},[242,306,307],{},[245,308,309],{},"POST \u002Fv1\u002Fwithdrawals",[242,311,312],{},"Create a payout\u002Fwithdrawal",[314,315,316,334],"warning",{},[200,317,318,319,322,323,325,326,329,330,333],{},"If you call these endpoints ",[204,320,321],{},"without"," sending the ",[245,324,247],{}," header, the system responds with HTTP ",[245,327,328],{},"400"," and code ",[245,331,332],{},"IDEMPOTENCY_KEY_REQUIRED"," immediately — it is a mandatory header.",[200,335,336,339,340,343,344,343,347,350,351,354,355,357],{},[204,337,338],{},"GET \u002F cancel \u002F read-back"," endpoints (e.g. ",[245,341,342],{},"GET \u002Fv1\u002Fdeposits\u002F:id",", ",[245,345,346],{},"GET \u002Fv1\u002Fwithdrawals",[245,348,349],{},"POST \u002Fv1\u002Fdeposits\u002F:id\u002Fcancel",") ",[204,352,353],{},"do not"," need to send ",[245,356,247],{},".",[359,360],"placeholder-note",{"value":361},"confirm the full list of S2S money-moving POSTs, in case there are additional S2S endpoints that create money",[213,363,365],{"id":364},"_3-ttl-and-replay-behavior","3. TTL and replay behavior",[367,368,369,376],"ul",{},[370,371,372,375],"li",{},[204,373,374],{},"TTL = 24 hours"," — within 24 h, a retry with the same key returns the original result. After that the old key is considered expired (purged) and is treated as a new record.",[370,377,378,379,382,383,386],{},"The ",[204,380,381],{},"scope of the key"," is separated by the (mode, entity) of the caller that the system derives from the credential — i.e. the same key in ",[204,384,385],{},"live and test will not collide"," (a test replay will not return a live result, and vice versa). The merchant does not have to manage scope.",[200,388,389],{},"Behavior across 3 cases:",[218,391,392,402],{},[221,393,394],{},[224,395,396,399],{},[227,397,398],{},"Situation",[227,400,401],{},"Result",[237,403,404,422,440],{},[224,405,406,412],{},[242,407,408,411],{},[204,409,410],{},"Same key + same body"," (path\u002Fmethod\u002Fbody all match)",[242,413,414,415,418,419],{},"The system replays the original response (same status + body) with header ",[245,416,417],{},"Idempotent-Replay: true"," — ",[204,420,421],{},"no new record is created",[224,423,424,429],{},[242,425,426],{},[204,427,428],{},"Same key + different body",[242,430,431,432,435,436,439],{},"The system rejects with HTTP ",[245,433,434],{},"422"," code ",[245,437,438],{},"IDEMPOTENCY_KEY_MISMATCH"," — \"Idempotency-Key was reused with a different request\" (prevents reusing a key for a different transaction)",[224,441,442,447],{},[242,443,444],{},[204,445,446],{},"New key",[242,448,449],{},"Processed as a new record as usual",[451,452,453,466],"caution",{},[200,454,455,456,459,460,462,463,357],{},"The system binds the key to the ",[204,457,458],{},"method + path + the entire body"," (a hash), so even a tiny change to the body with the same key is rejected as ",[245,461,438],{}," — when retrying you must send the ",[204,464,465],{},"exact same body",[200,467,468,469,472],{},"If a prior record failed with a server-level error (HTTP 5xx), the system rolls everything back — a retry with the same key can ",[204,470,471],{},"re-run cleanly"," (it does not get stuck on a dangling in-progress).",[213,474,476],{"id":475},"_4-recommended-key-format","4. Recommended key format",[367,478,479,493,502],{},[370,480,481,482,485,486,489,490,357],{},"The system ",[204,483,484],{},"does not enforce a format or length"," for the key — it accepts any string that is ",[204,487,488],{},"non-empty"," but must be ",[204,491,492],{},"unique per record",[370,494,495,498,499,357],{},[204,496,497],{},"Use a UUID v4"," (random, collision chance near zero), e.g. ",[245,500,501],{},"9f1c2e7a-3b4d-4f8a-9c10-2b6d5e7f8a90",[370,503,504,505,508],{},"Generate 1 key per transaction intent and ",[204,506,507],{},"keep that key"," so you can retry with the same key when the network fails.",[200,510,511],{},"Example request (deposit) with idempotency:",[513,514,519],"pre",{"className":515,"code":516,"language":517,"meta":518,"style":518},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl -X POST https:\u002F\u002Fapi.unkpay.co\u002Fv1\u002Fdeposits \\\n  -H \"X-Api-Key: unk_live_xxxxxxxxxxxx\" \\\n  -H \"X-Timestamp: 1718790000\" \\\n  -H \"X-Signature: \u003Chex hmac-sha256 per the canonical string>\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -H \"Idempotency-Key: 9f1c2e7a-3b4d-4f8a-9c10-2b6d5e7f8a90\" \\\n  -d '{\n    \"amount\": \"100.50\",\n    \"currency\": \"THB\"\n  }'\n","bash","",[245,520,521,544,562,576,590,604,618,630,636,642],{"__ignoreMap":518},[522,523,526,530,534,537,540],"span",{"class":524,"line":525},"line",1,[522,527,529],{"class":528},"sBMFI","curl",[522,531,533],{"class":532},"sfazB"," -X",[522,535,536],{"class":532}," POST",[522,538,539],{"class":532}," https:\u002F\u002Fapi.unkpay.co\u002Fv1\u002Fdeposits",[522,541,543],{"class":542},"sTEyZ"," \\\n",[522,545,547,550,554,557,560],{"class":524,"line":546},2,[522,548,549],{"class":532},"  -H",[522,551,553],{"class":552},"sMK4o"," \"",[522,555,556],{"class":532},"X-Api-Key: unk_live_xxxxxxxxxxxx",[522,558,559],{"class":552},"\"",[522,561,543],{"class":542},[522,563,565,567,569,572,574],{"class":524,"line":564},3,[522,566,549],{"class":532},[522,568,553],{"class":552},[522,570,571],{"class":532},"X-Timestamp: 1718790000",[522,573,559],{"class":552},[522,575,543],{"class":542},[522,577,579,581,583,586,588],{"class":524,"line":578},4,[522,580,549],{"class":532},[522,582,553],{"class":552},[522,584,585],{"class":532},"X-Signature: \u003Chex hmac-sha256 per the canonical string>",[522,587,559],{"class":552},[522,589,543],{"class":542},[522,591,593,595,597,600,602],{"class":524,"line":592},5,[522,594,549],{"class":532},[522,596,553],{"class":552},[522,598,599],{"class":532},"Content-Type: application\u002Fjson",[522,601,559],{"class":552},[522,603,543],{"class":542},[522,605,607,609,611,614,616],{"class":524,"line":606},6,[522,608,549],{"class":532},[522,610,553],{"class":552},[522,612,613],{"class":532},"Idempotency-Key: 9f1c2e7a-3b4d-4f8a-9c10-2b6d5e7f8a90",[522,615,559],{"class":552},[522,617,543],{"class":542},[522,619,621,624,627],{"class":524,"line":620},7,[522,622,623],{"class":532},"  -d",[522,625,626],{"class":552}," '",[522,628,629],{"class":532},"{\n",[522,631,633],{"class":524,"line":632},8,[522,634,635],{"class":532},"    \"amount\": \"100.50\",\n",[522,637,639],{"class":524,"line":638},9,[522,640,641],{"class":532},"    \"currency\": \"THB\"\n",[522,643,645,648],{"class":524,"line":644},10,[522,646,647],{"class":532},"  }",[522,649,650],{"class":552},"'\n",[652,653,654],"note",{},[200,655,656,657,660,661,664,665,668],{},"For how to compute ",[245,658,659],{},"X-Signature",", see ",[662,663,27],"a",{"href":28}," or use a ready-made client from the ",[662,666,667],{"href":185},"Code Samples"," that signs automatically.",[359,670],{"value":671},"confirm the Authorization \u002F HMAC header form of S2S in the Authentication section; this example uses only fields that exist (amount, currency) — add other CreateReq fields per the real spec",[673,674,675],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}",{"title":518,"searchDepth":525,"depth":546,"links":677},[678,679,680,681],{"id":215,"depth":546,"text":216},{"id":277,"depth":546,"text":278},{"id":364,"depth":546,"text":365},{"id":475,"depth":546,"text":476},"Every money-moving POST requires an Idempotency-Key header so a retry returns the original result instead of creating a duplicate","md",{},{"icon":45},{"title":42,"description":682},"fC-yQTTmUkmUk8vaUjCJQvxVE2Ur5FQ9erJlCzJXkxE",[689,691],{"title":37,"path":38,"stem":39,"description":690,"icon":40,"children":-1},"Every money field on the wire is a baht string with exactly 2 decimals, e.g. \"100.50\" — never a number, never satang",{"title":47,"path":48,"stem":49,"description":692,"icon":50,"children":-1},"Every error uses one JSON envelope — branch on error.code, never the message — plus the consolidated cross-cutting error reference",1781891152608]