Skip to main content

API Rate Limits

The LaunchMyStore scoped REST API (/api/v1/) is rate-limited per app + store using a sliding window. Limits are per-second and tier-based — the app’s tier on the developer dashboard controls the cap.
Rate limits apply only to the OAuth-scoped REST API under /api/v1/. Internal admin endpoints, public storefront routes, and the platform proxy routes (/api/apps/*) are not subject to this guard.

Limits by tier

Tier is set per-app on the developer dashboard. See App Types & Tiers.

Algorithm

A sliding 1-second window per (app, store) pair:
  1. Every request’s timestamp is recorded for the pair.
  2. On each request, entries older than 1 second are evicted and the remaining count is checked against the tier limit.
  3. If count >= limit, the request is rejected with HTTP 429. Otherwise the timestamp is added and the request proceeds.
This means the limit is a true rolling rate, not a fixed-bucket reset — a burst of N requests blocks further calls until enough of those timestamps age past one second.

Response headers

Every response from /api/v1/ includes these headers, whether the request succeeded or was rate-limited: Example:

429 response

When the cap is exceeded:
A 429 means this app’s requests on this store exceeded the cap. Other stores using the same app are unaffected. Other apps on the same store are unaffected.
Never let a 429 fall through as “no data”.The two failure modes are both silent:
  • Reads. If a helper collapses a failed request into an empty result, a config read returns {} — indistinguishable from a merchant who has configured nothing. An app that gates paid features on that config will quietly downgrade a paying merchant to its free tier for the duration of the burst, then recover, leaving nothing in the logs.
  • Writes. A dropped write means the value was simply never stored. The call returned, your code moved on, and the data is gone.
Retry on 429 (and 5xx), and make read helpers distinguish “the platform said there is nothing” from “the platform did not answer”. Caching the last known-good config and reusing it when a refresh fails is a cheap way to keep entitlement stable across a burst.

Best practices

Exponential backoff on 429

Always honor Retry-After and add a small random jitter to spread retries across multiple instances of your worker.

Read the headers proactively

Don’t wait for a 429 — check X-RateLimit-Remaining after every response and slow down when it drops below a safety threshold.

Batch requests where the API supports it

Several REST resources expose bulk endpoints to amortize the cap:
  • Metafields: POST /metafields/bulk upserts up to 250 metafields in one call. See Metafields.
  • Products: pagination via ?page=…&limit=… returns up to 250 products per call.
  • Orders: bulk fetch with ?ids=id1,id2,id3,….
One batched call costs one slot vs. N individual calls — usually the single biggest win for a sync-style app.

Use webhooks instead of polling

Many sync workflows poll the API every few seconds to detect changes. Subscribe to a webhook topic instead — LaunchMyStore pushes the event to your endpoint as it happens, costing zero rate-limit slots on your side.

Use background workers, not on-request fan-out

If a single end-user action triggers ten outbound API calls, those ten calls all count toward the per-second cap in the same window. Enqueueing them into a background worker that paces itself smooths the load.

Avoid the leader-election trap

Two instances of your app both polling on a one-second schedule will double the request rate. Use a Redis lock or a single scheduler to ensure only one instance fires the polled call per interval.

Multi-store apps

The rate-limit key includes both appId and storeId. A single app installed across 1000 stores has its own per-store window for each — the limits don’t pool. So an app at the basic tier with 1000 installs can sustain 40 × 1000 = 40,000 req/sec system-wide, as long as the requests are spread across stores.

Configuring tier on the developer dashboard

App tier is set on the developer dashboard’s app settings page. Tier upgrades are handled by:
  1. The merchant accepting a higher subscription tier for the app, or
  2. The developer requesting a tier upgrade via support (for first-party apps that don’t go through the marketplace flow).
Tier lookups are cached in-process for 60 seconds — a tier change can take up to 60s to propagate.

Failures and fallbacks

Not for individual apps via API. Tier-level limits apply uniformly. If your integration has a one-off catch-up backfill requirement, contact support — for some integrations a temporary enterprise tier can be granted.
No. Every authenticated request to /api/v1/ regardless of method counts as one slot.
Yes — every request that reaches the guard counts toward the window, even if it ultimately 4xx’s on validation. Avoid “ping-and-error” patterns.

See also

Authentication

OAuth flow, scopes, and Bearer-token format.

App Types & Tiers

What each tier unlocks beyond rate limits.

Webhooks Overview

Push notifications — zero rate-limit cost on your side.

Function Active Limits

A parallel per-shop cap for declarative functions.