Skip to content
UnknownPay
ไทย
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-Timestamp within 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_amount before credited).

Idempotency & errors

  • Every POST /v1/deposits and POST /v1/withdrawals sends an Idempotency-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_id on every error so you can report it to the team.

Deposit flow

  • You show the customer expected_amount to transfer (not amount), and use qr_payload for 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 PENDING as success — wait for the terminal webhook only.
  • You check available from GET /v1/balance before withdrawing (≥ amount + fee).
  • You send receiver_bank_provider as a bank_code (not bank_number) from GET /v1/banks.
  • You handle the withdrawal.failed / withdrawal.rejected / withdrawal.refunded webhooks (the money returns to the wallet).

Webhook

  • Your endpoint is HTTPS public (valid TLS, not localhost / a private IP).
  • You verify the X-Webhook-Signature from 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.success flow 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