JavaScript SDK Planned
The official JavaScript SDK wraps the message.com REST API and Socket.io endpoints into one idiomatic package. Works in modern browsers, Node 18+, Bun, and Deno. ESM first with a CommonJS fallback.
This SDK is on the Q1 2026 roadmap. The REST API and Socket.io endpoints it wraps are live today, so you can build against the underlying primitives now and swap in the SDK when it ships.
Installation
Pick your package manager. The bundle is roughly 12KB minified plus gzipped for the REST surface, with Socket.io as an optional peer-installable add-on.
npm install @message-com/sdk
# or
pnpm add @message-com/sdk
# or
yarn add @message-com/sdkInitialise the client
Construct a single client per process. The constructor takes either an API key (server-side) or a workspace JWT (when running inside the dashboard or a logged-in agent surface). See Authentication for the two modes.
import { Message } from "@message-com/sdk";
const msg = new Message({
apiKey: process.env.MESSAGE_API_KEY!, // server-side keys only
// workspaceId is inferred from the key
});Visitors
The most common backend job is keeping your customer records in sync with the visitor table in your workspace. The SDK exposes an idempotent visitors.upsert keyed by externalId or email.
// Upsert a visitor from your CRM webhook
await msg.visitors.upsert({
email: "[email protected]",
externalId: "crm-4567",
name: "Alice Johnson",
attributes: {
plan: "pro",
mrr: 99,
signupDate: "2025-11-04",
},
});Tickets
Tickets are just conversations with channel = "ticket". The SDK ships a thin helper so you do not have to remember the channel string.
// Create a ticket when Stripe tells you a charge failed
await msg.tickets.create({
visitorEmail: "[email protected]",
subject: "Auto-detected failed payment",
body: "Stripe charge ch_xyz failed. Reach out within 4h.",
tags: ["billing", "auto-created"],
});Real-time
The realtime namespace wraps the Socket.io /agent channel. It accepts the same event names documented on the agent namespace page and returns typed payloads.
// Subscribe to new conversations server-side
msg.realtime.on("conversation:new", (conv) => {
console.log("new conversation in queue", conv.id);
});
await msg.realtime.connect();Error handling
All errors surface as a typed MessageError with a numeric statusCode, a machine-readable error code, and a human message. The list of codes mirrors the REST API. See errors, rate limits, versioning.
Browser vs Node
The same package exports both a browser entrypoint that runs against a workspace JWT, and a node entrypoint for server-side API-key flows. Tree-shaking will eliminate the half you do not import.
- Browser builds rely on the platform
fetchandWebSocketAPIs. - Node builds use the built-in
fetchon Node 18+ (a polyfill is auto-loaded on older runtimes). - TypeScript types ship in-band; no separate
@typespackage needed.
Common pitfalls
- Do not ship your API key to the browser. If you need browser-side access, mint a workspace JWT server-side and pass it down. See the MDN reference on Authorization headers for context.
- Always set
externalIdwhen upserting visitors. Without it we fall back to email, which can collide when a visitor changes addresses. - Reconnect logic is built in on the realtime client. Do not wrap it in your own retry loop.