Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - markheydon/freeagent-dotnet: Open source FreeAgent API Client for .NET. · GitHub
Skip to content

Repository files navigation

FreeAgent .NET Client

A .NET client library for the FreeAgent API with OAuth 2.0 support, rate limiting, retries, typed transport errors, and pagination.

NuGetNuGet (prerelease)

⚠️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.

Features

  • ✅ 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

Installation

dotnet add package FreeAgent.Client

Quick Start

OAuth 2.0 Authentication

First, 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);

Using the Client

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.

Token Refresh

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);

API Coverage

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.

Rate Limiting

The client automatically handles FreeAgent rate limiting:

  • Respects X-RateLimit-* headers from the API
  • Default minimum delay between requests is zero unless configured otherwise

Retries

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-After for 429 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.

Error Handling

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}");}

Building from Source

# 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 Release

Development

Requirements:

  • .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.

Contributing

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.

Support

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.

Security

Do not disclose vulnerabilities in public issues or discussions.

See SECURITY.md for private vulnerability reporting and disclosure process.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Versioning

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.

Resources

About

Open source FreeAgent API Client for .NET.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages