Resend webhook deliveries
Manually re-deliver failed webhook events — optionally to a different endpoint.
One call, two ways to say WHICH deliveries. The simple way: pass a query — endpoint, event type, time window — and the server finds every failed delivery that matches and re-posts it (newest first, up to limit). The precise way: pass exact deliveries pairs when you already know them. Each accepted delivery is re-sent exactly once in the background — manual resends never enter the automatic retry schedule — and lands as a new manual attempt in the delivery history. Pass target_webhook_id with either mode to redirect every resend to another endpoint of your account (for example, after replacing a broken receiver).
POST /v3/webhooks/deliveries/resend
Resend by query (recommended)
No listing, no pair-building: describe the failures and the server does the rest. All filters are optional — an empty query: {} means "every failed delivery of the last 24 hours, on any endpoint".
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_id | UUID | Optional | Only deliveries to this endpoint. Omit to cover every endpoint of your account. |
event | string | Optional | Only deliveries of this event type — e.g. bounced, delivered, complained. |
since | ISO-8601 | Optional | Window start. Default: 24 hours ago; reaches at most 90 days back. |
until | ISO-8601 | Optional | Window end. Default: now. |
limit | integer | Optional | Resend at most this many (newest first), 1–100. Default 100. When has_more is true in the response, repeat the same call to drain the rest. |
Resend exact deliveries (advanced)
| Parameter | Type | Required | Description |
|---|---|---|---|
deliveries | array | Optional | 1–100 items of { webhook_id, event_id } — for when you already know exactly which deliveries to re-post. Provide either deliveries OR query, never both. |
target_webhook_id | UUID | Optional | Works with both modes. Redirect: post every resend to this endpoint of your account instead of each delivery’s original endpoint. Must be an enabled endpoint; the redirect (source endpoint + time) is recorded on the delivery history and in the audit trail. |
Eligibility
Only deliveries whose latest attempt is failed are resendable, and only real event deliveries — endpoint-test attempts have no source event and are skipped. Everything else is reported back with a reason: not_failed (latest attempt succeeded or is still retrying), not_found (no such delivery in the last 90 days), or locked (the same delivery was already submitted within the last 60 seconds — duplicate submissions are deduplicated).
Replay markers
Every resent delivery carries two extra request headers so your receiver can deduplicate safely when the original was actually processed before an outage: X-Wemail-Replay: true (present only on manual resends — organic first deliveries and automatic retries never send it) and X-Wemail-Delivery-Id: <event_id> — the source event id, stable across every replay of the same delivery and identical to the event_id you pass to this endpoint. The X-Webhook-Attempt header keeps counting from the delivery’s existing history (a first resend after 3 failed tries arrives as attempt 4).
Retention
Resend reaches up to 90 days back, bounded by your plan’s delivery-history retention: 30 days on Free, 12 months on paid plans — the same window as events and the Console Activity grid.
Responses
| Status | Description |
|---|---|
200 | OK. { results: [{ webhook_id, event_id, accepted, reason }], accepted_count, skipped_count, matched_count, has_more } — per-delivery acceptance detail; has_more (query mode) means more matches exist beyond limit, so repeat the call. |
400 | Validation error — malformed body, or target_webhook_id is not an enabled endpoint of your account. |
401 | Missing or invalid API key. |
429 | Rate limit exceeded (30 calls/minute). |
Code examples
# Resend two failed deliveries, redirected to a backup endpoint
curl -X POST https://api.wemail.io/v3/webhooks/deliveries/resend \
-H "Authorization: Bearer afn_live_…" \
-H "Content-Type: application/json" \
-d '{
"deliveries": [
{ "webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "event_id": "evt_01J8ZQ3K9WVA7M2P" },
{ "webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "event_id": "evt_01J8ZQ4T2XNC8R5D" }
],
"target_webhook_id": "4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
}'// Resend failed deliveries — here redirected to a backup endpoint
// of the same account. Only failed deliveries are eligible.
const { results } = await wemail.webhooks.resendDeliveries({
deliveries: [
{ webhook_id: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", event_id: "evt_01J8ZQ3K9WVA7M2P" },
{ webhook_id: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", event_id: "evt_01J8ZQ4T2XNC8R5D" },
],
target_webhook_id: "4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
});
for (const r of results) console.log(r.event_id, r.accepted, r.reason);result = wemail.webhooks.resend_deliveries(
deliveries=[
{"webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "event_id": "evt_01J8ZQ3K9WVA7M2P"},
{"webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "event_id": "evt_01J8ZQ4T2XNC8R5D"},
],
target_webhook_id="4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
)
for r in result["results"]:
print(r["event_id"], r["accepted"], r["reason"])$result = $wemail->webhooks->resendDeliveries([
'deliveries' => [
['webhook_id' => '9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c', 'event_id' => 'evt_01J8ZQ3K9WVA7M2P'],
['webhook_id' => '9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c', 'event_id' => 'evt_01J8ZQ4T2XNC8R5D'],
],
'target_webhook_id' => '4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f',
]);result = wemail.webhooks.resend_deliveries(
deliveries: [
{ webhook_id: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", event_id: "evt_01J8ZQ3K9WVA7M2P" },
{ webhook_id: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", event_id: "evt_01J8ZQ4T2XNC8R5D" }
],
target_webhook_id: "4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
)result, _ := client.Webhooks.ResendDeliveries(ctx, &wemail.ResendDeliveriesParams{
Deliveries: []wemail.DeliveryRef{
{WebhookID: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", EventID: "evt_01J8ZQ3K9WVA7M2P"},
{WebhookID: "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", EventID: "evt_01J8ZQ4T2XNC8R5D"},
},
TargetWebhookID: "4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
})JSONObject result = wemail.webhooks().resendDeliveries(
ResendDeliveriesParams.builder()
.delivery("9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "evt_01J8ZQ3K9WVA7M2P")
.delivery("9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", "evt_01J8ZQ4T2XNC8R5D")
.targetWebhookId("4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f")
.build());var result = await wemail.Webhooks.ResendDeliveriesAsync(new ResendDeliveriesParams {
Deliveries = new[] {
new DeliveryRef { WebhookId = "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", EventId = "evt_01J8ZQ3K9WVA7M2P" },
new DeliveryRef { WebhookId = "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c", EventId = "evt_01J8ZQ4T2XNC8R5D" },
},
TargetWebhookId = "4c1d2e3f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
});{
"results": [
{
"webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c",
"event_id": "evt_01J8ZQ3K9WVA7M2P",
"accepted": true,
"reason": null
},
{
"webhook_id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c",
"event_id": "evt_01J8ZQ4T2XNC8R5D",
"accepted": false,
"reason": "not_failed"
}
]
}