CompaniesHouse.Extensions.Microsoft.DependencyInjection 9.0.0

dotnet add package CompaniesHouse.Extensions.Microsoft.DependencyInjection --version 9.0.0
                    
NuGet\Install-Package CompaniesHouse.Extensions.Microsoft.DependencyInjection -Version 9.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CompaniesHouse.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CompaniesHouse.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
                    
Directory.Packages.props
<PackageReference Include="CompaniesHouse.Extensions.Microsoft.DependencyInjection" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CompaniesHouse.Extensions.Microsoft.DependencyInjection --version 9.0.0
                    
#r "nuget: CompaniesHouse.Extensions.Microsoft.DependencyInjection, 9.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CompaniesHouse.Extensions.Microsoft.DependencyInjection@9.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CompaniesHouse.Extensions.Microsoft.DependencyInjection&version=9.0.0
                    
Install as a Cake Addin
#tool nuget:?package=CompaniesHouse.Extensions.Microsoft.DependencyInjection&version=9.0.0
                    
Install as a Cake Tool

CompaniesHouse.NET

A .NET client for the Companies House Public Data API.

install from nuget downloads Build status

Upgrading from an earlier version? This is a major, deliberately breaking rewrite. See MIGRATION.md for the full list of changes and before/after snippets.

Installation

Two NuGet packages are published:

# The core client and all request/response models
dotnet add package CompaniesHouse

# Optional: DI helpers for ASP.NET Core / generic-host apps
dotnet add package CompaniesHouse.Extensions.Microsoft.DependencyInjection

Both packages multi-target net8.0, net9.0 and net10.0.

Getting an API key

Register an application on the Companies House developer hub to get an API key for the public data API.

Getting started

Constructing the client directly

using CompaniesHouse;

var settings = new CompaniesHouseSettings(apiKey);

using var client = new CompaniesHouseClient(settings);

CompaniesHouseClient implements IDisposable - always dispose it (or wrap it in a using block) once you're done, since it owns an underlying HttpClient.

You can also construct the client from your own HttpClient (useful in tests, or when you want full control over handlers/base address):

using var httpClient = new HttpClient { BaseAddress = CompaniesHouseUris.Default };
httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{apiKey}:")));

using var client = new CompaniesHouseClient(httpClient);

Dependency injection

Install CompaniesHouse.Extensions.Microsoft.DependencyInjection and register the client on your IServiceCollection. Several overloads are available, built on IOptions<CompaniesHouseClientOptions>:

// Simplest - just an API key
services.AddCompaniesHouseClient(apiKey);

// A custom base URI (e.g. against a sandbox/test host)
services.AddCompaniesHouseClient(new Uri("https://api.company-information.service.gov.uk/"), apiKey);

// Full control via a delegate
services.AddCompaniesHouseClient(options =>
{
    options.ApiKey = apiKey;
    options.BaseUri = CompaniesHouseUris.Default;
});

// Bind from IConfiguration (defaults to the "CompaniesHouse" section)
services.AddCompaniesHouseClient(configuration);

Every overload also accepts an optional configureHttpClientBuilder delegate, letting you customise the underlying IHttpClientBuilder (e.g. to add Polly resilience handlers):

services.AddCompaniesHouseClient(apiKey, builder => builder.AddStandardResilienceHandler());

Once registered, inject ICompaniesHouseClient - the main facade interface - into your dependencies:

public class MyPageModel(ICompaniesHouseClient client) : PageModel
{
    // ...
}

Document endpoints (GetDocumentMetadataAsync/DownloadDocumentAsync) talk to a separate host and are registered independently via AddCompaniesHouseDocumentClient, with the same set of overloads.

IConfiguration example

{
  "CompaniesHouse": {
    "ApiKey": "your-api-key",
    "BaseUri": "https://api.company-information.service.gov.uk/"
  }
}
services.AddCompaniesHouseClient(builder.Configuration);

Enum/value-type handling

Every "enum" in the Companies House API (company status, officer role, charge type, etc.) is modelled as a string-backed, readonly record struct rather than a plain C# enum. This is deliberate: Companies House regularly adds new wire values, and a plain enum throws (or silently defaults) the moment it sees one it doesn't recognise. See the design rationale for the full background.

CompanyStatus status = companyProfile.CompanyStatus;

status.Value;       // the raw wire value, e.g. "active"
status.HasValue;     // false only for the default/absent value
status.IsKnown;      // true if this library recognises the value
status.Description;  // a friendly description for known values, e.g. "Active"

Compare against the generated static members (CompanyStatus.Active, CompanyStatus.Dissolved, ...) rather than raw strings, and always keep a fallback arm for values you don't recognise yet:

var description = status switch
{
    _ when status == CompanyStatus.Active => "is active",
    _ when status == CompanyStatus.Dissolved => "is dissolved",
    _ when status.IsKnown => status.Description,
    _ => $"unrecognised status: {status.Value}", // never throws
};

New values ship as a new minor version of the CompaniesHouse package (the value types are generated from the official api-enumerations data)

  • you never need to hand-edit or wait on a code change to keep deserializing.

Reading responses

Every client method returns a CompaniesHouseResponse<T> — a discriminated union whose concrete subtype tells you exactly what happened:

Subtype When Extra property
Success 2xx Data (non-null), Headers
NotFound 404
RateLimited 429 RetryAfter
Unauthorized 401/403
ClientError other 4xx
ServerError 5xx RetryAfter

All subtypes expose StatusCode and ReasonPhrase. Transport failures (network errors, DNS, timeout) propagate as HttpRequestException from the underlying HttpClient.

Simple happy path

