Repository navigation
[FEAT] : Webhook Redelivery Nested Payload Bug #3128
Description
Problem Statement
Outbound webhooks in DevTrack dispatch a structured payload of type WebhookPayload (matching the shape { event: string, timestamp: string, data: Record<string, unknown> }). When a webhook delivery fails, this complete payload structure is logged in the webhook_deliveries table under the payload column.
When a developer clicks "Retry Delivery" in the webhooks dashboard, the retry route handler /api/webhooks/custom/[id]/deliveries/[deliveryId]/retry/route.ts reads this logged payload from the database and forwards it directly as the third parameter (data) to dispatchWebhook. Because dispatchWebhook automatically wraps its data argument in a new WebhookPayload shell, the final HTTP POST request is sent with a corrupt, nested structure:
{
"event": "goal.completed",
"timestamp": "2026-07-04T10:00:00.000Z",
"data": {
"event": "goal.completed",
"timestamp": "2026-07-03T12:00:00.000Z",
"data": {
// Original data is nested here
}
}
}This violates the API contract and breaks integrations that parse the webhook payload structure.
tch.
Proposed Solution
Extract and forward the nested data block of the original payload during redelivery:
- In the retry route handler
src/app/api/webhooks/custom/[id]/deliveries/[deliveryId]/retry/route.ts, parse thedelivery.payloaddatabase column. - Check if the parsed payload follows the standard
WebhookPayloadstructure (i.e. contains a top-leveldatakey). - If it does, extract
payloadData.dataand pass that extracted dictionary todispatchWebhookinstead of the full root object:// Extract original inner data to prevent double-nesting on dispatch const originalData = (payloadData && typeof payloadData === "object" && "data" in payloadData) ? (payloadData.data as Record<string, unknown>) : payloadData; const result2 = await dispatchWebhook(id, delivery.event, originalData);
- This ensures that when
dispatchWebhookconstructs the new payload, it wraps only the original event fields.
Feature Area
API / Backend
Alternatives Considered
- Modifying
dispatchWebhook: We considered modifying the core helper insrc/lib/webhooks.tsto detect if the incomingdatais already wrapped in aWebhookPayload. However,dispatchWebhookis called from various live events (goals, streaks, achievements) that always supply raw dictionaries. Adding check-logic there introduces unnecessary complexity to a critical path. Normalizing the input at the retry route boundary is cleaner and safer.
Acceptance Criteria
- Outbound webhook retries dispatch a payload structure that matches the original dispatch payload format (no nested
event/timestampkeys inside thedataobject). - Unit tests exist covering retry payload formatting, ensuring that the payload remains properly un-nested during a simulated retry dispatch.
Additional Context
No response
Activity
hrshjswniii commentedon Jul 4, 2026
Hiii @Priyanshu-byte-coder , i'd like to work on this issue as part of GSSoC'26
github-actions commentedon Jul 4, 2026
Assigned to @hrshjswniii! You have 7 days to open a PR. No PR after 7 days = auto-unassigned so others can pick it up. Good luck!
[-][FEAT] : Webhook Redelivery Nested Payload Bug (Quick Win - High Impact)[/-][+][FEAT] : Webhook Redelivery Nested Payload Bug [/+]github-actions commentedon Jul 12, 2026
✅ Closed as completed!
If DevTrack has been useful, a ⭐ star on the repo helps the project grow and reach more developers.