FaxCore.Ev6.RestClient
3.0.0
dotnet add package FaxCore.Ev6.RestClient --version 3.0.0
NuGet\Install-Package FaxCore.Ev6.RestClient -Version 3.0.0
<PackageReference Include="FaxCore.Ev6.RestClient" Version="3.0.0" />
<PackageVersion Include="FaxCore.Ev6.RestClient" Version="3.0.0" />
<PackageReference Include="FaxCore.Ev6.RestClient" />
paket add FaxCore.Ev6.RestClient --version 3.0.0
#r "nuget: FaxCore.Ev6.RestClient, 3.0.0"
#:package FaxCore.Ev6.RestClient@3.0.0
#addin nuget:?package=FaxCore.Ev6.RestClient&version=3.0.0
#tool nuget:?package=FaxCore.Ev6.RestClient&version=3.0.0
FaxCore EV6 REST Client
A .NET client for the FaxCore EV6 REST API. It handles OAuth sign-in, token refresh, HTTP calls and JSON, so you can send and manage faxes with plain C# calls.
Install
dotnet add package FaxCore.Ev6.RestClient
| Framework | Versions |
|---|---|
| .NET Framework | 4.7, 4.7.1, 4.7.2, 4.8 |
| .NET | 8.0, 9.0, 10.0 |
.NET 6 and 7 are no longer supported in 3.0.0. .NET applications must target .NET 8 or later.
Microsoft lists .NET Framework 4.7, 4.7.1, 4.7.2 and 4.8 as Active as of October 8, 2026. Support follows the lifecycle of the Windows version on which the runtime is installed, so deployments must use a supported Windows version and current updates. See Microsoft's .NET Framework support policy.
Quick start
You need a FaxCore EV6 server and an OAuth client ID and secret set up on it.
using FaxCore.Ev6.RestClient;
using FaxCore.Ev6.RestClient.Models.Request;
using var client = new FaxClient("https://your-faxcore-server.com", "client-id", "client-secret");
// 1. Upload the document
var upload = await client.UploadFile("invoice.pdf");
var file = upload.Data.First();
// 2. Send it
var sent = await client.SendMessage(new SendMessageRequest<MessageRecipient>
{
Message = new MessageRequest<MessageRecipient>
{
SenderName = "Accounts",
Subject = "Invoice #1234",
Priority = 70,
Recipients = new List<MessageRecipient>
{
new MessageRecipient { Name = "Jane Smith", Address = "15551234567", IsRawFax = true }
},
Documents = new List<Document>
{
new Document { Name = file.Id, Path = file.FileName, IsMerge = false }
},
Agents = new List<Agent>(),
Trackings = new List<Tracking> { new Tracking { Label = "Invoice", Value = "1234" } }
}
});
// 3. Check on it
var status = await client.GetMessageStatus(sent.Data.MessageId);
Console.WriteLine(status.Data.Status);
Request types are in FaxCore.Ev6.RestClient.Models.Request, enums such as FileType, FilterOption and AddressType are in Models.Enumerators, and FaxCoreException is in Models. Both Models and Models.Request define Document, Agent and Tracking. When sending, use the Models.Request ones. If you import both namespaces, write those names in full.
Setting up the client
Create one FaxClient and reuse it. Each instance caches its OAuth token and refreshes it before it expires, and it is safe to use from many threads at once. If you create a new client per request, every request signs in again.
On .NET 8+ the client's own HttpClient closes pooled connections after 2 minutes, so a long-lived client still picks up DNS changes. On .NET Framework, the default ServicePointManager settings control connection reuse.
Dependency injection
services.AddSingleton<IFaxClient>(_ =>
new FaxClient("https://your-faxcore-server.com", "client-id", "client-secret"));
To control the HTTP pipeline yourself (for example for retries, proxies or logging), pass in your own HttpClient. The singleton keeps that HttpClient for the life of the app, so IHttpClientFactory never gets to swap its handler. Let the connections expire on their own instead (UseSocketsHttpHandler needs Microsoft.Extensions.Http 8+):
services.AddHttpClient("FaxCore")
.UseSocketsHttpHandler((handler, _) => handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2))
.SetHandlerLifetime(Timeout.InfiniteTimeSpan);
services.AddSingleton<IFaxClient>(provider =>
{
var http = provider.GetRequiredService<IHttpClientFactory>().CreateClient("FaxCore");
return new FaxClient("https://your-faxcore-server.com", "client-id", "client-secret", http);
});
FaxClient disposes an HttpClient it created itself. It never disposes one you passed in.
IFaxClientFactory / FaxClientFactory offer the same constructors behind an interface, for code that needs to create clients at runtime.
Timeouts and cancellation
The default timeout is 1 minute. You can change it when the client creates its own HttpClient:
var client = new FaxClient(url, clientId, clientSecret, httpClient: null, timeout: TimeSpan.FromMinutes(5));
If you pass your own HttpClient, set the timeout on it instead. The timeout argument is then ignored.
Every method takes an optional CancellationToken as its last argument.
Retries
The client retries only one thing: a single retry when getting a token fails with a network error or a 5xx response. It never retries API calls, because retrying SendMessage could send a fax twice. If you want retries, add them to the HttpClient you pass in, and only for calls that are safe to repeat.
Common tasks
Download a fax
byte[] pdf = await client.DownloadMessage(new DownloadMessageRequest
{
MessageID = messageId,
DownloadType = FileType.PDF
});
File.WriteAllBytes("fax.pdf", pdf);
List folders and messages
var folders = await client.GetMessageFolders();
foreach (var folder in folders.Data)
Console.WriteLine(folder.Folder);
var inbox = await client.GetMessageList(new FolderListMessagesRequest
{
FolderName = "Inbox",
StartDate = DateTime.Today.AddDays(-7),
EndDate = DateTime.Today.AddDays(1),
Read = FilterOption.All,
Downloaded = FilterOption.All,
Pagination = new Pagination { Page = 1, MaxResults = 50 }
});
Search messages
var results = await client.SearchMessages(new MessageSearchRequest
{
FromDate = DateTime.Today.AddDays(-30),
ToDate = DateTime.Today.AddDays(1),
IsFailed = FilterOption.Yes,
Pagination = new Pagination { Page = 1, MaxResults = 25 }
});
foreach (var message in results.Data.Records)
Console.WriteLine($"{message.MessageNo} {message.Subject} {message.Status}");
FromDate and ToDate are always sent, so set them. IncludeSubdomain defaults to false.
Create a contact
var book = await client.CreateAddressBook("Suppliers");
await client.CreateContact(new CreateContactRequest
{
AddressBookId = book.Data.AddressBookId,
DisplayName = "Acme Billing",
PreferredAddressType = AddressType.Fax,
Addresses = new List<ContactAddressRequest>
{
new ContactAddressRequest { AddressType = AddressType.Fax, Address = "15551234567" }
}
});
Responses and errors
Most methods return FaxCoreResponse<T>, with Status, Message and Data. List methods return PagedResponse<T>. Its Data.Records holds the items and Data.Pagination holds the page info.
Failures throw FaxCoreException:
| Property | Contains |
|---|---|
ErrorCode |
HTTP status code |
HttpResponse |
Raw response body from the server |
Message |
Short description ("Authentication failed" for bad credentials) |
try
{
await client.GetMessageDetails(messageId);
}
catch (FaxCoreException ex)
{
Console.WriteLine($"{(int)ex.ErrorCode}: {ex.HttpResponse}");
}
A missing server URL, client ID or secret throws FaxCoreException from the constructor, with an ArgumentException inside.
API reference
| Area | Methods |
|---|---|
| Sending | UploadFile, SendMessage, SendMessageInternal, DelegateMessage, GetCoverPageItems |
| Status & details | GetMessageStatus, GetMessageDetails, GetMessageTracking, UpdateMessageTracking, GetMessageReadStatus, DeleteMessageStatus |
| Retrieving | DownloadMessage, RetrieveImage, MarkMessageAsDownloaded, ToggleMessageRead |
| Folders & search | GetMessageFolders, GetMessageList, SearchMessages, MoveMessageToFolder |
| Message actions | UpdateMessageSubject, ForwardMessageToUsers, AssignMessage, ApproveMessage, RetryMessage, CancelMessage, DeleteMessage, DeleteTrashMessages |
| Users | CreateUser, GetUserDetails, GetUserFaxSettings, UpdateUser, UpdateProfile, UpdateUserConfig, UserSearch, UserList, ActivateUsers, DeactivateUser, DeleteUser, ChangeUserDomain |
| Contacts | CreateAddressBook, GetAddressBooks, UpdateAddressBook, DeleteAddressBook, CreateContact, GetContact, ListContacts, UpdateContact, DeleteContact |
| MFP | GetMfpAddressBooks, GetMfpContacts |
| Printers | GetPrinters, CreatePrinter, DeletePrinters |
| Domains | GetDomains, CreateDomain |
| Inbound routes | CreateRoutingRule, SearchRoutingRules, EnableRoutingRule, DisableRoutingRule, DeleteRoutingRule |
Each method is documented with XML comments on IFaxClient, so your IDE shows the parameters and return types.
Upgrading from 2.x to 3.0
- .NET 6 and 7 targets and support were removed. Upgrade .NET applications to .NET 8 or later. The existing .NET Framework targets remain available on supported Windows versions.
SearchMessagesreturnsPagedResponse<MessageSearchItem>. Each item inData.Recordsis a message; theMessageSearchResultswrapper is gone.DelegationMessage.TrackingsusesModels.Request.Tracking(Label,Value).ContactAddressRequest.NotifyOnSend,NotifyOnReceiveandIsPrimarywere removed because the API has no such fields. UseNotifyOnSuccessandNotifyOnFailedon the contact.UserSearchRequesthas aPaginationproperty. Page size is now sent asmaxResult, which the server expects.HttpLoggingHandlerwas removed because it logged credentials and fax contents. Add your own logging to theHttpClientyou pass in, and redact secrets.- Several request field names were fixed to match the API (message move, user move, route search, contact addresses, user creation, message search). Calls that the server used to ignore now take effect.
Contributing
You need the .NET 10 SDK. The tests run on .NET 8, 9 and 10, so install those runtimes too.
dotnet build src/FaxCoreRestClient.sln
dotnet test src/FaxCore.Tests/FaxCore.Tests.csproj
The default test run is offline. It checks request JSON, response parsing, authentication, cancellation and HttpClient ownership against a fake HTTP handler.
Live tests
Live tests send real faxes. Run them only with a dedicated test account and a fax number you control. They create their own messages and delete them afterwards.
export FAX_SERVER_URL="https://your-faxcore-server.com"
export FAX_SERVER_CLIENT="client-id"
export FAX_SERVER_SECRET="client-secret"
export FAX_TEST_RECIPIENT="15551234567"
export FAXCORE_RUN_INTEGRATION_TESTS="1"
dotnet test src/FaxCore.Tests/FaxCore.Tests.csproj
You can put these in a local_settings.sh in the repo root, which scripts/run_sandbox.sh also loads for the sandbox console app. Never commit that file.
Packing a release
dotnet build src/FaxCoreRestClient.sln -c Release
dotnet pack src/FaxCore.Ev6.RestClient/FaxCore.Ev6.RestClient.csproj -c Release --no-build -o artifacts
Layout
| Path | What it is |
|---|---|
src/FaxCore.Ev6.RestClient |
The NuGet package. FaxClient is a partial class split by API area (MessageClient.cs, UserClient.cs, ...). HTTP and auth live in FaxCoreBaseClient.cs. |
src/FaxCore.Tests |
Offline tests, plus live tests in FaxCoreClientTests/ |
src/FaxCore.Sandbox |
Console app for manual testing against a server |
src/FaxCore.Functional.Core |
Small helpers used by the tests and sandbox |
faxcore_api.json |
The FaxCore API specification used to check request field names |
License
| Product | Versions 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. |
| .NET Framework | net47 is compatible. net471 is compatible. net472 is compatible. net48 is compatible. net481 was computed. |
-
.NETFramework 4.7
- System.Text.Json (>= 10.0.12)
-
.NETFramework 4.7.1
- System.Text.Json (>= 10.0.12)
-
.NETFramework 4.7.2
- System.Text.Json (>= 10.0.12)
-
.NETFramework 4.8
- System.Text.Json (>= 10.0.12)
-
net10.0
- No dependencies.
-
net8.0
- System.Text.Json (>= 10.0.12)
-
net9.0
- System.Text.Json (>= 10.0.12)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v3.0.0 - Audit fixes and corrected API contracts.
BREAKING CHANGES:
- Removed .NET 6/7 targets and support; .NET applications must target .NET 8 or later
- SearchMessages now returns PagedResponse<MessageSearchItem>; removed the extra MessageSearchResults wrapper
- DelegationMessage.Trackings now uses Models.Request.Tracking (label/value)
- HttpLoggingHandler was removed because it exposed credentials and fax contents
- Removed ContactAddressRequest.NotifyOnSend, NotifyOnReceive and IsPrimary; use contact-level notification settings
FIXES:
- Atomically publish one token snapshot; expiry and bearer credentials cannot come from different refreshes
- Correct folder/user moves, route search, contact addresses, user creation, and message search request fields
- Send maxResult for pagination; add pagination to user searches
- Map user-search, contact-creation, and pagination response fields explicitly
- Preserve named search-filter encoding and the bool IncludeSubdomain API until numeric meanings are verified on a live server
- Remove duplicated factory validation; keep constructor validation
- Use framework-provided HTTP assemblies instead of the legacy System.Net.Http NuGet package
- On .NET 8+, the client-owned HttpClient recycles pooled connections every 2 minutes so long-lived clients follow DNS changes
VALIDATION AND COMPATIBILITY:
- Offline request, parsing, authentication, cancellation, and HttpClient ownership regression tests
- Live tests require explicit opt-in, a dedicated account, and a configured recipient; only test-created messages are modified
- Verified latest stable direct dependencies, including System.Text.Json 10.0.12, Microsoft.NET.Test.Sdk 18.10.1 and xunit.runner.visualstudio 4.0.0
- Added net9.0 and net10.0 targets; offline tests run on .NET 8, 9 and 10
- Retained .NET Framework 4.7, 4.7.1, 4.7.2 and 4.8 targets; Microsoft lists these versions as Active, subject to the host Windows lifecycle
- Response fixtures are synthetic; live FaxCore response compatibility still requires integration verification
- Numeric search-filter mappings and server acceptance of named filters remain unverified; no live credentials were configured during validation