Rate limits protect the Entri API from abuse and ensure consistent performance for all users.
Rate limiting is not yet enforced on most endpoints. The X-RateLimit-* headers and 429 responses described below are planned features and are not currently returned by the API. This page documents the intended behavior for future reference.Some AI-related endpoints (batch translation) do apply throttling using the NestJS Throttler module.
When rate limiting is fully implemented, every API response will include:
| Header | Description |
|---|
X-RateLimit-Limit | The maximum number of requests allowed in the current window. |
X-RateLimit-Remaining | The number of requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp (seconds) when the current window resets. |
Retry-After | Present only on 429 responses. Seconds to wait before retrying. |
When the Limit is Exceeded
When a rate limit is exceeded, the API will return 429 Too Many Requests:
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "Too many requests. Please retry after 30 seconds.",
"timestamp": "2025-03-02T14:30:00.000Z",
"path": "/api/projects/proj_abc123/keys"
}
Exponential Backoff
When you receive a 429 response, wait the number of seconds indicated in Retry-After before retrying. For repeated failures, use exponential backoff with jitter to avoid thundering herd problems:
async function requestWithRetry(path, options = {}, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(`https://api.nt3.io/api${path}`, {
...options,
headers: {
"X-API-Key": process.env.ENTRI_API_KEY,
...options.headers,
},
});
if (response.status !== 429) {
return response;
}
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "1", 10);
const jitter = Math.random() * 1000;
const delay = retryAfter * 1000 * Math.pow(2, attempt) + jitter;
console.warn(`Rate limited. Retrying in ${Math.round(delay / 1000)}s...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new Error("Max retries exceeded");
}
import time
import random
import httpx
def request_with_retry(path: str, max_retries: int = 5, **kwargs):
headers = {"X-API-Key": "entri_your_token_here"}
with httpx.Client(base_url="https://api.nt3.io/api") as client:
for attempt in range(max_retries):
response = client.request(
kwargs.pop("method", "GET"),
path,
headers=headers,
**kwargs,
)
if response.status_code != 429:
return response
retry_after = int(response.headers.get("Retry-After", 1))
delay = retry_after * (2 ** attempt) + random.random()
print(f"Rate limited. Retrying in {delay:.1f}s...")
time.sleep(delay)
raise RuntimeError("Max retries exceeded")
Best Practices
Monitor remaining capacity. Read the X-RateLimit-Remaining header on each response. If the value is low, slow down your request rate before hitting the limit.
Batch operations. Use bulk endpoints where available rather than making individual requests. For example, use POST /api/projects/:projectId/keys/bulk to create many keys in one request instead of looping over single-key creates.
Cache responses. If your integration reads the same data frequently, cache the results locally for a short period rather than polling the API on every render or event.
Use the CLI for large syncs. The Entri CLI handles rate limit retries automatically and supports --json output for use in CI/CD pipelines:
entri push --json
entri pull --json
Avoid polling. Instead of polling the API to detect changes, use webhooks to receive real-time notifications when events occur.
If you routinely hit rate limits, review whether your integration can be restructured to use batch endpoints, reduce polling frequency, or react to webhooks instead.