Skip to content

POS bridge & ECR Hub

  • What the POS bridge is and why every lane needs one.
  • How the ECR Hub in Vendor Desktop reaches the hardware.
  • How to read the heartbeat and activity log when something stops working.

The POS bridge is a small local service that runs on the lane PC (or the Vendor Desktop app). It is the only thing in the system that talks to:

  • The receipt printer (ESC/POS or StarPRNT).
  • The card terminal over LAN (PAX) or WebSocket (CodePay).
  • The cash drawer (pulses the open signal).
  • The scale (USB / serial).
  • The customer display (secondary screen).

The browser / dashboard never talks to these devices directly. Instead:

Browser (vendor-web) ⇄ NestJS API ⇄ POS bridge (Vendor Desktop / lane PC) ⇄ Hardware

The authoritative relay is the bridge — even though apps/vendor-web also has a “probe” WebSocket for the same URL (used for heartbeats and settings), the real work happens on the desktop.

ECR Hub is the module inside Vendor Desktop that:

  1. Opens a WebSocket to the bridge URL stored on the terminal store device.
  2. Translates high-level events (sale.placed, payment.intent) into vendor-protocol calls to PAX or CodePay.
  3. Streams back terminal status (idle / card-read / payment-summary / signature-needed).

The bridge URL is built by the backend:

POST /api/v1/vendor/settings/devices/pos-bridge/activate

with the active store_id and terminal id — the response contains the WebSocket URL the lane PC opens.

Settings → Devices → Terminals (POS bridge).

You’ll see one entry per store device. Pick the active terminal and tap Activate. The dashboard shows:

  • Bridge URL (read-only — copy and paste into Vendor Desktop).
  • Status — connected / reconnecting / offline.
  • Last heartbeat — most recent ping from Vendor Desktop.
  • Activity log — every sale + payment event.

If the bridge is offline, every hardware interaction on that lane falls back to “manual mode” — receipts queue, card capture requires an owner click.

EventWhat it means
bridge.connectVendor Desktop opened the WebSocket.
bridge.heartbeatA ping from the desktop (every ~30s).
print.success / print.errorA receipt finished printing (or failed).
terminal.intentA payment intent was sent to the card terminal.
terminal.captureThe terminal confirmed capture.
terminal.voidThe terminal confirmed a post-capture void.
bridge.disconnectThe desktop closed the socket.

Use this log to debug “the cashier said the printer didn’t print” — the log tells you whether the desktop actually sent the job.

V. Distinguish transport on the device row

Section titled “V. Distinguish transport on the device row”

The device row carries two distinct sets of fields:

  • terminalWsUrl — for codepay_ws (a CodePay gateway WebSocket URL).
  • pax_lan — LAN IP / port for pax_lan PAX devices.

The UI lists the right fields for the device’s terminalRelayKind. Don’t mix them — copying a CodePay URL onto a PAX device produces a “press 0 on terminal” error from the ECR Hub.

  • Green — desktop is connected and pinging.
  • Yellow — desktop lost contact within the last minute; the dashboard will retry.
  • Red — desktop offline for over 2 minutes. Receipts queue; card payments need manual capture.

Bridge is green but the printer doesn’t print. The bridge is reachable, but the printer behind it isn’t. See Receipt printer troubleshooting.

Bridge red after a Vendor Desktop update. Restart the desktop. The WebSocket URL is regenerated on each activate, so a stale URL is the usual cause.

Two lanes share one bridge. Not recommended — the bridge is one-to-one with each terminalPos. Pair a second bridge for the second lane.

Card payment stuck on “pending”. Read Card terminal → “Pending stays for minutes”.