Webhooks

Delivery & Retry

What counts as a successful delivery, when Tonder retries, and how to avoid duplicates.

Tonder's webhook system is designed for reliability. If your endpoint is temporarily unavailable, we automatically retry the delivery.

How delivery works

A transaction status change or event occurs.

Tonder sends a POST request to your endpoint.

Your endpoint's response determines the next step.

Based on the response, the event is marked complete or scheduled for retry.

Retry policy

SettingValueDescription
Max retry attempts3We try to deliver the webhook up to 3 times.
Processing timeout30 seconds per attemptYour endpoint must respond within 30 seconds.
Retry interval60 secondsWe wait 60 seconds before retrying.
Total retry window~3 minutesThe maximum time spent retrying a single event.

Success and failure criteria

A delivery is successful if your endpoint responds with a 2xx code within 30 seconds. Any other response is a failure and a retry is scheduled. Scenarios that trigger retries:

  • 4xx errors (400, 401, 404, etc.) — client errors.
  • 5xx errors (500, 502, 503, etc.) — endpoint errors.
  • Timeouts when no response is received after 30 seconds.

Dead Letter Queue (DLQ)

After 3 failed attempts, the event is moved to a Dead Letter Queue for manual inspection. Failed events are stored for 30 days, accessible through the dashboard or via support, and can be retried manually after fixing the endpoint.

Implementation considerations

  • Acknowledge receipt immediately with a 200 OK to prevent timeouts.
  • Use metadata.external_id to deduplicate and avoid processing the same event twice.
  • Keep detailed logs of every webhook for debugging.
  • Ensure a malformed payload or a processing error doesn't crash your system.
  • Dedupe on metadata.external_id (works across Short + Long formats).
  • Keep an idempotency_key index in your DB.
  • Treat duplicate Pending + Success in Hybrid mode as intentional.
  • Always verify final status via GET /api/v1/transactions/{id}/.
  • Handle Declined for withdrawals as a terminal state.

Next steps

Was this page helpful?

On this page