MIT licensed · TypeScript-native · Node 20+

One API for
every messaging channel.

Msgly collapses 41 platforms — chat, email, SMS, push and voice — into a single unified interface. Register the adapters you need, send and receive in one format, and stop learning a new webhook payload every quarter.

0channel adapters
0unified message type
0core changes to add a channel
MITlicence

Why msgly

Multi-channel shouldn't mean multi-codebase.

Building a chatbot or notification system that works across channels means learning many different APIs, webhook formats, signature schemes and media rules. Msgly gives you one TypeScript-native interface over all of them — with retries, idempotency, capability checks and rate limiting already handled.

Channel names are open: ChannelName accepts any string, so you can publish a third-party adapter without waiting on a core release. Built-in names keep editor autocomplete.

echo-bot.ts
import express from 'express';
import { createHub } from '@msgly/core';
import { createTelegramAdapter } from '@msgly/telegram';
import { createWhatsAppAdapter } from '@msgly/whatsapp';

const hub = createHub();

hub.register(createTelegramAdapter({
  botToken: process.env.TELEGRAM_BOT_TOKEN!,
  webhookSecret: process.env.TELEGRAM_WEBHOOK_SECRET!,
}));

hub.register(createWhatsAppAdapter({
  phoneNumberId: process.env.WA_PHONE_ID!,
  accessToken: process.env.WA_TOKEN!,
  appSecret: process.env.META_APP_SECRET!,
  verifyToken: process.env.META_VERIFY_TOKEN!,
}));

// Verify credentials at startup — fail fast on bad tokens
await hub.connect({ throwOnFailure: true });

hub.on('message', async (msg) => {
  if (msg.content.type === 'text') {
    await hub.send({
      channel: msg.channel,
      account: msg.account,
      contact: msg.contact,
      content: { type: 'text', text: `You said: ${msg.content.text}` },
    });
  }
});

const app = express();
const handlers = hub.createWebhookHandler();
app.get('/webhook/:channel', handlers.get);
app.post('/webhook/:channel', handlers.post);
app.listen(3000);

Every module

41 adapters, one contract.

Each channel is its own package, so you install only what you ship. Every adapter implements the same Adapter interface and brings its own credential check.

Telegram

@msgly/telegram
Broadcast

Bot API, inline keyboards, and channel posting via @name

WhatsApp

@msgly/whatsapp
Policy-gated

Cloud Business API; approved MARKETING templates for campaigns

Messenger

@msgly/messenger
Broadcast

Meta Send API, plus publishPost() to the Page feed

Instagram

@msgly/instagram
Broadcast

Direct messages, plus publishPost() for feed posts and Reels

LINE

@msgly/line
Broadcast

broadcast() to all friends, multicast() to a segment

Discord

@msgly/discord
No campaigns

HTTP Interactions with buttons and message components

Microsoft Teams

@msgly/msteams
No campaigns

Bot Framework channel with Adaptive Card support

Slack

@msgly/slack
No campaigns

Events API and Block Kit; posts to a channel, not to users

WeChat

@msgly/wechat
Broadcast

massSend() to all followers or a tag group, quota-metered

Viber

@msgly/viber
Broadcast

broadcast() to up to 300 subscribers per call

Mattermost

@msgly/mattermost
No campaigns

Self-hosted chat over REST and outgoing webhooks

Rocket.Chat

@msgly/rocketchat
No campaigns

Self-hosted chat via REST plus outgoing webhooks

Google Chat

@msgly/googlechat
No campaigns

Service-account auth with Google-signed webhooks

Gmail

@msgly/gmail

Pub/Sub push delivery and MIME attachment handling

Outlook / M365

@msgly/outlook

Graph change notifications and attachment handling

SMTP / IMAP

@msgly/smtp
Outbound

Yahoo, Zoho, Fastmail or any custom mail server

Resend

@msgly/resend
Outbound

Transactional email over HTTP, Edge-compatible

Mailgun

