Home / Developers
Developers

Companies House API rate limits and how to work around them

Updated By
Short answerThe Companies House API allows 600 requests in a five-minute window per API key, which is two requests a second on average. Above that, every request returns HTTP 429 until the window resets. Throttle on the client, read the X-Ratelimit headers, back off on 429, cache data that does not change and use bulk files for whole-register jobs.

The limit in numbers

Companies House allows 600 requests within a five-minute period for each API key. That is the official figure on the rate limiting guide, checked on 17 October 2026. Spread evenly, it is one request every 0.5 seconds.

MeasureValue
Requests per window600
Window5 minutes
Average sustained rate2 per second, 7,200 per hour, 172,800 per day
Response when exceededHTTP 429 Too Many Requests
Higher limitOn request to Companies House, for a clear use case

The guide also warns that applications that regularly exceed or try to bypass the limit can be banned without notice. Creating extra keys to multiply your quota counts as trying to bypass it.

What a 429 looks like

Once you pass 600 requests, Companies House returns 429 Too Many Requests for every request until the five-minute window ends. Every response, including successful ones, carries headers that tell you where you stand. These headers come from a real response on 17 October 2026:

X-Ratelimit-Limit: 1200
X-Ratelimit-Remain: 1199
X-Ratelimit-Reset: 1792193909
X-Ratelimit-Window: 5m

X-Ratelimit-Remain is the number of requests left in the current window and X-Ratelimit-Reset is the Unix time in seconds when it resets. The limit in this example is 1,200 because Companies House raised it for that application on request; a standard key shows 600. The headers are not described on the rate limiting page, so treat them as useful but code a fallback in case they are missing.

Throttle and back off: Python

The safest pattern is to pace requests on your side so that you rarely see a 429 at all, then handle the ones you do see by waiting until the reset time. This client sends at most one request every 0.5 seconds, sleeps until X-Ratelimit-Reset on a 429, and retries server errors with exponential backoff and jitter.

import os
import random
import time

import requests

API = "https://api.company-information.service.gov.uk"


class CompaniesHouse:
    def __init__(self, key, per_window=600, window=300):
        self.s = requests.Session()
        self.s.auth = (key, "")  # key as username, empty password
        self.interval = window / per_window  # 0.5 s between calls for 600 per 5 min
        self.next_slot = 0.0

    def get(self, path, params=None, max_retries=6):
        for attempt in range(max_retries):
            # Client-side throttle: never send faster than the limit allows.
            wait = self.next_slot - time.monotonic()
            if wait > 0:
                time.sleep(wait)
            self.next_slot = time.monotonic() + self.interval

            r = self.s.get(API + path, params=params, timeout=30)
            if r.status_code == 429:
                reset = r.headers.get("X-Ratelimit-Reset")
                delay = max(1.0, int(reset) - time.time()) if reset else 2 ** attempt
                time.sleep(delay + random.uniform(0, 1))
                continue
            if r.status_code >= 500:
                time.sleep(2 ** attempt + random.uniform(0, 1))
                continue
            if r.status_code == 404:
                return None
            r.raise_for_status()
            return r.json()
        raise RuntimeError(f"Gave up on {path} after {max_retries} attempts")


if __name__ == "__main__":
    ch = CompaniesHouse(os.environ["CH_API_KEY"])
    for number in ["00445790", "10623966", "SC316774"]:
        profile = ch.get(f"/company/{number}")
        print(number, profile["company_name"], profile["company_status"])

This version is for one thread. If you run several workers against the same key, share the throttle (a lock around next_slot, or a Redis counter) or give each worker a fraction of the rate. Workers that each assume they own 600 requests will hit 429 within a minute.

Throttle and back off: TypeScript

The same logic in TypeScript for Node 18+ or Bun, using the built-in fetch. The throttle reserves a time slot before it awaits, so parallel calls with Promise.all still queue at two a second instead of firing at once.

const API = "https://api.company-information.service.gov.uk";
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

export class CompaniesHouse {
  private auth: string;
  private interval: number;
  private nextSlot = 0;

  constructor(key: string, perWindow = 600, windowSeconds = 300) {
    this.auth = "Basic " + Buffer.from(`${key}:`).toString("base64");
    this.interval = (windowSeconds * 1000) / perWindow; // 500 ms for 600 per 5 min
  }

