Skip to content

.NET / C# SDK

The C# SDK targets net8.0 and net10.0. NuGet:

Terminal window
dotnet add package Paylera.Sdk

Construct a client

using Paylera;
var paylera = new PayleraClient(new PayleraOptions
{
ApiKey = Environment.GetEnvironmentVariable("PAYLERA_KEY")!,
BaseUrl = PayleraEnvironment.Sandbox, // or .Live
ApiVersion = "2026-04-01",
});

PayleraOptions is plain record — easy to bind from IConfiguration. The client is thread-safe; create one and reuse it.

DI registration

builder.Services.AddPayleraClient(options =>
{
options.ApiKey = builder.Configuration["Paylera:ApiKey"]!;
options.BaseUrl = PayleraEnvironment.Sandbox;
options.ApiVersion = "2026-04-01";
});

AddPayleraClient registers IPayleraClient as a singleton.

Make a call

var customer = await paylera.Customers.CreateAsync(new()
{
Email = "ada@example.com",
Name = "Ada Lovelace",
BillingAddress = new() { Country = "US", PostalCode = "94105" },
});

CreateAsync auto-generates an idempotency key. Override with the overload:

await paylera.Customers.CreateAsync(request, idempotencyKey: "my-key");

Handle structured errors

try
{
var pay = await paylera.Invoices.PayAsync(invoiceId);
}
catch (PayleraApiException ex) when (ex.Problem == "payment.requires_action")
{
// ex.NextAction.Url is set
}
catch (PayleraApiException ex)
{
logger.LogWarning("Paylera error {Problem} (trace {TraceId}): {Detail}",
ex.Problem, ex.TraceId, ex.Detail);
throw;
}

List with pagination

await foreach (var sub in paylera.Subscriptions.ListAsync(new()
{
Status = ["active", "past_due"]
}))
{
Console.WriteLine($"{sub.Id} {sub.PlanCode} {sub.Status}");
}

The async-iterator walks pages for you. Bound the iteration with Take(N) if you only want a slice.

Idempotency helpers

var key = IdempotencyKey.From("subscribe", userId, planCode);
await paylera.Subscriptions.CreateAsync(req, idempotencyKey: key);

IdempotencyKey.From deterministically derives a key from intent fields — safe to reuse across retries.

Money

var amount = Money.Of(29.00m, "USD");
var sum = amount + Money.Of(5, "USD"); // operator-overloaded
var s = amount.ToString(); // "29.00 USD"

Money rejects mixed-currency arithmetic at compile time if both operands are typed Money — it throws at runtime if you’ve cast away the type.

Webhook verification

app.MapPost("/webhooks/paylera", async (HttpRequest req) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
var body = ms.ToArray();
var header = req.Headers["Paylera-Signature"].ToString();
if (!Webhooks.Verify(body, header, secret))
return Results.Unauthorized();
var evt = Webhooks.Parse(body);
// dispatch on evt.Type, evt.Id, evt.Data
return Results.Ok();
});

Webhooks.Verify does timing-safe comparison and replay-window checking.

Retries and timeouts

Defaults: 5 attempts on 429/5xx, exponential backoff with jitter, 30s per-request timeout. Tune via PayleraOptions.Retry and Timeout.

To disable automatic retries (you’ve got a smarter outer loop):

options.Retry.MaxAttempts = 0;

Observability

Pass an ILogger<PayleraClient> and the SDK logs request IDs, status codes, and trace IDs at Information. To get raw bodies on errors, set options.Logging.IncludeRawBodyOnError = true — only enable in dev; bodies may include PII.

Source

github.com/paylera/paylera-dotnet — issues and PRs welcome.