Skip to main content
Look up any error the Keenable API returns to find its cause and the exact fix. Each section has a stable anchor, so SDK error messages and agents can link straight to it. Over HTTP, an error body is JSON with an error and a message field. The SDKs raise an error whose message starts with the prefix shown under each entry, followed by the API’s message.

400 Invalid request parameters

Retry: fix, then retry. What you see If a parameter is missing or invalid, search and fetch return 400 with an error such as Invalid parameter. The body also has a message, and can have a details field that lists the validation errors. Cause A request parameter does not match what the endpoint accepts: a missing query or url, a value outside its range, a bad date filter, or a type the schema rejects. Both the keyed paths, such as /v1/search and /v1/fetch, and the /public paths return it. Fix
  1. Read the message and any details in the response body. They name the field that failed.
  2. Check the request against the Search or Fetch parameter list and send the call again with a corrected body.
  3. If the body says Missing app identifier instead, see 400 Missing app identifier.

400 Missing app identifier

Retry: fix, then retry. What you see
The SDKs send this header for you, so you get this error only over raw HTTP. Cause A keyless request to /v1/search/public or /v1/fetch/public arrived without the X-Keenable-Title header. Keyed requests to /v1/search or /v1/fetch never need this header. A 400 on those paths means an invalid parameter. Fix Add the header with your application’s name. This request includes it:
You get search results instead of the 400. If you have an API key, call /v1/search instead, which doesn’t need the header.

401 Malformed key

Retry: fix, then retry. What you see If the key has the wrong format, the API returns:
If a request to a keyed path such as /v1/search or /v1/fetch carries no key at all, the API returns:
The SDKs never send a request with no key. If KEENABLE_API_KEY isn’t set, they call the keyless /public paths, so you get the second body only over raw HTTP. If the key is malformed, the SDKs raise KeenableAuthError (Python, TypeScript) or *keenable.AuthError (Go) with the message prefix Keenable authentication failed (401). Cause Malformed API key means the value does not look like a Keenable key at all. Common causes are a truncated copy, a stray quote or space, or a placeholder such as keen_<your_key> left in place. Missing authentication means the request reached a keyed path without an X-API-Key or Authorization: Bearer header. Fix
  1. Check the value of KEENABLE_API_KEY. It starts with keen_ and has no quotes or whitespace around it.
  2. Over raw HTTP, send the key in the X-API-Key header. To call without a key, use /v1/search/public or /v1/fetch/public with an X-Keenable-Title header instead.
  3. To keep working while you sort it out, unset KEENABLE_API_KEY. The SDKs fall back to the keyless tier.

401 Invalid key

Retry: fix, then retry. What you see The API returns:
The SDKs raise KeenableAuthError (Python, TypeScript) or *keenable.AuthError (Go) with the message prefix Keenable authentication failed (401). Cause The key has the right format, but Keenable has no key with that value. A typo that keeps the keen_ prefix causes this. Fix
  1. Compare KEENABLE_API_KEY with the key in the console ↗.
  2. If you cannot find it there, create a new key and replace the old value. See API keys.
  3. To keep working while you sort it out, unset KEENABLE_API_KEY. The SDKs fall back to the keyless tier.

402 Out of credits

Retry: do not retry. What you see The SDKs raise KeenableAPIError (Python, TypeScript) or *keenable.APIError (Go) with status 402 and the message prefix Keenable: insufficient credits (402). Cause Your organization has spent its free monthly allowance of 100,000 requests and has no purchased credits left. Every retry returns the same 402 until someone adds credits or the allowance resets. See credits. Fix Stop and ask a human to buy credits or turn on auto top-up in the console ↗. SDK 0.1.x has no dedicated error type for 402, so catch the generic API error and check its status. This code stops on 402 and passes every other error through:
Your program exits with the message instead of retrying. SDK 0.2.0 adds a typed error for 402: KeenableCreditsError in Python and TypeScript, *keenable.CreditsError in Go. Once you upgrade, catch that type instead of checking the status.

403 Key rejected or revoked

