***

title: Use C# SDKs generated in Postman
max-toc-depth: 2
topictype: reference
---------------------

For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://learning.postman.com/llms.txt. For full content including API reference and SDK examples, see https://learning.postman.com/llms-full.txt.

This guide provides instructions for using C# SDKs generated by the Postman SDK Generator. It covers how to install the SDK into your project, run example code, and best practices for using the SDK effectively in your applications.

## SDK structure

The C# SDK includes the following key files:

* `[SdkName]Client.cs` — The main SDK client that implements `IDisposable` and provides access to all services.
* `Services/[ServiceName]Service.cs` — Service classes with async API methods.
* `Models/[ModelName].cs` — Data models (records or classes with `System.Text.Json` serialization).
* `Config/[SdkName]Config.cs` — SDK-level configuration record (environment, auth, timeout).
* `Config/RequestConfig.cs` — Per-request configuration overrides.
* `Config/RetryConfig.cs` — Retry policy configuration.
* `Config/ApiKeyAuthConfig.cs` — API key authentication configuration (generated when applicable).
* `Config/BasicAuthConfig.cs` — Basic authentication configuration (generated when applicable).
* `Http/Environment.cs` — Environment class with static named environment properties.
* `Http/ApiException.cs` — Base exception class for all API errors.
* `Http/Exceptions/[ModelName]Exception.cs` — Typed exception classes for spec-defined error models.
* `Models/Optional.cs` — An `Optional<T>` wrapper for optional fields.
* `Example/Program.cs` — Runnable example demonstrating SDK usage.
* `[SdkName].csproj` — .NET project and NuGet package configuration.

The following is an example of the typical structure of a generated C# SDK:

<Folder name="your-sdk" defaultOpen>
  <Files>
    <File name="README.md" comment="Main documentation" />

    <File name="[SdkName].csproj" comment=".NET project configuration" />

    <File name=".gitignore" comment="Git ignore rules" />

    <File name=".env.example" comment="Example environment variables" />
  </Files>

  <Folder name=".devcontainer">
    <File name="devcontainer.json" comment="Dev container configuration" />
  </Folder>

  <File name="[SdkName]Client.cs" comment="Main SDK client" />

  <Folder name="Config">
    <Files>
      <File name="[SdkName]Config.cs" comment="SDK-level configuration" />

      <File name="RequestConfig.cs" comment="Per-request configuration overrides" />

      <File name="RetryConfig.cs" comment="Retry policy configuration" />

      <File name="ApiKeyAuthConfig.cs" comment="API key authentication config" />

      <File name="BasicAuthConfig.cs" comment="Basic authentication config" />
    </Files>
  </Folder>

  <Folder name="Services">
    <File name="[ServiceName]Service.cs" comment="Service classes" />
  </Folder>

  <Folder name="Models">
    <Files>
      <File name="[ModelName].cs" comment="Data models" />

      <File name="Optional.cs" comment="Optional wrapper for optional fields" />
    </Files>
  </Folder>

  <Folder name="Http">
    <File name="Environment.cs" comment="Named environment constants" />

    <File name="ApiException.cs" comment="Base exception class for API errors" />

    <Folder name="Exceptions">
      <Files>
        <File name="[ModelName]Exception.cs" comment="Typed exception classes" />
      </Files>
    </Folder>

    <Folder name="Handlers">
      <Files>
        <File name="RetryHandler.cs" comment="Request retry handler" />

        <File name="...">
          Additional handlers
        </File>
      </Files>
    </Folder>
  </Folder>

  <Folder name="Example">
    <File name="Program.cs" comment="Runnable example demonstrating usage" />
  </Folder>

  <Folder name="documentation">
    <Folder name="services">
      <File name="[ServiceName].md" comment="Service documentation" />
    </Folder>

    <Folder name="models">
      <File name="[ModelName].md" comment="Model documentation" />
    </Folder>
  </Folder>
</Folder>

## Example usage

Each generated SDK includes an `Example/Program.cs` file demonstrating SDK initialization, making an API call, and basic error handling.

The example includes the following features:

