Skip to main content

Install

npm install @messages-dev/sdk

Initialize

import { createClient } from "@messages-dev/sdk";

const client = createClient();
The client automatically reads MESSAGES_API_KEY from your environment. To pass a key explicitly:
const client = createClient({ apiKey: "sk_live_..." });

Send a message

await client.sendMessage({
  from: "+15551234567",
  to: "+15559876543",
  text: "Hello from Messages.dev!",
});

Receive messages via webhooks

Create a webhook from the Webhooks page in your dashboard and copy the signing secret. Then handle incoming events on your server:
import { verifyWebhook } from "@messages-dev/sdk";

app.post("/webhooks", async (req, res) => {
  const event = await verifyWebhook(
    req.body,
    req.headers["x-webhook-signature"],
    "your_webhook_secret",
  );

  switch (event.event) {
    case "message.received":
      console.log(`New message from ${event.data.sender}: ${event.data.text}`);
      break;
    case "message.sent":
      console.log(`Message delivered: ${event.data.id}`);
      break;
  }

  res.sendStatus(200);
});
If the signature is invalid, verifyWebhook throws a SignatureVerificationError.

List messages

const messages = await client.listMessages({
  from: "+15551234567",
  to: "+15559876543",
});

Reactions

await client.sendReaction({
  from: "+15551234567",
  to: "+15559876543",
  messageId: "msg_abc123",
  type: "love",
});

const reactions = await client.listReactions({
  messageId: "msg_abc123",
});

Typing indicators

await client.startTyping({
  from: "+15551234567",
  to: "+15559876543",
});

await client.stopTyping({
  from: "+15551234567",
  to: "+15559876543",
});

Read receipts

await client.sendReadReceipt({
  from: "+15551234567",
  to: "+15559876543",
});

const receipts = await client.listReadReceipts({
  from: "+15551234567",
  to: "+15559876543",
});

Files

Upload files to send as message attachments:
const file = await client.uploadFile({
  from: "+15551234567",
  file: Buffer.from(imageData),
  filename: "photo.jpg",
  mimeType: "image/jpeg",
});
await client.sendMessage({
  from: "+15551234567",
  to: "+15559876543",
  text: "Check this out!",
  attachments: [file.id],
});

const { url } = await client.getFileUrl({ id: "file_abc123" });

Delivery tracking

await client.getOutboxItem({ id: "obx_xyz789" });

Lines

const lines = await client.listLines();

for (const line of lines.data) {
  console.log(line.handle, line.service, line.isActive);
}

Chats

const chats = await client.listChats({
  from: "+15551234567",
});

for (const chat of chats.data) {
  console.log(chat.identifier, chat.name, chat.lastMessageAt);
}

Webhooks

await client.createWebhook({
  from: "+15551234567",
  url: "https://example.com/webhooks",
  events: ["message.received", "message.sent"],
});

const webhooks = await client.listWebhooks({
  from: "+15551234567",
});

await client.deleteWebhook({ id: "wh_abc123" });

Pagination

List methods return a page object with data, hasMore, and nextCursor. Use for await...of to iterate through all results:
const page = await client.listMessages({
  from: "+15551234567",
  to: "+15559876543",
  limit: 10,
});

if (page.hasMore) {
  const nextPage = await client.listMessages({
    from: "+15551234567",
    to: "+15559876543",
    cursor: page.nextCursor,
  });
}

const messages = await client.listMessages({
  from: "+15551234567",
  to: "+15559876543",
});

for await (const message of messages) {
  console.log(message.text);
}

Error handling

All errors extend MessagesError and include the error type, code, and message from the API:
import { createClient, AuthenticationError, AuthorizationError, InvalidRequestError, NotFoundError } from "@messages-dev/sdk";

try {
  await client.sendMessage({
    from: "+15551234567",
    to: "+15559876543",
    text: "Hello!",
  });
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error("Bad API key:", err.code);
  } else if (err instanceof AuthorizationError) {
    console.error("Forbidden:", err.code);
  } else if (err instanceof InvalidRequestError) {
    console.error("Bad request:", err.code, err.param);
  } else if (err instanceof NotFoundError) {
    console.error("Not found:", err.code);
  }
}
Every error includes:
PropertyTypeDescription
typestringError category (e.g. authentication_error)
codestringMachine-readable code (e.g. invalid_api_key)
messagestringHuman-readable explanation
paramstring | undefinedThe parameter that caused the error
statusnumberHTTP status code
requestIdstringUnique request ID for debugging

Configuration

All options are passed to createClient:
const client = createClient({
  apiKey: "sk_live_...",
  baseUrl: "https://api.messages.dev",
  timeout: 30_000,
  maxRetries: 2,
});

TypeScript

The SDK is written in TypeScript and exports types for all resources:
import { createClient } from "@messages-dev/sdk";
import type {
  Line,
  Chat,
  Message,
  Reaction,
  Webhook,
  OutboxItem,
  WebhookEvent,
} from "@messages-dev/sdk";