Rate limits
elNudge API rate limits, 429 responses, and best practices for handling them.
elNudge applies rate limits to protect service reliability for all customers.
Limits
| Interface | Limit | Scope |
|---|---|---|
| REST API | 1,000 requests / minute | Per API key |
| SDK relay (event ingestion) | 10,000 events / minute | Per site key |
The SDK relay limit is designed for high-traffic stores. Under normal conditions — even during flash sales or peak traffic events — the 10,000 events/minute ceiling is effectively unlimited for a single storefront.
429 responses
When you exceed the REST API rate limit, the API responds with HTTP 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{
"error": "RateLimitExceeded",
"message": "Too many requests. Retry after 12 seconds."
}
The Retry-After header tells you exactly how many seconds to wait before retrying. Always read this value rather than hardcoding a wait time.
Best practices
Cache session data client-side
If your application displays session or nudge data in a dashboard or reporting view, cache API responses for a reasonable TTL (60–300 seconds). Most session data does not change second-to-second — fetching it repeatedly wastes your request budget.
Use pagination cursors
When exporting or syncing large datasets, use the ?cursor= pagination parameter rather than making repeated calls with different ?from= and ?to= ranges. Cursor-based pagination is more efficient and less likely to produce duplicate or missing records.
# First page
curl "https://api.elnudge.com/v1/sessions?limit=200" \
-H "Authorization: Bearer sk_live_XXXXXXXX"
# Subsequent pages — use next_cursor from previous response
curl "https://api.elnudge.com/v1/sessions?limit=200&cursor=eyJpZCI6InN..." \
-H "Authorization: Bearer sk_live_XXXXXXXX"
Implement exponential backoff
On a 429 response, wait for the Retry-After duration, then retry. For repeated failures, apply exponential backoff with jitter to avoid thundering herd problems.
async function fetchWithBackoff(url, options, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
const retryAfter = parseInt(response.headers.get('Retry-After') || '1', 10);
// Exponential backoff: wait Retry-After, then double each attempt, plus jitter
const baseWait = retryAfter * 1000;
const backoff = baseWait * Math.pow(2, attempt);
const jitter = Math.random() * 1000;
const waitMs = Math.min(backoff + jitter, 60000); // cap at 60 seconds
console.warn(`Rate limited. Retrying in ${Math.round(waitMs / 1000)}s (attempt ${attempt + 1})`);
await new Promise(resolve => setTimeout(resolve, waitMs));
}
throw new Error('Max retries reached after rate limiting');
}
// Usage
const response = await fetchWithBackoff(
'https://api.elnudge.com/v1/sessions?limit=200',
{ headers: { Authorization: 'Bearer sk_live_XXXXXXXX' } }
);
Avoid polling for real-time data
If you need real-time session or nudge events, contact support about webhook options. Polling the REST API for real-time data is inefficient and will consume your request budget quickly.
Checking your current usage
Your current request count for the rolling minute window is returned in response headers on every successful API response:
| Header | Value |
|---|---|
X-RateLimit-Limit | Your limit (1000) |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Monitor X-RateLimit-Remaining in your application if you are making high-volume API calls.