Delivery

How a webhook is delivered, what counts as a successful delivery, and how to recover events your endpoint missed.

Tonder sends each event to your endpoint once. Your endpoint's response is recorded, but it does not trigger a redelivery — so your integration needs its own way to recover an event it rejected or missed.

How delivery works

A transaction status change or event occurs.

Tonder sends a POST request to your endpoint.

Your endpoint's response is recorded as a successful or a failed delivery.

Success and failure criteria

A delivery is successful if your endpoint responds with a 2xx code within 30 seconds.

ResponseWhat we do
2xx within 30 secondsDelivery recorded as successful.
4xx (400, 401, 404, etc.)Delivery recorded as failed. An internal alert is raised. The event is not resent.
5xx (500, 502, 503, etc.)Delivery recorded as failed. An internal alert is raised. The event is not resent.
Timeout (no response after 30 seconds)Delivery recorded as failed. An internal alert is raised. The event is not resent.

What this means for your integration

An event your endpoint rejects or misses is not redelivered. Build for that:

  • Answer 2xx immediately, before running your business logic, so that an internal error on your side does not turn a delivered event into a failed one.
  • Reconcile by polling GET /api/v1/transactions/{id}/ for any period during which your endpoint was unavailable or returning errors.
  • If you detect lost events, contact support with the date range.

Do not treat the webhook as your only source of truth. A payment or withdrawal whose notification you never received still reached its final status — the transaction endpoint always has it.

Implementation considerations

  • 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