Skip to content
Elara One docs

Rate limits

The request budgets per store and per caller, the rate-limit headers, per-shopper limits with X-Client-IP, and how to back off on 429.

Rate limits keep one busy caller from slowing a store down for everyone else. Each budget counts requests per store and per caller over a short window. When a budget is spent, the API answers 429 RATE_LIMITED until the window moves on.

The budgets

Applies toBudget
The storefront and merchant API in general600 requests a minute, per store and caller IP
Register, sign in, password reset, profile and password changes, guest order lookup10 a minute, per store and caller IP
Form submissions (POST /v1/forms/{handle})30 a minute, per store and caller IP
Search suggestions (GET /v1/search/suggest)1,200 a minute, per store and caller IP
Search events (POST /v1/search/events)300 batches a minute, per store and caller IP
Chat60 a minute, per conversation (or signed-in customer)
Marketing consent confirmation (POST /v1/marketing/confirm)10 a minute and 30 an hour, per store and caller IP
Account deletion (DELETE /v1/account)3 a minute and 10 an hour per account, and 20 an hour per IP

Search suggestions, search events and chat have their own budgets instead of the general one, so typing in a search box never uses up the budget your product pages need. The other tighter budgets apply to routes that take passwords or codes, where guessing must stay slow.

Headers

Responses on rate-limited routes tell you where you stand:

HeaderMeaning
X-RateLimit-LimitThe size of the budget for this route
X-RateLimit-RemainingHow many requests are left in the current window
Retry-AfterOn a 429: how many seconds to wait before trying again
429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
Content-Type: application/json

{ "error": { "code": "RATE_LIMITED", "message": "Too many requests." } }

Browser code can read these headers too: they are exposed through CORS.

Per-shopper limits with X-Client-IP

A "caller" is the IP address the request comes from. For a storefront that calls the API from its own server, that is your server's IP, so every shopper would share one budget. Busy shops would run out quickly.

To give each shopper their own budget, send the shopper's IP address in X-Client-IP on every server call. The API trusts it only together with a valid X-Tenant-Secret; on a browser call, or without the secret, it is ignored.

Forward the shopper's IP from your server
// Next.js route handler: the shopper's IP from your hosting's proxy header.
const shopperIp = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim()

const res = await fetch('https://api.elaraone.app/api/v1/products', {
  headers: {
    'X-Tenant-Key': process.env.ELARAONE_TENANT_KEY!,
    'X-Tenant-Secret': process.env.ELARAONE_TENANT_SECRET!,
    ...(shopperIp ? { 'X-Client-IP': shopperIp } : {}),
  },
})
  • Send one IPv4 or IPv6 address, with no port and no list.
  • Only take the IP from a header your hosting platform sets and overwrites. A header a visitor can set themselves lets them pick their own budget.
  • Never forward X-Forwarded-For to the API itself. Send X-Client-IP instead.
  • The same IP is used for the per-IP parts of the tighter budgets, such as sign-in.

Back off on 429

  1. Stop sending requests in that budget.
  2. Wait for the number of seconds in Retry-After.
  3. Retry. If the request changes something, retry with the same Idempotency-Key (see idempotency).

For background jobs and integrations, also:

  • watch X-RateLimit-Remaining and slow down before it reaches zero;
  • spread work out instead of running it in bursts, and run jobs one at a time per store;
  • use exponential backoff with jitter for repeated failures, and stop after a few attempts;
  • sync CRM records with filter[updated_since] instead of re-reading everything (see pagination).

For shoppers, keep the page usable: keep the current search results on screen, and show a short "try again in a moment" message rather than an error page.

Staging stores

Staging stores, where your plan includes them, also have a daily ceiling: by default 20,000 API requests and 1,000 form submissions. Over it, the API answers 429 STAGING_LIMIT, with Retry-After set to the end of the day in UTC.