ReturnMate

Duplicate Webhooks

Understand and handle duplicate webhook deliveries.

2 min read
Last updated 14 July 2026

ReturnMate outbound webhooks are delivered at least once — your endpoint may occasionally receive the same event more than once. Your handler should treat this as normal.

Why Duplicates Occur

ReturnMate retries delivery whenever it doesn't observe a 2xx response: retries fire after roughly 1s, 4s and 16s (four attempts in total), and each attempt times out after 10 seconds. This means duplicates typically come from:

  • Your endpoint returned a 2xx, but too slowly — the attempt timed out and was retried even though you processed it
  • A transient non-2xx (e.g. 502 from a proxy) after your handler had already done the work
  • Network failures where the response was lost

Deduplicating

There is no delivery-ID header. The only headers sent are Content-Type: application/json and X-Webhook-Signature (an HMAC-SHA256 of the raw body, when you have a webhook secret configured). Retries of the same event send an identical payload, so deduplicate on the payload itself:

{
  "event": "offline_repair.status_changed",
  "timestamp": "2026-07-14T02:15:00.000Z",
  "data": {
    "id": "rma_cuid",
    "rmaNumber": "RMA-2026-001234",
    "externalRef": "your-reference",
    "externalSource": "your-system"
  }
}

Build a dedupe key from (event, data.id, timestamp) — or from your own externalRef plus event — and skip anything you've already processed:

async function handleWebhook(req) {
  const { event, timestamp, data } = req.body;
  const key = `${event}:${data.id}:${timestamp}`;

  if (await alreadyProcessed(key)) {
    return { status: 200 }; // duplicate — acknowledge and skip
  }

  await process(req.body);
  await markProcessed(key); // unique constraint recommended
  return { status: 200 };
}

Best Practices

  • Return 2xx quickly — acknowledge first, do heavy work asynchronously (attempts time out after 10 seconds)
  • Make handlers idempotent so a replayed event is harmless
  • Enforce the dedupe key with a database unique constraint
  • Verify the X-Webhook-Signature before processing
Was this helpful?
Contact Support