Companies House
Companies House Company Officers API
Every officer a UK company has ever appointed - serving and resigned - off the official statutory register: name, role, appointment and resignation dates, correspondence address, nationality, country of residence, month-and-year date of birth, and identity-verification status. 35 officers per page. Keyed by company_number, which you get from the search endpoint. Costs 1 credit per request.
Authorizations
AuthorizationstringheaderrequiredBearer authentication header of the form Bearer <token>, where <token> is your Scavio API key (e.g. Bearer sk_live_your_key).
Body
application/jsoncompany_numberstringrequiredUK company number, 1-20 characters. Zero-padded to 8 and upper-cased for you, so 445790 and sc090312 both resolve - the register itself 404s on those forms. Registry prefixes supported: SC, NI, OC/SO/NC, FC, BR, CE. Up to two letters followed by digits, 8 characters after padding; anything else is a 400.
Example: 00445790
pageintegerdefault:1Results page, 1-based, 35 officers per page. NO upper bound - unlike search, this endpoint has no page cap, and a page past the last one is an ordinary 200 with an empty officers[] rather than an error. That document is indistinguishable upstream from a company with genuinely no officers, so loop on has_next_page rather than on a page count.
Example: 2
Request
from scavio import ScavioClient
client = ScavioClient(api_key="sk_live_your_key")
# There is no server-side active/resigned filter - the register's own toggle
# is client-side. Filter on each officer's status yourself.
page = client.companies_house.officers("00445790")
data = page["data"]
serving = [o for o in data["officers"] if o["status"] == "Active"]
for officer in serving:
print(officer["name"], "-", officer["role"], "since", officer["appointed_on"])
print(data["active_officers_count"], "serving across", data["total_pages"], "pages")Response