@msgly/mailgun
Outbound

Transactional email, inbound routes and signed event webhooks

Postmark

@msgly/postmark
Outbound

Transactional email with message streams and bounce webhooks

SendGrid

@msgly/sendgrid
Outbound

Inbound Parse and ECDSA-signed event webhooks

Amazon SES

@msgly/ses
Outbound

High-volume email, SigV4 with SNS bounce handling

Twilio SMS

@msgly/twilio-sms
Outbound

SMS and MMS, with media attachments and receipts

Exotel

@msgly/exotel
Outbound

India-focused SMS with DLT template compliance

MSG91

@msgly/msg91
Outbound

India SMS through the DLT Flow API, template-first

Vonage

@msgly/vonage-sms
Outbound

Global SMS delivery with signed inbound webhooks

Plivo

@msgly/plivo
Outbound

Global SMS and MMS with V3 signature verification

Telnyx

@msgly/telnyx
Outbound

Global SMS and MMS, Ed25519-signed webhooks

Dial

@msgly/dial
Policy-gated

Agent-provisioned numbers — SMS, MMS and iMessage with HMAC-signed webhooks

Genesys SMS

@msgly/genesys-sms
No campaigns

Genesys Cloud CX contact-center SMS, OAuth2 client-credentials, JSON notification webhooks

Twilio Voice

@msgly/twilio-voice

TwiML flows, Gather input and outbound calls

Reddit

@msgly/reddit
Broadcast

Subreddit posts, thread replies and inbox polling

TikTok

@msgly/tiktok
Broadcast

Video and photo publishing, comment replies and DMs

FCM

@msgly/fcm
Outbound

Push to Android, iOS and web, plus topic broadcast

APNs

@msgly/apns
Outbound

Apple push direct — iOS, macOS and Safari, no Firebase in the path

Web Push

@msgly/web-push
Outbound

Browser notifications over VAPID, encrypted per subscription

Expo Push

@msgly/expo-push
Outbound

React Native push via Expo, with ticket and receipt tracking

RCS

@msgly/rcs-twilio
Policy-gated

Branded rich cards and suggestion chips via Twilio, with SMS fallback

Plivo Voice

@msgly/plivo-voice
No campaigns

IVR and outbound calls, sharing the Plivo SMS credentials

Vonage Voice

@msgly/vonage-voice
No campaigns

NCCO-driven IVR and outbound calls

Exotel Voice

@msgly/exotel-voice
No campaigns

India click-to-call and App Bazaar flow dialling

Genesys Voice

@msgly/genesys-voice
No campaigns

Genesys Cloud CX telephony via the Conversations API — no inline IVR markup

Core

@msgly/core

Hub, adapter contract, retries, storage, campaigns

No adapter for LinkedIn or X/Twitter DM.

Neither has a usable API for this — LinkedIn's messaging API is partner-gated, and automating the web UI violates their terms and gets accounts banned. iMessage is reachable through @msgly/dial, on a Dial-provisioned number.

What each channel can actually carry

Capabilities are not uniform, and pretending otherwise is how a send fails in production. Every adapter declares what it supports; the hub refuses anything else up front.

