What Registrum adds on top of Companies House
The Companies House API is free and official — but it returns raw metadata with no financial data, no computed fields, and no resilience. Registrum adds 15 data categories and the infrastructure to use it reliably in production.
The response, side by side
Same company (Tesco PLC, 00445790), same instant. Highlighted fields are computed, derived, or entirely new.
{
"company_name": "TESCO PLC",
"company_number": "00445790",
"company_status": "active",
"type": "plc",
"date_of_creation": "1947-11-27",
"registered_office_address": { ... },
"sic_codes": ["47110"],
"accounts": { "next_accounts": { "due_on": "2024-07-24" }, "last_accounts": { "made_up_to": "2024-02-24" } },
"confirmation_statement": { "next_due": "2025-06-15" },
"links": { "filing_history": "...", "officers": "..." },
}
≈ 10 fields · No financial data · Dates require calculation · No quality signals
{
"company_name": "TESCO PLC",
"company_number": "00445790",
"company_status": "active",
"company_age_years": 78,enriched
"accounts": { "overdue": false, "next_due": "2024-07-24" },enriched
"sic_codes": ["47110"],
"sic_descriptions": ["Retail sale in non-specialised stores"],enriched
"financials": { "turnover": { "current": 68190000000 }, "profit_after_tax": { "current": 1400000000 }, ... },new field
"cached": true,
"credits_remaining": 49,
}
Field-by-field comparison
| Data category | Companies House (direct) | Registrum |
|---|---|---|
| Company name / number / status | ✓ Raw | ✓ Same |
| Company age | ✗ Must calculate from date_of_creation | ✓ company_age_years pre-computedenriched |
| Accounts overdue | ✗ Must compare two date fields | ✓ accounts.overdue booleanenriched |
| Confirmation overdue | ✗ Must compare two date fields | ✓ confirmation_statement.overdue booleanenriched |
| SIC code descriptions | ✗ Codes only (e.g. 47110) | ✓ Human-readable descriptions includedenriched |
| Revenue / turnover | ✗ Link to iXBRL filing document only | ✓ Parsed JSON integer (actual GBP)new field |
| Profit & loss statement | ✗ Not available via API | ✓ Full P&L: gross profit, operating profit, PATnew field |
| Balance sheet | ✗ Not available via API | ✓ Assets, liabilities, equity, net assetsnew field |
| Employee count | ✗ Not available via API | ✓ average_employees from filingsnew field |
| Prior year financials | ✗ Not available via API | ✓ prior field on every financial valuenew field |
| Director list | ✓ Paginated (multiple calls required) | ✓ Deduplicated, single endpointimproved |
| Director appointments | ✗ One API call per director | ✓ Included in directors responsenew field |
| Director network (related companies) | ✗ Many paginated calls, manual dedup required | ✓ One network endpoint, auto-traversalnew field |
| Rate limit protection | ✗ 600 req/5min, errors propagate to your app | ✓ Cached responses, shared budget shieldedinfrastructure |
| Resilience on CH outage | ✗ 5xx errors propagate to your app | ✓ Stale cache served with X-Data-Stale headerinfrastructure |
| Request tracing | ✗ No correlation IDs | ✓ X-Request-Id on every responseinfrastructure |
| Data quality signals | ✗ None | ✓ data_quality block with completeness rationew field |
The real cost of doing it yourself
The director network endpoint collapses ~16 paginated CH API calls into one. Each of those raw calls counts toward your 600 req/5min limit — and produces no caching. With Registrum the result is cached for 24h and shared across all your requests.
# Python — director network with raw CH API
# Requires multiple paginated calls
import requests, base64
def get_network(company_number, ch_api_key):
auth = base64.b64encode(f"{ch_api_key}:".encode()).decode()
headers = {"Authorization": f"Basic {auth}"}
base = "https://api.company-information.service.gov.uk"
# Step 1: get officers
officers = requests.get(
f"{base}/company/{company_number}/officers",
headers=headers
).json().get("items", [])
network = {}
seen_officers = set()
for officer in officers:
link = officer.get("links", {}).get("officer", {})
appts_path = link.get("appointments", "")
officer_id = appts_path.strip("/").split("/")[1]
if officer_id in seen_officers:
continue
seen_officers.add(officer_id)
# Step 2: one call per officer
appts = requests.get(
f"{base}/officers/{officer_id}/appointments",
headers=headers
).json().get("items", [])
for a in appts:
cn = a.get("appointed_to", {}).get("company_number")
if cn and cn != company_number:
network.setdefault(cn, []).append(officer["name"])
# Result: 1 + N calls (N = number of officers)
# Tesco has ~15 officers = ~16 CH API calls
# No caching. Rate limit consumed every time.
return network# Python — director network with Registrum
# One call. Cached 24h. Rate-limit safe.
import requests
def get_network(company_number, api_key):
r = requests.get(
f"https://api.registrum.co.uk/v1/company/{company_number}/network",
params={"depth": 1},
headers={"X-API-Key": api_key},
)
data = r.json()["data"]
return data["companies"]
# Returns: list of connected companies
# sorted by connection strength (shared directors)Try it free
50 free calls per month. All endpoints. No credit card.