PaycodeConnect 1.2.4
dotnet add package PaycodeConnect --version 1.2.4
NuGet\Install-Package PaycodeConnect -Version 1.2.4
<PackageReference Include="PaycodeConnect" Version="1.2.4" />
<PackageVersion Include="PaycodeConnect" Version="1.2.4" />
<PackageReference Include="PaycodeConnect" />
paket add PaycodeConnect --version 1.2.4
#r "nuget: PaycodeConnect, 1.2.4"
#:package PaycodeConnect@1.2.4
#addin nuget:?package=PaycodeConnect&version=1.2.4
#tool nuget:?package=PaycodeConnect&version=1.2.4
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
SynchronizationContextcaptured duringSetup(), 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:
- With messages — after calling
RequestLostMessages(), it delivers an array ofEMVDatathat were not confirmed. - 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");
Print Transaction
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 | Versions 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. |
-
net6.0
- QRCoder (>= 1.6.0)
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 |