Skip to content
UnknownPay
ไทย
Webhooks

Endpoint Requirements, Retries & SSRF

What your webhook endpoint must do, the retry/backoff schedule, replay, and the HTTPS/SSRF rules that reject an INVALID_URL

Merchant endpoint requirements

You must:

  • Accept an HTTP POST at the URL you configured and return HTTP 2xx (200–299) on successful receipt — any other status counts as "delivery failed" and will be retried.
  • Respond quickly: our client has a total 10-second timeout per request (5-second connect timeout). Responding too slowly counts as a failure → retry. We recommend you ack 2xx immediately and process asynchronously.
  • Do idempotency with event_id: the event_id (<id>:<event_type>) is stable for one event throughout. Retries/replays send the same event_id — if you have already processed it, return 2xx without doing the work again (e.g. store received event_ids in your DB with a unique constraint).
Never trust a single delivery — process by event_id idempotently. Retries and replays re-send the same event_id; if you have already handled it, return 2xx and do not re-apply the effect.

How the system retries

  • If you return non-2xx, time out, or are unreachable → the system retries with exponential backoff.
  • Maximum 9 attempts (the first one + retries) per this backoff schedule:
    retry #delay before re-sending
    110 seconds
    21 minute
    35 minutes
    430 minutes
    52 hours
    66 hours
    712 hours
    824 hours

    The total retry window is roughly 24 hours. After that the event is considered terminal failed (it is logged).
  • Circuit breaker: if your URL fails 5 times in a row, the system "opens the breaker" and temporarily stops sending to that URL for 1 minute, then tries again (to avoid hammering a downed endpoint) — this does not affect each event's 24-hour deadline.
  • Replay: you can re-send the same event from the delivery log page in the Portal (the system enqueues a new delivery with the same event_id).

You can view the delivery history (delivery log) on the Webhook page in the Portal — filterable by status. Each record has: event_id, event_type, status (delivered / retrying / failed), attempts, created_at (no payload, to prevent PII leaks).

URL requirements (HTTPS + SSRF)

The destination URL must pass these conditions (checked at configuration time → returns 422 INVALID_URL if it fails, and re-checked at real dial time as a backstop):

  • Must be https:// onlyhttp:// is rejected, and redirects that downgrade to non-https are blocked.
  • Must not point to internal/private addresses (SSRF protection) — hosts that resolve to these IPs are rejected:
    • loopback (127.0.0.1, ::1)
    • RFC1918 private (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
    • link-local / cloud metadata (169.254.0.0/16, e.g. 169.254.169.254)
    • carrier-grade NAT RFC 6598 (100.64.0.0/10)
    • unspecified (0.0.0.0) and IPv6 ULA (fc00::/7)
  • Redirects may be followed up to 5 hops, and every hop must be https.
Your endpoint must therefore be a public host with TLS (a real domain + a valid certificate). You cannot use localhost, an internal IP, or a tunnel that resolves to a private IP.
Pending confirmation — if you need to test locally, specify the recommended method (e.g. a public HTTPS tunnel that resolves to a public IP)