The most comprehensive .NET client for UK Parliament APIs. 100% API coverage - all 12 public Parliament APIs supported including Petitions, Members, Bills, Committees, Divisions, Interests, Questions, Treaties, Erskine May, and NOW.
$ dotnet add package Uk.Parliament![]()
The most comprehensive .NET library for UK Parliament APIs
100% API coverage - All 12 public Parliament APIs supported
This .NET library provides complete coverage of all 12 UK Parliament public APIs:
✅ Petitions API - Public petitions to Parliament
✅ Members API - MPs, Lords, constituencies, parties
✅ Bills API - Parliamentary legislation
⚠️ Committees API - Committee inquiries and submissions
🔴 Commons Divisions API - House of Commons voting records
🔴 Lords Divisions API - House of Lords voting records
✅ Member Interests API - Register of Members' Financial Interests
✅ Written Questions & Statements API - Parliamentary questions and statements
✅ Oral Questions & Motions API - Oral questions and motions
✅ Treaties API - International treaties laid before Parliament
✅ Erskine May API - Parliamentary procedure reference
✅ NOW (Annunciator) API - Real-time chamber status
Status: 9/12 APIs fully functional, 3/12 affected by Parliament infrastructure issues
Version 10.0.9 - Complete Refit-based implementation with type-safe REST API access.
Install via NuGet:
dotnet add package Uk.Parliament
Or via Package Manager Console:
Install-Package Uk.Parliament
using Uk.Parliament;
using Uk.Parliament.Extensions;
// Create unified client for all Parliament APIs
var client = new ParliamentClient();
// Petitions API
var petitions = await client.Petitions.GetAsync(state: "open", pageSize: 10);
foreach (var petition in petitions.Data)
{
Console.WriteLine($"{petition.Attributes.Action}: {petition.Attributes.SignatureCount:N0} signatures");
}
// Members API
var members = await client.Members.SearchAsync(name: "Smith", isCurrentMember: true, take: 10);
foreach (var member in members.Items)
{
Console.WriteLine($"{member.Value.NameFullTitle} - {member.Value.LatestParty?.Name}");
}
// Bills API
var bills = await client.Bills.GetBillsAsync(take: 10);
foreach (var bill in bills.Items)
{
Console.WriteLine($"{bill.ShortTitle} ({bill.BillTypeId})");
}
// Treaties API
var treaties = await client.Treaties.GetTreatiesAsync(status: "In Force", take: 10);
foreach (var treaty in treaties.Items)
{
Console.WriteLine($"{treaty.Value.CommandPaperNumber}: {treaty.Value.Title}");
}
// NOW API - Real-time chamber status
var status = await client.Now.GetCommonsStatusAsync();
Console.WriteLine($"Commons sitting: {status.IsSitting}");
if (status.IsSitting)
{
Console.WriteLine($"Current business: {status.CurrentBusiness}");
}
// Memory-efficient streaming (recommended for large datasets)
await foreach (var petition in client.Petitions.GetAllAsync(state: "open", pageSize: 50))
{
Console.WriteLine($"{petition.Attributes.Action}");
// Process one at a time - no memory overhead
}
// Or get all as a materialized list
var allPetitions = await client.Petitions.GetAllListAsync(state: "closed");
Console.WriteLine($"Total: {allPetitions.Count}");
// In Program.cs
services.AddSingleton<ParliamentClient>();
// Or with custom options
services.AddSingleton(sp => new ParliamentClient(new ParliamentClientOptions
{
UserAgent = "MyApp/1.0",
Timeout = TimeSpan.FromSeconds(30)
}));
// Inject into your services
public class MyService
{
private readonly ParliamentClient _parliament;
public MyService(ParliamentClient parliament)
{
_parliament = parliament;
}
}
Access public petitions to UK Parliament.
// Search petitions
var petitions = await client.Petitions.GetAsync(
search: "climate",
state: "open",
page: 1,
pageSize: 20);
// Get specific petition with full details
var petition = await client.Petitions.GetByIdAsync(700143);
Console.WriteLine($"Signatures: {petition.Data.Attributes.SignatureCount:N0}");
Console.WriteLine($"State: {petition.Data.Attributes.State}");
// Signatures by country
foreach (var country in petition.Data.Attributes.SignaturesByCountry)
{
Console.WriteLine($"{country.Name}: {country.SignatureCount:N0}");
}
Status: 27/27 tests passing ✅
Information about MPs, Lords, constituencies, and political parties.
// Search members
var members = await client.Members.SearchAsync(
name: "Johnson",
house: 1, // 1=Commons, 2=Lords
isCurrentMember: true);
// Get member details
var member = await client.Members.GetByIdAsync(172);
// Search constituencies
var constituencies = await client.Members.SearchConstituenciesAsync("London", take: 10);
Status: 17/17 tests passing ✅
Parliamentary legislation information.
// List bills
var bills = await client.Bills.GetBillsAsync(
searchTerm: "Budget",
currentHouse: "Commons",
take: 10);
// Get bill details
var bill = await client.Bills.GetBillByIdAsync(123);
// Get bill types
var billTypes = await client.Bills.GetBillTypesAsync();
Status: 12/12 tests passing ✅
Parliamentary committee information (API occasionally returns 500 errors from Parliament servers).
// List committees
var committees = await client.Committees.GetCommitteesAsync(take: 10);
// Get committee details
var committee = await client.Committees.GetCommitteeByIdAsync(1);
Status: 7/13 tests passing ⚠️ (Parliament API unstable)
Voting records (blocked by Parliament API 500 errors).
// When Parliament fixes API:
// var divisions = await client.CommonsDivisions.GetDivisionsAsync();
// var lordsDivisions = await client.LordsDivisions.GetDivisionsAsync();
Status: Interface complete, blocked by 100% API failure rate 🔴
Register of Members' Financial Interests.
// Get member's interests
var interests = await client.Interests.GetMemberInterestsAsync(172);
foreach (var category in interests.Categories)
{
Console.WriteLine($"{category.Category.Name}:");
foreach (var interest in category.Interests)
{
Console.WriteLine($" - {interest.InterestDetails}");
}
}
// Search interests
var results = await client.Interests.SearchInterestsAsync("employment", take: 10);
Status: 4/4 tests passing ✅
Parliamentary questions and ministerial statements.
// Get written questions
var questions = await client.QuestionsStatements.GetWrittenQuestionsAsync(
tabledWhenFrom: DateTime.Now.AddMonths(-1),
isAnswered: true,
take: 20);
// Get written statements
var statements = await client.QuestionsStatements.GetWrittenStatementsAsync(
madeWhenFrom: DateTime.Now.AddDays(-7),
take: 20);
// Get daily reports
var reports = await client.QuestionsStatements.GetDailyReportsAsync(
dateFrom: DateTime.Now.AddDays(-7));
Status: 4/4 tests passing ✅
Oral questions and parliamentary motions.
// Get oral questions
var questions = await client.OralQuestionsMotions.GetOralQuestionsAsync(
house: "Commons",
dateFrom: DateTime.Now.AddMonths(-1));
// Get motions (including Early Day Motions)
var motions = await client.OralQuestionsMotions.GetMotionsAsync(
motionType: "Early Day Motion",
isActive: true);
Status: 3/3 tests passing ✅
International treaties laid before Parliament.
// Get treaties
var treaties = await client.Treaties.GetTreatiesAsync(
status: "In Force",
dateLaidFrom: DateTime.Now.AddYears(-1));
// Get treaty details
var treaty = await client.Treaties.GetTreatyByIdAsync(123);
// Get treaty business items
var businessItems = await client.Treaties.GetTreatyBusinessItemsAsync(123);
// Get government organizations
var orgs = await client.Treaties.GetGovernmentOrganisationsAsync();
Status: 4/4 tests passing ✅
The authoritative guide to parliamentary procedure.
// Search parliamentary procedure
var results = await client.ErskineMay.SearchAsync("voting procedure", take: 10);
// Get all parts
var parts = await client.ErskineMay.GetPartsAsync();
// Get chapters in a part
var chapters = await client.ErskineMay.GetChaptersAsync(partNumber: 1);
// Get sections in a chapter
var sections = await client.ErskineMay.GetSectionsAsync(chapterNumber: 1, take: 20);
Status: 3/3 tests passing ✅
Real-time chamber status and business information.
// Get current Commons status
var status = await client.Now.GetCommonsStatusAsync();
Console.WriteLine($"Sitting: {status.IsSitting}");
Console.WriteLine($"Current: {status.CurrentBusiness}");
// Get upcoming business
var upcoming = await client.Now.GetUpcomingBusinessAsync("Commons");
// Get current business
var current = await client.Now.GetCurrentBusinessAsync("Lords");
Status: 4/4 tests passing ✅
var options = new ParliamentClientOptions
{
UserAgent = "MyApp/1.0",
Timeout = TimeSpan.FromSeconds(60),
EnableDebugValidation = false, // Strict JSON validation
EnableVerboseLogging = true, // Full HTTP logs
Logger = loggerFactory.CreateLogger("ParliamentClient")
};
var client = new ParliamentClient(options);
| API | Unit Tests | Integration Tests | Total | Status |
|---|---|---|---|---|
| Petitions | 17 | 10 | 27 | ✅ 100% |
| Members | 6 | 11 | 17 | ✅ 100% |
| Bills | 3 | 9 | 12 | ✅ 100% |
| Committees | 1 | 6 | 7 | ⚠️ 54% |
| Divisions | 4 | 0 | 4 | 🔴 Unit only |
| Interests | 4 | 8 | 12 | ✅ 100% unit |
| Questions/Statements | 4 | 15 | 19 | ✅ 100% unit |
| Oral Questions | 3 | 8 | 11 | ✅ 100% unit |
| Treaties | 4 | 6 | 10 | ✅ 100% unit |
| Erskine May | 3 | 6 | 9 | ✅ 100% unit |
| NOW | 4 | 4 | 8 | ✅ 100% unit |
| TOTAL | 53 | 83 | 136 | 86 passing |
git clone https://github.com/panoramicdata/Uk.Parliament.git
cd Uk.Parliament
dotnet build
dotnet test
v1.x:
var client = new PetitionsClient();
var result = await client.GetPetitionAsync(123, CancellationToken.None);
if (result.Ok) { /* use result.Data */ }
v2.0+:
var client = new ParliamentClient();
var petition = await client.Petitions.GetByIdAsync(123);
// Direct access, throws ApiException on error
Contributions welcome! Priority areas:
MIT License - see LICENSE file
Copyright © 2025 Panoramic Data Limited
Thanks to the UK Parliament Digital Service for providing these public APIs.
For API issues, contact: softwareengineering@parliament.uk