ContentInteractiveConversation
Channeltextimagevideoaudiofilebuttonsquick replieslistscta urlcardstemplatesreactionstyping
Telegram@msgly/telegramtext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions supportedtyping supported
WhatsApp@msgly/whatsapptext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies supportedlists supportedcta url supportedcards not supportedtemplates supportedreactions supportedtyping supported
Messenger@msgly/messengertext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping supported
Instagram@msgly/instagramtext supportedimage supportedvideo supportedaudio not supportedfile not supportedbuttons not supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions supportedtyping supported
LINE@msgly/linetext supportedimage supportedvideo supportedaudio supportedfile not supportedbuttons supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping supported
Discord@msgly/discordtext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Microsoft Teams@msgly/msteamstext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping supported
Slack@msgly/slacktext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
WeChat@msgly/wechattext supportedimage supportedvideo supportedaudio supportedfile not supportedbuttons not supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Viber@msgly/vibertext supportedimage supportedvideo supportedaudio not supportedfile supportedbuttons supportedquick replies supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Mattermost@msgly/mattermosttext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions supportedtyping not supported
Rocket.Chat@msgly/rocketchattext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions supportedtyping not supported
Google Chat@msgly/googlechattext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Gmail@msgly/gmailtext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Outlook / M365@msgly/outlooktext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
SMTP / IMAP@msgly/smtptext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Resend@msgly/resendtext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Mailgun@msgly/mailguntext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Postmark@msgly/postmarktext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
SendGrid@msgly/sendgridtext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Amazon SES@msgly/sestext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Twilio SMS@msgly/twilio-smstext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Exotel@msgly/exoteltext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
MSG91@msgly/msg91text supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates supportedreactions not supportedtyping not supported
Vonage@msgly/vonage-smstext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Plivo@msgly/plivotext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Telnyx@msgly/telnyxtext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Dial@msgly/dialtext supportedimage supportedvideo supportedaudio supportedfile supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions supportedtyping supported
Genesys SMS@msgly/genesys-smstext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Twilio Voice@msgly/twilio-voicetext supportedimage not supportedvideo not supportedaudio supportedfile not supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Reddit@msgly/reddittext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
TikTok@msgly/tiktoktext supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
FCM@msgly/fcmtext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
APNs@msgly/apnstext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Web Push@msgly/web-pushtext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Expo Push@msgly/expo-pushtext supportedimage supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
RCS@msgly/rcs-twiliotext supportedimage supportedvideo supportedaudio not supportedfile supportedbuttons supportedquick replies supportedlists not supportedcta url supportedcards supportedtemplates supportedreactions not supportedtyping not supported
Plivo Voice@msgly/plivo-voicetext supportedimage not supportedvideo not supportedaudio supportedfile not supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Vonage Voice@msgly/vonage-voicetext supportedimage not supportedvideo not supportedaudio supportedfile not supportedbuttons supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Exotel Voice@msgly/exotel-voicetext not supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported
Genesys Voice@msgly/genesys-voicetext not supportedimage not supportedvideo not supportedaudio not supportedfile not supportedbuttons not supportedquick replies not supportedlists not supportedcta url not supportedcards not supportedtemplates not supportedreactions not supportedtyping not supported

Generated at build time by constructing every adapter and reading the capabilities object it reports — not a hand-maintained table. The hub checks these before sending and throws UnsupportedFeature rather than silently degrading.

60-second quickstart

From zero to a live bot.

Start with Telegram — the easiest channel. No business verification, no Meta App, no Pages. You need Node.js 20+ and a Telegram account.

01

Install

Only the channels you actually need.

npm install @msgly/core @msgly/telegram
02

Get a bot token

Message @BotFather on Telegram, send /newbot, copy the token. No business verification, no Meta App.

TELEGRAM_BOT_TOKEN=123456789:ABC-DEF...
TELEGRAM_WEBHOOK_SECRET=any-random-string
03

Register and connect

Credentials are verified at boot, so bad tokens fail fast with an actionable hint.

const hub = createHub();
hub.register(createTelegramAdapter({
  botToken: process.env.TELEGRAM_BOT_TOKEN!,
  webhookSecret: process.env.TELEGRAM_WEBHOOK_SECRET!,
}));
await hub.connect({ throwOnFailure: true });
04

Go live

Expose port 3000 with ngrok, register the webhook URL with Telegram, and send your bot a message.

ngrok http 3000

Features in detail

The unglamorous parts, already done.

Signature verification, exponential backoff, duplicate webhooks, per-platform size caps — the work that makes a messaging integration production-ready rather than demo-ready.

Startup credentials check

Every adapter ships verifyCredentials(). hub.connect() calls the platform whoami endpoint for each channel and returns either confirmation or a precise hint — which env var, where to find it, how to regenerate.

