A ghost fulfilment is a parcel that ships for an order that no longer exists. The customer cancelled, the refund was issued, and the box went out anyway. You pay forward freight, return freight and handling on revenue you already gave back — and because the order shows as cancelled everywhere you look, the shipment never appears in any report you review.

This is not a warehouse discipline problem. It is a distributed systems problem wearing a logistics costume, and treating it as the former is why it keeps happening.

The Race Condition

Between a customer clicking cancel and a parcel leaving the dock, several independent systems must agree. They do not share a clock, a transaction, or in most cases a direct connection:

  1. The storefront records the cancellation and refunds.
  2. A webhook fires to the fulfilment integration — or a scheduled job polls for changes on a 15–30 minute cycle.
  3. The 3PL's WMS receives the update and attempts to halt the pick.
  4. The pick list was printed earlier and is already on the floor. Paper does not receive webhooks.
  5. The label is generated, the courier manifest is closed, the parcel is on the truck.

Anywhere the update arrives after step 4, the physical process wins. The window is small — often minutes — but it is exactly the window in which most cancellations occur, because buyers cancel almost immediately after ordering.

Polling Guarantees the Failure

If your fulfilment integration polls on a 15-minute cycle, you have accepted an average 7.5-minute blind spot and a worst case of 15. That is a design decision, not bad luck. The same cancellation that arrives at minute 1 of a cycle is caught; at minute 14 it is not.

Webhooks close most of that gap but introduce their own failure modes, which is where most teams stop investigating and where the remaining losses live.

The Webhook Failures That Cause Ghost Shipments

Kepler's webhook-watchdog and webhook-idempotency engines separate the failures worth alerting on, because they need different fixes:

  • WEBHOOK_DELIVERY_LATENCY_SLA_BREACH_HIGH — the event arrived, but late. This is the direct ghost-shipment cause and the one most teams never measure, because a late webhook still looks like a successful webhook in the logs.
  • WEBHOOK_RETRY_EXHAUSTION_STALLED_WARNING — delivery failed repeatedly and the platform gave up. The cancellation never arrived at all. Silent by construction: nothing in your system knows about a message it never received.
  • WEBHOOK_HMAC_SIGNATURE_DROPPED_CRITICAL and WEBHOOK_HMAC_SIGNATURE_INVALID_CRITICAL — events rejected at the gate. Correct security behaviour, and a total loss of the event unless something is watching rejection counts.
  • WEBHOOK_DUPLICATE_IDEMPOTENCY_KEY_COLLISION_CRITICAL — the same event processed twice. Platforms guarantee at-least-once delivery, not exactly-once, so duplicates are normal traffic and your handler must be idempotent.
  • WEBHOOK_CLOCK_DRIFT_EXCEEDED_WARNING — sender and receiver disagree about time, which breaks both signature validation windows and any ordering logic built on timestamps.

The load-bearing insight: a webhook endpoint returning 200 tells you the message was accepted, not that it arrived in time to stop anything. Latency is the metric that matters here, and almost nobody graphs it.

A Worked Example

Illustrative model. Inputs are stated so you can substitute your own; these are not measured results or an industry benchmark.

2,000 orders/day, a 4% cancellation rate, and a 15-minute polling cycle where 20% of cancellations land inside the blind spot after the pick list has printed:

  • Cancellations/day: 80 — of which ~16 fall in the window
  • If half of those are already picked and shipped: 8 ghost shipments/day
  • Forward ₹95 + return ₹110 + handling ₹25 = ₹230 each → ₹1,840/day

Roughly ₹55,000 a month on these inputs, none of it visible in a cancelled-orders report, plus the units out of stock for a fortnight while they travel in both directions.

The Controls, In Order of Effectiveness

  1. A dispatch-time status check. The single highest-value control: before a parcel is manifested, re-query order status from the source of truth rather than trusting the pick list. This closes the race regardless of how the cancellation propagated, and it is the only control that works when the webhook never arrived at all.
  2. Event-driven cancellation, not polling. Subscribe to the cancellation event directly. This shrinks the window; the dispatch check closes what remains.
  3. Monitor webhook latency and retry exhaustion, not just endpoint uptime. Alert on the p99 delivery lag and on any retry exhaustion at all.
  4. Idempotent handlers keyed on event ID. Assume duplicates. A cancellation processed twice must be harmless.
  5. Reconcile daily. Every AWB carrying freight, anti-joined against orders with a valid non-cancelled status. This catches what the first four missed and is the audit that tells you whether the controls are actually working.

The Cost Recovery Side

Once a ghost shipment has happened, two costs are recoverable and usually are not pursued. If the parcel was cancelled before courier pickup but still carries a freight charge, that is dead freight and is disputable on the courier invoice. And if the buyer refuses delivery, the unit returns — so it belongs in your RTO reconciliation rather than being written off as a mystery.

The wider reconciliation, including how dead freight surfaces in a courier invoice audit: The Ultimate Guide to E-Commerce Profit Leak Audits.

Related Guides

⚡ Try This Verification Rule in the Sandbox

Test sample payloads in our zero-dependency interactive explorer.

Open Free API Sandbox →

🧮 Interactive Profit Leak Estimator

LIVE ESTIMATOR

Estimate your monthly financial loss from courier weight creep, dead freight, and gateway fee drift:

Estimated Monthly Profit Leaks:₹28,875 / mo (₹3,46,500 / yr)
Based on standard 10.5% volumetric weight creep & 1.2% cancellation dead freight across industry benchmarks.
⚡ AUDIT TOOL & TEMPLATE PACK

Trap Commerce Operations Discrepancies Automatically

Run a free instant diagnostic on your data or grab our verified operations templates on Gumroad: