n1coePayDocs API reference

.NET SDK

N1co.EPay calls the ePay API from your .NET server, with dependency injection, coded exceptions and webhook verification.

  1. Install N1co.EPay on your server (net8.0 or net10.0).
  2. Register the client with AddN1coEPay and your secret key.
  3. Create intents with PaymentIntents.CreateAsync and verify webhooks with N1coWebhook.ConstructEvent.
dotnet add package N1co.EPay

A complete minimal API: it creates the intent and receives the webhook.

Program.cs
using N1co.EPay;

var builder = WebApplication.CreateBuilder(args);
// "N1co" section: SecretKey, BaseUrl, Timeout, MaxRetries, AppInfo.
builder.Services.AddN1coEPay(o =>
{
    o.SecretKey = builder.Configuration["N1co:SecretKey"]!;
    o.BaseUrl = N1coClient.DevBaseUrl; // https://api-epay.dev.n1co.dev
});
var webhookSecret = builder.Configuration["N1co:WebhookSecret"]!; // whsec_…
var app = builder.Build();

app.MapPost("/checkout/payment-intent", async (N1coClient n1co) =>
{
    // The amount comes from your order, never from the browser.
    var intent = await n1co.PaymentIntents.CreateAsync(new()
    {
        Amount = 1250,
        Currency = "USD",
        Customer = new CustomerInput { Id = "cust-1001", Name = "Ana López", Email = "ana.lopez@example.com", Phone = "+503 7000-1234" },
        Reference = "order-8812",
    });
    return Results.Ok(new { client_secret = intent.ClientSecret });
});

app.MapPost("/webhooks/n1co", async (HttpRequest request) =>
{
    using var body = new MemoryStream();
    await request.Body.CopyToAsync(body); // the raw bytes, exactly as sent

    Event evt;
    try
    {
        evt = N1coWebhook.ConstructEvent(body.ToArray(), request.Headers, webhookSecret);
    }
    catch (WebhookSignatureException)
    {
        return Results.BadRequest();
    }

    if (evt.Type == EventType.PaymentIntentSucceeded && evt.Data.Object is PaymentIntentEventObject intent)
    {
        // Fulfill the order for intent.Id; skip repeated evt.Id values.
    }
    return Results.NoContent();
});

app.Run();

AddN1coEPay registers N1coClient as a singleton and validates the options at startup. Without DI, create a single new N1coClient(secretKey, options) and reuse it. The page confirms the payment as in Charge.

Errors#

Every API, network or signature failure is an N1coException with Code, StatusCode, GetDetail("field") and RequestId. Branch on Code, never on Message.

try
{
    await n1co.PaymentIntents.CreateAsync(parameters);
}
catch (InvalidRequestException e)
{
    logger.LogWarning("{Field} {Code}", e.GetDetail("field"), e.GetDetail("code"));
}
catch (N1coException e)
{
    logger.LogError("{Code} {Status} {RequestId}", e.Code, e.StatusCode, e.RequestId);
}

The codes are in Errors. Canceling through your CancellationToken throws OperationCanceledException, not an SDK exception.

Common mistakes#

  • Reading the body as JSON before verifying. Verify the raw bytes; a deserialized and reserialized model does not match the signature.
  • The secret key in Blazor WebAssembly. The key lives only on the server: your WebAssembly app calls your backend, never the API. A Blazor Server component may inject N1coClient.
  • Expecting retries from a resilience handler. The API has no idempotency keys, so the SDK strips retry handlers from its client, including those from .NET Aspire service defaults. After a ConnectionException on a POST, read the object or wait for its webhook.
  • Leaving out BaseUrl. Without it, the client uses the production host, which arrives with the production release.

The client options, using your own HttpClient, the models and GET retries are in the package README.