Delivery and Retries
What counts as a delivered webhook, how Tonder retries a failed one, and how to resend events yourself.
Tonder treats an event as delivered when your server answers any 2xx in under 10 seconds.
If it doesn't, Tonder retries automatically — up to 6 attempts over about 8.5 hours — and you can
resend any event yourself from the Events log.
Webhooks 2.0 is enabled per account. If Developers in your dashboard has no Events tab, your account is on the previous version: ask your Tonder contact to enable it.
Without Webhooks 2.0, each event is delivered once.
Retry schedule
| Attempt | Wait since the previous attempt |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
Each wait varies by ±10% so retries don't all land on your server at once. If the 6th attempt fails, the event is Failed.

How Tonder reads your response
| Your server answers | What happens |
|---|---|
Any 2xx within 10 seconds | Delivered. No more attempts. |
429 or 503 with a Retry-After header | The next attempt waits as long as you ask, up to 6 hours. |
410 Gone | The endpoint no longer exists: the event is Failed, with no more attempts. |
| Any other code, a timeout or a connection error | Retried on the schedule above. |
A disabled or deleted endpoint gets no retries: its pending events end as Failed with "Endpoint unavailable".
Resend events yourself
One event. In the Events log, open the event and click Resend event.
- If the event was still being retried and your resend fails, it keeps the automatic attempts it had left.
- If it was already Failed or Delivered, the resend is a single attempt.
- You can't resend while an automatic attempt is about to go out (±1 minute), or twice within 30 seconds.
Every failed event. Retry all resends the Failed events that match the current filter — up to 5,000, at 10 per second.
Manual resends count toward the total attempts but not toward the 6 automatic ones, so a counter
can read 7/6.
What this means for your integration
- Answer
2xximmediately, then process in your own queue — you have 10 seconds. - Deduplicate on the
webhook-idheader. A retry or a resend carries the samewebhook-id. - Don't rely on arrival order. A retried
payment_Pendingcan arrive afterpayment_Success; use the payload'sstatusandcreated. - After an outage, check the Events log once your server is back: anything left Failed can be resent.
- Dedupe on the
webhook-idheader with Webhooks 2.0 — a retry or a resend carries the same one. Without Webhooks 2.0, dedupe onid+event_type. Correlate withmetadata.external_id, which repeats on every event of a transaction and works across Short + Long formats. - Keep processed
webhook-ids for at least 60 days — an event can be resent while it is kept. - Keep an
idempotency_keyindex in your DB. - Treat duplicate Pending + Success in Hybrid mode as intentional.
- Always verify final status via
GET /api/v1/transactions/{id}/. - Handle all five withdrawal terminal states —
Success,Declined,Cancelled,FailedandReturned;Returnedarrives afterSuccess.
Without Webhooks 2.0
Accounts on the previous version get each event once. The response is recorded, but it does not trigger a redelivery:
| Response | What we do |
|---|---|
| 2xx within 30 seconds | Delivery 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. |
Reconcile by polling GET /api/v1/transactions/{id}/ for any period during which your endpoint was
unavailable or returning errors, and if you detect lost events, contact
support with the date range. Deduplicate on id + event_type:
metadata.external_id repeats on every event of the same transaction, so it correlates but cannot
tell Pending from Success.
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.
