How to Fix Shopify Rate Limit (HTTP 429), Webhook Timeouts, and API Errors
Resolve Shopify API 429 Too Many Requests, 500/503 errors, and webhook failures by implementing leaky bucket algorithms, exponential backoff, and GraphQL.
- HTTP 429 Too Many Requests occurs when your app exceeds Shopify's REST (leaky bucket) or GraphQL (calculated cost) API rate limits.
- Shopify 500, 502, 503, and timeout errors often result from heavy queries, unpaginated requests, or temporary platform degradation.
- Shopify webhooks not working or being dropped happens when your endpoint fails to return a 200 OK within 5 seconds.
- Quick Fix: Implement the Leaky Bucket algorithm with exponential backoff, read the Retry-After header, and decouple webhook ingestion from processing.
| Method | When to Use | Time | Risk |
|---|---|---|---|
| Exponential Backoff & Retry-After | Handling occasional 429s or 50x errors gracefully | Low | Low |
| Migrate REST to GraphQL | Heavy data fetching constantly hitting REST limits | High | Low |
| Message Queue (Redis/SQS/Celery) | High-throughput webhook processing and syncs | Medium | Low |
| Blind Retries w/o Delays | Never (can lead to permanent app blocks or IP bans) | Low | High |
Understanding the Error
When scaling a Shopify integration or custom app, encountering API limits and connectivity errors is a rite of passage. Shopify heavily monitors and throttles traffic to protect its infrastructure, resulting in strict rate limiting and aggressive timeout rules. If you are seeing Shopify 429 Too Many Requests, Shopify 500 Internal Server Error, Shopify 502 Bad Gateway, Shopify 503 Service Unavailable, or experiencing Shopify webhook not working issues, your application is likely struggling with API concurrency, inefficient queries, or synchronous webhook processing.
Shopify manages API traffic using different algorithms depending on the API type:
- REST API (Leaky Bucket): The standard limit is 40 requests per app, per store. The bucket 'empties' at a rate of 2 requests per second. Shopify Plus stores get double these limits (80 burst, 4 req/sec).
- GraphQL API (Calculated Cost): Queries are assigned a point cost based on complexity (e.g., fetching 100 products costs more than fetching 1). The limit is 1,000 points, replenishing at 50 points per second.
When these limits are breached, Shopify returns an HTTP 429 Too Many Requests error. Persistent abuse without backing off can lead to temporary or permanent API bans.
Similarly, server-side errors (500, 502, 503) and timeouts (504) often point to queries that are simply too large for Shopify's database clusters to process within standard latency windows. Furthermore, authentication errors like Shopify 401 Unauthorized and Shopify 403 Forbidden indicate invalid tokens or missing access scopes, which frequently happen if a merchant uninstalls an app or token rotation fails.
Step 1: Diagnose the Exact Error Code
Before implementing a fix, you must identify precisely which subsystem is failing. Check your application logs or network inspector for the following HTTP status codes and headers:
Diagnosing 429 Rate Limits:
Inspect the HTTP response headers on your REST API calls. You will see a header named X-Shopify-Shop-Api-Call-Limit. Its value looks like 39/40. If the first number reaches the second number, your next request will trigger a 429 Too Many Requests. Additionally, Shopify provides a Retry-After header indicating how many seconds you must wait before trying again.
Diagnosing 5xx Errors and Timeouts:
If you see 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, or connection timeouts, the issue is usually payload size. Are you requesting massive amounts of unpaginated data? Are you using overly complex GraphQL queries spanning multiple nested connections? While 503s can sometimes indicate Shopify platform maintenance, they are more commonly triggered by expensive queries overwhelming the shard your store is hosted on.
Diagnosing Webhook Failures:
If your Shopify webhooks are not working, check your server's response time. Shopify expects a 200 OK response within 5 seconds. If your server takes 6 seconds because it's synchronously writing to a database or resizing an image, Shopify treats it as a timeout failure. After 19 consecutive failures over 48 hours, Shopify will silently delete your webhook subscription.
Diagnosing 401/403 Errors:
An HTTP 401 Unauthorized means your X-Shopify-Access-Token is missing, invalid, or expired. An HTTP 403 Forbidden means your token is valid, but your app lacks the required OAuth scopes (e.g., trying to modify an order without the write_orders scope) or the merchant's plan doesn't support the feature.
Step 2: Implement the Fix
Depending on the exact error, apply the following architectural fixes to your application.
Fix 1: Handling 429 Rate Limits with Leaky Bucket & Backoff
Never write a raw API call without a wrapper. Your HTTP client must be rate-limit aware. When you receive a 429, you must catch the exception, read the Retry-After header, pause execution, and retry.
If you are using Python, an implementation using the requests library and a standard time.sleep mechanism is essential. You should also proactively check the X-Shopify-Shop-Api-Call-Limit header and intentionally sleep your thread if the ratio hits 38/40 to avoid the 429 altogether.
Fix 2: Solving Webhook Timeouts (The 5-Second Rule)
The most common architectural mistake in Shopify development is processing webhooks synchronously. To fix Shopify webhook not working or timeout issues, you must decouple ingestion from processing.
- Receive the webhook payload.
- Immediately push the payload into a background queue (e.g., AWS SQS, Redis + Celery/Sidekiq, RabbitMQ).
- Return an
HTTP 200 OKto Shopify immediately. - Let your background workers process the queue asynchronously at their own pace.
This guarantees your endpoint always responds within milliseconds, completely eliminating Shopify webhook timeouts and preventing webhook deletion.
Fix 3: Mitigating 500, 502, and 503 Errors
If you are hitting 5xx errors, you are likely requesting too much data.
- Use Pagination: Never attempt to pull thousands of resources at once. Use cursor-based pagination (
since_idin REST, or standard cursors in GraphQL) with alimitof 50-100 items per page. - Migrate to GraphQL: REST payloads are bloated. If you only need a product's ID and Title, GraphQL allows you to request only those fields, dramatically reducing query execution time and the likelihood of 502/504 gateways timeouts.
- Use the Bulk Operations API: For syncing entire catalogs (e.g., 50,000+ products), do not use the standard REST or GraphQL endpoints. Use the GraphQL Bulk Operations API. Shopify will process the query asynchronously on their servers and provide a URL to a JSONL file when complete.
Fix 4: Resolving 401 and 403 Authorization Issues
If you suddenly receive 401 Unauthorized on previously working endpoints, the merchant likely uninstalled your app. You should listen to the app/uninstalled webhook to clean up stale access tokens in your database.
If you receive a 403 Forbidden, verify your requested access scopes during the OAuth flow. If Shopify released a new API version that requires stricter scopes, you must prompt the merchant to re-authenticate and accept the new permissions.
Step 3: Proactive Monitoring
Do not wait for users to report broken syncs. Implement robust logging for all API interactions. Track the frequency of 429s and 5xx errors using tools like Datadog, Sentry, or New Relic. Alert your engineering team if the rate of 429s exceeds 5% of total requests, as this indicates your backoff strategy is failing or your background workers are misconfigured.
Frequently Asked Questions
import time
import requests
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def shopify_request_with_retry(url, headers, max_retries=5):
retries = 0
while retries < max_retries:
response = requests.get(url, headers=headers)
# Success
if response.status_code == 200:
# Proactively check limit to avoid hitting 429
call_limit = response.headers.get('X-Shopify-Shop-Api-Call-Limit')
if call_limit:
current, maximum = map(int, call_limit.split('/'))
if maximum - current <= 2:
logger.warning("Approaching API limit. Sleeping for 2 seconds.")
time.sleep(2)
return response.json()
# Rate Limited (429)
if response.status_code == 429:
retry_after = float(response.headers.get('Retry-After', 2.0))
logger.error(f"429 Rate limited! Sleeping for {retry_after} seconds...")
time.sleep(retry_after)
retries += 1
continue
# Server Errors & Timeouts (5xx)
if response.status_code in [500, 502, 503, 504]:
backoff = 2 ** retries # Exponential backoff: 1, 2, 4, 8 seconds
logger.error(f"Shopify Server Error {response.status_code}. Retrying in {backoff} seconds...")
time.sleep(backoff)
retries += 1
continue
# Auth Errors (401, 403)
if response.status_code in [401, 403]:
logger.critical(f"Auth Error {response.status_code}: Check token and scopes.")
response.raise_for_status()
# Other client errors
response.raise_for_status()
raise Exception("Max retries exceeded while calling Shopify API")
# Example usage:
# headers = {'X-Shopify-Access-Token': 'shpat_xxxxx', 'Content-Type': 'application/json'}
# data = shopify_request_with_retry('https://store.myshopify.com/admin/api/2023-10/products.json', headers)Error Medic Editorial
Error Medic Editorial is a team of Senior DevOps and Site Reliability Engineers dedicated to solving complex infrastructure and API integration challenges. With decades of combined experience managing high-throughput e-commerce systems, we provide actionable, code-first solutions for scaling modern web applications.