* SDK configuration
* Type-safe API calls
* Error handling with custom exceptions

<Tabs>
  <Tab title="Location">
    `Example/Program.cs`
  </Tab>

  <Tab title="Run the example">
    ```bash
    cd path/to/your-sdk/Example
    dotnet run
    ```
  </Tab>

  <Tab title="Example code structure">
    ```csharp
    using YourSdk;
    using YourSdk.Config;
    using YourSdk.Models;
    using Environment = YourSdk.Http.Environment;

    var config = new YourSdkConfig { AccessToken = "YOUR_ACCESS_TOKEN" };
    var client = new YourSdkClient(config);

    try
    {
        var response = await client.Users.ListUsersAsync(limit: 10);
        Console.WriteLine(response);
    }
    catch (Exception error)
    {
        Console.WriteLine($"Error: {error}");
    }
    ```
  </Tab>
</Tabs>

## Install the C# SDK

You can install the generated C# SDK into your project using NuGet or by referencing it directly from the filesystem.

### Install using NuGet

To install the SDK from NuGet, run:

```bash
dotnet add package YourSdk
```

Then use it in your code:

```csharp
using YourSdk;
using YourSdk.Config;
var config = new YourSdkConfig { };
var client = new YourSdkClient(config);
```

### Install from a local path

If the SDK isn't published to NuGet yet, you can reference it directly from the filesystem using `ProjectReference` in your `.csproj` file.

```xml
<ItemGroup>
  <ProjectReference Include="../path/to/YourSdk/YourSdk.csproj" />
</ItemGroup>
```

Alternatively, build the SDK as a NuGet package and add it to a local feed:

```bash
cd path/to/your-sdk
dotnet pack -o ./nupkgs

# Add local feed to NuGet sources
dotnet nuget add source ./nupkgs --name local-sdk
# Install from local feed
dotnet add package YourSdk --source local-sdk
```

## Publish to NuGet

Publishing your SDK to NuGet.org makes it available to any .NET developer using `dotnet add package`.

### Prerequisites

To publish your SDK to NuGet, you need the following:

* A NuGet.org account.
* An API key from your NuGet account settings.

### Configure the project file

The generated `[SdkName].csproj` already includes the metadata required for publishing. Review and update the following fields before publishing.

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <PackageId>YourSdk</PackageId>
    <Version>1.0.0</Version>
    <Authors>Your Name</Authors>
    <Description>SDK for Your API</Description>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/your-org/your-sdk</PackageProjectUrl>
    <RepositoryUrl>https://github.com/your-org/your-sdk</RepositoryUrl>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
</Project>
```

### Publish your C# SDK to NuGet

To publish your SDK to NuGet, do the following:

1. Build and pack the SDK.

   ```bash
   cd path/to/your-sdk
   dotnet pack -c Release -o ./nupkgs
   ```

2. Publish to NuGet.

   ```bash
   dotnet nuget push ./nupkgs/YourSdk.1.0.0.nupkg \
   --api-key YOUR_NUGET_API_KEY \
   --source https://api.nuget.org/v3/index.json
   ```

3. Verify the publication at `https://www.nuget.org/packages/YourSdk`. Packages are typically indexed within 15–30 minutes.

### Publish updates

To publish updates to your SDK, run the following:

```bash
# Update the version in your .csproj
# Then pack and push
dotnet pack -c Release -o ./nupkgs
dotnet nuget push ./nupkgs/YourSdk.1.0.1.nupkg \
  --api-key YOUR_NUGET_API_KEY \
  --source https://api.nuget.org/v3/index.json
```

### Best practices for publishing C# SDKs

Use the following best practices when publishing your C# SDK to NuGet:

* Use semantic versioning.
* Generate and include XML documentation by setting `<GenerateDocumentationFile>true</GenerateDocumentationFile>` in your `.csproj` file.
* Tag releases in Git.
* Include a `.snupkg` symbols package for debugging support by adding `<IncludeSymbols>true</IncludeSymbols>` and `<SymbolPackageFormat>snupkg</SymbolPackageFormat>`.

## Advanced usage

