--- title: "Installing or upgrading to the v3 C# SDK" slug: "installing-or-upgrading-to-the-v3-c-sharp-sdk" updated: 2026-04-15T13:16:39Z published: 2026-04-15T13:16:39Z canonical: "support.lusid.com/installing-or-upgrading-to-the-v3-c-sharp-sdk" --- > ## Documentation Index > Fetch the complete documentation index at: https://support.lusid.com/llms.txt > Use this file to discover all available pages before exploring further. # Installing or upgrading to the v3 C# SDK > [!WARNING] > **Important**: This is the latest version. Information about older versions can be found [here](/v1/docs/installing-or-upgrading-to-v2-csharp-sdks). The v3 C# SDK is a universal SDK that provides access to LUSID and to all the other applications in the [FINBOURNE platform](/v1/docs/understanding-all-the-applications-in-the-finbourne-platform) from a single package in .NET 8+ environments. You no longer need to install and authenticate to separate SDKs to integrate LUSID with applications such as Drive, Workflow Service, Luminesce and so on. ## Installation To get started, install the universal SDK from [NuGet](https://www.nuget.org/packages/Finbourne.Sdk): ```shell dotnet add package Finbourne.Sdk ``` Note the following: - .NET 8 or later is required. - We recommend pinning the SDK to an exact version to control when you take updates and make your builds repeatable. Note this is a new package, so the version number starts at `0.0.1`. - Alternatively, you can download the source by [cloning the Github repo](https://github.com/finbourne/finbourne-sdk-csharp). If you do, note the `main` branch may not always correspond to the latest REST API version. ## Using directives Add `using` directives for the API factory and endpoints and models for all the FINBOURNE applications you intend to use, for example: ```csharp // General: using Finbourne.Sdk.Extensions;                 // Required for API factory using Finbourne.Sdk.Client;                     // For error handling // To use LUSID: using Finbourne.Sdk.Services.Lusid.Api;         // Endpoints using Finbourne.Sdk.Services.Lusid.Model;       // Models // To use the Workflow Service: using Finbourne.Sdk.Services.Workflow.Api;      // Endpoints using Finbourne.Sdk.Services.Workflow.Model;    // Models ``` ## Authentication The most secure method is OAuth2. If you haven’t already, [create a SDK application](/v1/docs/how-do-i-generate-and-reveal-a-client-secret) encapsulating a client ID, secret and token URL, and store them with the credentials of a valid LUSID user as either environment variables or in a secrets file. The SDK uses these credentials to obtain a short-lived access token from FINBOURNE's identity provider (Okta) on demand, which it can then refresh periodically. > **Note**: If environment variables are set, they are preferred over a secrets file. [More information](/v1/docs/how-do-i-use-an-api-access-token-with-the-lusid-sdk). You *can* use a long-lived [personal access token](/v1/docs/what-is-a-personal-access-token) (PAT) instead of OAuth2, but note this is less secure. ### Using environment variables All applications share a `FBN_BASE_URL` pointing to the root of your LUSID domain, for example `acme-prod.lusid.com`: ```shell # OAuth2 (more secure): setx FBN_BASE_URL "https://acme-prod.lusid.com"                                   # Root of your FBN domain setx FBN_TOKEN_URL "https://acme-prod.identity.lusid.com/oauth2/.../v1/token"     # Okta token endpoint setx FBN_USERNAME "..." setx FBN_PASSWORD "..." setx FBN_CLIENT_ID "..." setx FBN_CLIENT_SECRET "..." # PAT: setx FBN_BASE_URL "https://acme-prod.lusid.com" setx FBN_ACCESS_TOKEN "..." ``` ### Using a secrets file A secrets file is a JSON document with profiles, one per LUSID domain you wish to connect to. Note the file must have at least one `default` profile. You can [switch between profiles](/v1/docs/installing-or-upgrading-to-the-v3-c-sharp-sdk#instantiation) to connect to different domains dynamically. The following example has two profiles: `default` connects to an `acme-prod.lusid.com` domain (authenticating using OAuth2) and a second `staging` profile connects to an `acme-sit.lusid.com` domain (authenticating using a PAT): ```json {  "profiles": {    "default": {      "baseUrl": "https://acme-prod.lusid.com/",      "tokenUrl": "https://acme-prod.identity.lusid.com/oauth2/.../v1/token",      "username": "...",      "password": "...",      "clientId": "...",      "clientSecret": "..."    },    "staging": {      "baseUrl": "https://acme-sit.lusid.com",      "accessToken": "..."    }  } } ``` The active profile is determined in the following order: 1. The `FBN_PROFILE` environment variable, if set. 2. The `profile_name` parameter when you instantiate the SDK, if specified (see below). 3. The `default` profile. ## Instantiation Build an API factory using `ApiFactoryBuilder()`. A single API factory instance is thread-safe and can be shared across your application. If you are using environment variables you can call `Build()` with no arguments. If using a secrets file: - You must pass the path to `Build()`. - You can optionally pass the name of a profile to connect to a particular LUSID domain dynamically. [More configuration options](/v1/docs/installing-or-upgrading-to-the-v3-c-sharp-sdk#configuration) ### Synchronous SDK ```csharp string secretsFile = "/path/to/secrets.json"; string profile = "staging"; IApiFactory apiFactory = new ApiFactoryBuilder().Build(   apiSecretsFilename: secretsFile,   profileName: profile ); // Get API instances for the applications you intend to use: var instrumentsApi = apiFactory.Api(); var taskDefinitionsApi = apiFactory.Api(); // Call methods: var listInstrResponse = instrumentsApi.ListInstruments(); ``` ### Asynchronous SDK The SDK has full asynchronous support. Call `*Async` method variants with `await`, so for example `ListInstrumentsAsync()` instead of `ListInstruments()`: ```csharp string secretsFile = "/path/to/secrets.json"; IApiFactory apiFactory = new ApiFactoryBuilder().Build(apiSecretsFilename: secretsFile); // Get API instances for the applications you intend to use: var instrumentsApi = apiFactory.Api(); var taskDefinitionsApi = apiFactory.Api(); // Call methods: var listInstrResponse = await instrumentsApi.ListInstrumentsAsync(); ``` ### Configuration You can optionally configure timeout and rate limit retry settings using `ConfigurationOptions`, either globally or as overrides per API call: ```csharp // Set globally: var myOptions = new ConfigurationOptions {    TimeoutMs = 9999,         // Default is 1800000 (30 minutes)    RateLimitRetries = 50     // Default is 2 }; IApiFactory apiFactory = new ApiFactoryBuilder().Build(opts: myOptions); // Overrides per API call: var myOption = new ConfigurationOptions { TimeoutMs = 8888 }; var listInstrResponse = instrumentsApi.ListInstruments(opts: myOption); ``` Note you can also set these as [environment variables](/v1/docs/installing-or-upgrading-to-the-v3-c-sharp-sdk#appendix-b-environment-variable-reference), but `ConfigurationOptions` is preferred if you do both. ## Hello world The following example authenticates to the synchronous SDK using environment variables and calls the `ListInstruments()` method to invoke the [ListInstruments](https://www.lusid.com/docs/api/lusid/endpoints/instruments/ListInstruments) API, writing certain fields to the command line: ```csharp using Finbourne.Sdk.Extensions; using Finbourne.Sdk.Client; using Finbourne.Sdk.Services.Lusid.Api; // Instantiate: IApiFactory apiFactory = new ApiFactoryBuilder().Build(); // Build Instruments API and list first five instruments: try {    var instrumentsApi = apiFactory.Api();    var listInstrResponse = instrumentsApi.ListInstruments(limit: 5);    foreach (var instrument in listInstrResponse.Values)    {        Console.WriteLine($"LUID: {instrument.LusidInstrumentId}");        Console.WriteLine($"Name: {instrument.Name}");        Console.WriteLine($"Asset Class: {instrument.AssetClass}");        Console.WriteLine("---");        } } catch (ApiException e) {    Console.WriteLine(e); } ``` ![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/image-X32P9PL0.png?sv=2026-02-06&spr=https&st=2026-11-04T01%3A47%3A13Z&se=2026-11-04T02%3A47%3A13Z&sr=c&sp=r&sig=eJ6h%2B4xUnlOafclI%2B6uFsIuAwlo9tgUQsfoNQe%2B9K3U%3D) For more information on FINBOURNE APIs, start with the articles in this KB, our [API sandbox](/v1/docs/getting-started-with-the-lusid-rest-api-and-sdks), and library of [Jupyter Notebooks](https://github.com/finbourne/finbourne-notebooks). ## Appendix A: Migration checklist If you are upgrading from v2: - If using environment variables, replace per-application variables such as `FBN_LUSID_API_URL` and `FBN_WORKFLOW_API_URL` with `FBN_BASE_URL`, and point to the root of your domain (without an `/api` suffix). - If using a secrets file, make sure the JSON document matches the new [profile specification](/v1/docs/installing-or-upgrading-to-the-v3-c-sharp-sdk#using-a-secrets-file). Also replace per-application keys such as `lusidUrl` and `workflowUrl` with `baseUrl`, and point to the root of your domain (without an `/api` suffix). - Replace all per-application packages (for example `Lusid.Sdk`, `Finbourne.Workflow.Sdk`) with the single `Finbourne.Sdk` package. - Update all `using` directives to the `Finbourne.Sdk.*` namespace. ## Appendix B: Environment variable reference | `FBN_BASE_URL` | Root of the LUSID domain to connect to | | --- | --- | | `FBN_TOKEN_URL` | Okta token URL for OAuth2 flow | | `FBN_USERNAME` | LUSID user name for OAuth2 flow | | `FBN_PASSWORD` | LUSID user password for OAuth2 flow | | `FBN_CLIENT_ID` | Client ID for OAuth2 flow | | `FBN_CLIENT_SECRET` | Client secret for OAuth2 flow | | `FBN_ACCESS_TOKEN` | Personal access token (less secure than OAuth2) | | `FBN_APP_NAME` | Application name header | | `FBN_PROFILE` | Sets the active profile in a `secrets.json` file | | `FBN_TIMEOUT_MS` | Timeout configuration option | | `FBN_RATE_LIMIT_RETRIES` | Rate limit retries configuration option |