A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.
⚠️ Prerelease software. This package is currently in alpha. Public APIs may change between releases. See VERSIONING.md for the full versioning policy and stability expectations.
- ✅ OAuth 2.0 authentication with automatic token refresh
- ✅ Rate limiting support to respect API constraints
- ✅ Bounded retries for transient failures
- ✅ Typed SDK exception model
- ✅ Pagination support (single-page and auto-pagination)
- ✅ Company API support (company details, business categories, tax timeline)
- ✅ Contacts API support (list page and auto-pagination)
- ✅ Supports .NET 8.0 and .NET 10.0 (primary focus)
- ✅ Fully async/await
- ✅ Comprehensive XML documentation
dotnet add package FreeAgent.ClientFirst, create an OAuth client to handle the authentication flow:
usingFreeAgent.Client;varoauthClient=newFreeAgentOAuthClient(clientId:"your-client-id",clientSecret:"your-client-secret",redirectUri:"https://localhost:5001/callback");// Step 1: Generate authorization URL and redirect uservarauthUrl=oauthClient.GetAuthorizationUrl(state:"optional-state");// Redirect user to authUrl// Step 2: Exchange authorization code for tokens (in your callback handler)vartoken=awaitoauthClient.ExchangeCodeForTokenAsync(code);Once you have an access token, create a FreeAgent client:
usingFreeAgent.Client;// Option 1: With just an access tokenusingvarclient=newFreeAgentClient("your-access-token");// Option 2: With OAuth client for automatic token refreshusingvarclient=newFreeAgentClient(oauthClient,token);// Get company informationvarcompany=awaitclient.Company.GetCompanyAsync();Console.WriteLine($"Company: {company.Name}");Console.WriteLine($"Currency: {company.Currency}");// Get company business categoriesvarcategories=awaitclient.Company.GetBusinessCategoriesAsync();Console.WriteLine($"Categories returned: {categories.Count}");// Get upcoming tax eventsvartimeline=awaitclient.Company.GetTaxTimelineAsync();Console.WriteLine($"Upcoming tax events: {timeline.Count}");// Contacts single-page accessvarfirstPage=awaitclient.Contacts.GetContactsPageAsync(page:1,perPage:25);Console.WriteLine($"Contacts page 1 items: {firstPage.Items.Count}");// Contacts auto-paginationawaitforeach(varcontactinclient.Contacts.GetAllContactsAsync(perPage:50)){Console.WriteLine(contact.ContactName);}Note: The client implements IDisposable and should be disposed when done to release HTTP resources properly.
Tokens can be refreshed manually:
if(token.TimeUntilExpiry<TimeSpan.FromMinutes(5)&&!string.IsNullOrEmpty(token.RefreshToken)){varnewToken=awaitoauthClient.RefreshTokenAsync(token.RefreshToken);// Update your stored token}Or use the client with automatic refresh:
// This will automatically refresh the token when neededvarclient=newFreeAgentClient(oauthClient,token);Currently, this library supports:
- Company API:
- Get company information
- List all business categories
- Get upcoming tax events
- Contacts API:
- Get a single contacts page
- Auto-paginate all contacts
More endpoints will be added in future releases.
The client automatically handles FreeAgent rate limiting:
- Respects
X-RateLimit-*headers from the API - Default minimum delay between requests is zero unless configured otherwise
The client applies bounded retries by default for transient failures:
- Retries up to
MaxNetworkRetries = 2(in addition to the initial request) - Uses exponential backoff with optional jitter
- Honors
Retry-Afterfor429 Too Many Requests - Retries safe methods (
GET,DELETE) by default - Mutating methods are not retried unless explicitly opted in via
FreeAgentHttpClientOptions.AdditionalRetriableMethods
You can configure retry behavior through FreeAgentHttpClientOptions on FreeAgentClient constructors.
The library provides specific exception types:
usingFreeAgent.Client;try{varcompany=awaitclient.Company.GetCompanyAsync();}catch(FreeAgentRateLimitExceptionex){// Handle rate limit exceededConsole.WriteLine($"Rate limit exceeded: {ex.Message}");Console.WriteLine($"Attempts: {ex.AttemptCount}");Console.WriteLine($"Retry-After: {ex.RetryAfter}");}catch(FreeAgentOAuthExceptionex){// Handle OAuth errorsConsole.WriteLine($"OAuth error: {ex.Message}");}// (Timeout, network, and transport exceptions are surfaced as FreeAgentApiException)catch(FreeAgentApiExceptionex){// Handle other API errorsConsole.WriteLine($"API error: {ex.Message}");Console.WriteLine($"Status code: {ex.StatusCode}");Console.WriteLine($"Attempts: {ex.AttemptCount}");}# Clone the repository
git clone https://github.com/markheydon/freeagent-dotnet.git
cd freeagent-dotnet
# Build
dotnet build
# Run tests
dotnet test# Create NuGet package
dotnet pack src/FreeAgent.Client/FreeAgent.Client.csproj -c ReleaseRequirements:
- .NET 8.0 SDK (runtime and SDK)
- .NET 10.0 SDK (runtime and SDK)
The published package targets both .NET 8.0 and .NET 10.0. Both runtimes are required locally to build and test the SDK across both target frameworks. To run tests for a single framework, use dotnet test -f net10.0 or dotnet test -f net8.0.
Contributions are welcome.
Please read CONTRIBUTING.md before opening a pull request.
By participating in this project, you agree to follow CODE_OF_CONDUCT.md.
Use GitHub Discussions for setup and usage questions.
For confirmed bugs and actionable work items, use the repository issue templates.
See SUPPORT.md for support routing and expectations.
Do not disclose vulnerabilities in public issues or discussions.
See SECURITY.md for private vulnerability reporting and disclosure process.
This project is licensed under the MIT License - see the LICENSE file for details.
This package follows Semantic Versioning. Until the MVP is complete, all releases carry a prerelease tag (e.g. 0.1.0-alpha.1). Prerelease packages do not carry stability guarantees — public APIs may change between versions.
See VERSIONING.md for the full policy, stage transition criteria, and when the first stable 1.0.0 will be released.