The following sections cover advanced usage topics for the generated C# SDK, including authentication, asynchronous calls, environment management, hierarchical configuration, error handling, and timeouts and retries.

### Authentication

The SDK supports various authentication methods. Configure authentication when creating the configuration record passed to the SDK client constructor.

The SDK includes authentication support based on the security schemes defined in your API specification. The following examples show the possible authentication methods.

<Tabs>
  <Tab title="API Key">
    ```csharp
    var apiKeyConfig = new ApiKeyAuthConfig("your-api-key");
    var config = new YourSdkConfig { ApiKeyAuth = apiKeyConfig };
    var client = new YourSdkClient(config);
    ```
  </Tab>

  <Tab title="Bearer Token">
    ```csharp
    var config = new YourSdkConfig { AccessToken = "your-bearer-token" };
    var client = new YourSdkClient(config);
    ```
  </Tab>

  <Tab title="Basic Auth">
    ```csharp
    var basicAuthConfig = new BasicAuthConfig("your-username", "your-password");
    var config = new YourSdkConfig { BasicAuth = basicAuthConfig };
    var client = new YourSdkClient(config);
    ```
  </Tab>

  <Tab title="OAuth 2.0">
    ```csharp
    var config = new YourSdkConfig
    {
        ClientId = "your-client-id",
        ClientSecret = "your-client-secret",
    };
    var client = new YourSdkClient(config);
    // SDK automatically handles token acquisition and refresh
    ```
  </Tab>
</Tabs>

Each generated auth property is only present in the configuration when the corresponding auth type is defined in the specification.

### Asynchronous calls and cancellation

All service methods are asynchronous and follow the standard .NET async/await pattern. Every method accepts an optional `CancellationToken` as its last parameter, allowing you to cancel in-flight requests.

```csharp
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var pets = await client.Pets.ListPetsAsync(cancellationToken: cts.Token);
```

### Environment management

The SDK generates an `Environment` class with static properties for each named server defined in your API specification.

```csharp
// Use a named environment constant
client.SetEnvironment(Environment.Production);
// Or set a custom base URL
client.SetBaseUrl("https://staging.api.example.com");
```

Available environments are defined in `Http/Environment.cs` as static properties. If your API specification includes servers with names like "production", "development", or "staging", those are generated as properties on the `Environment` class for easy reference.

```csharp
public class Environment
{
    public static Environment Default     { get; } = new("https://api.example.com/");
    public static Environment Production  { get; } = new("https://api.example.com/");
    public static Environment Development { get; } = new("https://api-dev.example.com/");
    public static Environment Staging     { get; } = new("https://api-staging.example.com/");
}
```

### Hierarchical configuration

C# supports four levels of configuration. Each level overrides the previous, with request-level being the most specific.

```csharp
// 1. SDK level — default for all services and methods
var config = new YourSdkConfig { AccessToken = "sdk-token" };
var client = new YourSdkClient(config);
client.SetBaseUrl("https://api.example.com");
client.SetTimeout(TimeSpan.FromSeconds(10));
// 2. Service level — override for all methods in UsersService
client.Users.SetConfig(new RequestConfig(
    BaseUrl: "https://legacy.api.example.com",
    Timeout: TimeSpan.FromSeconds(15)
));
// 3. Method level — override for GetUserAsync only
client.Users.SetGetUserAsyncConfig(new RequestConfig(
    BaseUrl: "https://v2.api.example.com"
));
// 4. Request level — override for this single call only
var user = await client.Users.GetUserAsync(
    "123",
    requestConfig: new RequestConfig(
        Timeout: TimeSpan.FromSeconds(30),
        AccessToken: "request-scoped-token"
    )
);
```

`RequestConfig` is a C# record with optional properties. Only the values you provide override the inherited configuration; omitted properties fall through to the next level.

### Error handling

Service methods throw exceptions on API errors. The base exception class is `ApiException`, which wraps the underlying `HttpResponseMessage`. Catch `ApiException` for general error handling.

