GatekeeperX.Events.Sdk 1.0.5

dotnet add package GatekeeperX.Events.Sdk --version 1.0.5
                    
NuGet\Install-Package GatekeeperX.Events.Sdk -Version 1.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GatekeeperX.Events.Sdk" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GatekeeperX.Events.Sdk" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="GatekeeperX.Events.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GatekeeperX.Events.Sdk --version 1.0.5
                    
#r "nuget: GatekeeperX.Events.Sdk, 1.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GatekeeperX.Events.Sdk@1.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GatekeeperX.Events.Sdk&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=GatekeeperX.Events.Sdk&version=1.0.5
                    
Install as a Cake Tool

GatekeeperX.Events.Sdk

SDK oficial de .NET para integración con GatekeeperX Events API - Plataforma de detección de fraude y evaluación de riesgo en tiempo real.

NuGet .NET

Características

  • 🔒 Detección de Fraude - Evaluación de riesgo en tiempo real
  • 🏗️ Patrón Builder - API fluida para construir requests
  • 🔄 Reintentos Automáticos - Políticas de reintento con backoff exponencial
  • 📊 Scoring de Riesgo - Scores detallados y reglas coincidentes
  • 🌐 Multi-Ambiente - Soporte para Sandbox y Producción

Instalación

dotnet add package GatekeeperX.Events.Sdk

O via Package Manager Console:

Install-Package GatekeeperX.Events.Sdk

Inicio Rápido

using GatekeeperX.Events.Sdk;
using GatekeeperX.Events.Sdk.Models.Request;

// Crear cliente
using var client = EventsApiClient.Builder()
    .Sandbox()
    .WithOrganizationId("tu-organization-id")
    .WithApiKey("tu-api-key")
    .Build();