  private async throttle() {
    const now = Date.now();
    const slot = Math.max(now, this.nextSlot);
    this.nextSlot = slot + this.interval; // reserve the slot before awaiting
    if (slot > now) await sleep(slot - now);
  }

  async get<T = any>(path: string, maxRetries = 6): Promise<T | null> {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      await this.throttle();
      const res = await fetch(API + path, { headers: { Authorization: this.auth } });
      if (res.status === 429) {
        const reset = Number(res.headers.get("X-Ratelimit-Reset"));
        const delay = reset ? Math.max(1000, reset * 1000 - Date.now()) : 2 ** attempt * 1000;
        await sleep(delay + Math.random() * 1000);
        continue;
      }
      if (res.status >= 500) {
        await sleep(2 ** attempt * 1000 + Math.random() * 1000);
        continue;
      }
      if (res.status === 404) return null;
      if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
      return (await res.json()) as T;
    }
    throw new Error(`Gave up on ${path} after ${maxRetries} attempts`);
  }
}

const ch = new CompaniesHouse(process.env.CH_API_KEY!);
const numbers = ["00445790", "10623966", "SC316774"];
const profiles = await Promise.all(numbers.map((n) => ch.get(`/company/${n}`)));
for (const p of profiles) console.log(p?.company_number, p?.company_name, p?.company_status);

Both samples were run against the live API on 17 October 2026. Save the TypeScript as ch.ts and run it with CH_API_KEY=... bun ch.ts or npx tsx ch.ts.

Batch and cache what does not change

Most of the quota is wasted on data you already have. A few habits cut request counts sharply:

Use bulk files for whole-register jobs

For anything that touches every company, the API is the wrong tool. At 600 requests per five minutes, one profile request for each of the 5,704,712 companies on the 1 October 2026 register file takes 33 days on one key, and that is before filing history or documents.

The free bulk products give you the same data in hours. The monthly Free Company Data Product has every live company in CSV, the daily and monthly accounts files contain every electronically filed set of accounts, and the PSC snapshot is refreshed daily. Use the API only for the companies that changed. See Companies House bulk data explained for formats and sizes.

Requesting a higher limit

Companies House says that if your application needs a higher limit than the default, you should contact it, and it does grant increases. Explain what the application does, how many companies you look up per day, why bulk data does not cover it and what you cache. A specific, modest request with a clear purpose is more likely to succeed than a vague request for the maximum.

When a hosted dataset is cheaper

If what you actually need is accounts figures rather than live register data, the arithmetic changes. Getting net assets for one company from the official API takes three calls (filing history, document metadata, document content) plus your own parser, and about 30% of active companies have no machine-readable accounts at all.

A hosted API returns the parsed figures in one call. Ours covers about 37 million iXBRL filings since 2008. The free key gives 50 requests a month and needs no card: get one on the developer docs page. For a comparison of providers, see Companies House API alternatives.

FAQ

What is the Companies House API rate limit?

600 requests in any five-minute window for each API key, according to the Companies House developer guide checked on 17 October 2026. That averages two requests a second. When you exceed it, the API returns HTTP 429 for every request until the window ends. Companies House can raise the limit for applications that need more, on request.

How long does a 429 last?

Until the end of the current five-minute window, so at most five minutes. Read the X-Ratelimit-Reset header, which gives the reset time as Unix seconds, and sleep until then rather than retrying in a tight loop. Retrying immediately does not help: each retry is another rejected request, and repeated abuse can get the application banned.

Can I use several API keys to get around the limit?

Companies House warns that applications which try to bypass the rate limit can be banned without notice. Splitting one workload across many keys to multiply the quota is exactly that. The supported routes are to ask for a higher limit, use the free bulk products for large jobs, or cache more aggressively.

Does the Document API have a rate limit too?

Yes. Document API responses carry their own rate limit headers, and in our tests on 17 October 2026 they counted separately from the main API. Note the spelling: the Document API sends X-Ratelimit-Remaining, the main API sends X-Ratelimit-Remain. For large numbers of accounts, the free bulk accounts files are far more efficient and contain the same iXBRL files.

Try it with a free key. 50 requests a month, REST and MCP, no card. Company register, iXBRL financial history since 2008 and watchlist alerts.

Get a free API key