```csharp
using YourSdk.Http.Exceptions;
try
{
    var user = await client.Users.GetUserAsync("123");
    Console.WriteLine(user);
}
catch (ApiException e)
{
    Console.Error.WriteLine($"Status: {(int)e.Response.StatusCode}");
    Console.Error.WriteLine($"Reason: {e.Response.ReasonPhrase}");
}
```

To handle specific status codes, run the following:

```csharp
try
{
    await client.Users.DeleteUserAsync("123");
}
catch (ApiException e)
{
    switch ((int)e.Response.StatusCode)
    {
        case 404:
            Console.WriteLine("User not found");
            break;
        case 403:
            Console.WriteLine("Permission denied");
            break;
        default:
            Console.WriteLine($"API error: {e.Message}");
            break;
    }
}
```

When the API specification defines typed error response models (for example, a `NotFoundError` schema on a 404 response), the SDK generates a corresponding typed exception class that extends `ApiException`. Access the deserialized error model through the named property on the exception:

```csharp
using YourSdk.Http.Exceptions;
try
{
    await client.Users.GetUserAsync("123");
}
catch (NotFoundErrorException e)
{
    // Typed exception with deserialized error model
    Console.WriteLine($"Code: {e.NotFoundError.Code}");
    Console.WriteLine($"Message: {e.NotFoundError.Message}");
    Console.WriteLine($"Request ID: {e.NotFoundError.RequestId}");
}
catch (ApiException e)
{
    // Fallback for unmapped error responses
    Console.WriteLine($"API error: {(int)e.Response.StatusCode}");
}
```

### Timeouts and retries

To set a global timeout, run the following:

```csharp
client.SetTimeout(TimeSpan.FromSeconds(10));
```

The timeout can also be set at construction time through `RequestConfig` on the config:

```csharp
var config = new YourSdkConfig { };
var client = new YourSdkClient(config);
client.SetTimeout(TimeSpan.FromSeconds(10));
```

To configure retries, pass a `RetryConfig` record at construction time or per-request:

```csharp
var retryConfig = new RetryConfig(
    MaxRetryAttempts: 3,
    Delay: TimeSpan.FromMilliseconds(150),
    MaxDelay: TimeSpan.FromMilliseconds(5000),
    BackoffMultiplier: 2.0,
    UseJitter: true
);
var config = new YourSdkConfig { };
var client = new YourSdkClient(config);
// Override retry config at the request level
var pets = await client.Pets.ListPetsAsync(
    requestConfig: new RequestConfig(RetryConfig: retryConfig)
);
```

The following table shows the default retry configuration values used by the SDK if no `RetryConfig` is provided:

| Property               | Default                                      |
| ---------------------- | -------------------------------------------- |
| MaxRetryAttempts       | 3                                            |
| Delay                  | 150ms                                        |
| MaxDelay               | 5000ms                                       |
| BackoffMultiplier      | 2.0                                          |
| UseJitter              | true                                         |
| Retryable status codes | 5xx, 408, 429                                |
| Retryable HTTP methods | GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS |

### Validation

The SDK validates required parameters before sending the request. If a required argument is null, the service method throws an `ArgumentNullException` immediately, without making an HTTP call.

```csharp
try
{
    // Throws if a required parameter is null
    await client.Users.CreateUserAsync(username: null, email: "user@example.com");
}
catch (ArgumentNullException e)
{
    Console.WriteLine($"Validation failed: {e.ParamName} is required");
}
```

No manual validation calls are needed. Validation is built into every service method.

### Optional and nullable field handling

The SDK uses two patterns to represent optional and nullable fields, providing a clear distinction between undefined, `null`, and present values. This is important when building request models, as omitting an optional field versus explicitly setting it to `null` produces different JSON payloads.

* **Required non-nullable fields** are plain C# types and must always be provided and can't be `null`.
* **Required nullable fields** use C# nullable types (`string?`, `long?`) and must be provided, but may be `null`.
* **Optional fields** use the `Optional<T>` struct. This wrapper distinguishes between "not provided" (field omitted from JSON) and "provided with a value" (field included in JSON, even if `null` for `Optional<T?>`).

