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

# C#

> Use the Dodo Payments C# SDK to create checkout sessions, customers, and subscriptions from .NET, with typed models, automatic retries, and pagination.

The C# SDK gives .NET applications typed access to the Dodo Payments REST API. Every API method is asynchronous and returns a `Task`, requests and responses are typed classes, and the client retries failed requests for you.

## Installation

Install the package from [NuGet](https://www.nuget.org/packages/DodoPayments.Client):

```bash theme={null}
dotnet add package DodoPayments.Client
```

<Info>
  The SDK requires .NET Standard 2.0 or later, and it also ships a .NET 8 build. It works with ASP.NET Core, console applications, and other .NET project types. The examples on this page use C# 12 syntax, such as collection expressions.
</Info>

## Quick Start

Create a client, then create a checkout session:

```csharp theme={null}
using System;
using DodoPayments.Client;
using DodoPayments.Client.Models.CheckoutSessions;

// Configured using the DODO_PAYMENTS_API_KEY, DODO_PAYMENTS_WEBHOOK_KEY, and DODO_PAYMENTS_BASE_URL environment variables
DodoPaymentsClient client = new();

CheckoutSessionCreateParams parameters = new()
{
    ProductCart =
    [
        new()
        {
            ProductID = "pdt_123",
            Quantity = 1,
        },
    ],
};

var checkoutSessionResponse = await client.CheckoutSessions.Create(parameters);

Console.WriteLine(checkoutSessionResponse.SessionID);
```

If you don't set `BearerToken`, the client reads the `DODO_PAYMENTS_API_KEY` environment variable. If you don't set `BaseUrl` or `DODO_PAYMENTS_BASE_URL`, the client connects to live mode. To use test mode, see [Environments](#environments). A test mode API key works only in test mode.

<Warning>
  Keep API keys in environment variables, user secrets, or Azure Key Vault. Never hardcode them in your source code or commit them to version control.
</Warning>

## Core Features

<CardGroup cols={2}>
  <Card title="Async/Await" icon="bolt">
    Every API method returns a `Task` and accepts an optional `CancellationToken`.
  </Card>

  <Card title="Strong Typing" icon="shield-check">
    Typed request and response classes, with nullable reference type annotations.
  </Card>

  <Card title="Smart Retries" icon="repeat">
    Two retries by default, with exponential backoff, for connection errors and retryable status codes.
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation">
    An exception class for each common HTTP error status, with the status code and response body.
  </Card>
</CardGroup>

## Configuration

### Environment Variables

Store your API key in an environment variable:

```bash .env theme={null}
DODO_PAYMENTS_API_KEY=your_api_key_here
```

A client created with `new()` reads its settings from the environment:

```csharp theme={null}
// Automatically reads from environment variables
DodoPaymentsClient client = new();
```

The client reads these environment variables when you don't set the matching property:

| Property | Environment variable | Required | Default value |
| - | - | - | - |
| `BearerToken` | `DODO_PAYMENTS_API_KEY` | true | - |
| `WebhookKey` | `DODO_PAYMENTS_WEBHOOK_KEY` | false | - |
| `BaseUrl` | `DODO_PAYMENTS_BASE_URL` | true | `"https://live.dodopayments.com"` |

If neither `BearerToken` nor `DODO_PAYMENTS_API_KEY` is set, the client throws `DodoPaymentsInvalidDataException`. `WebhookKey` holds your webhook signing secret, but the C# SDK has no method that verifies webhook signatures. To verify them, follow [Webhooks](/developer-resources/webhooks).

### Manual Configuration

Set properties on the client to override the environment variables:

```csharp theme={null}
DodoPaymentsClient client = new() { BearerToken = "My Bearer Token" };
```

### Environments

The client connects to live mode (`https://live.dodopayments.com`) by default. To use test mode (`https://test.dodopayments.com`), set `BaseUrl` to `EnvironmentUrl.TestMode`:

```csharp theme={null}
using DodoPayments.Client.Core;

DodoPaymentsClient client = new() { BaseUrl = EnvironmentUrl.TestMode };
```

### Retries

The SDK retries connection errors and responses with status 408, 409, 429, or 500 and above. It retries twice by default, with exponential backoff. Set `MaxRetries` to change the number of retries, or set it to `0` to turn retries off:

```csharp theme={null}
// Custom retry count
DodoPaymentsClient client = new() { MaxRetries = 3 };
```

### Timeouts

Each request attempt times out after 1 minute by default. The timeout doesn't include retries. Set `Timeout` to change it:

```csharp theme={null}
DodoPaymentsClient client = new() { Timeout = TimeSpan.FromSeconds(30) };
```

### Per-Request Overrides

To change settings for a single call, call `WithOptions` on the client or on a service. It returns a modified copy that shares the same connection pool, and the original client doesn't change:

```csharp theme={null}
var response = await client
    .WithOptions(options => options with
    {
        Timeout = TimeSpan.FromSeconds(10),
        MaxRetries = 5,
    })
    .CheckoutSessions.Create(parameters);
```

## Common Operations

The examples in this section use the `client` from [Quick Start](#quick-start).

### Create a Checkout Session

Create a checkout session, then redirect the customer to the returned `CheckoutUrl`:

```csharp theme={null}
var parameters = new CheckoutSessionCreateParams
{
    ProductCart =
    [
        new()
        {
            ProductID = "pdt_123",
            Quantity = 1
        }
    ],
    ReturnUrl = "https://yourdomain.com/return"
};

var session = await client.CheckoutSessions.Create(parameters);
Console.WriteLine($"Checkout URL: {session.CheckoutUrl}");
```

Each checkout URL works once and expires after 24 hours. For every session option, see [Checkout Sessions](/developer-resources/checkout-session).

### Manage Customers

Create a customer with an email address and name, then retrieve it by ID:

```csharp theme={null}
using DodoPayments.Client.Models.Customers;

// Create a customer
var customer = await client.Customers.Create(new CustomerCreateParams
{
    Email = "customer@example.com",
    Name = "John Doe"
});

// Retrieve customer
var retrieved = await client.Customers.Retrieve(new CustomerRetrieveParams { CustomerID = "cus_123" });
Console.WriteLine($"Customer: {retrieved.Name} ({retrieved.Email})");
```

`Customers.Retrieve` also accepts the ID as a string, for example `client.Customers.Retrieve("cus_123")`.

### Handle Subscriptions

Create a subscription, then charge it if it's an on-demand subscription.

<Warning>
  `POST /subscriptions` (the SDK's `Subscriptions.Create` method) is **deprecated**. It still works for existing integrations, but new integrations should create subscriptions through a [Checkout Session](/developer-resources/checkout-session).
</Warning>

```csharp theme={null}
using DodoPayments.Client.Models.Payments;
using DodoPayments.Client.Models.Subscriptions;

// Create a subscription
var subscription = await client.Subscriptions.Create(new SubscriptionCreateParams
{
    Billing = new BillingAddress
    {
        Country = "US",
        City = "San Francisco",
        State = "CA",
        Street = "1 Market St",
        Zipcode = "94105",
    },
    Customer = new AttachExistingCustomer { CustomerID = "cus_123" },
    ProductID = "pdt_456",
    Quantity = 1,
});

// Charge an on-demand subscription
// ProductPrice is in the lowest currency denomination (e.g., 2500 = $25.00 USD)
var charge = await client.Subscriptions.Charge(new SubscriptionChargeParams
{
    SubscriptionID = subscription.SubscriptionID,
    ProductPrice = 2500,
});
```

<Info>
  `Billing` requires only `Country`, a two-letter ISO country code. `Customer` takes an `AttachExistingCustomer` to attach an existing customer or a `NewCustomer` to create one. `Charge` is for [on-demand subscriptions](/developer-resources/ondemand-subscriptions), and `ProductPrice` is in the smallest currency unit.
</Info>

## Error Handling

When the API returns an error status, the SDK throws a subclass of `DodoPaymentsApiException`, which has `StatusCode` and `ResponseBody` properties. The exception class depends on the status code. All 4xx exceptions inherit from `DodoPayments4xxException`.

| Status | Exception |
| - | - |
| 400 | `DodoPaymentsBadRequestException` |
| 401 | `DodoPaymentsUnauthorizedException` |
| 403 | `DodoPaymentsForbiddenException` |
| 404 | `DodoPaymentsNotFoundException` |
| 422 | `DodoPaymentsUnprocessableEntityException` |
| 429 | `DodoPaymentsRateLimitException` |
| 5xx | `DodoPayments5xxException` |
| others | `DodoPaymentsUnexpectedStatusCodeException` |

A 4xx status without its own class, such as 409, throws `DodoPayments4xxException`. `DodoPaymentsUnexpectedStatusCodeException` covers statuses outside the 4xx and 5xx ranges.

The SDK also throws these exceptions:

* `DodoPaymentsIOException`: An I/O or network error.
* `DodoPaymentsInvalidDataException`: The SDK couldn't interpret the response data, for example because a required property is missing.
* `DodoPaymentsException`: The base class of every SDK exception.

## Pagination

List methods return one page of results. You can iterate over every item or move through the pages yourself.

### Auto-Pagination

`Paginate` returns an `IAsyncEnumerable` that fetches the next page when it needs it:

```csharp theme={null}
var page = await client.Payments.List();
await foreach (var item in page.Paginate())
{
    Console.WriteLine(item);
}
```

### Manual Pagination

To work with one page at a time, read `Items`, then call `HasNext()` and `Next()`:

```csharp theme={null}
var page = await client.Payments.List();
while (true)
{
    foreach (var item in page.Items)
    {
        Console.WriteLine(item);
    }
    if (!page.HasNext())
    {
        break;
    }
    page = await page.Next();
}
```

To set the page size, pass a `PaymentListParams` from the `DodoPayments.Client.Models.Payments` namespace, for example `client.Payments.List(new PaymentListParams { PageSize = 50 })`.

## ASP.NET Core Integration

Register one client as a singleton in the dependency injection container, and read the API key from configuration:

```csharp Program.cs theme={null}
using DodoPayments.Client;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<DodoPaymentsClient>(sp =>
{
    var configuration = sp.GetRequiredService<IConfiguration>();
    return new DodoPaymentsClient
    {
        BearerToken = configuration["DodoPayments:ApiKey"]
    };
});

var app = builder.Build();
app.Run();
```

Add the key to your configuration, for example in `appsettings.json`:

```json appsettings.json theme={null}
{
  "DodoPayments": {
    "ApiKey": "your_api_key_here"
  }
}
```

<Tip>
  In development, store the key with [user secrets](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets) instead of in `appsettings.json`:

  ```bash theme={null}
  dotnet user-secrets init
  dotnet user-secrets set "DodoPayments:ApiKey" "your_api_key_here"
  ```
</Tip>

## Resources

<CardGroup cols={2}>
  <Card title="NuGet Package" icon="box" href="https://www.nuget.org/packages/DodoPayments.Client">
    Package versions and install commands.
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/dodopayments/dodopayments-csharp">
    Source code, releases, and examples.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Every endpoint, parameter, and response.
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/bYqAp4ayYh">
    Ask questions and talk with other developers.
  </Card>
</CardGroup>

## Support

For help with the C# SDK:

* **Discord**: Join the [community server](https://discord.gg/bYqAp4ayYh) for real-time help.
* **Email**: Contact [support@dodopayments.com](mailto:support@dodopayments.com).
* **GitHub**: Open an issue on the [repository](https://github.com/dodopayments/dodopayments-csharp).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.