> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nordicfinancialnews.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limit exceeded

> The 429 problem type returned when a request exceeds a rate limit.

<Info>
  Problem type: `https://docs.nordicfinancialnews.com/problems/rate-limit-exceeded`
</Info>

The API returns this problem type with HTTP `429` when a request exceeds a rate limit.

The limit you will normally meet is the per-API-key one, which is hourly. Separate per-IP limits run over shorter windows and apply to all API traffic, so a burst can trip one of those before you reach your hourly ceiling. Semantic searches draw on [their own smaller budget](#the-semantic-search-sub-limit) as well. Always read `Retry-After` rather than assuming which limit you hit.

This condition is temporary. The same request succeeds once the current window resets, so treat it as a signal to slow down rather than an error in your request.

## Example response

```json theme={"dark"}
{
  "type": "https://docs.nordicfinancialnews.com/problems/rate-limit-exceeded",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "Rate limit of 100 requests per hour exceeded. Please retry after 1847 seconds.",
  "instance": "urn:request:7f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c"
}
```

The response body uses the `application/problem+json` media type.

## Response headers

| Header                  | Description                                                                                                                                  |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `Retry-After`           | Seconds to wait before retrying. Always present on this problem type                                                                         |
| `X-RateLimit-Limit`     | Your hourly request ceiling                                                                                                                  |
| `X-RateLimit-Remaining` | Requests left against that ceiling. `0` when it is the limit you hit, but see the [semantic sub-limit](#the-semantic-search-sub-limit) below |
| `X-RateLimit-Reset`     | Seconds until the window resets                                                                                                              |

Windows are fixed rather than sliding, so your allowance returns all at once when the window rolls over rather than trickling back. `Retry-After` counts the seconds until that moment.

## How to fix it

Read `Retry-After` and wait that many seconds before retrying. Do not retry immediately, and do not retry on a fixed short interval, because those requests are rejected too and still count toward the IP-level limits.

```python Python theme={"dark"}
import time
import requests

def get(url, headers, max_attempts=5):
    for attempt in range(max_attempts):
        response = requests.get(url, headers=headers)
        if response.status_code != 429:
            return response
        if attempt == max_attempts - 1:
            break
        time.sleep(int(response.headers.get("Retry-After", 60)))
    raise RuntimeError("Rate limited after %d attempts" % max_attempts)
```

To avoid hitting the limit at all:

* Watch `X-RateLimit-Remaining` on every response and slow down as it approaches zero, rather than waiting for the `429`.
* Use [conditional requests](/guides/caching). A `304 Not Modified` still counts toward your hourly rate limit, but it saves bandwidth and does not count toward your monthly quota.
* Narrow your polling. [Cursor pagination](/guides/pagination) with `updated_after` retrieves only what changed instead of re-reading a full page.
* Request only the fields you need with [field projection](/guides/field-projection).

Your current limits and usage are shown in [API key settings](https://nordicfinancialnews.com/settings/api_keys).

## The semantic search sub-limit

Searches that pass `mode=semantic` draw on a second, smaller budget: **120 semantic searches per hour per API key**. This is separate from and additional to your plan's request limit, so you can exhaust it while your ordinary allowance is untouched.

One budget covers every resource. Semantic searches against articles, stories and companies all draw from the same 120, rather than getting one allowance each. It is enforced inside the application rather than at the edge, so MCP tool calls count against it exactly as REST requests do.

Every semantic request draws from the budget, including one whose filters match nothing. A search that returns an empty page still costs you a call.

Both sources return this same problem type, so tell them apart by `detail`:

```json theme={"dark"}
{
  "type": "https://docs.nordicfinancialnews.com/problems/rate-limit-exceeded",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "Too many semantic searches (120 per hour per API key, shared across every semantic-mode resource). Retry after 1847 seconds, or drop mode=semantic to use keyword search meanwhile.",
  "instance": "urn:request:7f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c"
}
```

<Warning>
  The `X-RateLimit-*` headers describe your plan's request limit, not this sub-limit. On a semantic `429` you can see a non-zero `X-RateLimit-Remaining`, because that budget genuinely is not exhausted. Read `Retry-After` and `detail` instead.
</Warning>

Keyword search is not affected while the sub-limit is in effect. Dropping `mode=semantic` lets you keep querying immediately, at the cost of keyword rather than semantic ranking. As with [semantic search unavailable](/problems/semantic-unavailable), make that switch explicit so you always know which ranking produced your results.

`Retry-After` counts the seconds to the top of the hour, when the full 120 returns at once.

## Not the same as a monthly quota

An hourly rate limit and a monthly usage quota are separate ceilings, and they return different problem types. If you have exhausted your monthly allowance, you get `monthly-limit-exceeded` instead, which also uses status `429`. Branch on `type`, not on the status code alone.

A rate limit clears within the hour. A monthly quota does not clear until your plan's reset date.

## Related

* [Error handling](/guides/errors) for the full problem type list
* [Authentication](/guides/authentication) for rate limit headers and what counts toward your quota
* [Caching](/guides/caching) for reducing request volume with ETags