boot.ts
const report = await hub.connect();
// telegram → ok: '@my_bot'
// whatsapp → unauthorized (+ hint)

// Or fail fast when booting:
await hub.connect({
  throwOnFailure: true,
});

One webhook handler, every channel

hub.createWebhookHandler() returns { get, post } for any Express-like framework: Meta GET handshake, per-platform HMAC signature verification, channel dispatch and idempotent de-duplication by externalId.

server.ts
const wh = hub.createWebhookHandler();

app.get('/webhook/:channel', wh.get);
app.post('/webhook/:channel', wh.post);

Smart retry

Transient failures retry with exponential backoff and jitter. Permanent failures — bad credentials, invalid recipients — fail immediately instead of burning your rate limit.

hub.ts
const hub = createHub({
  retry: {
    attempts: 4,
    baseDelayMs: 250,
  },
});

State persistence

Bring any KV store — Redis, DynamoDB, Cloudflare KV. The hub uses it for idempotency keys, conversation state and suppression, so restarts and multiple instances stay consistent.

hub.ts
const hub = createHub({
  storage: redisStorage(redisClient),
});

Capability checks

Ask before you send. Channels differ on attachments, buttons, templates and reactions — msgly answers up front rather than failing at the API boundary.

react.ts
const can = hub.supports(
  'telegram', 'reaction',
);

if (can) {
  await hub.react({ /* ... */ });
}

Platform limits enforced

Text length caps, attachment size and MIME restrictions are validated locally before the request goes out, so you get a clear error instead of an opaque platform rejection.

limits.ts
// 4096 chars on Telegram,
// 1600 on SMS — both checked
// before the network call.
await hub.send({ /* ... */ });

Campaigns

Send to many, without getting throttled.

hub.sendBulk() fans one message out to a contact list, paced to the channel's rate limit. One bad recipient never aborts the campaign: it resolves rather than rejecting, and result.results comes back in input order so you can zip it against your own list.

Conservative per-channel defaults ship built in (Slack 1/s, Twilio long code 1/s, Gmail ~2/s, Discord 5/s, Telegram 25/s, WhatsApp 60/s), overridable per call, per adapter or per hub. Cancelling via signal gives you partial results instead of throwing them away.

campaign.ts
const result = await hub.sendBulk({
  channel: 'whatsapp',
  account: { channel: 'whatsapp', channelAccountId: process.env.WA_PHONE_ID! },
  recipients: customers.map((c) => ({
    contact: { channel: 'whatsapp', channelUserId: c.phone },
    metadata: { crmId: c.id },
  })),
  // A function, so every recipient gets their own template variables:
  content: (r) => ({
    type: 'template',
    templateName: 'order_update',
    language: 'en_US',
    variables: { '1': nameFor(r.contact), '2': orderFor(r.contact) },
  }),
  concurrency: 8,
  onProgress: (p) => console.log(`${p.completed}/${p.total}`),
  signal: AbortSignal.timeout(60_000),
});

console.log(`sent ${result.sent}, failed ${result.failed}`);

Which channels suit campaigns

Built for outbound

SES, SMTP, Resend, SendGrid, Twilio SMS, Exotel, MSG91, Vonage, Plivo, Telnyx, FCM

Email, SMS and push, fanned out per recipient. Honour opt-outs.

Native broadcast

LINE, WeChat, Viber, Telegram, FCM topics

One API call reaches the whole audience — no per-recipient fan-out.

Feed publishing

Instagram, Facebook Pages, Reddit, TikTok

publishPost() puts a post on the feed. No recipient, so it sits outside send().

Policy-gated

WhatsApp

Real campaign channel, but needs approved MARKETING templates and opt-in.

Reply-only DMs

Messenger, Instagram DMs

24h window and message tags only — no DM marketing broadcast.

Not campaign channels

Slack, Teams, Discord, Mattermost, Rocket.Chat, Google Chat

