Webhooks
Retries & Timeouts

Retries & Timeouts

Retry Behavior

Retry behavior depends on whether the webhook is synchronous or asynchronous — they use two different delivery paths.

WITHDRAW_REQUEST

WITHDRAW_REQUEST is delivered synchronously by default, but asynchronously (via the durable outbox, same as below) when your operator is on external-approval mode — in that mode the decision comes from your POST /withdraw/:id/decision callback, not from the webhook response. See Withdrawals.

Synchronous mode: delivered inline while AbstraPay waits for your approve/deny response. The inline client retries up to 2 times with a 5-second delay between attempts. Only network-level errors are retried:

  • Connection reset (ECONNRESET)
  • Timeout (ETIMEDOUT)
  • Connection refused (ECONNREFUSED)
  • Host unreachable (EHOSTUNREACH)
  • HTTP 5xx, 408, 429 responses

Application-level errors (non-zero error code in the response) are not retried.

Asynchronous — DEPOSIT and WITHDRAW_COMPLETE

These events are delivered through a durable outbox, not inline. If your endpoint is unreachable or returns an error, the outbox retries up to 5 attempts with exponential backoff (~20s, then 40s, 80s, … capped at 15 minutes between attempts). After the attempts are exhausted, the event is moved to a dead-letter queue for manual retry from the management panel (see Management Panel) — nothing is silently dropped.

⚠️

Make your handler idempotent. Because the outbox retries, the same DEPOSIT or WITHDRAW_COMPLETE event may be delivered to you more than once. Deduplicate deposits on idempotencyKey and withdrawal completions on withdrawRequestId (the withdrawal UUID — the same id sent on WITHDRAW_REQUEST; a separate sessionId field carries the session), and ignore duplicates, so you never credit or debit a user twice.


Timeouts

TimeoutValue
Connect10 seconds
Headers10 seconds
Body15 seconds

Ensure your endpoint responds within these limits.