// Crear request
var request = EventRequest.Builder()
    .WithEventType("create_cashout")
    .WithTimestamp(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
    .WithCustomer(Customer.Builder()
        .WithCustomerId("cust_001")
        .WithEmail("usuario@ejemplo.com")
        .Build())
    .WithMovement(Movement.Builder()
        .WithMovementId("mov_001")
        .WithAmount(Money.Builder()
            .WithAmount(50000m)
            .WithAmountInMinorUnits(5000000)
            .WithCurrencyCode("COP")
            .Build())
        .Build())
    .Build();

// Enviar evento
var response = await client.ProcessEventAsync(request);

if (response.Decision == "allow")
{
    // Transacción permitida
}
else if (response.Decision == "block")
{
    // Transacción bloqueada
}

Configuración del Cliente

Básica

using var client = EventsApiClient.Builder()
    .Sandbox()  // o .Production()
    .WithOrganizationId("tu-organization-id")
    .WithApiKey("tu-api-key")
    .Build();

Avanzada

using var client = EventsApiClient.Builder()
    .Production()
    .WithOrganizationId("tu-organization-id")
    .WithApiKey("tu-api-key")
    .WithTimeout(TimeSpan.FromSeconds(30))
    .WithMaxRetries(3)
    .WithRetryBackoff(TimeSpan.FromMilliseconds(500))
    .WithRetryMultiplier(2.0)
    .WithMaxBackoff(TimeSpan.FromSeconds(10))
    .WithLogger(logger)
    .Build();

Opciones de Configuración

Método Descripción Default
.Sandbox() Usar ambiente sandbox -
.Production() Usar ambiente producción -
.WithOrganizationId(string) ID de organización Requerido
.WithApiKey(string) API Key Requerido
.WithTimeout(TimeSpan) Timeout del request 30 segundos
.WithMaxRetries(int) Máximo de reintentos 3
.WithRetryBackoff(TimeSpan) Delay inicial de reintento 500ms
.WithRetryMultiplier(double) Multiplicador de backoff 2.0
.WithMaxBackoff(TimeSpan) Máximo delay de backoff 10 segundos
.WithHttpClient(HttpClient) HttpClient personalizado Auto-creado
.WithLogger(ILogger) Logger personalizado Ninguno

Métodos Disponibles

ProcessEventAsync (Asíncrono - Recomendado)

var response = await client.ProcessEventAsync(
    request, 
    returnScore: true,
    cancellationToken: default
);

ProcessEvent (Síncrono)

var response = client.ProcessEvent(request, returnScore: true);
Parámetro Descripción
request Objeto EventRequest con los datos del evento
returnScore true para esperar evaluación completa, false para respuesta inmediata

Ejemplo Completo: create_cashout

var request = EventRequest.Builder()
    .WithEventType("create_cashout")
    .WithTimestamp(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
    
    // ═══════════════════════════════════════════════════════════════
    // MOVEMENT
    // ═══════════════════════════════════════════════════════════════
    .WithMovement(Movement.Builder()
        .WithMovementId("7e43e0ce-69ab-406d-baa4-8ce0c31df36d")
        .WithCustomerId("cust_001")
        .WithExternalId("1955346017")
        .WithType("4")
        .WithStatus("pending")
        .WithCreatedAt(DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"))
        .WithProcessedBy("system")
        .WithChannel("mobile")
        .WithAmount(Money.Builder()
            .WithCurrencyCode("COP")
            .WithAmount(25000m)
            .WithAmountInMinorUnits(2500000)
            .Build())
        
        // Origin
        .WithOrigin(MovementOrigin.Builder()
            .WithPaymentMethod(MovementPaymentMethod.Builder()
                .WithType("bankAccount")
                .WithPaymentMethodId("pm_origin_001")
                .WithAccountNumber("100000056298")
                .WithStatus("active")
                .WithAlias("Mi cuenta principal")
                .WithCustomFields(new Dictionary<string, object>
                {
                    { "thirdPartyId", 11 }
                })
                .Build())
            .WithCustomFields(new Dictionary<string, object>
            {
                { "accountBalanceHistoricId", "uuid-balance" },
                { "finalValue", 4000 }
            })
            .Build())
        
        // Destination
        .WithDestination(MovementDestination.Builder()
            .WithPaymentMethod(MovementPaymentMethod.Builder()
                .WithType("bankAccount")
                .WithPaymentMethodId("pm_dest_001")
                .WithAccountNumber("200000012345")
                .WithBankId("001")
                .WithBankCode("BANCOLOMBIA")
                .WithCustomFields(new Dictionary<string, object>
                {
                    { "externalAccountId", "ext-acc-uuid" },
                    { "achAccountId", "ach-uuid" }
                })
                .Build())
            .Build())
        .Build())
    
    // ═══════════════════════════════════════════════════════════════
    // CUSTOMER
    // ═══════════════════════════════════════════════════════════════
    .WithCustomer(Customer.Builder()
        .WithCustomerId("cust_001")
        .WithPhoneNumber("+573001234567")
        .WithEmail("usuario@ejemplo.com")
        .WithEmailVerifiedAt(true)
        .WithFirstName("Juan")
        .WithLastName("Pérez")
        .WithBirthDate("1990-05-18")
        .WithGender("1")
        .WithIsPep(false)
        .WithThirdPartyId("0")
        .WithTags(new List<string> { "verified", "premium" })
        .WithCreatedAt("2024-01-01T00:00:00Z")
        .WithUpdatedAt("2024-06-01T00:00:00Z")
        
        // Address
        .WithAddress(Location.Builder()
            .WithCountry("CO")
            .WithCity("Bogotá")
            .WithRegion("DC")
            .WithStreet1("Calle 100 #15-20")
            .Build())
        
        // Identification Document
        .WithIdentificationDocument(IdentificationDocument.Builder()
            .WithType("CC")
            .WithNumber("12345678")
            .WithExpeditionDate("2020-01-01")
            .WithExpirationDate("2030-01-01")
            .Build())
        
        // External Risk
        .WithExternalRisk(new List<ExternalRisk>
        {
            ExternalRisk.Builder()
                .WithSegment(1)
                .WithScore(85)
                .WithScoreProvider("COINK_INTERNAL")
                .Build()
        })
        
        // Custom Fields
        .WithCustomFields(new Dictionary<string, object>
        {
            { "fullName", "Juan Pérez García" },
            { "fixPhoneNumber", "+5714567890" }
        })
        .Build())
    
    // ═══════════════════════════════════════════════════════════════
    // PAYMENT METHOD (root level)
    // ═══════════════════════════════════════════════════════════════
    .WithPaymentMethod(PaymentMethod.Builder()
        .WithType("bankAccount")
        .WithPaymentMethodId("pm_origin_001")
        .WithAccountNumber("100000056298")
        .WithBankCode("BANCOLOMBIA")
        .Build())
    
    .Build();

// Enviar y procesar respuesta
var response = await client.ProcessEventAsync(request, returnScore: true);

Respuesta

Estructura de EventResponse

public class EventResponse
{
    public string? RequestId { get; set; }      // ID único de la petición
    public string? Decision { get; set; }       // "allow", "block", "review"
    public string? Source { get; set; }         // Tipo de evento evaluado
    public List<string>? Rules { get; set; }    // Reglas que coincidieron
    public Evaluation? Evaluation { get; set; } // Detalles de la evaluación
}

public class Evaluation
{
    public double? Score { get; set; }                    // Score de riesgo (0-100)
    public List<MatchedRule>? MatchedRules { get; set; }  // Reglas que coincidieron
    public List<string>? Rules { get; set; }              // Lista de reglas
}

public class MatchedRule
{
    public string? Rule { get; set; }        // Nombre de la regla
    public string? Description { get; set; } // Descripción
}

Uso de la Respuesta

var response = await client.ProcessEventAsync(request, returnScore: true);

// Información básica
Console.WriteLine($"RequestId: {response.RequestId}");
Console.WriteLine($"Decision: {response.Decision}");
Console.WriteLine($"Score: {response.Evaluation?.Score}");

// Evaluar decisión
switch (response.Decision?.ToLower())
{
    case "allow":
        // ✅ Aprobar transacción
        break;
    case "block":
        // ❌ Rechazar transacción
        break;
    case "review":
        // ⚠️ Enviar a revisión manual
        break;
}

// Obtener reglas que coincidieron
if (response.Evaluation?.MatchedRules?.Any() == true)
{
    foreach (var rule in response.Evaluation.MatchedRules)
    {
        Console.WriteLine($"Regla: {rule.Rule} - {rule.Description}");
    }
}

Manejo de Errores

using GatekeeperX.Events.Sdk.Exceptions;

try
{
    var response = await client.ProcessEventAsync(request);
}
catch (ValidationException ex)
{
    // HTTP 400/422 - Datos inválidos
    Console.WriteLine($"Error de validación: {ex.Message}");
    Console.WriteLine($"Código: {ex.ErrorCode}");
}
catch (AuthenticationException ex)
{
    // HTTP 401 - API Key inválida
    Console.WriteLine($"Error de autenticación: {ex.Message}");
}
catch (AuthorizationException ex)
{
    // HTTP 403 - Sin permisos
    Console.WriteLine($"Sin autorización: {ex.Message}");
}
catch (NotFoundException ex)
{
    // HTTP 404 - Recurso no encontrado
    Console.WriteLine($"No encontrado: {ex.Message}");
}
catch (RateLimitException ex)
{
    // HTTP 429 - Rate limit excedido
    Console.WriteLine($"Rate limit excedido. Reintentar en: {ex.RetryAfter}s");
}
catch (ServerException ex)
{
    // HTTP 5xx - Error del servidor
    Console.WriteLine($"Error del servidor [{ex.StatusCode}]: {ex.Message}");
    Console.WriteLine($"RequestId: {ex.RequestId}");
}
catch (GatekeeperXTimeoutException ex)
{
    // Timeout de la petición
    Console.WriteLine($"Timeout: {ex.Message}");
}
catch (NetworkException ex)
{
    // Error de conectividad
    Console.WriteLine($"Error de red: {ex.Message}");
}
catch (GatekeeperXException ex)
{
    // Excepción base para cualquier error del SDK
    Console.WriteLine($"Error: {ex.Message}");
    Console.WriteLine($"Código: {ex.ErrorCode}");
    Console.WriteLine($"RequestId: {ex.RequestId}");
}

Inyección de Dependencias

Registro del Cliente

// En Program.cs o Startup.cs
services.AddSingleton<EventsApiClient>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    var logger = sp.GetService<ILogger<EventsApiClient>>();
    
    var environment = config["GatekeeperX:Environment"] ?? "sandbox";
    
    var builder = environment.ToLower() == "production"
        ? EventsApiClient.Builder().Production()
        : EventsApiClient.Builder().Sandbox();
    
    return builder
        .WithOrganizationId(config["GatekeeperX:OrganizationId"]!)
        .WithApiKey(config["GatekeeperX:ApiKey"]!)
        .WithTimeout(TimeSpan.FromSeconds(
            config.GetValue<int>("GatekeeperX:TimeoutSeconds", 10)))
        .WithMaxRetries(config.GetValue<int>("GatekeeperX:MaxRetries", 2))
        .WithLogger(logger!)
        .Build();
});

Configuración en appsettings.json

{
    "GatekeeperX": {
        "Environment": "sandbox",
        "OrganizationId": "tu-organization-id",
        "ApiKey": "tu-api-key",
        "TimeoutSeconds": 10,
        "MaxRetries": 2
    }
}

Ejemplo de Servicio de Fraude

public interface IFraudService
{
    Task<FraudResult> EvaluateAsync(Guid transferId);
}

public class FraudResult
{
    public bool IsApproved { get; set; }
    public string? RequestId { get; set; }
    public decimal? RiskScore { get; set; }
    public string? Decision { get; set; }
    public string? Reason { get; set; }
    
    public static FraudResult Approved(string? requestId = null) => new()
    {
        IsApproved = true,
        RequestId = requestId,
        Decision = "allow"
    };
    
    public static FraudResult Rejected(string reason, string? requestId = null, decimal? score = null) => new()
    {
        IsApproved = false,
        RequestId = requestId,
        RiskScore = score,
        Decision = "block",
        Reason = reason
    };
}

public class FraudService : IFraudService
{
    private readonly EventsApiClient _client;
    private readonly IFraudTransactionRepository _repository;
    private readonly ILogger<FraudService> _logger;

    public FraudService(
        EventsApiClient client,
        IFraudTransactionRepository repository,
        ILogger<FraudService> logger)
    {
        _client = client;
        _repository = repository;
        _logger = logger;
    }

    public async Task<FraudResult> EvaluateAsync(Guid transferId)
    {
        try
        {
            // 1. Obtener datos de la transacción
            var data = await _repository.GetTransactionDataAsync(transferId);
            
            if (data == null)
            {
                _logger.LogWarning("No se encontraron datos para transferId: {TransferId}", transferId);
                return FraudResult.Approved(); // Fail-open
            }
            
            // 2. Construir request
            var request = BuildEventRequest(data);
            
            // 3. Enviar a GatekeeperX
            var response = await _client.ProcessEventAsync(request, returnScore: true);
            
            _logger.LogInformation(
                "Fraude evaluado - TransferId: {TransferId}, Decision: {Decision}, Score: {Score}, RequestId: {RequestId}",
                transferId, response.Decision, response.Evaluation?.Score, response.RequestId);
            
            // 4. Interpretar respuesta
            return InterpretResponse(response);
        }
        catch (GatekeeperXException ex)
        {
            _logger.LogError(ex, 
                "Error evaluando fraude para TransferId: {TransferId}", transferId);
            
            // Fail-open: permitir si hay error
            return FraudResult.Approved();
        }
    }

    private EventRequest BuildEventRequest(FraudTransactionDataDto data)
    {
        return EventRequest.Builder()
            .WithEventType("create_cashout")
            .WithTimestamp(data.CreationDate.ToUnixTimeMilliseconds())
            .WithMovement(BuildMovement(data))
            .WithCustomer(BuildCustomer(data))
            .WithPaymentMethod(BuildRootPaymentMethod(data))
            .Build();
    }

    private Movement BuildMovement(FraudTransactionDataDto data)
    {
        return Movement.Builder()
            .WithMovementId(data.TransferId.ToString())
            .WithCustomerId(data.UserId.ToString())
            .WithExternalId(data.CustomId ?? "")
            .WithType(data.OperationId?.ToString() ?? "")
            .WithStatus(data.StatusId?.ToString() ?? "")
            .WithCreatedAt(data.CreationDate.ToString("yyyy-MM-ddTHH:mm:ssZ"))
            .WithChannel(data.Channel ?? "mobile")
            .WithAmount(Money.Builder()
                .WithCurrencyCode("COP")
                .WithAmount(data.Amount ?? 0m)
                .WithAmountInMinorUnits((long)((data.Amount ?? 0m) * 100))
                .Build())
            .WithOrigin(BuildOrigin(data))
            .WithDestination(BuildDestination(data))
            .Build();
    }

    private MovementOrigin BuildOrigin(FraudTransactionDataDto data)
    {
        return MovementOrigin.Builder()
            .WithPaymentMethod(MovementPaymentMethod.Builder()
                .WithType(data.OriginAccountType ?? "bankAccount")
                .WithPaymentMethodId(data.OriginUserId?.ToString() ?? "")
                .WithAccountNumber(data.OriginAccountNumber ?? "")
                .WithStatus(data.OriginAccountStatus?.ToString() ?? "")
                .WithAlias(data.OriginAlias ?? "")
                .WithCustomFields(new Dictionary<string, object>
                {
                    { "thirdPartyId", data.OriginThirdPartyId ?? 0 }
                })
                .Build())
            .WithCustomFields(new Dictionary<string, object>
            {
                { "accountBalanceHistoricId", data.OriginAccountBalanceHistoricId?.ToString() ?? "" },
                { "finalValue", data.OriginFinalValue ?? 0 }
            })
            .Build();
    }

    private MovementDestination BuildDestination(FraudTransactionDataDto data)
    {
        var pmBuilder = MovementPaymentMethod.Builder()
            .WithType(data.DestinationAccountType ?? "bankAccount")
            .WithPaymentMethodId(data.DestinationUserId?.ToString() ?? "")
            .WithAccountNumber(data.DestinationAccountNumber ?? "");

        if (data.IsExternal == true)
        {
            pmBuilder
                .WithBankId(data.DestinationBankId?.ToString() ?? "")
                .WithBankCode(data.DestinationBankName ?? "")
                .WithCustomFields(new Dictionary<string, object>
                {
                    { "externalAccountId", data.DestinationExternalAccountId?.ToString() ?? "" },
                    { "achAccountId", data.AssociatedDataAchAccountId?.ToString() ?? "" },
                    { "canceledAt", data.DestinationCancelDate?.ToString("o") ?? "" }
                });
        }
        else
        {
            pmBuilder
                .WithBankCode("COINK")
                .WithCustomFields(new Dictionary<string, object>
                {
                    { "isInternal", true }
                });
        }

        return MovementDestination.Builder()
            .WithPaymentMethod(pmBuilder.Build())
            .Build();
    }

    private Customer BuildCustomer(FraudTransactionDataDto data)
    {
        var builder = Customer.Builder()
            .WithCustomerId(data.UserId.ToString())
            .WithPhoneNumber(data.UserPhoneNumber ?? "")
            .WithEmail(data.UserEmail ?? "")
            .WithFirstName(data.UserNames ?? "")
            .WithLastName(data.UserLastNames ?? "")
            .WithThirdPartyId(data.UserThirdPartyId?.ToString() ?? "0")
            .WithCreatedAt(data.UserCreatedDate?.ToString("yyyy-MM-ddTHH:mm:ssZ") ?? "")
            .WithUpdatedAt(data.UserUpdatedDate?.ToString("yyyy-MM-ddTHH:mm:ssZ") ?? "");

        if (data.UserBirthDate.HasValue)
            builder.WithBirthDate(data.UserBirthDate.Value.ToString("yyyy-MM-dd"));

        if (data.UserGenderId.HasValue)
            builder.WithGender(data.UserGenderId.Value.ToString());

        if (data.UserIsPep.HasValue)
            builder.WithIsPep(data.UserIsPep.Value);

        // Address
        if (data.UserCityId.HasValue || data.UserStateId.HasValue)
        {
            builder.WithAddress(Location.Builder()
                .WithCountry("CO")
                .WithCity(data.UserCityId?.ToString() ?? "")
                .WithRegion(data.UserStateId?.ToString() ?? "")
                .WithStreet1(data.UserAddress ?? "")
                .Build());
        }

        // Identification Document
        if (!string.IsNullOrEmpty(data.UserDocumentNumber))
        {
            builder.WithIdentificationDocument(IdentificationDocument.Builder()
                .WithType(data.UserDocumentTypeId?.ToString() ?? "")
                .WithNumber(data.UserDocumentNumber)
                .WithExpeditionDate(data.UserDocumentExpeditionDate?.ToString("yyyy-MM-dd") ?? "")
                .Build());
        }

        // External Risk
        if (data.Segment.HasValue)
        {
            builder.WithExternalRisk(new List<ExternalRisk>
            {
                ExternalRisk.Builder()
                    .WithSegment(data.Segment.Value)
                    .WithScoreProvider("COINK_INTERNAL")
                    .Build()
            });
        }

        // Custom Fields
        builder.WithCustomFields(new Dictionary<string, object>
        {
            { "fullName", data.UserRegisterName ?? "" },
            { "fixPhoneNumber", data.UserFixPhoneNumber ?? "" }
        });

        return builder.Build();
    }

    private PaymentMethod BuildRootPaymentMethod(FraudTransactionDataDto data)
    {
        return PaymentMethod.Builder()
            .WithType(data.OriginAccountType ?? "bankAccount")
            .WithPaymentMethodId(data.OriginUserId?.ToString() ?? "")
            .WithAccountNumber(data.OriginAccountNumber ?? "")
            .WithBankCode(data.IsExternal == true ? data.DestinationBankName ?? "" : "COINK")
            .Build();
    }

    private FraudResult InterpretResponse(EventResponse response)
    {
        var decision = response.Decision?.ToUpperInvariant() ?? "";
        var isApproved = decision is "ALLOW" or "APPROVE" or "ACCEPT";

        if (isApproved)
        {
            return new FraudResult
            {
                IsApproved = true,
                RequestId = response.RequestId,
                RiskScore = (decimal?)(response.Evaluation?.Score),
                Decision = response.Decision
            };
        }

        var reason = response.Evaluation?.MatchedRules?.FirstOrDefault()?.Rule 
            ?? response.Decision 
            ?? "FRAUD_REJECTED";

        return new FraudResult
        {
            IsApproved = false,
            RequestId = response.RequestId,
            RiskScore = (decimal?)(response.Evaluation?.Score),
            Decision = response.Decision,
            Reason = reason
        };
    }
}

Registro del Servicio de Fraude

// En Program.cs o Startup.cs
services.AddSingleton<EventsApiClient>(/* ... */);
services.AddScoped<IFraudTransactionRepository, FraudTransactionRepository>();
services.AddScoped<IFraudService, FraudService>();

Modelos Disponibles

Request Models

Modelo Descripción
EventRequest Request principal del evento
Movement Movimiento (cashout, cashin, transfers)
MovementOrigin Origen del movimiento
MovementDestination Destino del movimiento
MovementPaymentMethod Método de pago en movimiento
Customer Información del cliente
IdentificationDocument Documento de identidad
ExternalRisk Evaluación de riesgo externo
PaymentMethod Método de pago (nivel raíz)
Money Montos monetarios
Location Direcciones
Device Información del dispositivo
Transaction Transacciones de compra/venta
Merchant Información del comercio
Order Información de la orden
PointOfSale Terminal POS

Response Models

Modelo Descripción
EventResponse Respuesta del evento
Evaluation Detalles de la evaluación
MatchedRule Regla que coincidió

Exceptions

Excepción HTTP Code Descripción
ValidationException 400/422 Datos inválidos
AuthenticationException 401 API Key inválida
AuthorizationException 403 Sin permisos
NotFoundException 404 Recurso no encontrado
RateLimitException 429 Rate limit excedido
ServerException 5xx Error del servidor
GatekeeperXTimeoutException - Timeout
NetworkException - Error de red
GatekeeperXException - Base exception

Buenas Prácticas

  1. Reutilizar el Cliente - Crea una única instancia y reutilízala (es thread-safe)
  2. Usar Métodos Async - Prefiere ProcessEventAsync sobre ProcessEvent
  3. Configurar Timeouts - Ajusta según tus SLAs (recomendado: 5-10 segundos)
  4. Manejar Todas las Excepciones - Implementa manejo para todos los tipos
  5. Loguear RequestIds - Guarda los RequestIds para troubleshooting
  6. Fail-Open vs Fail-Close - Decide qué hacer cuando el servicio no responde:
    • Fail-Open: Permitir transacción si hay error (mejor UX, más riesgo)
    • Fail-Close: Rechazar transacción si hay error (más seguro, peor UX)

Requisitos

  • .NET 6.0, 7.0 o 8.0
  • Microsoft.Extensions.Logging.Abstractions (incluido)

Soporte

Para soporte técnico:

Licencia

MIT License - Ver LICENSE para más detalles.


Desarrollado por GatekeeperX

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 129 4/14/2026
1.0.4 104 4/14/2026
1.0.3 111 4/13/2026
1.0.2 116 3/3/2026
1.0.1 113 2/27/2026
1.0.0 111 2/27/2026