```csharp
// Present with a value
Optional<string>.Of("hello world")
// Explicitly null — sends "null" in JSON
Optional<string?>.Of(null)
// Not provided — field is omitted from JSON entirely
Optional<string>.NotProvided()
// default is equivalent to NotProvided
Optional<string> notProvided = default;
```

The following examples show the full range of field combinations:

```csharp
// Example 1: All fields set
var model = new ModelWithOptionalNullableDefaultValues(
    requiredString: "alice",                          // Required non-nullable
    requiredInteger: 30L,                             // Required non-nullable
    requiredNullableString: "present",                // Required nullable with value
    requiredNullableInteger: null,                    // Required nullable set to null
    optionalString: Optional<string>.Of("hello"),     // Optional with value
    optionalInteger: Optional<long>.Of(10L),          // Optional with value
    optionalNullableString: Optional<string?>.Of(null), // Optional nullable set to null
    optionalNullableInteger: default                  // Optional not provided → omitted
);
// JSON sent to server:
// {
//   "requiredString": "alice",
//   "requiredInteger": 30,
//   "requiredNullableString": "present",
//   "requiredNullableInteger": null,
//   "optionalString": "hello",
//   "optionalInteger": 10,
//   "optionalNullableString": null
//   // optionalNullableInteger omitted
// }
// Example 2: Minimal — only required fields
var minimalModel = new ModelWithOptionalNullableDefaultValues(
    requiredString: "bob",
    requiredInteger: 25L,
    requiredNullableString: null,
    requiredNullableInteger: null
    // Optional fields omitted — excluded from JSON entirely
);
// JSON sent to server:
// {
//   "requiredString": "bob",
//   "requiredInteger": 25,
//   "requiredNullableString": null,
//   "requiredNullableInteger": null
// }
// Example 3: Mixed — some optional fields provided, others omitted
var mixedModel = new ModelWithOptionalNullableDefaultValues(
    requiredString: "carol",
    requiredInteger: 35L,
    requiredNullableString: "required",
    requiredNullableInteger: null,
    optionalString: Optional<string>.Of("engineer"),   // Present
    optionalNullableString: Optional<string?>.Of(null) // Explicitly null
    // optionalInteger and optionalNullableInteger omitted
);
// JSON sent to server:
// {
//   "requiredString": "carol",
//   "requiredInteger": 35,
//   "requiredNullableString": "required",
//   "requiredNullableInteger": null,
//   "optionalString": "engineer",
//   "optionalNullableString": null
// }
```

When reading responses, `Optional<T>` fields deserialized from the server response will have `IsProvided = true` if the field was present in the JSON (even if `null` for nullable types), and `IsProvided = false` if the field was absent.

```csharp
var result = await client.Models.GetModelAsync(request);
if (result.OptionalString.IsProvided)
{
    Console.WriteLine($"Optional string: {result.OptionalString.Value}");
}
else
{
    Console.WriteLine("Optional string was not present in response");
}
```

### Resource cleanup

The SDK client implements `IDisposable` and manages the lifecycle of its internal `HttpClient`. Always dispose of the client when you are finished using it to release HTTP resources.

```csharp
// Option 1: using statement (recommended)
using var client = new YourSdkClient(config);
var pets = await client.Pets.ListPetsAsync();
// Option 2: explicit dispose
var client = new YourSdkClient(config);
try
{
    var pets = await client.Pets.ListPetsAsync();
}
finally
{
    client.Dispose();
}
```

## Additional resources

Consider the following resources for using and customizing your C# SDK:

* SDK documentation — Check the `documentation/` directory inside your SDK for per-service and per-model reference pages.
* XML documentation — Enable `<GenerateDocumentationFile>true</GenerateDocumentationFile>` in the `.csproj` file and browse IntelliSense docs directly in your IDE.
* [NuGet Gallery](https://www.nuget.org/) — Once published, your SDK's page is available at `https://www.nuget.org/packages/YourSdk`.
* Example usage — See `Example/Program.cs` for a runnable demonstration of the SDK.
* Dependencies — The SDK targets .NET 6 or later and uses `System.Text.Json` for serialization and [Polly](https://github.com/App-vNext/Polly) for retry resilience.