PaycodeConnect 1.2.4

dotnet add package PaycodeConnect --version 1.2.4
                    
NuGet\Install-Package PaycodeConnect -Version 1.2.4
                    
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="PaycodeConnect" Version="1.2.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PaycodeConnect" Version="1.2.4" />
                    
Directory.Packages.props
<PackageReference Include="PaycodeConnect" />
                    
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 PaycodeConnect --version 1.2.4
                    
#r "nuget: PaycodeConnect, 1.2.4"
                    
#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 PaycodeConnect@1.2.4
                    
#: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=PaycodeConnect&version=1.2.4
                    
Install as a Cake Addin
#tool nuget:?package=PaycodeConnect&version=1.2.4
                    
Install as a Cake Tool

PayCode Connect .NET SDK

📦 Connect your .NET application to a PayCode PoS terminal over a peer-to-peer network.

Installation

dotnet add package PaycodeConnect

Setup

Initialize the SDK by calling Setup(), which creates a local node on the current machine. This should be called once during your app's initialization.

using PaycodeConnectSDK;

PaycodeConnect node = new PaycodeConnect();
node.Setup();

// With a completion callback
node.Setup((resultCode) =>
{
    // ResultCode.Success on success
});

Connecting

To pair with a PoS terminal, generate a connection ticket and display it as a QR code. The SDK includes a built-in QR code generator that returns a base64-encoded PNG:

string ticket = node.GenerateTicket();
string qrBase64 = node.GenerateQRCodeBase64(ticket);

Display the QR using your UI framework of choice:

// WinUI / UWP example
qrImage.Source = Base64ToImage(qrBase64);

BitmapImage Base64ToImage(string base64)
{
    byte[] bytes = Convert.FromBase64String(base64);
    using MemoryStream ms = new MemoryStream(bytes);
    BitmapImage img = new BitmapImage();
    img.SetSource(ms.AsRandomAccessStream());
    return img;
}

Once the QR code is scanned by a PayCode PoS terminal, the connection is established.

Reconnecting

The SDK automatically persists the last connected ticket. You can reconnect to the last known terminal without scanning a QR again:

node.ReconnectToLastNode((resultCode) =>
{
    // ResultCode.Success on success
});

Receiving Events

PayCodeConnect exposes C# events for connection state, presence, EMV transaction lifecycle, and barcode scanning.

Note: All events are posted back to the SynchronizationContext captured during Setup(), so they are safe to use for UI updates in frameworks like WPF, WinUI, and MAUI.

Connected

Fires when the connection state with a PoS terminal changes.

node.ConnectionChange += (sender, e) =>
{
    bool isConnected = e.Connected;
};

EMV State

Fires throughout the EMV transaction lifecycle after calling StartEMV(). The callback receives an EMVData object whose fields are populated depending on the current state:

State Fields Description
NotStarted State EMV process has not started
AwaitingCard State Terminal is waiting for a card
Processing State Transaction is being processed
Error State, Message, Code Transaction failed
Success State, Transaction Transaction completed successfully
Reversal State, Message, Code Reversal result — Code is 0 for success, 1 for error

If metadata was provided in the StartEMV call, it will be present in the Metadata field of every EMVData event for that transaction.

node.EMVStateChange += (sender, e) =>
{
    EMVData data = e.Data;

    // Access metadata echoed back from StartEMV
    var meta = data.GetMetadata<OrderMetadata>();
    if (meta != null)
    {
        string orderId = meta.OrderId;
        int table = meta.Table;
    }

    switch (data.State)
    {
        case EMVState.AwaitingCard:
            statusText.Text = "Present card on terminal...";
            break;
        case EMVState.Processing:
            statusText.Text = "Processing...";
            break;
        case EMVState.Success:
            statusText.Text = $"Approved! Auth: {data.Transaction?.Authorization}";
            break;
        case EMVState.Error:
            statusText.Text = $"Error {data.Code}: {data.Message}";
            break;
        case EMVState.Reversal:
            statusText.Text = data.Code == 0 ? "Reversal successful" : "Reversal failed";
            break;
    }
};

Presence

Fires with false when messages are no longer reaching the connected PoS terminal, even if the connection hasn't been fully lost. Fires with true once the terminal becomes responsive again. This corresponds to the yellow warning icon shown on the PoS device.

