> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# .NET Server SDK

> The [Fingerprint Server C#/.NET SDK](https://github.com/fingerprintjs/dotnet-sdk) is an easy way to interact with our Server API from your .NET application. You can retrieve visitor history or individual identification events. View our [.NET Server SDK quickstart](/docs/dotnet-server-quickstart) for a step-by-step guide to get started.

## How to install

Install the package from NuGet.

```bash Bash theme={"theme":"github-dark-dimmed"}
dotnet add package Fingerprint.ServerSdk
```

Initialize the client instance and use it to make API requests. You need to specify your secret API key and region (if it is not US/Global).

```csharp C# theme={"theme":"github-dark-dimmed"}
using Fingerprint.ServerSdk.Api;
using Fingerprint.ServerSdk.Extensions;
using Fingerprint.ServerSdk.Client;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddFingerprint(options =>
{
    options.AddTokens(new BearerToken("SECRET-API-KEY"));
    // options.Region = Region.Eu;
});

var app = builder.Build();
var api = app.Services.GetRequiredService<IFingerprintApi>();

// Search events
var events = await api.SearchEventsAsync(new SearchEventsRequest().WithVisitorId("VISITOR_ID"));
Console.WriteLine(events.Ok());

// Get a specific identification event
var getEvent = await api.GetEventAsync("EVENT_ID");
Console.WriteLine(getEvent.Ok());
```

## Migration guide for .NET SDK v8

Version 8 migrates the SDK from Server API v3 to v4. This is a breaking change.

This section summarizes the most important changes from previous versions.

### Package and namespace rename

The package name changed from `FingerprintPro.ServerSdk` to `Fingerprint.ServerSdk`, and all namespaces changed from `FingerprintPro.ServerSdk.*` to `Fingerprint.ServerSdk.*`.

```html Project.csproj theme={"theme":"github-dark-dimmed"}
<!-- [!code --] -->
<PackageReference Include="FingerprintPro.ServerSdk" Version="7.11.0" />
<!-- [!code ++] -->
<PackageReference Include="Fingerprint.ServerSdk" Version="8.4.0" />
```

```csharp C# theme={"theme":"github-dark-dimmed"}
using FingerprintPro.ServerSdk.Api; // [!code --]
using FingerprintPro.ServerSdk.Client; // [!code --]
using FingerprintPro.ServerSdk.Model; // [!code --]
using Fingerprint.ServerSdk.Api; // [!code ++]
using Fingerprint.ServerSdk.Client; // [!code ++]
using Fingerprint.ServerSdk.Model; // [!code ++]
```

### Client construction

In v7, you created a `Configuration` object and passed it to a `FingerprintApi` constructor. In v8, you register a service on a `generichost` builder with `AddFingerprint` and resolve it as `IFingerprintApi`.

```csharp C# theme={"theme":"github-dark-dimmed"}
var configuration = new Configuration("SECRET_API_KEY"); // [!code --]
// configuration.Region = Region.Eu; // [!code --]
var api = new FingerprintApi(configuration); // [!code --]
var builder = WebApplication.CreateBuilder(args); // [!code ++]
builder.Services.AddFingerprint(options => // [!code ++]
{ // [!code ++]
    options.AddTokens(new BearerToken("SECRET_API_KEY")); // [!code ++]
    // options.Region = Region.Eu; // [!code ++]
}); // [!code ++]
var app = builder.Build(); // [!code ++]
var api = app.Services.GetRequiredService<IFingerprintApi>(); // [!code ++]
```

### Async methods and response objects

All API methods are now asynchronous and return a response object instead of the deserialized model directly. Use `IsOk` and `Ok()` to access the result, or the `TryOk` helper.

```csharp C# theme={"theme":"github-dark-dimmed"}
var ev = api.GetEvent("REQUEST_ID"); // [!code --]
var response = await api.GetEventAsync("EVENT_ID"); // [!code ++]
if (response.IsOk) // [!code ++]
{ // [!code ++]
    var ev = response.Ok(); // [!code ++]
} // [!code ++]
```

### `requestId` renamed to `eventId`

Server API v4 renamed the `request_id` parameter to `event_id`, so the identifier passed to `GetEventAsync` and `UpdateEventAsync` is now called `eventId`.

```csharp C# theme={"theme":"github-dark-dimmed"}
var response = await api.GetEventAsync(requestId: "REQUEST_ID"); // [!code --]
var response = await api.GetEventAsync(eventId: "EVENT_ID"); // [!code ++]
```

### Event structure

`GetEventAsync` returns an `Event` with a flatter structure. The data that was previously nested under `Products.<signal>.Data` is now available at the top level.

```csharp C# theme={"theme":"github-dark-dimmed"}
EventsGetResponse response = api.GetEvent("REQUEST_ID"); // [!code --]
var visitorId = response.Products.Identification.Data.VisitorId; // [!code --]
var botResult = response.Products.Botd.Data.Bot.Result; // [!code --]
Event ev = (await api.GetEventAsync("EVENT_ID")).Ok(); // [!code ++]
var visitorId = ev.Identification.VisitorId; // [!code ++]
var botResult = ev.Bot; // [!code ++]
```

### Search events

`SearchEventsAsync` takes a `SearchEventsRequest` builder instead of positional and named arguments.

```csharp C# theme={"theme":"github-dark-dimmed"}
var response = api.SearchEvents(10, bot: "bad", visitorId: "VISITOR_ID"); // [!code --]
var request = new SearchEventsRequest() // [!code ++]
    .WithLimit(10) // [!code ++]
    .WithBot(SearchEventsBot.Bad) // [!code ++]
    .WithVisitorId("VISITOR_ID"); // [!code ++]
var response = await api.SearchEventsAsync(request); // [!code ++]
```

### `GetVisits` and `GetRelatedVisitors` removed

`GetVisits` and `GetRelatedVisitors` have been removed. Use `SearchEventsAsync` with `WithVisitorId` to get the events for a visitor.

```csharp C# theme={"theme":"github-dark-dimmed"}
var visits = api.GetVisits("VISITOR_ID"); // [!code --]
var request = new SearchEventsRequest().WithVisitorId("VISITOR_ID"); // [!code ++]
var response = await api.SearchEventsAsync(request); // [!code ++]
```

### Handling sealed client results from a v3 JavaScript agent

.NET SDK v8 will fail to deserialize the decrypted payload of a [sealed client result](/docs/sealed-client-results) sent by a v3 JavaScript agent into an `Event` because the payload is an `EventsGetResponse` (i.e., the v3 event format), not an `Event`.

To upgrade to .NET SDK v8 without requiring a concurrent upgrade to the v4 JavaScript agent, you can fall back to using the Server API if unsealing the sealed client results fails.
To enable this fallback path, your frontend must send the event ID alongside the sealed client results, as recommended by the [sealed client results guide](/docs/sealed-client-results#step-3-send-sealed_result-to-your-backend).

Instead of `Sealed.UnsealEventResponse`, which decrypts and deserializes in one call, use `Sealed.Unseal` to decrypt the payload and then deserialize it into an `Event` separately. This lets you detect a deserialization failure and fall back to the Server API, which also returns an `Event`.

```csharp C# theme={"theme":"github-dark-dimmed"}
// Partial example (imports and surrounding class omitted).
private static async Task<Event> GetEvent(
    IFingerprintApi api,
    byte[] sealedResult,
    string eventId,
    Sealed.DecryptionKey[] keys)
{
    // First, decrypt the sealed results.
    var payload = Sealed.Unseal(sealedResult, keys);

    // Next, attempt to deserialize the payload into an event.
    try
    {
        var ev = JsonSerializer.Deserialize<Event>(payload);
        if (ev == null)
        {
            throw new JsonException("Deserialized event was null");
        }
        return ev;
    }
    catch (JsonException)
    {
        // The payload could not be deserialized as a v4 Event. Fall back to the
        // Server API using the event ID sent alongside the sealed client results.
        Console.WriteLine("Could not deserialize unsealed payload as a v4 Event, falling back to Server API");
        var response = await api.GetEventAsync(eventId);
        return response.Ok();
    }
}
```

## Documentation

You can find the full documentation in the official [GitHub repository](https://github.com/fingerprintjs/dotnet-sdk/).
