Use C# SDKs generated in Postman

View as Markdown

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/Exceptions/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.
  • examples/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:

your-sdk
README.md
[SdkName].csproj
.gitignore
.env.example
.devcontainer
[SdkName]Client.cs
Config
Services
Models
Http
examples
documentation

Example usage

Each generated SDK includes an examples/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

examples/Program.cs

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:

$dotnet add package YourSdk

Then use it in your code:

1using YourSdk;
2using YourSdk.Config;
3var config = new YourSdkConfig { };
4var 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.

1<ItemGroup>
2 <ProjectReference Include="../path/to/YourSdk/YourSdk.csproj" />
3</ItemGroup>

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

$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.

1<Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup>
3 <PackageId>YourSdk</PackageId>
4 <Version>1.0.0</Version>
5 <Authors>Your Name</Authors>
6 <Description>SDK for Your API</Description>
7 <PackageLicenseExpression>MIT</PackageLicenseExpression>
8 <PackageProjectUrl>https://github.com/your-org/your-sdk</PackageProjectUrl>
9 <RepositoryUrl>https://github.com/your-org/your-sdk</RepositoryUrl>
10 <TargetFramework>net6.0</TargetFramework>
11 </PropertyGroup>
12</Project>

Publish your C# SDK to NuGet

To publish your SDK to NuGet, do the following:

  1. Build and pack the SDK.

    $cd path/to/your-sdk
    $dotnet pack -c Release -o ./nupkgs
  2. Publish to NuGet.

    $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:

$# 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.

1var apiKeyConfig = new ApiKeyAuthConfig("your-api-key");
2var config = new YourSdkConfig { ApiKeyAuth = apiKeyConfig };
3var client = new YourSdkClient(config);

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.

1using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
2var 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.

1// Use a named environment constant
2client.SetEnvironment(Environment.Production);
3// Or set a custom base URL
4client.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.

1public class Environment
2{
3 public static Environment Default { get; } = new("https://api.example.com/");
4 public static Environment Production { get; } = new("https://api.example.com/");
5 public static Environment Development { get; } = new("https://api-dev.example.com/");
6 public static Environment Staging { get; } = new("https://api-staging.example.com/");
7}

Hierarchical configuration

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

1// 1. SDK level — default for all services and methods
2var config = new YourSdkConfig { AccessToken = "sdk-token" };
3var client = new YourSdkClient(config);
4client.SetBaseUrl("https://api.example.com");
5client.SetTimeout(TimeSpan.FromSeconds(10));
6// 2. Service level — override for all methods in UsersService
7client.Users.SetConfig(new RequestConfig(
8 BaseUrl: "https://legacy.api.example.com",
9 Timeout: TimeSpan.FromSeconds(15)
10));
11// 3. Method level — override for GetUserAsync only
12client.Users.SetGetUserAsyncConfig(new RequestConfig(
13 BaseUrl: "https://v2.api.example.com"
14));
15// 4. Request level — override for this single call only
16var user = await client.Users.GetUserAsync(
17 "123",
18 requestConfig: new RequestConfig(
19 Timeout: TimeSpan.FromSeconds(30),
20 AccessToken: "request-scoped-token"
21 )
22);

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.

1using YourSdk.Http.Exceptions;
2try
3{
4 var user = await client.Users.GetUserAsync("123");
5 Console.WriteLine(user);
6}
7catch (ApiException e)
8{
9 Console.Error.WriteLine($"Status: {(int)e.ResponseMessage.StatusCode}");
10 Console.Error.WriteLine($"Reason: {e.ResponseMessage.ReasonPhrase}");
11}

To handle specific status codes, run the following:

1try
2{
3 await client.Users.DeleteUserAsync("123");
4}
5catch (ApiException e)
6{
7 switch ((int)e.ResponseMessage.StatusCode)
8 {
9 case 404:
10 Console.WriteLine("User not found");
11 break;
12 case 403:
13 Console.WriteLine("Permission denied");
14 break;
15 default:
16 Console.WriteLine($"API error: {e.Message}");
17 break;
18 }
19}

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:

1using YourSdk.Http.Exceptions;
2try
3{
4 await client.Users.GetUserAsync("123");
5}
6catch (NotFoundErrorException e)
7{
8 // Typed exception with deserialized error model
9 Console.WriteLine($"Code: {e.NotFoundError.Code}");
10 Console.WriteLine($"Message: {e.NotFoundError.Message}");
11 Console.WriteLine($"Request ID: {e.NotFoundError.RequestId}");
12}
13catch (ApiException e)
14{
15 // Fallback for unmapped error responses
16 Console.WriteLine($"API error: {(int)e.ResponseMessage.StatusCode}");
17}

