A TypeScript SDK for interacting with KioskEngine Platform hardware devices. This SDK provides a simple and type-safe way to communicate with various hardware devices such as payment terminals, card dispensers and fiscal printers.
- 🔒 Type-safe API with full TypeScript support
- 🎮 Easy device management and communication
- 🔄 Automatic reconnection handling
- 🏖 Sandbox mode for testing
- 📝 Comprehensive logging system
- 🎯 Event-driven architecture
- ⚡ Promise-based async API
- Payment terminal
- Fiscal printer
- Thermal printer
npm install @kioskengine/sdk
# or
yarn add @kioskengine/sdk
# or
pnpm add @kioskengine/sdk
import {
KioskEngineBuilder,
DeviceType,
SDKEventType,
LogLevel,
ProductItem,
} from "@kioskengine/sdk";
// Create SDK instance
const sdk = new KioskEngineBuilder()
.withSandboxMode(process.env.NODE_ENV === "development")
.withDevice(DeviceType.PAYMENT_TERMINAL)
.build();
// Subscribe to events
sdk.on(SDKEventType.CONNECTED, (event) => {
console.log("SDK Connected!", event);
});
// Initialize SDK
await sdk.initialize();
// Get payment terminal
const terminal = sdk.getPaymentTerminal();
// Get terminal status
const status = await terminal.getStatus();
console.log("Terminal status:", status);
// Define products for the transaction
const products: ProductItem[] = [
{
id: "SKU123",
name: "Premium Coffee",
quantity: 2,
unit_price: 599, // $5.99 per unit
},
{
id: "SKU456",
name: "Croissant",
quantity: 1,
unit_price: 299, // $2.99 per unit
},
];
// Initialize a transaction
// Total amount will be calculated automatically: (2 * $5.99) + (1 * $2.99) = $14.97
const result = await terminal.initializeTransaction(products);
console.log("Transaction result:", result);
The SDK can be configured using the builder pattern:
const sdk = new KioskEngineBuilder()
.withSandboxMode(true) // Enable sandbox mode for testing
.withWebSocketUrl("ws://your-server:5000") // Custom WebSocket URL
.withDevice(DeviceType.PAYMENT_TERMINAL) // Add payment terminal device
.withTimeout(10000) // Set custom timeout (10 seconds)
.build();
Each product in a transaction must include:
interface ProductItem {
id: string; // Unique identifier of the product
name: string; // Name of the product
quantity: number; // Quantity being purchased
unit_price: number; // Price per unit in cents (e.g., 599 for $5.99)
}
// Get payment terminal instance
const terminal = sdk.getPaymentTerminal();
// Define products
const products: ProductItem[] = [
{
id: "COFFEE-001",
name: "Espresso",
quantity: 2,
unit_price: 399, // $3.99 each
},
{
id: "PASTRY-001",
name: "Chocolate Muffin",
quantity: 1,
unit_price: 299, // $2.99 each
},
];
try {
// Initialize transaction
// Total amount: (2 * $3.99) + (1 * $2.99) = $10.97
const result = await terminal.initializeTransaction(products);
if (result.auth_res === "approval") {
console.log("Transaction approved!");
console.log("Amount:", result.amount);
console.log("Card type:", result.card_type);
console.log("Authorization code:", result.card_payment_data.auth_code);
} else {
console.log("Transaction declined:", result.auth_res);
}
} catch (error) {
if (error instanceof TimeoutError) {
console.error("Transaction timed out");
} else {
console.error("Transaction failed:", error);
}
}
In sandbox mode, you can test declined transactions by including [decline]
in any product name. For example:
const products: ProductItem[] = [
{
id: "TEST-001",
name: "Test Product [decline]", // This will trigger a declined transaction
quantity: 1,
unit_price: 1000,
},
];
const result = await terminal.initializeTransaction(products);
// result.auth_res will be "refusal"
// result.card_payment_data.auth_response will be "ODMOWA"
// result.card_payment_data.auth_response_code will be "0005"
Monitor transaction progress using events:
// Subscribe to transaction events
sdk.on(SDKEventType.TRANSACTION_STARTED, (event) => {
console.log("Transaction started:", event.data);
// event.data contains: { amount: number, products: ProductItem[] }
});
sdk.on(SDKEventType.TRANSACTION_COMPLETED, (event) => {
console.log("Transaction completed:", event.data);
// event.data contains the TransactionResponse
});
sdk.on(SDKEventType.TRANSACTION_ERROR, (event) => {
console.error("Transaction failed:", event.data.error);
});
The transaction response includes:
interface TransactionResponse {
auth_res: "approval" | "refusal" | "unable_to_complete_transaction";
amount: number;
card_type: string;
card_payment_data: {
transaction_time: string;
transaction_date: string;
card_name: string;
masked_card_number: string;
auth_code: string;
// ... additional payment details
};
}
The SDK provides comprehensive support for fiscal printer operations. Here's how to use the fiscal printer:
import { KioskEngineBuilder, DeviceType } from "@kioskengine/sdk";
const sdk = new KioskEngineBuilder()
.withSandboxMode(process.env.NODE_ENV === "development")
.withDevice(DeviceType.FISCAL_PRINTER)
.build();
await sdk.initialize();
// Get fiscal printer instance
const printer = sdk.getFiscalPrinter();
const status = await printer.getStatus();
console.log("Printer status:", status);
// status contains:
// - command_queue: "empty" | "not_empty" | "unknown"
// - connection: "ok" | "error"
// - device: "ok" | "error_in_menu" | "error_waitin_for_key" | "error_waiting_for_user_reaction" | "unknown"
// - mechanism: "ok" | "error_lever_raised" | ... (various error states)
// - paper_sensor: "ok" | "no_paper" | "low_paper" | "not_ok"
// - connection_details: error details (when connection is "error")
const products = [
{
name: "Coffee",
number: 2,
price: 5.99, // $5.99
tax_code: 1, // Tax rate code
},
{
name: "Croissant",
number: 1,
price: 2.99, // $2.99
tax_code: 1,
},
];
try {
// Optional parameters
const customerNip = "1234567890"; // Customer tax number
const discount = "10"; // 10% discount
const paymentMethod = "card"; // Payment method (cash, card, etc.)
const result = await printer.printFiscalReceipt(
products,
customerNip,
discount,
paymentMethod
);
if (result.print_result === "ok") {
console.log("Receipt printed successfully");
} else {
console.log("Print error:", result.print_result_details);
}
} catch (error) {
console.error("Failed to print receipt:", error);
}
const cardPaymentData = {
auth_res: "approval",
transaction_nr: "1023",
terminal_id: "82328135",
merchandiser_id: "76328988",
acceptor_id: "A0000000041010",
auth_code: "471948",
total_transaction_price: "535",
card_name: "VISA",
masked_card_number: "************1234",
method_of_reading_card: "C", // C for chip, M for magnetic, E for contactless, etc.
masked_card_expire_date: "**/**",
transaction_date: "20240315", // Format: YYYYMMDD
transaction_time: "143000", // Format: HHMMSS
// Required fields
auth_code_source: "1", // "1" for online authorization
cardholder_authorization_method: "A", // Authorization method
// EMV fields
emv_transaction_cryptogram: "55E13384CCA22CFD",
emv_application_identifier: "A0000000041010",
terminal_printing_indicator: "0",
// DCC (Dynamic Currency Conversion) fields
transaction_currency_code: "EUR", // Set to EUR or USD for DCC mode
terminal_currency: "PLN",
transaction_amount_in_terminal_currency: "1000",
currency_exchange_rate: "0.2400570",
dcc_text1: "THIS CURRENCY CONVERSION SERVICE IS PROVIDED BY VISA",
dcc_text2:
"I HAVE BEEN OFFERED A CHOICE OF CURRENCIES AND HAVE CHOSEN TO PAY IN EUR",
};
const result = await printer.printCardPaymentReceipt(cardPaymentData);
console.log("Card payment receipt result:", result);
The receipt will automatically be formatted as a DCC receipt when:
-
transaction_currency_code
is EUR or USD (not PLN) -
terminal_currency
is set to PLN (local currency)
In DCC mode, the receipt will include:
- Both original amount in PLN and converted amount in the foreign currency
- Currency exchange rate information
- Additional legal texts (provided in dcc_text1 and dcc_text2)
- Special formatting based on the card brand (VISA vs MasterCard)
For standard domestic transactions:
- Set
transaction_currency_code
to "PLN" or leave it empty - The receipt will be printed in standard Polish format with a single amount in PLN
// Print a QR code (simplified API)
const qrCode = "https://example.com/order/123";
const result = await printer.printQRCode(qrCode);
console.log("QR code print result:", result);
// Print an order number (must be exactly 3 digits)
const result = await printer.printOrderNumber("042"); // Valid: 3 digits
// Invalid examples (will throw an error):
// await printer.printOrderNumber("42"); // Error: less than 3 digits
// await printer.printOrderNumber("1234"); // Error: more than 3 digits
// await printer.printOrderNumber("abc"); // Error: non-numeric characters
console.log("Order number print result:", result);
The order number must:
- Be exactly 3 numeric digits (000-999)
- Be provided as a string
- Contain only numeric characters
// Initialize and print daily report with optional ID
const reportId = 3; // Optional identifier for the report
const report = await printer.initDailyReport(reportId);
console.log("Daily report date:", report.report_date);
console.log("Print result:", report.print_result);
console.log("Completed:", report.completed); // Indicates if report generation completed successfully
// Subscribe to print events
sdk.on(SDKEventType.PRINT_STARTED, (event) => {
console.log("Print operation started:", event.data);
});
sdk.on(SDKEventType.PRINT_COMPLETED, (event) => {
console.log("Print operation completed:", event.data);
});
sdk.on(SDKEventType.PRINT_ERROR, (event) => {
console.error("Print operation failed:", event.data.error);
});
The SDK provides comprehensive support for thermal printer operations, allowing you to create receipts, labels, and other printed content.
import { KioskEngineBuilder, DeviceType } from "@kioskengine/sdk";
const sdk = new KioskEngineBuilder()
.withSandboxMode(process.env.NODE_ENV === "development")
.withDevice(DeviceType.THERMAL_PRINTER)
.build();
await sdk.initialize();
// Get thermal printer instance
const printer = sdk.getThermalPrinter();
const status = await printer.getStatus();
console.log("Printer status:", status);
// status contains:
// - connection: "ok" | "error"
// - paper_level: "ok" | "low" | "empty"
// - error_status: "ok" | string
// - online: boolean
// - printer_type: string
// - last_check: string (timestamp)
// - connection_details: string (optional error details)
The thermal printer uses a command-based API where you create an array of commands to execute:
// Create an array of print commands
const commands = [
{
command: "print_text",
value: "Hello, World!",
align: "center",
bold: true,
width_size: 2,
height_size: 2,
},
{
command: "feed_lines",
value: 2,
},
{
command: "print_qr",
value: "https://example.com",
size: 8,
},
{
command: "feed_lines",
value: 3,
},
{
command: "cut_paper",
},
];
// Send commands to the printer
const result = await printer.print(commands);
console.log("Print result:", result);
For convenience, the SDK provides utility methods to create properly formatted commands:
// Create commands using utility methods
const commands = [
printer.createTextCommand("Hello, World!", {
align: "center",
bold: true,
width_size: 2,
height_size: 2,
}),
printer.createFeedLinesCommand(2),
printer.createQRCommand("https://example.com", 8),
printer.createFeedLinesCommand(3),
printer.createCutPaperCommand(),
];
// Send commands to the printer
const result = await printer.print(commands);
The SDK includes a utility to generate a complete receipt with a single method call:
const receiptCommands = printer.generateReceiptCommands({
title: "ACME Store",
subtitle: "123 Main Street, Anytown",
items: [
{ name: "Coffee", quantity: 2, price: 599 }, // $5.99 each
{ name: "Croissant", quantity: 1, price: 299 }, // $2.99 each
{ name: "Orange Juice", quantity: 1, price: 349 }, // $3.49 each
],
total: 1846, // $18.46
orderNumber: "A42",
footer: "Thank you for shopping with us",
qrCode: "https://example.com/receipt/42",
});
const result = await printer.print(receiptCommands);
The thermal printer supports the following commands:
-
Print Text
printer.createTextCommand("Text to print", { align: "left" | "center" | "right", // default: "left" font: "a" | "b", // default: "a" bold: true | false, // default: false width_size: 1 - 8, // default: 1 height_size: 1 - 8, // default: 1 });
-
Feed Lines
printer.createFeedLinesCommand(numberOfLines); // default: 1
-
Cut Paper
printer.createCutPaperCommand(partial); // default: true
-
Print QR Code
printer.createQRCommand("data", size); // size default: 6
-
Print Barcode
printer.createBarcodeCommand("5901234123457", { height: 64, // default: 64 width: 2 - 6, // default: 3 position: "below" | "above" | "both" | "none", // default: "below" font: "a" | "b", // default: "a" });
-
Print Image
printer.createImageCommand("/path/to/image.png", highDensity); // highDensity default: true
-
Print Logo
printer.createLogoCommand(logoNumber); // default: 1
-
Initialize Printer
printer.createInitializeCommand();
-
Set Print Mode
printer.createPrintModeCommand({ font_b: true | false, // default: false emphasized: true | false, // default: false width_size: 1 - 8, // default: 1 height_size: 1 - 8, // default: 1 underline: true | false, // default: false });
-
Set Paper Width
printer.createPaperWidthCommand(58 | 80); // 58mm or 80mm
// Subscribe to print events
sdk.on(SDKEventType.PRINT_STARTED, (event) => {
console.log("Print operation started:", event.data);
});
sdk.on(SDKEventType.PRINT_COMPLETED, (event) => {
console.log("Print operation completed:", event.data);
});
sdk.on(SDKEventType.PRINT_ERROR, (event) => {
console.error("Print operation failed:", event.data.error);
});
In sandbox mode, all print operations will be simulated. To simulate printing failures, include the string [fail]
in any text command:
const failingCommand = printer.createTextCommand("Test failure [fail]");
const result = await printer.print([failingCommand]);
// result.success will be false
// result.errors will contain details about the simulated failure
The SDK provides different log levels that can be configured:
import { KioskEngine, LogLevel } from "@kioskengine/sdk";
KioskEngine.setLogLevel(LogLevel.DEBUG); // Set to DEBUG for development
Available log levels:
- DEBUG: Detailed information for debugging
- INFO: General information about operations
- WARN: Warning messages for potential issues
- ERROR: Error messages for operation failures
The SDK uses an event-driven system to notify about various states and operations:
sdk.on(SDKEventType.DEVICE_READY, (event) => {
console.log("Device is ready:", event.deviceType);
});
sdk.on(SDKEventType.TRANSACTION_COMPLETED, (event) => {
console.log("Transaction completed:", event.data);
});
Available events:
- CONNECTED: SDK successfully connected
- DISCONNECTED: SDK disconnected
- DEVICE_READY: Device is initialized and ready
- DEVICE_ERROR: Device encountered an error
- TRANSACTION_STARTED: Payment transaction started
- TRANSACTION_COMPLETED: Payment transaction completed
- TRANSACTION_ERROR: Payment transaction failed
The SDK is written in TypeScript and provides full type definitions. No additional @types packages are required.
Copyright © 2024 KioskEngine. All rights reserved.