node.PresenceChange += (sender, e) =>
{
    bool hasPresence = e.Presence;
};

Scanner

You can use a connected PoS terminal as a barcode scanner. To enable this, first set the ScannerPrefixes capability (see Set Capabilities). Once configured, this event fires whenever the terminal scans a matching barcode.

node.TerminalScanner += (sender, e) =>
{
    string barcode = e.Content;
};

Lost Messages

When using the lost messages system, this event fires in two scenarios:

  1. With messages — after calling RequestLostMessages(), it delivers an array of EMVData that were not confirmed.
  2. With a flag — after calling RequestHasLostMessages(), it delivers a boolean indicating whether lost messages exist.
node.LostMessagesEvent += (sender, e) =>
{
    if (e.Messages != null)
    {
        foreach (EMVData msg in e.Messages)
        {
            // Process each lost message
        }
    }

    if (e.HasLostMessages.HasValue)
    {
        bool hasLost = e.HasLostMessages.Value;
    }
};

Commands

Once connected, you can remotely control the PoS terminal through the following commands:

Command Description
StartEMV(amount, emvType?, metadata?) Start a transaction
ReverseTransaction(folio) Reverse a previous transaction
PrintTransaction(folio) Reprint a transaction receipt
SetCapabilities(capabilities) Configure terminal capabilities
Authorize(email, password) Authenticate with the terminal
SetPin(payload) Set a PIN on the terminal
AuthorizePin(pin) Authenticate using a PIN
Logout() Log out of the terminal
RequestLostMessages() Request unconfirmed messages
RequestHasLostMessages() Check if lost messages exist
ClearLostMessages() Clear all lost messages
Shutdown(restart?) Disconnect and shut down the node

All commands return a ResultCode and accept an optional CompletionCallback for the inner async operation.

Start EMV

Starts an EMV transaction on the connected PoS terminal. The amount is a string in MXN. The optional emvType parameter defaults to EMVType.Combined and can be set to Emv (Visa/Mastercard), Amex, or Combined (auto-detect). Subscribe to the EMVStateChange event to track the transaction lifecycle.

The optional metadata parameter accepts any serializable object that will be echoed back in every EMVData event for this transaction. This is useful for associating application-specific context (e.g., order IDs, table numbers) with a transaction without managing external state.

A convenience overload StartEMV(amount, emvType, callback) is available so you can pass a callback without specifying metadata.

node.StartEMV("150.00");

// Or specify the EMV type
node.StartEMV("150.00", EMVType.Amex);

// With a callback (no need to pass null for metadata)
node.StartEMV("150.00", EMVType.Combined, (code) =>
{
    // ResultCode.Success on success
});

// With metadata
node.StartEMV("150.00", EMVType.Combined, new { orderId = "abc-123", table = 5 });

// With metadata and a callback
node.StartEMV("150.00", EMVType.Combined, new { orderId = "abc-123", table = 5 }, (code) =>
{
    // ResultCode.Success on success
});

Reverse Transaction

Reverses a previously completed transaction by its folio number. Listen to the EMVStateChange event for the reversal result.

node.ReverseTransaction("123456789");

Reprints the receipt for a previously completed transaction by its folio number.

node.PrintTransaction("123456789");

Set Capabilities

Configures the terminal's capabilities. Available options:

Option Type Description
ScannerPrefixes string[]? Barcode prefixes that enable the scanner event
PingInternetConnectivity bool? Enable internet connectivity checks
ForceRemoteControl bool? Force the terminal into remote control mode
DisableManualPayments bool? Disable manual payment entry on the terminal
LostMessagesSyncMode string? "Auto" or "Manual" — controls lost message sync behavior
node.SetCapabilities(new Capabilities
{
    ScannerPrefixes = new[] { "PREFIX1", "PREFIX2" },
    ForceRemoteControl = true,
});

Authorize

Authenticates with the connected PoS terminal using email and password. If the terminal is already logged in, this command is ignored.

node.Authorize("user@example.com", "password");

Set PIN

Sets a PIN on the terminal for PIN-based authentication. Requires the account password for verification.

node.SetPin(new PinPayload { Pin = "1234", Password = "password" });

Authorize PIN

Authenticates with the terminal using a previously configured PIN.

node.AuthorizePin("1234");

Logout

Logs out of the connected PoS terminal.

node.Logout();

Lost Messages

