EPAS Client Library
Last updated: 2026-05-19
Overview
The EPAS Client Library is the recommended integration layer for ECR applications that communicate directly with Westpay payment terminals. It hides the raw EPAS XML protocol, manages terminal connectivity, sequences messages, exposes callbacks for cashier interaction, and returns typed transaction responses.
Without the library, an ECR must build and parse EPAS XML messages, keep track of protocol state, handle terminal customisations, and maintain the socket connection. With the library, the same purchase can be expressed as a normal API call:
.NET
csharpApiResult result = epas.Purchase(59.00m, out TransactionResponse response);
Java
javaPair<ApiDefinitions.ApiResult, TransactionResponse> result = epas.purchase(new ApiDefinitions().new PurchaseTransactionAmounts(59.00));
Swift
swiftlet response = try await client.purchase(59.00)
Choose a Library
| Library | Package | Primary client | Notes |
|---|---|---|---|
| .NET | Westpay.Epas | EpasClient | .NET Framework 4.7.2 class library distributed as EpasClientLibrary.dll. |
| Java | se.westpay.epas | EpasClient | Java client library distributed as library-1.4.5.jar. |
| Swift | EpasClient | EpasClient | Swift Package Manager package for macOS and iPadOS. |
Integration Journey
Follow this flow for .NET, Java, and Swift integrations:
- Add the library to your ECR project.
- Implement the client application callback interface.
- Create one client instance for each terminal connection.
- Connect to the terminal.
- Log in with terminal environment details.
- Start a transaction.
- Handle callbacks, receipts, and the final transaction response.
- Handle disconnections and reconnect by connecting and logging in again.
Step 1 - Add the Library
Add the release artifact to your application and reference it from your ECR project.
Use the language tabs below to switch between .NET, Java, and Swift.
.NET
csharpusing Westpay.Epas;
Reference EpasClientLibrary.dll from your .NET Framework 4.7.2 project.
Java
javaimport se.westpay.epas.connections.classes.EpasClient; import se.westpay.epas.services.ApiDefinitions; import se.westpay.epas.services.IClientApp; import se.westpay.epas.utils.export.IPEndPoint;
Add library-1.4.5.jar to your application classpath.
Swift
swiftimport EpasClient
Add the local or published Swift package to Xcode through Swift Package Manager.
Step 2 - Implement the Client Callbacks
The client library calls your ECR when it needs to display cashier text, print receipts, collect cashier decisions, or report terminal state. Keep callback methods quick; long-running UI work should be marshalled onto your UI thread. The example below shows the same integration shape in each wrapper.
.NET
csharppublic sealed class PosClientApp : IClientApp { public void Display(string text) { cashierDisplay.Text = text.Replace("\n", Environment.NewLine); } public void PrintReceipt(ReceiptData receipt) { receiptStore.Add(receipt); printer.Print(receipt.GenerateSimpleReceipt(32)); } public void PrintReport(string report) { printer.Print(report); } public bool VerifySignature(string displayText, out bool signatureOk) { Display(displayText); signatureOk = cashierPrompts.Confirm("Signature OK?"); return true; } public void Log(LogLevel level, string text) { appLog.Write(level, text); } }
Java
javapublic final class PosClientApp implements IClientApp { @Override public void Display(String text) { cashierDisplay.setText(text.replace("\n", System.lineSeparator())); } @Override public void PrintReceipt(ReceiptData receipt) { receiptStore.add(receipt); printer.print(receipt.generateSimpleReceipt(32)); } @Override public Pair<Boolean, Boolean> VerifySignature(String displayText) { Display(displayText); boolean accepted = cashierPrompts.confirm("Signature OK?"); return new Pair<>(true, accepted); } @Override public void Log(ApiDefinitions.LogLevel level, String text) { appLog.write(level, text); } }
Swift
swiftimport EpasClient @MainActor final class PosClientApp: EpasClientDelegate { func display(text: String) { cashierDisplay.text = text } func printReceipt(receipt: ReceiptData) { receiptStore.append(receipt) printer.print(receipt.generateSimpleReceipt(width: 32)) } func printReport(report: String) { printer.print(report) } func verifySignature(displayText: String) async -> BooleanCallbackResult? { display(text: displayText) return BooleanCallbackResult(handled: true, value: true) } func log(level: LogLevel, text: String) { appLog.write(level: level, text: text) } }
Step 3 - Create the Client
Create one client instance per terminal connection. If your ECR talks to several terminals at the same time, keep a separate EpasClient per terminal.
.NET
csharpIClientApp clientApp = new PosClientApp(); EpasClient epas = new EpasClient(clientApp); epas.LinkStatus = linkUp => appLog.Write(LogLevel.Status, $"Link up: {linkUp}"); epas.BusyStatus = busy => appLog.Write(LogLevel.Status, $"Terminal busy: {busy}"); epas.CardStatus = inserted => appLog.Write(LogLevel.Status, $"Card inserted: {inserted}");
Java
javaIClientApp clientApp = new PosClientApp(); EpasClient epas = new EpasClient(clientApp); epas.complete();
Java status notifications are enabled through the IClientApp notification flags and delivered to methods such as LinkStatusNotification, BusyStatusNotification, CardActionNotification, and CardAcceptedNotification.
Swift
swiftlet clientApp = PosClientApp() let client = EpasClient(delegate: clientApp)
Swift status notifications are delivered through EpasClientDelegate methods such as linkStatusChanged, busyStatusChanged, cardStatusChanged, and epasMessageReceived.
Step 4 - Connect to the Terminal
Network connection details identify the terminal IP and port. A successful connect only means the library established the low-level terminal link; you still need to log in before running transactions.
.NET
csharpvar connection = new TerminalNetworkConnection { TerminalConnectionDetails = new IPEndPoint(IPAddress.Parse("192.168.10.25"), 6001), UseKeepAlive = true }; ApiResult result = epas.ConnectNetwork(connection, forceReconnect: false); if (result != ApiResult.OK) { throw new InvalidOperationException($"Unable to connect: {result}"); }
Java
javaApiDefinitions definitions = new ApiDefinitions(); ApiDefinitions.TerminalNetworkConnection connection = definitions.new TerminalNetworkConnection(); connection.TerminalConnectionDetails = new IPEndPoint("192.168.10.25", 6001); connection.UseKeepAlive = true; ApiDefinitions.ApiResult result = epas.connectNetwork(connection); if (result != ApiDefinitions.ApiResult.OK) { throw new IllegalStateException("Unable to connect: " + result); }
Swift
swiftlet connection = TerminalNetworkConnection( terminalConnectionDetails: IPEndPoint("192.168.10.25", 6001), useKeepAlive: true ) try await client.connect(connection)
Step 5 - Log In
Login sends the terminal ID, operator, language, configuration host, and authorisation host to the terminal. The ECR normally logs in once after connecting; there is no need to log in for every transaction.
.NET
csharpvar environment = new TerminalEnvironment { TerminalId = "80000082", OperatorId = "cashier_1", ISO639_1_LanguageCode = TerminalEnvironment.LangSwedish, ConfigurationServer = new IPEndPoint(IPAddress.Parse("185.27.171.42"), 55133), AuthorisationServer = new IPEndPoint(IPAddress.Parse("185.27.171.42"), 55144) }; ApiResult result = epas.Login(environment, out LoginResponse login); if (result == ApiResult.OK && login.LoggedIn) { appLog.Write(LogLevel.Status, "Terminal is ready for transactions"); }
Java
javaApiDefinitions.TerminalEnvironment environment = definitions.new TerminalEnvironment(); environment.TerminalId = "80000082"; environment.OperatorId = "cashier_1"; environment.SetLanguageCode("sv-SE"); environment.ConfigurationServer = new IPEndPoint("185.27.171.42", 55133); environment.AuthorisationServer = new IPEndPoint("185.27.171.42", 55144); Pair<ApiDefinitions.ApiResult, LoginResponse> loginResult = epas.login(environment); if (loginResult.getKey() == ApiDefinitions.ApiResult.OK && loginResult.getValue().isLoggedIn()) { appLog.write(ApiDefinitions.LogLevel.Status, "Terminal is ready for transactions"); }
Swift
swiftlet environment = TerminalEnvironment( terminalId: "80000082", workstationId: "pos_1", configurationServer: IPEndPoint("185.27.171.42", 55133), authorisationServer: IPEndPoint("185.27.171.42", 55144), operatorId: "cashier_1", iso639_1_LanguageCode: TerminalEnvironment.langSwedish ) let login = try await client.login(environment) guard login.loggedIn else { throw EpasClientError.invalidState("Terminal login was rejected.") }
Step 6 - Start a Transaction
Transaction methods return when the terminal has completed the flow, which can take time because the cardholder may need to present a card, enter PIN, or respond to prompts. Run transaction calls away from the UI thread unless your platform integration already uses asynchronous APIs.
.NET
csharpTransactionResponse response; ApiResult result = epas.Purchase(100.00m, out response); if (result == ApiResult.OK) { if (response.Approved) { completeSale(response.TransactionReference); } else { showDecline(response.ErrorCondition, response.AdditionalInformation); } }
Java
javaApiDefinitions.PurchaseTransactionAmounts amounts = definitions.new PurchaseTransactionAmounts(100.00); Pair<ApiDefinitions.ApiResult, TransactionResponse> result = epas.purchase(amounts); if (result.getKey() == ApiDefinitions.ApiResult.OK) { TransactionResponse response = result.getValue(); if (response.isApproved()) { completeSale(response.getTransactionReference()); } else { showDecline(response.toString()); } }
Swift
swiftlet response = try await client.purchase(100.00) if response.approved { completeSale(response.transactionReference) } else { showDecline(response.errorCondition, response.additionalInformation) }
Step 7 - Print Receipts and Store the Result
The terminal supplies receipt data through the receipt callback. Store the receipt data even if you print immediately; it is useful for audit, receipt retry, and transaction reporting.
.NET
csharppublic void PrintReceipt(ReceiptData receipt) { receiptRepository.Save(receipt); string text = receipt.GenerateSimpleReceipt(32); receiptPrinter.Print(text); }
Java
java@Override public void PrintReceipt(ReceiptData receipt) { receiptRepository.save(receipt); String text = receipt.generateSimpleReceipt(32); receiptPrinter.print(text); }
Swift
swiftfunc printReceipt(receipt: ReceiptData) { receiptRepository.save(receipt) let text = receipt.generateSimpleReceipt(width: 32) receiptPrinter.print(text) }
Step 8 - Handle Disconnects and Aborts
The library does not automatically reconnect. If the link drops, the terminal aborts any active transaction and logs out. Reconnect by calling the connection method again, then log in again.
.NET
csharpepas.LinkStatus = linkUp => { if (!linkUp) { appLog.Write(LogLevel.Error, "Terminal disconnected"); reconnectWorkflow.Schedule(); } }; ApiResult abortResult = epas.RequestTransactionAbort();
Java
java@Override public void LinkStatusNotification(boolean linkUp) { if (!linkUp) { appLog.write(ApiDefinitions.LogLevel.Error, "Terminal disconnected"); reconnectWorkflow.schedule(); } } ApiDefinitions.ApiResult abortResult = epas.requestTransactionAbort();
Swift
swiftfunc linkStatusChanged(isConnected: Bool) { if !isConnected { appLog.write(level: .error, text: "Terminal disconnected") reconnectWorkflow.schedule() } } try await client.abort()
Next Steps
- Use .NET Library for .NET-specific APIs, callbacks, and transaction examples.
- Use Java Library for Java-specific packages, callback signatures, and transaction examples.
- Use Swift Library for Swift Package Manager setup, async APIs, and Apple platform examples.
- Use Transactions for purchase, refund, reversal, pre-amount, administrative operations, and diagnostic APIs.
- Use Receipts and Events for receipt data, DCC, card identification, and terminal notifications.