RM

Duplicate Webhooks

Understand and handle duplicate webhook deliveries.

2 min read
Last updated 31 December 2024

Webhooks may occasionally be delivered more than once. This guide explains why and how to handle it.

Why Duplicates Occur

Technical Causes

CauseDescription
Network timeoutRequest succeeded but response lost
Retry after error5xx error triggered retry
System recoveryWebhooks replayed after outage
Shopify retriesShopify resends on failure

It's By Design

Webhooks are "at least once" delivery:

  • Guaranteed to be delivered
  • May be delivered multiple times
  • Your system should handle duplicates

Handling Duplicates

Idempotency Keys

Use delivery IDs to detect duplicates:

async function handleWebhook(request) {
  const deliveryId = request.headers['x-returnmate-delivery-id'];

  // Check if already processed
  const existing = await db.webhooks.findOne({ deliveryId });
  if (existing) {
    console.log('Duplicate webhook, skipping');
    return { status: 200 };
  }

  // Process the webhook
  await processWebhookPayload(request.body);

  // Record as processed
  await db.webhooks.insert({ deliveryId, processedAt: new Date() });

  return { status: 200 };
}

Database Constraints

Use unique constraints:

  • Store webhook delivery IDs
  • Use database uniqueness
  • Let duplicates fail silently

Shopify Webhook Duplicates

Shopify webhooks can also duplicate:

Common Scenarios

  1. Order update during high traffic
  2. App reinstallation
  3. Webhook endpoint timeout
  4. Shopify internal retries

Handling Strategy

// For Shopify order webhooks
async function handleOrderWebhook(order) {
  const key = `order-${order.id}-${order.updated_at}`;

  if (await alreadyProcessed(key)) {
    return; // Skip duplicate
  }

  await processOrder(order);
  await markProcessed(key);
}

Monitoring Duplicates

What to Track

  • Total webhooks received
  • Duplicates detected
  • Duplicate rate (should be < 1%)

Alerting

Set alerts if duplicate rate exceeds threshold:

  • Normal: < 1%
  • Investigate: 1-5%
  • Problem: > 5%

Best Practices

  • Always implement idempotency
  • Store delivery IDs with TTL
  • Use database unique constraints
  • Monitor duplicate rates
  • Log duplicates for debugging
TTL for Delivery IDs

Store delivery IDs for 7-14 days, then purge. Duplicates typically arrive within hours, not weeks.

Was this helpful?
Contact Support