@paycode/connect
v0.1.4
Published
PayCode Connect SDK for TypeScript
Downloads
43
Readme
PayCode Connect TypeScript SDK
📦 For a full working integration, check out the example app.
Setup
Initialize the SDK by calling setup(), which returns a promise that resolves to the PayCodeConnect singleton instance. This should be called once during your app's initialization.
import { setup } from "@paycode/connect";
// Using async/await
const pc = await setup();
// Or with a promise chain
setup().then((pc) => { /* ... */ });React hook example
import { type PayCodeConnect, setup } from "@paycode/connect";
import { useEffect, useState } from "react";
export function usePayCode() {
const [pc, setPc] = useState<PayCodeConnect | null>(null);
useEffect(() => {
setup().then(setPc);
}, []);
return pc;
}Connecting
To pair with a PoS terminal, generate a connection ticket and display it as a QR code. In this example we use the qrcode package to render it:
const ticket = pc.generateTicket();
// Render the ticket as a QR code
import QRCode from "qrcode";
QRCode.toCanvas(document.getElementById("qcanvas"), ticket, {});Once the QR code is scanned by a PayCode PoS terminal, the connection is established.
Reconnecting
After a successful first connection, the SDK persists the pairing ticket in local storage. If the user later revisits your site (or refreshes the page) and the PoS terminal is still active, you can restore the connection instantly, no QR code required:
await pc.reconnectToLastNode();This will throw an error if no previous connection exists, so you should handle that case:
try {
await pc.reconnectToLastNode();
} catch {
// No previous session, fall back to QR code pairing
const ticket = pc.generateTicket();
QRCode.toCanvas(document.getElementById("qcanvas"), ticket, {});
}You can set reconnect to retry the connection automatically by passing retryTimes parameter:
await pc.reconnectToLastNode(3); // This will retry 3 timesReceiving events
PayCodeConnect exposes a typed event emitter, allowing you to subscribe to events like connected, presence, scanner, and emvState using callback handlers.
Connected event
Fires when the connection state with a PoS terminal changes. Returns true when connected and false when the connection is lost.
pc.on("connected", (connected: boolean) => { /* ... */ });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 |
|---|---|---|
| awaitingCard | state, metadata? | Terminal is waiting for a card to be presented |
| processing | state, metadata? | Transaction is being processed |
| error | state, message, code, metadata? | Transaction failed |
| success | state, transaction, metadata? | Transaction completed successfully |
| reversal | state, message, code, metadata? | Reversal result — code is 0 for success, 1 for error |
Note: If
metadatawas passed tostartEMV(), it will be present on every state event for that transaction.
pc.on("emvState", (data: EMVData) => {
// handle state change
});Example payloads per state:
// awaitingCard, processing
{ state: "awaitingCard" }
// error
{ state: "error", message: "Transaction failed", code: -8019 }
// success
{ state: "success", transaction: { authorization: "...", reference: "...", folio: "...", /* ... */ } }
// reversal
{ state: "reversal", message: "success", code: 0 }Presence event
Fires with false when messages are no longer reaching the connected PoS terminal, even if the connection hasn't been fully lost yet. Fires with true once the terminal becomes responsive again.
pc.on("presence", (hasPresence: boolean) => { /* ... */ });Scanner event
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 barcode, returning the scanned value as a string.
pc.on("scanner", (barcode: string) => { /* ... */ });Commands
Once connected, you can remotely control the PoS terminal through the following commands:
| Command | Description |
|---|---|
| startEMV(amount, emvType?, metadata?) | Start a transaction |
| cancelEMV() | Cancel 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(pin, password) | Set a PIN on the terminal |
| authorizePin(pin) | Authenticate using a PIN |
| logout() | Log out of the terminal |
Start EMV
Starts an EMV transaction on the connected PoS terminal. The amount is in MXN only for now. The optional emvType parameter defaults to "Combined" and can be set to "Emv", "Amex", or "Combined". Subscribe to the emvState event to track the transaction lifecycle.
| Parameter | Type | Default | Description |
|---|---|---|---|
| amount | number | (required) | The transaction amount in MXN. |
| emvType | "Emv" | "Amex" | "Combined" | "Combined" | The type of EMV transaction. |
| metadata | Record<string, unknown> | undefined | Arbitrary data to attach to this transaction. Echoed back on every emvState event for this transaction. |
await pc.startEMV(150.00);
// Or specify the EMV type
await pc.startEMV(150.00, "Amex");
// Pass metadata to correlate events with your application state
await pc.startEMV(150.00, "Combined", {
customerId: 1234,
orderId: "ORD-5678",
});When metadata is provided, it is included in the metadata field of every emvState event emitted for that transaction:
pc.on("emvState", (data: EMVData) => {
console.log(data.state); // "awaitingCard" | "processing" | "success" | ...
console.log(data.metadata); // { customerId: 1234, orderId: "ORD-5678" }
});Cancel EMV
Cancels an EMV transaction that is still in the state 'awaitingCard', if it has started processing the transaction can't be cancelled and this call will be ignored.
await pc.cancelEMV();Reverse Transaction
Reverses a previously completed transaction by its folio number. Listen to the emvState event for the reversal result.
await pc.reverseTransaction("123456789");Print Transaction
Reprints the receipt for a previously completed transaction by its folio number.
await pc.printTransaction("123456789");Set Capabilities
Configures the terminal's capabilities. Available options:
scannerPrefixes— Array of barcode prefixes to enable the scanner eventpingInternetConnectivity— Enable internet connectivity checksforceRemoteControl— Force the terminal into remote control modedisableManualPayments— Disable manual payment entry on the terminal
await pc.setCapabilities({
scannerPrefixes: ["PREFIX1", "PREFIX2"],
forceRemoteControl: true,
});Authorize
Authenticates with the connected PoS terminal using email and password credentials.
await pc.authorize("[email protected]", "password");Set PIN
Sets a PIN on the terminal for PIN-based authentication. Requires the account password for verification.
await pc.setPin("1234", "password");Authorize PIN
Authenticates with the terminal using a previously configured PIN.
await pc.authorizePin("1234");Logout
Logs out of the connected PoS terminal.
await pc.logout();