Guides
Errors and retries
Read noxstock error envelopes and retry only when it is safe.
Every error response uses this shape:
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Please slow request rate and retry.",
"retryable": true
}
}Retry policy
| Code | HTTP | Retry? | What to do |
|---|---|---|---|
UNAUTHORIZED | 401 | No | Check X-API-Key; rotate/recreate if revoked. |
PLAN_UPGRADE_REQUIRED | 403 | No | Upgrade to Starter/Builder or use free routes. |
SYMBOL_INVALID | 400 | No | Fix ticker format. |
SYMBOL_UNKNOWN | 404 | No | Use /v2/search and /v2/coverage. |
PARAM_INVALID | 400 | No | Fix query params. |
RATE_LIMITED | 429 | Yes | Wait Retry-After or until X-RateLimit-Reset. |
UPSTREAM_UNAVAILABLE | 503 | Yes | Retry with backoff. |
AUTH_UPSTREAM_UNAVAILABLE | 503 | Yes | Retry shortly; API key verification is temporarily unavailable. |
PREREQUISITE_MISSING | 409 | No/conditional | Call the underlying route first if your workflow depends on cached prerequisites. |
JavaScript retry example
async function requestWithRetry(url: string, apiKey: string, attempts = 3) {
for (let attempt = 1; attempt <= attempts; attempt++) {
const res = await fetch(url, { headers: { "X-API-Key": apiKey } });
const body = await res.json();
if (res.ok) return body.data;
const retryable = body?.error?.retryable === true;
if (!retryable || attempt === attempts) throw new Error(body.error.message);
const retryAfter = Number(res.headers.get("Retry-After") ?? "1");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
}Common mistakes
- Retrying
UNAUTHORIZEDafter a key was revoked. - Treating
PLAN_UPGRADE_REQUIREDas an outage. - Ignoring
Retry-Afteron 429/503. - Parsing the response as raw endpoint data instead of
{ data }.