Retry: do not retry; check the key, then ask a human. What you see A revoked key returns:
The SDKs raise KeenableAuthError (Python, TypeScript) or *keenable.AuthError (Go) with the message prefix Keenable authentication failed (403). Cause 403 means the server won’t accept this key. Two cases return the same status:
  • On /v1/search, /v1/fetch and /mcp, the key usually exists but was revoked in your organization.
  • On /mcp-public, a key the server doesn’t accept also returns 403, not 401, so a mistyped or unknown key looks like a revoked one. See MCP server.
Fetch also returns 403 for reasons unrelated to your key. If the body says "error": "Upstream forbidden", the target site blocked the fetch, for example with a bot check. If it says Fetching from private/internal hosts is not allowed, the URL points at a private address. In both cases, check the error and message before you touch the key, and try a different URL instead. Fix
  1. Compare the key value with the one in the console ↗. Fix typos, stray quotes and leftover placeholders before treating the key as revoked.
  2. If the value matches and still gets 403, ask a human with console access to issue a new key, then update KEENABLE_API_KEY.
  3. On /mcp-public, you can also drop the key and stay on the public tier, or switch the URL to /mcp once the key is confirmed.

404 Page not found

Retry: fix the URL, then retry. What you see If the target page doesn’t exist, fetch returns 404:
Search does not use this status. Cause Keenable couldn’t find the URL you passed to Fetch: a typo, a moved page, or a link that never resolved. Fix Check the URL, then call fetch again with a corrected one. Retrying the same URL returns the same 404. If search gave you the link, try the next result instead.

422 Content could not be extracted

Retry: fix the URL or skip; do not retry the same URL. What you see If the page exists but Keenable can’t extract readable content from it, fetch returns 422 with "error": "Unprocessable entity" and a message such as The page is behind a login or paywall. Search returns 422 with Search failed and a status code in the message when the search fails in a way a retry won’t fix. Cause The URL is reachable, but extraction failed: an unsupported domain, a login wall or paywall, a page that is mostly binary or empty of text, an error status from the target site, or a failure inside the extractor. Fix Don’t retry the same URL. It fails the same way every time. Try a different URL from search, or fetch a cleaner source for the same topic. If many URLs from one site fail, the domain is probably unsupported, so skip that site.

429 Rate limit exceeded

Retry: wait, then retry. What you see The SDKs raise KeenableRateLimitError (Python, TypeScript) or *keenable.RateLimitError (Go) with the message prefix Keenable rate limit exceeded (429). Responses carry these headers, and a 429 adds Retry-After: Cause You sent requests faster than your limit allows:
  • Keyless: 1,000 requests per hour and 10 per second per IP, on a pool shared with everyone else on your egress address.
  • With an API key: 10 requests per second per organization, with no hourly cap.
See rate limits for every tier. A 429 can also come from further down the line. If the message says the target server rate-limited the fetch, or that search or fetch is temporarily rate-limited, your own limit isn’t the cause. Those responses carry Retry-After: 1. Fix Wait for the time in Retry-After, then retry. If you hit the keyless hourly cap, add an API key: it removes the hourly cap and gives you your own limit. For a higher per-second limit, talk to us.

5xx Server error

Retry: retry up to 3 times. What you see The SDKs raise KeenableAPIError (Python, TypeScript) or *keenable.APIError (Go) with the message prefix Keenable API error (5xx), where 5xx is the actual status, such as 500 or 503. Cause Something failed on Keenable’s side or on the way to the target page. The request itself is fine. The error field tells the cases apart:
  • 502 Bad gateway: fetch couldn’t reach the target page, for example after a DNS, TLS or connection failure.
  • 503 Authentication temporarily unavailable: Keenable couldn’t verify your key. The response carries Retry-After: 5.
  • 504 Gateway timeout: the target page took too long to respond.
  • 529 Overloaded: search is temporarily overloaded. The response carries Retry-After: 1.
Fix Retry up to 3 times, waiting longer before each attempt (for example 1, 2 and 4 seconds). If the response has a Retry-After header, wait at least that long. If the error persists after 3 attempts, stop and report it.

Report a problem

Responses from search and fetch carry an X-Request-Id header. Include its value when you get help, so we can find your request in our logs. The Go SDK adds it to the error message as request_id. If Keenable rejects a request before it reaches search or fetch, such as one that returns 400 or 401, the response has no request ID. For those, include the time of the request and the full response body.