Timeouts and retries

To set a global timeout, run the following:

1client.SetTimeout(TimeSpan.FromSeconds(10));

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

1var config = new YourSdkConfig { };
2var client = new YourSdkClient(config);
3client.SetTimeout(TimeSpan.FromSeconds(10));

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

1var retryConfig = new RetryConfig(
2 MaxRetryAttempts: 3,
3 Delay: TimeSpan.FromMilliseconds(150),
4 MaxDelay: TimeSpan.FromMilliseconds(5000),
5 BackoffMultiplier: 2.0,
6 UseJitter: true
7);
8var config = new YourSdkConfig { };
9var client = new YourSdkClient(config);
10// Override retry config at the request level
11var pets = await client.Pets.ListPetsAsync(
12 requestConfig: new RequestConfig(RetryConfig: retryConfig)
13);

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

PropertyDefault
MaxRetryAttempts3
Delay150ms
MaxDelay5000ms
BackoffMultiplier2.0
UseJittertrue
Retryable status codes5xx, 408, 429
Retryable HTTP methodsGET, 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.

1try
2{
3 // Throws if a required parameter is null
4 await client.Users.CreateUserAsync(username: null, email: "user@example.com");
5}
6catch (ArgumentNullException e)
7{
8 Console.WriteLine($"Validation failed: {e.ParamName} is required");
9}

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?>).
1// Present with a value
2Optional<string>.Of("hello world")
3// Explicitly null — sends "null" in JSON
4Optional<string?>.Of(null)
5// Not provided — field is omitted from JSON entirely
6Optional<string>.NotProvided()
7// default is equivalent to NotProvided
8Optional<string> notProvided = default;

The following examples show the full range of field combinations:

1// Example 1: All fields set
2var model = new ModelWithOptionalNullableDefaultValues(
3 requiredString: "alice", // Required non-nullable
4 requiredInteger: 30L, // Required non-nullable
5 requiredNullableString: "present", // Required nullable with value
6 requiredNullableInteger: null, // Required nullable set to null
7 optionalString: Optional<string>.Of("hello"), // Optional with value
8 optionalInteger: Optional<long>.Of(10L), // Optional with value
9 optionalNullableString: Optional<string?>.Of(null), // Optional nullable set to null
10 optionalNullableInteger: default // Optional not provided → omitted
11);
12// JSON sent to server:
13// {
14// "requiredString": "alice",
15// "requiredInteger": 30,
16// "requiredNullableString": "present",
17// "requiredNullableInteger": null,
18// "optionalString": "hello",
19// "optionalInteger": 10,
20// "optionalNullableString": null
21// // optionalNullableInteger omitted
22// }
23// Example 2: Minimal — only required fields
24var minimalModel = new ModelWithOptionalNullableDefaultValues(
25 requiredString: "bob",
26 requiredInteger: 25L,
27 requiredNullableString: null,
28 requiredNullableInteger: null
29 // Optional fields omitted — excluded from JSON entirely
30);
31// JSON sent to server:
32// {
33// "requiredString": "bob",
34// "requiredInteger": 25,
35// "requiredNullableString": null,
36// "requiredNullableInteger": null
37// }
38// Example 3: Mixed — some optional fields provided, others omitted
39var mixedModel = new ModelWithOptionalNullableDefaultValues(
40 requiredString: "carol",
41 requiredInteger: 35L,
42 requiredNullableString: "required",
43 requiredNullableInteger: null,
44 optionalString: Optional<string>.Of("engineer"), // Present
45 optionalNullableString: Optional<string?>.Of(null) // Explicitly null
46 // optionalInteger and optionalNullableInteger omitted
47);
48// JSON sent to server:
49// {
50// "requiredString": "carol",
51// "requiredInteger": 35,
52// "requiredNullableString": "required",
53// "requiredNullableInteger": null,
54// "optionalString": "engineer",
55// "optionalNullableString": null
56// }

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.

1var result = await client.Models.GetModelAsync(request);
2if (result.OptionalString.IsProvided)
3{
4 Console.WriteLine($"Optional string: {result.OptionalString.Value}");
5}
6else
7{
8 Console.WriteLine("Optional string was not present in response");
9}

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.

1// Option 1: using statement (recommended)
2using var client = new YourSdkClient(config);
3var pets = await client.Pets.ListPetsAsync();
4// Option 2: explicit dispose
5var client = new YourSdkClient(config);
6try
7{
8 var pets = await client.Pets.ListPetsAsync();
9}
10finally
11{
12 client.Dispose();
13}

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 — Once published, your SDK’s page is available at https://www.nuget.org/packages/YourSdk.
  • Example usage — See examples/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 for retry resilience.