Rate limits
The API is rate limited per API key (falling back to client IP for an unauthenticated request). Neuji sets the limit and window and may change them, so read them from the response headers rather than hard-coding a number.
Headers
Every /v1 response includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in the current window. |
X-RateLimit-Remaining |
Requests remaining in the current window. |
X-RateLimit-Reset |
Unix epoch second at which the window resets. |
When you exceed the limit the API responds with HTTP 429 and a Retry-After header (seconds to wait):
{ "error": { "type": "rate_limited", "message": "Rate limit exceeded. Slow down and retry after the reset.", "request_id": "…" } }
Handling 429
Back off and retry after Retry-After seconds. A simple, reliable pattern:
# Inspect your current budget from the headers of any response. curl -sD - -o /dev/null "https://api.neuji.com/v1/search?q=test" \ -H "Authorization: Bearer $NEUJI_API_KEY" | grep -i '^x-ratelimit'
async Task<HttpResponseMessage> GetWithRetryAsync(HttpClient http, string url) { while (true) { var res = await http.GetAsync(url); if (res.StatusCode != System.Net.HttpStatusCode.TooManyRequests) return res; var wait = res.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(1); await Task.Delay(wait); } }
async function getWithRetry(url, init) { for (;;) { const res = await fetch(url, init); if (res.status !== 429) return res; const wait = Number(res.headers.get("retry-after") ?? "1") * 1000; await new Promise((r) => setTimeout(r, wait)); } }
Rate limiting is separate from billing. See Errors for the 402 responses returned when
your membership is inactive or your credit balance is empty.