ERRORS

Error codes

Errors use standard HTTP status codes plus a stable code you can switch on in your app. Messages are written for humans and name the problem parameter.

Error format

Every error response has the same four fields:

400 Bad Request
{
  "status": "error",
  "code": "parameterInvalid",
  "message": "Parameter 'from' must be an ISO-8601 date (YYYY-MM-DD) or datetime (e.g. 2026-01-31T13:45:00Z); URL-encode '+' in offsets as %2B (got 'yesterday').",
  "requestId": "01JBDX4Q8Z6M3N2P1R0S9T8V7W"
}
code
Stable, machine-readable identifier. Branch on this, not on the message text.
message
Plain-English explanation. May change wording over time.
requestId
Unique ID for the request, also sent in the X-Request-Id header on every response.

Validation errors are reported one at a time, so fix the reported parameter and try again.

Error code reference

API error codes
StatusCodeRetry?How to fix
400parameterInvalidNoFix the parameter named in message (unknown name, bad value or repeated parameter).
401apiKeyMissingNoSend your key. See authentication.
401apiKeyInvalidNoCheck the key for typos or missing characters.
404notFoundNoThe article or resource does not exist (or is no longer available).
404routeNotFoundNoCheck the path, including the /v1 prefix.
405methodNotAllowedNoUse GET (or HEAD).
429rateLimitedYesWait for the Retry-After seconds, then retry.
402insufficientCreditsNoSharedstack could not reserve the maximum charge for this article request (`insufficientCredits`). `X-Credits-Remaining` is `unknown` if Stack does not return a balance.
500internalErrorYesRetry with backoff. If it persists, contact support with the requestId.
503serviceUnavailableYesRetry with backoff and check API status.

Retrying safely

Retry only 429 rateLimited and 5xx errors. Wait for Retry-After when it's present, otherwise back off exponentially with some random jitter. Don't retry quotaExceeded: it won't succeed until your quota resets. The SDKs do all of this for you.

const RETRYABLE = new Set([429, 500, 502, 503, 504]);

export async function getWithRetry(url, { attempts = 4 } = {}) {
  for (let attempt = 0; ; attempt++) {
    const response = await fetch(url, { headers: { "X-Api-Key": process.env.NEWSSEARCHAPI_API_KEY } });
    const body = await response.json();
    if (response.ok) return body;

    const giveUp = !RETRYABLE.has(response.status) || body.code === "quotaExceeded" || attempt + 1 >= attempts;
    if (giveUp) throw new Error(`${body.code}: ${body.message} (requestId ${body.requestId})`);

    const retryAfter = Number(response.headers.get("Retry-After"));
    const delay = retryAfter > 0 ? retryAfter * 1000 : 2 ** attempt * 500 + Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, delay));
  }
}

Getting help

If an error doesn't make sense, email developer support with the requestId. Your console's request logs also show every call, its status and its request ID.

Stuck or found a mistake?Email developer support

Esc to close · ↑↓ Tab to move through results