SDK C# / .NET
El SDK de C# permite integrar TAYPI en aplicaciones ASP.NET Core, Blazor, .NET MAUI, y cualquier proyecto .NET.
Instalacion
dotnet add package Taypi.NetO desde el Package Manager de Visual Studio:
Install-Package Taypi.NetRequisitos: .NET 6.0+.
Configuracion
using Taypi.Net;
var client = new TaypiClient(
publicKey: "taypi_pk_test_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
secretKey: "taypi_sk_test_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
options: new TaypiOptions
{
Sandbox = true, // true = sandbox.taypi.pe (default), false = app.taypi.pe
Timeout = 30, // Timeout en segundos (default: 30)
Retries = 2, // Reintentos en errores 5xx (default: 2)
}
);NUNCA EXPONGAS TU SECRET KEY
La secret key solo debe existir en tu backend. Nunca la incluyas en codigo frontend (Blazor WebAssembly), repositorios publicos, logs ni archivos de configuracion sin proteger.
Metodos
Todos los metodos son asincronos y retornan Task<T>.
CreateCheckoutSessionAsync
Crea un pago y devuelve un checkout_token para usar con Checkout.js.
var session = await client.CreateCheckoutSessionAsync(new CreateCheckoutRequest
{
Amount = "50.00",
Currency = "PEN",
Reference = "ORD-12345",
Description = "Compra en Mi Tienda",
Metadata = new Dictionary<string, string>
{
["customer_email"] = "cliente@example.com",
},
});
Console.WriteLine(session.PaymentId); // "a14dfb8e-d5c2-4a69-bae4-4688fef5eac2"
Console.WriteLine(session.CheckoutToken); // "ctk_a1b2c3..."
Console.WriteLine(session.CheckoutUrl); // "https://sandbox.taypi.pe/pay/a14dfb8e..."
Console.WriteLine(session.ExpiresAt); // DateTimeOffsetCreatePaymentAsync
Crea un pago y devuelve la informacion completa del QR.
var payment = await client.CreatePaymentAsync(new CreatePaymentRequest
{
Amount = "150.00",
Currency = "PEN",
Reference = "ORD-67890",
Description = "Servicio de consultoria",
});
Console.WriteLine(payment.PaymentId); // UUID del pago
Console.WriteLine(payment.Status); // "pending"
Console.WriteLine(payment.QrImage); // Data URI base64
Console.WriteLine(payment.CheckoutUrl); // URL para pago por enlace
Console.WriteLine(payment.ExpiresAt); // DateTimeOffsetGetPaymentAsync
Consulta el estado actual de un pago.
var payment = await client.GetPaymentAsync("a14dfb8e-d5c2-4a69-bae4-4688fef5eac2");
Console.WriteLine(payment.Status); // "pending", "completed", "expired", "cancelled"
Console.WriteLine(payment.Amount); // "50.00"
Console.WriteLine(payment.PaidAt); // DateTimeOffset? o nullListPaymentsAsync
Lista pagos con filtros opcionales.
var payments = await client.ListPaymentsAsync(new ListPaymentsRequest
{
Status = "completed",
From = new DateOnly(2026, 3, 1),
To = new DateOnly(2026, 3, 15),
Page = 1,
PerPage = 20,
});
Console.WriteLine(payments.Total);
foreach (var p in payments.Data)
{
Console.WriteLine($"{p.PaymentId}: {p.Amount} ({p.Status})");
}CancelPaymentAsync
Cancela un pago en estado pending.
var result = await client.CancelPaymentAsync("a14dfb8e-d5c2-4a69-bae4-4688fef5eac2");
Console.WriteLine(result.Status); // "cancelled"
Console.WriteLine(result.Message); // "Pago cancelado exitosamente"VerifyWebhook
Verifica la firma HMAC-SHA256 de un webhook entrante. Este metodo es sincronico.
bool isValid = client.VerifyWebhook(rawBody, signatureHeader);Ejemplo: ASP.NET Core (Minimal API)
using Taypi.Net;
var builder = WebApplication.CreateBuilder(args);
// Registrar TaypiClient como singleton
builder.Services.AddSingleton(new TaypiClient(
publicKey: builder.Configuration["Taypi:PublicKey"]!,
secretKey: builder.Configuration["Taypi:SecretKey"]!,
options: new TaypiOptions
{
Sandbox = builder.Configuration.GetValue<bool>("Taypi:Sandbox"),
}
));
var app = builder.Build();
// Crear sesion de checkout
app.MapPost("/api/crear-pago", async (TaypiClient taypi) =>
{
try
{
var session = await taypi.CreateCheckoutSessionAsync(new CreateCheckoutRequest
{
Amount = "50.00",
Currency = "PEN",
Reference = $"ORD-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}",
Description = "Compra en Mi Tienda",
});
return Results.Json(new { checkout_token = session.CheckoutToken });
}
catch (TaypiException ex)
{
return Results.Json(new { error = ex.Message }, statusCode: ex.HttpStatus);
}
});
// Webhook
app.MapPost("/api/webhooks/taypi", async (HttpContext context, TaypiClient taypi) =>
{
using var reader = new StreamReader(context.Request.Body);
var rawBody = await reader.ReadToEndAsync();
var signature = context.Request.Headers["Taypi-Signature"].FirstOrDefault() ?? "";
if (!taypi.VerifyWebhook(rawBody, signature))
{
return Results.StatusCode(401);
}
var webhookEvent = System.Text.Json.JsonSerializer.Deserialize<WebhookEvent>(rawBody);
if (webhookEvent?.Event == "payment.completed")
{
// Actualizar orden en tu base de datos
Console.WriteLine($"Pago completado: {webhookEvent.PaymentId}");
}
return Results.Ok("OK");
});
app.Run();
// Modelo para deserializar el webhook
record WebhookEvent
{
public string Event { get; init; } = "";
public string PaymentId { get; init; } = "";
public string Amount { get; init; } = "";
public string Status { get; init; } = "";
public string Reference { get; init; } = "";
}Ejemplo: ASP.NET Core (Controllers)
Configuracion en Program.cs
using Taypi.Net;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSingleton(new TaypiClient(
publicKey: builder.Configuration["Taypi:PublicKey"]!,
secretKey: builder.Configuration["Taypi:SecretKey"]!,
options: new TaypiOptions
{
Sandbox = builder.Configuration.GetValue<bool>("Taypi:Sandbox"),
}
));
var app = builder.Build();
app.MapControllers();
app.Run();Configuracion en appsettings.json
{
"Taypi": {
"PublicKey": "taypi_pk_test_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"SecretKey": "taypi_sk_test_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"Sandbox": true
}
}Controller
using Microsoft.AspNetCore.Mvc;
using Taypi.Net;
[ApiController]
[Route("api")]
public class PaymentController : ControllerBase
{
private readonly TaypiClient _taypi;
public PaymentController(TaypiClient taypi)
{
_taypi = taypi;
}
[HttpPost("crear-pago")]
public async Task<IActionResult> CreateCheckout()
{
try
{
var session = await _taypi.CreateCheckoutSessionAsync(new CreateCheckoutRequest
{
Amount = "50.00",
Currency = "PEN",
Reference = $"ORD-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}",
Description = "Compra en Mi Tienda",
});
return Ok(new { checkout_token = session.CheckoutToken });
}
catch (TaypiException ex)
{
return StatusCode(ex.HttpStatus, new { error = ex.Message });
}
}
[HttpPost("webhooks/taypi")]
public async Task<IActionResult> Webhook()
{
using var reader = new StreamReader(Request.Body);
var rawBody = await reader.ReadToEndAsync();
var signature = Request.Headers["Taypi-Signature"].FirstOrDefault() ?? "";
if (!_taypi.VerifyWebhook(rawBody, signature))
{
return Unauthorized("Firma invalida");
}
var webhookEvent = System.Text.Json.JsonSerializer.Deserialize<WebhookPayload>(rawBody);
if (webhookEvent?.Event == "payment.completed")
{
// Actualizar orden en tu base de datos
}
return Ok("OK");
}
}
public record WebhookPayload
{
public string Event { get; init; } = "";
public string PaymentId { get; init; } = "";
public string Amount { get; init; } = "";
public string Status { get; init; } = "";
public string Reference { get; init; } = "";
}Manejo de errores
El SDK lanza TaypiException en caso de errores:
using Taypi.Net;
using Taypi.Net.Exceptions;
try
{
var payment = await client.CreatePaymentAsync(new CreatePaymentRequest
{
Amount = "50.00",
Currency = "PEN",
Reference = "ORD-12345",
});
}
catch (TaypiException ex)
{
Console.WriteLine(ex.Message); // "El monto debe ser mayor a S/ 1.00"
Console.WriteLine(ex.Code); // "PAYMENT_INVALID_AMOUNT"
Console.WriteLine(ex.HttpStatus); // 422
}Tipos de error
| Codigo | HTTP | Descripcion |
|---|---|---|
AUTH_KEY_INVALID | 401 | API key invalida o revocada |
AUTH_SIGNATURE_INVALID | 403 | Firma HMAC incorrecta |
RATE_LIMIT_EXCEEDED | 429 | Excediste el limite de 60 req/min |
PAYMENT_NOT_FOUND | 404 | El pago no existe |
PAYMENT_INVALID_AMOUNT | 422 | Monto fuera de rango |
VALIDATION_ERROR | 422 | Datos de entrada invalidos |
SERVICE_UNAVAILABLE | 503 | Servicio temporalmente no disponible |
Ver la lista completa en la referencia de errores.