Call .Data directly — it returns the deserialized body on Success and throws InvalidOperationException for every other subtype, so you never silently get null:

var company = (await client.GetCompanyProfileAsync(companyNumber)).Data;
Console.WriteLine(company.CompanyName);

Full branching

Use a switch expression when you need to handle specific outcomes:

var result = await client.GetCompanyProfileAsync(companyNumber);

var message = result switch
{
    CompaniesHouseResponse<CompanyProfile>.Success { Data: var company } =>
        $"Found: {company.CompanyName}",

    CompaniesHouseResponse<CompanyProfile>.NotFound =>
        "Company not found.",

    CompaniesHouseResponse<CompanyProfile>.RateLimited { RetryAfter: var delay } =>
        $"Rate limited — retry after {delay}.",

    CompaniesHouseResponse<CompanyProfile>.Unauthorized =>
        "Check your API key.",

    CompaniesHouseResponse<CompanyProfile>.ServerError { StatusCode: var code, RetryAfter: var delay } =>
        $"Server error {code} — retry after {delay}.",

    _ => $"Unexpected response: {result.StatusCode}",
};

Usage

Searching for resources

var request = new SearchAllRequest
{
    Query = "Jay2Base",
    StartIndex = 0,
    ItemsPerPage = 10
};

var result = await client.SearchAllAsync(request);

foreach (var item in result.Data.Items)
{
    // Do something...
}

For a specific resource type, use SearchCompanyAsync, SearchOfficerAsync, SearchDisqualifiedOfficerAsync, SearchCompaniesAlphabeticallyAsync, SearchDissolvedCompaniesAsync or AdvancedCompanySearchAsync with the matching request type.

var companies = await client.SearchCompanyAsync(new SearchCompanyRequest { Query = "Jay2Base" });
var officers = await client.SearchOfficerAsync(new SearchOfficerRequest { Query = "Jay2Base" });
var disqualified = await client.SearchDisqualifiedOfficerAsync(new SearchDisqualifiedOfficerRequest { Query = "Jay2Base" });

Getting a company profile

var result = await client.GetCompanyProfileAsync("10440441");

result is a NotFound subtype if there was no match for that company number.

Getting the company officer list

var result = await client.GetOfficersAsync("03977902");

// Optionally page the results
var page = await client.GetOfficersAsync("03977902", startIndex: 10, pageSize: 10);

A single officer appointment can be fetched directly:

var officer = await client.GetOfficerByAppointmentIdAsync("03977902", appointmentId);

Getting officer appointments

var result = await client.GetAppointmentsAsync(officerId, startIndex: 0, pageSize: 25);

Getting the company filing history

var result = await client.GetCompanyFilingHistoryAsync("10440441", startIndex: 0, pageSize: 25);

var item = await client.GetFilingHistoryByTransactionAsync("10440441", transactionId);

Getting company insolvency information

var result = await client.GetCompanyInsolvencyInformationAsync("10440441");

result is a NotFound subtype if there is no insolvency information for the company.

Getting persons with significant control

var result = await client.GetPersonsWithSignificantControlAsync("10440441", startIndex: 0, pageSize: 25);

Getting charges

var charges = await client.GetChargesListAsync("10440441", startIndex: 0, pageSize: 25);

var charge = await client.GetChargeByIdAsync("10440441", chargeId);

Getting the registered office address

var result = await client.GetRegisteredOfficeAddress("10440441");

Getting document metadata and downloading a document

var metadata = await client.GetDocumentMetadataAsync("FIxRR8teCKodjkBLRDHv2Cb8y0-nQ7T5G3BEXfWtOu4");

var document = await client.DownloadDocumentAsync("FIxRR8teCKodjkBLRDHv2Cb8y0-nQ7T5G3BEXfWtOu4");

metadata/document is a NotFound subtype if there was no metadata/document for the given id.

More endpoints land progressively - see .plans/ for what's in flight.

Sample project

A runnable end-to-end example, covering direct construction, DI registration, search, company profile, officers, and gracefully handling an unrecognised enum value, lives in samples/SampleProject.

Contributing

  1. Fork
  2. Hack!
  3. Pull Request

See AGENTS.md for repository conventions, build/test commands and the design decisions behind the v-next rewrite.

Maintainer release notes

NuGet publishing is driven by the CI Docker build, which produces the final .nupkg artifacts in ./artifacts. Before push-to-NuGet, CI validates that each package contains README.md and has nuspec <readme>README.md</readme> metadata so NuGet.org renders the project README correctly.

Running tests

dotnet restore
dotnet build -c Release
dotnet test  -c Release

Integration tests hit the real Companies House API and need an API key in the COMPANIES_HOUSE_API_KEY environment variable - they're skipped/fail without one, which is expected when working offline.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
9.0.0 112 7/6/2026
9.0.0-pre82 92 7/6/2026
9.0.0-pre81 99 7/6/2026
9.0.0-pre80 96 7/6/2026
9.0.0-pre79 91 7/6/2026
9.0.0-pre78 98 7/4/2026
9.0.0-pre77 105 7/3/2026
9.0.0-pre76 94 7/3/2026
9.0.0-pre75 96 7/3/2026
9.0.0-pre71 94 7/3/2026
9.0.0-pre70 97 7/3/2026
9.0.0-pre69 101 7/3/2026
8.0.67 274 7/3/2026
8.0.64 3,990 4/14/2026
8.0.58 8,047 8/24/2025
8.0.56 296 8/24/2025
8.0.55 300 8/24/2025
8.0.53 249 8/24/2025
8.0.52 248 8/24/2025
8.0.40 1,164 6/28/2025
Loading failed