Go-live
Go-live Checklist
Everything to verify before switching from test to live — credentials, money, idempotency, deposit, withdrawal, webhook, and sandbox
Before switching from test to real live, verify every item below.
The two highest-impact mistakes are the 100× money bug (sending or reading money as a number / satang instead of a baht string) and treating
201 PENDING as success for a withdrawal. Confirm both are handled before you go live.Credentials & connectivity
- You have a live API key + secret stored in a secret store (not hardcoded in code/repo) — the secret is shown only once; if lost, you must rotate.
- Your server's clock is synced with NTP (to keep
X-Timestampwithin the ±300-second window). - Your HMAC signing code signs the same raw body bytes you actually send, and includes the query string on line 2 of the canonical string.
- You have reported the production server IP/CIDR to the UnknownPay team to be added to the IP allowlist (surface
s2s) and confirmed requests pass.
Money (avoid the 100× bug)
- Every money field is sent/read as a baht string with 2 decimals — not a number and not satang.
- Money is parsed as a decimal, not a float.
- You handle money fields that are
null/ omitted (e.g.matched_amount,credited_amountbefore credited).
Idempotency & errors
- Every
POST /v1/depositsandPOST /v1/withdrawalssends anIdempotency-Key(UUID v4), and retries reuse the same key + same body. - Logic branches on
error.code(never parses the message) and is default-safe for unknown codes. - You log
error.request_idon every error so you can report it to the team.
Deposit flow
- You show the customer
expected_amountto transfer (notamount), and useqr_payloadfor PROMPTPAY_QR. - You send all 3 payer fields (anti-fraud) for both PROMPTPAY_QR and BANK_TRANSFER.
- You handle deposit expiry (~5–7 minutes) by creating a new one.
Withdrawal flow
- You do not treat
201 PENDINGas success — wait for the terminal webhook only. - You check
availablefromGET /v1/balancebefore withdrawing (≥amount+fee). - You send
receiver_bank_provideras abank_code(notbank_number) fromGET /v1/banks. - You handle the
withdrawal.failed/withdrawal.rejected/withdrawal.refundedwebhooks (the money returns to the wallet).
Webhook
- Your endpoint is HTTPS public (valid TLS, not localhost / a private IP).
- You verify the
X-Webhook-Signaturefrom the raw body bytes in constant time. - You apply idempotency by
event_id(to avoid reprocessing on retry/replay). - You return 2xx fast (< 10 seconds) and process asynchronously.
- You subscribe to all events you need and the Portal "test" button has passed.
Sandbox
- You have run the full
deposit.successflow in test mode (create deposit → simulate-transfer → receive webhook) successfully.
Pending confirmation — add/remove checklist items to match your team's real onboarding policy, and confirm whether a sign-off step with the team is required before enabling live
