Rate limits
Neuroon enforces rate limiting per endpoint, not per subscription plan. Plan quotas (synced products, monthly searches) are a separate concept from request throttling and are documented elsewhere. See Plan quotas vs rate limit below.
There are two throttling layers: one on /api/plugin/shops/* (authenticated with Shop API Key) and another on /api/widget/* (authenticated with Widget Token). Limits are global per endpoint — they do not vary by plan.
Per-endpoint limits
| Endpoint | Limit | Window |
|---|---|---|
POST /api/plugin/shops/{shopId}/products/sync | 100 req | 1 min |
GET /api/plugin/shops/me | 60 req | 1 min |
GET /api/plugin/shops/{shopId}/verification-data | 20 req | 1 min |
POST /api/plugin/shops/{shopId}/verify | 5 req | 5 min |
DELETE /api/plugin/shops/{shopId}/verify | 5 req | 5 min |
/api/widget/search* | 200 req | 1 min |
/api/widget/suggestions* | 300 req | 1 min |
/api/widget/compare* | 10 req | 1 min |
/api/widget/analytics* | 500 req | 1 min |
| Other rate-limited endpoints | 100 req | 1 min |
Response headers
| Header | When emitted | Meaning |
|---|---|---|
X-RateLimit-Limit | All rate-limited responses (200 and 429) | Total quota for this endpoint |
X-RateLimit-Remaining | All rate-limited responses | Remaining requests in the current window |
Retry-After | Only on 429 | Seconds to wait before retrying (equals window size) |
Successful response:
HTTP/1.1 200 OK
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 187
Content-Type: application/json
429 error body
When the bucket is exhausted:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
Retry-After: 60
Content-Type: application/json
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again later.",
"retryAfter": 60,
"limit": 200,
"remaining": 0,
"timestamp": "2026-05-06T10:15:00Z"
}
Exponential backoff
Retry only on 429 and 5xx. Honor Retry-After. Recommended pattern: 1s, 2s, 4s, 8s with jitter, max 3-5 attempts.
using Polly;
using Polly.Extensions.Http;
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => (int)msg.StatusCode == 429)
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: (attempt, response, ctx) =>
{
if (response.Result?.Headers.RetryAfter?.Delta is TimeSpan retryAfter)
return retryAfter;
return TimeSpan.FromMilliseconds(
Math.Pow(2, attempt) * 1000 + Random.Shared.Next(0, 250));
},
onRetryAsync: (_, _, _, _) => Task.CompletedTask);
var http = new HttpClient(new PolicyHttpMessageHandler(retryPolicy)
{ InnerHandler = new HttpClientHandler() });Plan quotas vs rate limit
These are two distinct layers. Don't confuse them:
| Concept | What it controls | Where to see it | Granularity |
|---|---|---|---|
| Rate limit (this page) | Per-minute / per-five-minute spikes | X-RateLimit-* headers, 429 error | Per endpoint, identical for all callers |
| Plan quota | Total monthly volume and catalog cap | GET /api/plugin/shops/me → maxProducts, productsCount, maxSearchesPerMonth, searchesThisMonth | Per shop, depends on plan |
The plan tier (BASIC, GROWTH, PRO, ENTERPRISE) influences maxProducts and maxSearchesPerMonth returned by /shops/me, not the per-endpoint rate limits, which are global. If your integration needs higher monthly volume, contact support to upgrade plan; per-endpoint rate limits are not raised by plan tier.
Best practices
- Cache
/api/plugin/shops/mefor ~5 min on the client like the official WordPress plugin does; the endpoint allows only 60 req/min andproductsCount/searchesThisMonthevolve slowly. - Don't abuse
widget-compare(10/min): cache results or batch comparisons. - Sync products in batches of up to 500 (sync endpoint cap) and space out calls; the
syncbucket allows 100 req/min, enough for large catalogs if they paginate well. - Don't retry
400,401,403,404or422— these are deterministic and won't fix themselves. - Honor
Retry-Afterstrictly. Ignoring it can lead to abuse and manual block.
Further reading
- Errors — full envelope of remaining 4xx/5xx errors.
- Shop API Key — generation, rotation and Origin validation.
- Widget Token — 24 h TTL and rotation.