The recipient is a room, not a person. Post to a channel instead.

Broadcast

Some channels don't need fan-out at all.

LINE, WeChat, Viber and Telegram have a real broadcast primitive: one API call reaches the entire audience, with no per-recipient cost and no rate-limit pacing to worry about. Reaching 100,000 LINE friends is a single request, not 100,000 of them.

Instagram and Facebook are different again — publishPost() puts a post on the feed. A post has no recipient, so it deliberately sits outside send() rather than pretending to be a message.

broadcast.ts
// LINE: one call reaches every friend — no fan-out, no per-recipient cost
await line.broadcast(
  { type: 'text', text: 'Sale starts now' },
  { retryKey: 'spring-sale-2026' },   // a timeout cannot double-send
);

// WeChat: all followers, or one tag group. Metered at 4/month.
await wechat.massSend({ type: 'text', text: 'New arrivals' }, { tagId: 7 });

// Viber: up to 300 subscribers per call, with per-recipient failures returned
const r = await viber.broadcast(ids, { type: 'text', text: 'Sale' });
r.metadata?.failed; // [{ id, status }] — feed these to the suppression store

// Telegram: a channel is just another chat id
await hub.send({
  channel: 'telegram',
  contact: { channel: 'telegram', channelUserId: '@acme_announcements' },
  content: { type: 'text', text: 'Shipped v2' },
  account: { channel: 'telegram', channelAccountId: 'acme_bot' },
});

// Instagram / Facebook: publishing, not messaging
await instagram.publishPost({
  imageUrl: 'https://cdn.acme.com/promo.jpg',
  caption: 'Spring sale is live',
});

Compliance

Opt-outs are not optional.

sendBulk consults a SuppressionStore before every send — required by TCPA and TRAI/DLT for SMS, and CAN-SPAM and GDPR for email. Suppressed recipients come back as skipped, never failed, and cost no rate limit.

If the store is unreachable the send is skipped rather than sent: not sending is the recoverable mistake. Only permanent failures suppress — a deferral or a full mailbox is left alone. Email adapters also emit the List-Unsubscribe header Gmail and Yahoo have required from bulk senders since February 2024.

suppression.ts
import { createHub, createInMemorySuppressionStore, applyConsentIntent } from '@msgly/core';

const suppression = createInMemorySuppressionStore(); // use a KV store in production
const hub = createHub({ suppressionStore: suppression });

// Capture STOP / UNSUBSCRIBE replies automatically
hub.on('message', (msg) => applyConsentIntent(msg, suppression));

// Hard bounces and spam complaints suppress themselves
hub.on('delivery', (r) => applyDeliveryReceipt(r, 'resend', suppression));

const result = await hub.sendBulk({ /* ... */ });
console.log(result.sent, result.skipped); // skipped = opted out

Architecture

Four layers, clean contracts.

Adding a new channel is one new package — no core changes needed. You own the top layer, the platforms own the bottom, and the two in between are the only ones msgly asks you to think about.

Your appExpress · worker@msgly/corehub · retriesAdapterone packagePlatform APITelegram · TwilioCustomerphone · inboxsend() — outboundhandleWebhook() — inbound
Your appyours

Express, Fastify, Next.js route handlers, a worker — anything that can receive an HTTP POST.

↓ send↑ receive
@msgly/coremsgly

Unified types, the MessagingHub orchestrator, retries, idempotency, capability checks, rate limiting, storage and suppression.

↓ send↑ handleWebhook
Channel adaptersmsgly · 41 packages

One package per platform. Each implements the same Adapter interface and ships its own verifyCredentials().

↓ HTTP↑ webhooks
Platform APIstheirs

Telegram, Meta, LINE, Twilio, Google, Microsoft, AWS, Firebase and the rest.

Install

Ship your first channel today.

Install only the channels you need. Everything is MIT licensed and TypeScript-native.

npm install @msgly/core @msgly/whatsapp @msgly/telegram @msgly/twilio-sms