Shopify Webhooks and Idempotency: Is Your Integration Reliable?
Does your Shopify integration risk duplicate orders or lost events? A decision guide for webhooks, idempotency, and reliable integration design.
- shopify
- webhook
- idempotency
- integration
- development
Orders landing twice in ERP, stock updating incorrectly, or duplicate emails to customers — the problem is usually not Shopify but webhook handler design. Shopify delivers events at least once; the same order notification can arrive multiple times. Without idempotency, an integration is not reliable.
Who is this for?
Store owner: Building a custom integration or agency project; you want a technical checklist for "is the system reliable?"
Agency / integration developer: Connecting ERP, logistics, print-on-demand, or CRM; webhook architecture must be correct.
Founder / product owner: Planning a Shopify app; you want to know how background processes should behave in production.
The decision problem: What does your integration do when it receives the same event twice? If the answer is "we don't know" or "hasn't happened yet," you carry risk.
The concrete problem: when webhooks are required
Webhooks are needed when:
- Pushing orders to external systems on creation
- Stock or price synchronization
- Customer or subscription data updates
- Cleanup on app removal (
app/uninstalled)
Polling (periodically querying the API) is an alternative but adds latency and rate limits; webhooks are preferred for real-time operations. If you choose webhooks, you choose idempotency — it is unavoidable.
Typical failure points:
- Handler cannot respond within 30 seconds → Shopify retries → duplicate processing
orders/updatedandorders/createarrive out of order → missing or stale data- No HMAC verification → fake request risk
- Temporary and permanent errors both return 5xx → infinite retry or data loss
Decision framework and checklist
Basic security
-
X-Shopify-Hmac-Sha256validates raw body - Failed verification requests return 401
Idempotency (preventing duplicate processing)
-
X-Shopify-Webhook-Idstored in database; if seen before, return 200 without reprocessing - Alternative: upsert by topic + resource ID (e.g. order ID) combination
- Idempotency key used for external API calls (if supported)
Performance and retry
- Handler returns fast 2xx; heavy work in queue/worker
- 5xx on temporary errors (for retry); 2xx + log on permanent errors (prevent infinite retry)
- Dead letter queue or failed job queue exists
Ordering tolerance
-
orders/updatedcan arrive beforeorders/create— scenario handled - Older event timestamps cannot overwrite newer data
- Deferral or retry logic for missing resources
Observability
- Webhook success/error metrics monitored
- Idempotency tested in staging by resending the same payload
Practical rule: Webhook ID table + fast response + async processing — without this trio, do not call a production integration complete.
How to choose webhook topics
Opening a webhook for every Shopify event creates unnecessary complexity. Minimum set by need:
- Order flow →
orders/create, optionallyorders/updatedororders/cancelled - Stock sync →
inventory_levels/updateorproducts/update - App lifecycle →
app/uninstalled - Subscription-based app →
app_subscriptions/update
Each handler should have a single responsibility; "one endpoint does everything" makes testing and idempotency harder. In staging, deliberately replay the same payload using Shopify CLI webhook trigger or Partner dashboard test delivery — the most valuable validation before production.
As a store owner, ask your agency: "What happens if the same order notification arrives twice?" Without a clear written answer, the integration should not be considered reliable.
Request an idempotency test report in integration delivery: proof that the second arrival of the same webhook ID does not trigger processing. This clarifies the gap between "seems to work" and "reliable in production." Do not skip this test even at low order volume; retry behavior is the same.
Common mistakes
Returning 200 and skipping idempotency. After retry, the same order gets invoiced or shipped twice.
Synchronous heavy processing. A 45-second ERP call inside the handler causes timeout and repeated delivery.
Checking only "does order exist?" without storing webhook ID. orders/updated and orders/create are different events; order ID alone may not be enough.
Computing HMAC on parsed JSON. Verification must use raw request body.
Single happy-path test in staging. Idempotency is not proven until you deliberately send the same webhook twice.
Frequently asked questions
How long should webhook ID records be kept?
Shopify's retry window is roughly 48 hours. Keeping records for at least 72 hours is common and safe practice. Longer retention increases storage cost; write a cleanup policy based on your volume.
Is idempotency enough without a queue?
Idempotency prevents duplicate processing, but synchronous heavy work increases timeout and retry risk. Queue plus idempotency is a more robust production architecture.
How to choose between polling and webhooks?
Real-time order/stock flow → webhooks. Hourly reports or low-volume sync → polling acceptable. Hybrid models (webhook + periodic reconciliation) strengthen data consistency.
How to audit an existing integration?
Check webhook logs for multiple processing records with the same X-Shopify-Webhook-Id. If handler duration exceeds 5 seconds, evaluate moving to async. Repeat HMAC and idempotency checklist in staging.
Next step
If webhook and idempotency design is not clear in your integration project, reviewing architecture is the cheapest insurance. Write briefly about your current flow (ERP, logistics, custom app) to info@murattanriover.com.tr — we can scan for reliability gaps together.