The lost messages system lets you recover EMV transaction messages that were not confirmed (e.g., due to a disconnection during a transaction).

// Check if there are lost messages
node.RequestHasLostMessages();

// Retrieve all lost messages
node.RequestLostMessages();

// Clear all lost messages
node.ClearLostMessages();

Results are delivered through the LostMessagesEvent (see Lost Messages event).

Shutdown

Disconnects and shuts down the current node. Set restart to true to automatically call Setup() again after shutdown.

// Shutdown permanently
node.Shutdown();

// Shutdown and restart
node.Shutdown(true);

Properties

Property Type Description
Connected bool Whether a remote node is currently connected
NodeSetup bool Whether the local node has been initialized via Setup()
Presence bool Whether the connected terminal is responsive

Types

EMVData

Data sent by the PoS terminal throughout the EMV process. Fields are populated depending on the current EMVState.

public struct EMVData
{
    public EMVState State { get; set; }
    public int? Code { get; set; }
    public string? Message { get; set; }
    public Transaction? Transaction { get; set; }
    public string? id { get; set; }
    public bool? lost { get; set; }
    public object? Metadata { get; set; }

    public T? GetMetadata<T>()
    {
        if (Metadata is JsonElement element)
            return element.Deserialize<T>();
        return default;
    }
}

The Metadata field contains the same data passed to StartEMV. Use the GetMetadata<T>() helper to deserialize it into your own type:

// Define a class matching the metadata you passed to StartEMV
public class OrderMetadata
{
    public string OrderId { get; set; }
    public int Table { get; set; }
}

// Deserialize in the event handler
var meta = emvData.GetMetadata<OrderMetadata>();

Transaction

Transaction details received when EMVState is Success.

public struct Transaction
{
    public string Authorization { get; set; }
    public string Reference { get; set; }
    public string Folio { get; set; }
    public string? Type { get; set; }
    public string? CardBrand { get; set; }
    public string? CardNumber { get; set; }
    public string? Issuer { get; set; }
    public string? Total { get; set; }
    public string? Subtotal { get; set; }
    public string? Tip { get; set; }
    public string? Arqc { get; set; }
    public string? Aid { get; set; }
    public string? Al { get; set; }
    public string? Tvr { get; set; }
    public string? Tsi { get; set; }
}

Capabilities

public struct Capabilities
{
    public string[]? ScannerPrefixes { get; set; }
    public bool? PingInternetConnectivity { get; set; }
    public bool? ForceRemoteControl { get; set; }
    public bool? DisableManualPayments { get; set; }
    public string? LostMessagesSyncMode { get; set; }
}

PinPayload

public struct PinPayload
{
    public string Pin { get; set; }
    public string Password { get; set; }
}

EMVState

public enum EMVState
{
    NotStarted,
    AwaitingCard,
    Processing,
    Success,
    Error,
    Reversal
}

EMVType

public enum EMVType
{
    Emv,      // Visa / Mastercard
    Amex,     // American Express
    Combined  // Auto-detect (default)
}

ResultCode

public enum ResultCode
{
    Success = 0,
    StateUnavailable = 1,
    NodeUnavailable = 2,
    RuntimeUnavailable = 3,
    SenderNotAvailable = 4,
    ConnectionTimeout = 5,
    EndpointOnlineTimeout = 6,
    Utf8Conversion = 7,
    IrohEndpointBind = 8,
    IrohJoin = 9,
    GossipApi = 10,
    GossipNet = 11,
    IrohKeyParse = 12,
    Decode = 13,
    Json = 14,
    Anyhow = 15,
    TryLock = 16,
    Nul = 17,
    SetLogger = 18,
    Panic = 999
}

LostMessagesSyncMode

public enum LostMessagesSyncMode
{
    Auto,
    Manual
}
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 was computed.  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 was computed.  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.2.4 96 5/12/2026
1.2.3 91 5/6/2026
1.2.2 212 11/24/2025
1.2.1 171 10/31/2025
1.2.0 210 10/27/2025
1.1.2 189 7/30/2025
1.1.1 203 7/14/2025
1.1.0 203 6/17/2025
1.0.5 231 3/31/2025
1.0.4 182 1/29/2025
1.0.3 234 1/10/2025
1.0.2 237 12/26/2024
1.0.1 236 12/24/2024
1.0.0 211 12/24/2024