Skip to content
Richard Randak edited this page May 11, 2022 · 22 revisions

Installation

We recommend and support installation as NuGet package. For more information and help about NuGet and installation please visit https://www.nuget.org/.

  • Install NuGet package Fortnox.NET.SDK in Visual Studio
  • PM> Install-Package Fortnox.NET.SDK

NuGet Link - https://www.nuget.org/packages/Fortnox.NET.SDK/

Prerequisites

SDK is implemented with .NET Standard 2.0

Minimal prerequisites are .NET Framework 4.6.1 or .NET Core 2.0

Check compatibility table for more details - https://docs.microsoft.com/en-us/dotnet/standard/net-standard

Connection

In order to connect to the main API you will need an access-token. In case of the old auth workflow, a client-secret is also required.

The client-secret is provided to you when you create an app in your Fortnox developer portal. In order to get the access-token, you need to follow the activation / authentication worfklow.

There are currently two authentication workflows.

  • StaticToken Auth - legacy workflow, valid only for unpublished apps. Requires one-time setup and resulting with never-expiring GUID access token
  • Standard Auth - standard OAuth2 workflow. More secure. Requires a simple web server for end-user interaction and resulting in a JWT access token and a refresh token.

For more details about these workflows, see Fortnox Auth.

Once the access token is retrieved, the FortnoxClient is used as an entry point for all the requests. It serves as a factory for creating connectors to specific resources. The connectors can be accessed simply by a property.

  1. Wrap the credentials to an authorization class, depending on which authorization workflow you are using.
var authorization = new StaticTokenAuth("your_static_accesstoken", "your_client_secret");

or

var authorization = new StandardAuth("your_oauth_accesstoken");
  1. Create Fortnox client providing the credentials.
var fortnoxClient = new FortnoxClient(authorization);
var customerConnector = fortnoxClient.CustomerConnector;

You can inject your own HttpClient to FortnoxClient through constructor or property. By doing this, you can handle the low-level connection settings or inject a connection mock.

var customHttpClient = new HttpClient()
{
    Timeout = TimeSpan.FromSeconds(10)
    // Other HTTP client configuration...
};

var fortnoxClient = new FortnoxClient(authorization, customHttpClient);

By default, the FortnoxClient is throttling the requests to not trigger the API rate limit and avoid the TooManyRequest error. Basically, the client executes only 4 requests per second. This can be turned off by an additional parameter in the constructor.

var fortnoxClient = new FortnoxClient(authorization, useRateLimiter: false)

or

var fortnoxClient = new FortnoxClient(authorization, yourhttpClient, useRateLimiter: false)

Security

Fortnox requires TLS protocol version 1.2+

By default, the SDK should use this protocol as well. If the connection can not be established, check the ServicePointManager.SecurityProtocol. It should contain the Tls12 or a SystemDefault value.

Structure

The package is generally built upon connectors, entities and subsets, where connector provides methods to handle resources in form of entities and subsets. Search data objects were added to aggregate filters and settings for Find methods.

CRUD

// create a customer
var customer = new Customer()
{
    CustomerNumber = "123",
    Name = "Stefan Andersson",
};

await customerConnector.CreateAsync(customer);

// read a customer
customer = await customerConnector.GetAsync("123");

// update a customer
customer.Name = "Stefan Karlsson";
await customerConnector.UpdateAsync(customer);

// delete a customer
await customerConnector.DeleteAsync("123");

Search

Fortnox defines several parameters to filter and limit the list of retrieved entities for each resource endpoint. In SDK, they are aggregated to Search classes. Some parameters are common (e.g. Limit, Offset, Page, SortOrder), but unfortunately it is not 100% guaranteed to work for all of the endpoints due to server-side inconsistency and limited documentation.

var searchSettings = new CustomerSearch()
{
    // Limit the page size to 50
    Limit = 50,

    // Select page
    Page = 1, // by default

    // Sort
    SortBy = Sort.By.Customer.CustomerNumber,
    SortOrder = Sort.Order.Descending,

    // Do only incorporate modified in last week
    LastModified = DateTime.Now.AddDays(-7),

    // Narrow by name
    Name = "Stefan"
};

// Get a list of customers with metadata
var customers = await customerConnector.FindAsync(searchSettings);

foreach (var item in customers.Entities)
{
    // Please note that this is a subset and not a full customer entity
    // however you can always get the full entity using the connector's Get method if needed
    Console.WriteLine(item.CustomerNumber);
}

The result of the Find method is usually a collection with metadata. The metadata provides information about the current and total pages.

Exception handling

The connectors does not keep information about the error anymore. Instead, two custom exceptions are thrown.

  • FortnoxApiException in case of server error response. Contains additional data about the response.
  • NoResponseException in case of no response from the server. Contains inner exception due to which no response was obtained.

Therefore, a single try-catch is needed, optionally with multiple catch clauses for special handling of the exception types. No additionally check for connector's error is needed anymore.

Customer customer;

try
{
    customer = await customerConnector.GetAsync("1234");
}
catch (Exception ex)
{
    // do something
    Console.WriteLine(ex.Message);
}
Clone this wiki locally