vellTRDocs
SDKs.NET

Kvell .NET SDK

v1.1.4Requirements: .NET 6.0+

Install

Shell
dotnet add package Kvell.Net

Initialize

C#
using Kvell;

var kvell = new KvellClient(new KvellOptions
{
    ApiKey = Environment.GetEnvironmentVariable("KVELL_API_KEY"),
    SecretKey = Environment.GetEnvironmentVariable("KVELL_SECRET_KEY"),
    Environment = "sandbox", // switch to "production" when you go live
});

Quickstart

C#
using Kvell;

var kvell = new KvellClient(new KvellOptions
{
    ApiKey = Environment.GetEnvironmentVariable("KVELL_API_KEY"),
    SecretKey = Environment.GetEnvironmentVariable("KVELL_SECRET_KEY"),
    Environment = "sandbox",
});

// Amounts are always integers in kuruş (1/100 TRY) — 15000 = 150.00 TRY
var session = await kvell.PaymentSessions.CreateAsync(new CreateSessionParams
{
    TransactionId = "ORDER-2026-001",
    Amount = 15000,
    Currency = "TRY",
    Description = "Order #1234",
    ReturnUrl = "https://merchant.example.com/return",
});

Console.WriteLine($"Redirect the buyer to: {session.CheckoutUrl}");

Error handling

C#
using Kvell;
using Kvell.Exceptions;

var kvell = new KvellClient(new KvellOptions
{
    ApiKey = Environment.GetEnvironmentVariable("KVELL_API_KEY"),
    SecretKey = Environment.GetEnvironmentVariable("KVELL_SECRET_KEY"),
    Environment = "sandbox",
});

try
{
    var payment = await kvell.Payments.ChargeAsync(new ChargeParams
    {
        TransactionId = "ORDER-2026-001",
        Amount = 15000, // kuruş
        Currency = "TRY",
        CardToken = "tok_9f8e7d6c5b4a",
    });
    Console.WriteLine($"Captured payment {payment.PaymentId}");
}
catch (KvellError err)
{
    switch (err.Code)
    {
        case "KVELL-PAY-4001":
            Console.Error.WriteLine($"Card declined (requestId={err.RequestId})");
            break;
        case "KVELL-GW-1002":
            Console.Error.WriteLine($"Signature invalid, check your secret key (requestId={err.RequestId})");
            break;
        default:
            Console.Error.WriteLine($"Kvell error {err.Code} (requestId={err.RequestId})");
            break;
    }
    throw;
}

Verify webhooks

C#
using System.Security.Cryptography;
using System.Text;

var app = WebApplication.Create();
var seenEventIds = new HashSet<string>(); // swap for Redis/DB in production

app.MapPost("/webhooks/kvell", async (HttpRequest request) =>
{
    using var reader = new StreamReader(request.Body);
    var rawBody = await reader.ReadToEndAsync(); // raw body, never the parsed JSON
    var signature = request.Headers["X-Kvell-Signature"].ToString();
    var eventId = request.Headers["X-Kvell-Event-Id"].ToString();

    var secret = Environment.GetEnvironmentVariable("KVELL_WEBHOOK_SECRET")!;
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody));
    var expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();

    if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(signature), Encoding.UTF8.GetBytes(expected)))
        return Results.Unauthorized();
    if (!seenEventIds.Add(eventId))
        return Results.Ok("duplicate");

    var evt = System.Text.Json.JsonSerializer.Deserialize<KvellEvent>(rawBody);
    switch (evt?.EventType)
    {
        case "payment.captured":
            // Fulfil the order asynchronously; respond fast below
            break;
    }

    return Results.Ok("ok");
});

app.Run();