Skip to main content
The Store API enforces rate limits to protect against abuse and ensure fair usage. Rate limits are applied per API key or per IP address depending on the endpoint.

Default Limits

EndpointLimitScopeWindow
All endpoints300 requestsPer API key1 minute
POST /auth/login5 requestsPer IP1 minute
POST /auth/register3 requestsPer IP1 minute
POST /auth/refresh10 requestsPer IP1 minute
POST /auth/oauth/callback5 requestsPer IP1 minute
The global rate limit is tracked by your publishable API key (X-Spree-Api-Key). If the key is not provided, the limit falls back to the client’s IP address. Authentication endpoints have stricter per-IP limits to prevent brute-force attacks.

Rate Limit Headers

Every Store API response includes headers that show your current rate limit usage:
HeaderDescription
X-RateLimit-LimitMaximum number of requests allowed per window
X-RateLimit-RemainingNumber of requests remaining in the current window
Retry-AfterSeconds to wait before retrying (only present when limit is reached)
Example response headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295

Rate Limit Response

When you exceed the rate limit, the API returns a 429 Too Many Requests response:
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Please retry later."
  }
}
The response includes rate limit headers and a Retry-After header indicating how many seconds to wait before retrying:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
Retry-After: 60

SDK Retry Handling

The Spree SDK automatically handles rate-limited responses with built-in retry logic and exponential backoff:
import { createSpreeClient } from '@spree/sdk'

const client = createSpreeClient({
  baseUrl: 'http://localhost:3000',
  publishableKey: 'spree_pk_xxx',
  retry: {
    maxRetries: 2,         // Number of retry attempts (default: 2)
    baseDelay: 300,        // Initial delay in ms (default: 300)
    maxDelay: 10000,       // Maximum delay in ms (default: 10000)
  },
})
The SDK respects the Retry-After header and only retries on 429 status codes for non-GET requests. For GET/HEAD requests, it also retries on 500, 502, 503, and 504 errors.

Configuring Rate Limits

If you’re self-hosting Spree, you can adjust rate limits in your initializer:
# config/initializers/spree.rb
Spree::Api::Config[:rate_limit_per_key] = 300  # Global limit per API key
Spree::Api::Config[:rate_limit_window] = 60    # Window in seconds
Spree::Api::Config[:rate_limit_login] = 5      # Login attempts per IP
Spree::Api::Config[:rate_limit_register] = 3   # Registration attempts per IP
Spree::Api::Config[:rate_limit_refresh] = 10   # Token refresh per IP
Spree::Api::Config[:rate_limit_oauth] = 5      # OAuth callbacks per IP
Rate limiting uses Rails.cache as the backing store. For production environments with multiple application servers, ensure you’re using a shared cache store like Redis:
# config/environments/production.rb
config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }