JavaScript SDK (HTTP + MQTT)

receiptkit is the official JavaScript SDK for ReceiptKit. It supports both HTTP and MQTT transports, with React hooks, server utilities, and framework-agnostic clients.

Package & Source

npm package: npmjs.com/package/receiptkit · GitHub source: github.com/receiptkit-io/js

When should I use this vs. the REST API?

Use the REST API for simple fire-and-forget print jobs. Use the SDK's MQTT capabilities when you need real-time features: printer status monitoring, bridge discovery, live connection state, or high-frequency printing with minimal latency.

Installation

npm
npm install receiptkit
pnpm
pnpm add receiptkit

Peer dependency: react (optional, only needed for React hooks).

Package Exports

The SDK has dedicated entry points for different environments:

ImportEnvironmentUse Case
receiptkitAnyCore client + session APIs, types, topic builders, utilities
receiptkit/httpAnyHTTP-only session API (no MQTT dependency)
receiptkit/mqttAnyMQTT-focused session API (explicit transport choice)
receiptkit/reactBrowserReact provider, hooks (useReceiptKit, useBridgeStatus, etc.)
receiptkit/serverNode.jsServer-side singleton, serverPublish, serverRequestResponse

Which entry point should I use?

Use CaseRecommended Import
Simple request/response printing from web, server, or edgereceiptkit/http
Real-time status, discovery, or low-latency pub/sub workflowsreceiptkit or receiptkit/mqtt
React app with provider + hooksreceiptkit/react
Node.js API routes with shared singleton MQTT connectionreceiptkit/server

Quick Start

import { ReceiptKitSession } from "receiptkit/http";

const session = new ReceiptKitSession({
  apiKey: "rk_pub_your_public_key",
  orgId: "your-org-id",
  printerEndpoint: "tcp:00:11:62:32:5a:2a",
  templateId: "your-template-id",
});

const result = await session.print({
  data: {
    storeName: "My Store",
    total: "$9.99",
  },
});

console.log(result.status); // "success"

Client Configuration

OptionTypeDescription
apiKey *stringAPI key for MQTT authentication
orgId *stringOrganization ID (scopes all topics)
endpointstringAWS IoT endpoint (has sensible default)
environment"browser" | "server"Auto-detected. Controls client ID format and connection behavior
autoSubscribeStatusbooleanAuto-subscribe to bridge status on connect (default: true)
keepalivenumberMQTT keepalive in seconds (default: 60)
reconnectPeriodnumberReconnect interval in ms (default: 5000)
connectTimeoutnumberConnection timeout in ms (default: 10000)
debugbooleanEnable debug logging (default: auto-detect based on NODE_ENV)

React Hooks

useReceiptKit()

Access the MQTT client instance and connection status.

const { client, status } = useReceiptKit();
// status: "disconnected" | "connecting" | "connected" | "error"

useBridgeStatus(bridgeId)

Subscribe to a bridge's real-time status. Returns cached status with live updates.

const bridge = useBridgeStatus("bridge-abc123");
// bridge.connectionLevel: "live" | "stale" | "offline"
// bridge.printers: LivePrinter[]
// bridge.stats: { received, completed, failed }

usePrinterStatus(bridgeId, printerEndpoint)

Subscribe to a specific printer's hardware status (paper, cover, errors).

const printer = usePrinterStatus("bridge-abc123", "tcp:00:11:62:32:5a:2a");
// printer.statusLevel: "ready" | "paper-low" | "paper-out" | "cover-open" | ...
// printer.online: boolean

useBridgeDiscover()

Discover all bridges in your organization. Broadcasts a discovery request and collects responses.

const { bridges, isDiscovering, discover } = useBridgeDiscover();
// bridges: Map<string, BridgeStatusResponse>
// Call discover() to trigger a new scan

Topic Builders

All MQTT topics are org-scoped. Use topic builders to generate correct topic strings instead of constructing them manually:

TypeScript
import { createTopicBuilders } from "receiptkit";

const topics = createTopicBuilders({ apiKey: "rk_pub_...", orgId: "your-org-id" });

// ── to-bridge (client/server → bridge) ────────────────────────────────
topics.print("bridge-abc123")
// → "receiptkit/org/{orgId}/to-bridge/bridge-abc123/print"

topics.bridgeStatusPoll("bridge-abc123")
// → "receiptkit/org/{orgId}/to-bridge/bridge-abc123/status-poll"

topics.bridgeDiscover()
// → "receiptkit/org/{orgId}/to-bridge/broadcast/discover"

// ── to-client (bridge → client/dashboard) ─────────────────────────────
topics.bridgeStatus("bridge-abc123")
// → "receiptkit/org/{orgId}/to-client/bridge-abc123/status"

topics.bridgePrintResult("bridge-abc123")
// → "receiptkit/org/{orgId}/to-client/bridge-abc123/print-result"

topics.bridgePresence("bridge-abc123")
// → "receiptkit/org/{orgId}/to-client/bridge-abc123/presence"

// ── Wildcard subscriptions ────────────────────────────────────────────
topics.allToClient()
// → "receiptkit/org/{orgId}/to-client/+/+"

topics.allBridgePresence()
// → "receiptkit/org/{orgId}/to-client/+/presence"

Events

The client emits events for connection changes and incoming messages:

TypeScript
const client = ReceiptKitClient.getInstance();

client.on("connectionChange", (status) => {
  console.log("MQTT status:", status);
  // "disconnected" | "connecting" | "connected" | "error"
});

client.on("bridgeStatus", (bridgeId, status) => {
  console.log(`Bridge ${bridgeId}:`, status);
});

client.on("printerStatus", (bridgeId, mac, status) => {
  console.log(`Printer ${mac}:`, status);
});

client.on("bridgePresence", (bridgeId, isOnline) => {
  console.log(`Bridge ${bridgeId} is ${isOnline ? "online" : "offline"}`);
});

Key Concepts

Global Singleton

The client maintains one MQTT connection per page or process. Use ReceiptKitClient.getOrInit() in re-entrant environments (React Strict Mode, HMR) to reuse the existing instance.ReceiptKitClient.init() intentionally resets the previous instance.

StatusCache (Synchronous Reads)

Bridge and printer status is cached in memory. You can read status synchronously via client.getStatusCache() without async MQTT round-trips. The cache is updated automatically when status messages arrive.

Auto-Reconnect

The underlying MQTT.js library handles reconnection automatically with a configurable interval (default: 5 seconds). The client never kills the connection on timeout — it lets MQTT.js keep trying.

Org-Scoped Isolation

All topics are automatically namespaced to the configured orgId. Cross-org messaging is impossible — the MQTT broker (AWS IoT Core) enforces topic-level access control via org-scoped IoT policies.

Related Pages