Search the UK Companies House register by name, then pull a company's full register entry, its officers, and its filing history as structured JSON. 4 endpoints, 1 credit each.
数据分析
UK Company Data API - Companies House Filings and Officers
试用Search the UK Companies House register by name, then pull a company's full register entry, its officers, and its filing history as structured JSON. 4 endpoints, 1 credit each.
它能做什么
Search the UK Companies House register by name, then pull a company's full register entry, its officers, and its filing history as structured JSON. 4 endpoints, 1 credit each.
技能文档
Companies House via Scavio
Search the UK register by company name, then read the full register entry, the officers current and resigned, and the complete filing history. All four endpoints return structured JSON from the official UK registry.
When to trigger
Use this skill when the user asks to:
- Find a UK company's registration number from its name
- Check whether a UK company is active, dissolved, or overdue on its accounts
- List a company's directors and secretaries, current and resigned
- Read a company's filing history and pull the filed PDFs
- Run KYB or due-diligence checks on a UK counterparty
- Look up SIC codes, incorporation dates, registered offices or previous names
- Build UK B2B datasets or company-monitoring pipelines
Setup
Get a free API key at scavio.dev (50 free credits to get started, no card required):
export SCAVIO_API_KEY=sk_live_your_key
Every request is a POST with a JSON body and:
Authorization: Bearer $SCAVIO_API_KEY
Endpoints
Base URL: https://api.scavio.dev. All paths are under /api/v1/companieshouse. Every endpoint costs 1 credit.
| Endpoint | Credits | What it returns |
|---|---|---|
POST /api/v1/companieshouse/search | 1 | Start here. Name search returning the company number |
POST /api/v1/companieshouse/company | 1 | Full register entry for one company |
POST /api/v1/companieshouse/officers | 1 | Officers current and resigned, 35 per page |
POST /api/v1/companieshouse/filing-history | 1 | Filings, most recent first, with the filed PDF |
Note the last path is hyphenated: /filing-history.
Workflow
Search first. Everything except /search is keyed by the company number.
- Find the company: call
/companieshouse/searchwithquery. The register matches current and former names, so a rebranded company is still findable under its old one. - Read the entry: call
/companieshouse/companywithcompany_number. - People: call
/companieshouse/officerswith the same number. - Filings: call
/companieshouse/filing-historywith the same number.
Company numbers are normalised for you
company_number is deliberately loose - there is no format check. The register 404s on /company/445790 and /company/sc090312 for companies that genuinely exist, so the transport zero-pads and upper-cases the value before sending it. That means a number copied off a letterhead, or one a spreadsheet stripped the leading zeros from, still resolves.
Registry prefixes supported: SC (Scotland), NI (Northern Ireland), OC / SO / NC (LLPs), FC (overseas), BR (UK establishment), CE (charitable incorporated organisation).
Pagination
The three paginated endpoints behave differently at the end of the list, and it matters.
/search-page1-50, 20 results per page, hard-capped at page 50. The register serves a 1000-result window per term whatever hit count it prints: it will claim 10,000 hits for a broad term and then answer page 51 with an HTTP 416. Narrow the query rather than paging deeper./officers-page, 35 per page, no upper bound. Past the last page the register answers an ordinary200with an empty list./filing-history-page, no upper bound, same empty-200behaviour past the end.
So on officers and filings, an empty page is the stop signal - and it is indistinguishable from a company that has no officers or no filings at all. Check page 1 before concluding anything.
/company returns a single object and takes no paging parameter.
Parameters
Search (/search)
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | required | Company name or fragment (1-200 chars, non-blank). Matches current and former names. |
page | integer | 1 | 1-50. 20 results per page; the register only serves the first 1000 matches. |
Company (/company)
| Parameter | Type | Default | Description |
|---|---|---|---|
company_number | string | required | 1-20 chars. Zero-padded and upper-cased for you. |
Officers (/officers)
| Parameter | Type | Default | Description |
|---|---|---|---|
company_number | string | required | |
page | integer | 1 | 35 per page. No upper bound - past the last page is a 200 with an empty list. |
Filing history (/filing-history)
| Parameter | Type | Default | Description |
|---|---|---|---|
company_number | string | required | |
page | integer | 1 | No upper bound - past the last page is a 200 with an empty list. |
Examples
import requests
BASE = "https://api.scavio.dev"
# Your key from https://scavio.dev. Load it from your environment or secret
# store in real code - keep it out of source control.
API_KEY = "sk_your_key_here"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1. Find the company number - matches former names too
hits = requests.post(f"{BASE}/api/v1/companieshouse/search", headers=HEADERS,
json={"query": "Monzo Bank", "page": 1}).json()
# 2. Full register entry. Loose numbers are fine - "445790" and "sc090312" both work.
company = requests.post(f"{BASE}/api/v1/companieshouse/company", headers=HEADERS,
json={"company_number": "09446231"}).json()
# 3. Officers, current and resigned
officers = requests.post(f"{BASE}/api/v1/companieshouse/officers", headers=HEADERS,
json={"company_number": "09446231", "page": 1}).json()
# 4. Filings, most recent first (note the hyphen in the path)
filings = requests.post(f"{BASE}/api/v1/companieshouse/filing-history", headers=HEADERS,
json={"company_number": "09446231", "page": 1}).json()
Officers and filings have no upper page bound, so page until a page comes back empty - that is the only stop signal:
def walk(path, company_number, max_pages=10):
"""1 credit per page. Stop on the first empty page."""
pages = []
for page in range(1, max_pages + 1):
data = requests.post(f"{BASE}/api/v1/companieshouse/{path}", headers=HEADERS,
json={"company_number": company_number, "page": page}).json()["data"]
if not data:
break # empty page: past the end (or nothing to list at all)
pages.append(data)
return pages
Response shapes
Every response uses the envelope { data, response_time, credits_used, credits_remaining }.
- search - company number, name, status, incorporation or dissolution date, registered office address, and the matched former names. 20 per page.
- company - status, type, incorporation and dissolution dates, registered office, SIC codes, previous names, accounts and confirmation-statement due dates with overdue flags, and whether it has charges, insolvency history, officers or UK establishments. An
FCcompany also returns home registry, legal form and governing law; aBRreturns its parent; aCEreturns the charity number. - officers - name, role, appointment and resignation dates, correspondence address, nationality, country of residence, month-and-year date of birth, and identity-verification status. 35 per page.
- filing-history - date, filing type code (
AA,CS01,SH03), description, register annotations and child documents, and a link to the filed PDF with its page count.
Counting active officers. officers_count is every appointment ever made and resignations_count is how many of those ended, so the number of currently-appointed officers is the difference, not officers_count. There is no server-side active/resigned filter - the register does that client-side - so filter on each officer's status in the response.
A filing still being processed carries a processing_note instead of a document. That is not an error and the document is not missing permanently.
Guardrails
- Every call is 1 credit. A full profile (search + company + officers + filings) is 4.
- Search is capped at page 50. The register serves a 1000-result window per term no matter what hit count it prints, and page 51 is an HTTP 416. Never promise an exhaustive list from a broad term - narrow the query.
- On officers and filing history, an empty page means either "past the end" or "there are none". Do not report "no directors" from an empty page 3 - check page 1.
- Do not compute active officers as
officers_count. Subtractresignations_count, or count rows whosestatussays active. - A missing document with a
processing_noteis a filing the register has not finished processing. Say that, rather than "the document is unavailable". - Officer records include a partial date of birth and a correspondence address. This is public register data, but treat it with care: do not compile it into profiles of private individuals beyond what the user actually asked for.
- Never fabricate company numbers, officer names, dates or filing codes. Only return API data, and quote the company number alongside the name so the user can verify.
Failure handling
400means an invalid or missing parameter, e.g. a blankquery. Fix and retry.401means the API key is invalid or missing. CheckSCAVIO_API_KEY.404means the company number does not resolve. The transport already pads and upper-cases, so re-check the number via/searchrather than reformatting it yourself.429means rate or usage limit exceeded. Wait before retrying. See https://scavio.dev/docs/rate-limits.502/503mean upstream is temporarily unavailable - wait a few seconds and retry.- If a name search returns nothing, try a shorter fragment - the register matches former names, so an old trading name is worth a second attempt.
- If
SCAVIO_API_KEYis not set, prompt the user to export it before continuing.
Python SDK
langchain-scavio has no Companies House tool - use the Scavio SDK directly:
pip install scavio==0.15.0
from scavio import ScavioClient
client = ScavioClient() # reads SCAVIO_API_KEY
hits = client.companies_house.search("Monzo Bank")
company = client.companies_house.company("09446231")
officers = client.companies_house.officers("09446231", page=1)
filings = client.companies_house.filing_history("09446231", page=1)
JavaScript / TypeScript:
npm install scavio@0.15.0
import { Scavio } from "scavio";
const scavio = new Scavio(); // reads SCAVIO_API_KEY
const hits = await scavio.companiesHouse.search({ query: "Monzo Bank" });
const filings = await scavio.companiesHouse.filingHistory({ company_number: "09446231" });
相关技能
Enrich a list of companies (names, domains, or LinkedIn URLs) with firmographic data like industry, employee count, headquarters, and founding year. Use when the user wants to enrich, look up, or research a batch of companies.
Retrieve overseas shareholders, executives and ultimate beneficial owners by company ID. Analyze equity structure for due‑diligence, investment research and competitor background checks. Trigger: ultimate beneficial owner check, corporate equity structure lookup, overseas shareholder research, company due‑diligence, related‑party transaction screening, identify actual company controllers
Search for people at a company by domain and role keywords. Returns obfuscated profiles (first name, last-name initial, title, company). No email addresses....
Handelsregister AI (handelsregister.ai). Use this skill for ANY Handelsregister AI request — searching and reading data. Whenever a task involves Handelsregister AI, use this skill instead of calling the API directly.
Discover and qualify target companies from public evidence