
Research
/Security News
OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.
callmebot-notifier
Advanced tools
Typed notification library for Node.js with WhatsApp, Telegram, Signal, Email, Discord, Slack, Google Chat, and Microsoft Teams.
Multi-channel notification delivery for Node.js. Send alerts to WhatsApp, Telegram, Web Push, Discord, Slack, Teams, Google Chat and Email with retry, fallback and severity routing.
CallMeBot is not the official WhatsApp API. Use this package for personal and low-risk notifications.
Use HTTP-only entrypoints for Cloudflare Workers, edge runtimes, and serverless environments:
import { whatsapp } from "callmebot-notifier/whatsapp";
import { telegram } from "callmebot-notifier/telegram";
import { telegram } from "callmebot-notifier/telegram";
export default {
async fetch(_request: Request, env: { TELEGRAM_BOT_TOKEN: string; TELEGRAM_CHAT_ID: string }) {
const channel = telegram({
botToken: env.TELEGRAM_BOT_TOKEN,
chatId: env.TELEGRAM_CHAT_ID
});
await channel.send("Hello from Cloudflare Workers");
return new Response("sent");
}
};
Additional entrypoints are available from callmebot-notifier/core, /email, /webpush, and /express.
The email, webpush, and express entrypoints are Node-specific.
The root import remains fully supported for backward compatibility.
You can buy me a coffee or two if you find helpfull my node.
If you buy me a coffee I would like to thank you in advance for your donation.
signal-cli-rest-api)| Feature | Supported |
|---|---|
| WhatsApp via CallMeBot | Yes |
| Telegram | Yes |
| Web Push | Yes |
| Discord | Yes |
| Slack | Yes |
| Google Chat | Yes |
| Microsoft Teams | Yes |
| Signal via signal-cli | Yes |
| Yes | |
| Retry | Yes |
| Fallback | Yes |
| Severity routing | Yes |
| Templates | Yes |
| Express API | Yes |
| GitHub Action | Yes |
npm install callmebot-notifier
PHONE=393331112223
APIKEY=your-callmebot-apikey
TELEGRAM_BOT_TOKEN=1234567980:XXXX5x0XX2XxxXxx1XXXxxXxXXxXX6X-Tho
TELEGRAM_CHAT_ID=990099009
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
GCHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/.../messages?key=...&token=...
TEAMS_WEBHOOK_URL=https://...
SIGNAL_API_URL=http://localhost:8080
SIGNAL_NUMBER=+391234567890
SIGNAL_RECIPIENTS=+399876543210
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=tuoindirizzo@gmail.com
SMTP_PASS=xxxx xxxx xxxx xxxx
EMAIL_FROM=tuoindirizzo@gmail.com
EMAIL_TO=destinatario@dominio.com
import { fromEnv } from "callmebot-notifier";
const notifier = fromEnv();
await notifier.send("Deployment done");
notify()import { notify, whatsapp, telegram } from "callmebot-notifier";
await notify({
channels: [
whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" }),
telegram({
botToken: process.env.TELEGRAM_BOT_TOKEN ?? "",
chatId: process.env.TELEGRAM_CHAT_ID ?? ""
})
],
message: "Server is down"
});
Create VAPID keys once, keep private key server-side, and store each browser subscription in your application database. Then pass one subscription to webpush():
import { webpush } from "callmebot-notifier";
const channel = webpush({
subscription, // Browser PushSubscription serialized with JSON.stringify()
vapidDetails: {
subject: "mailto:alerts@example.com",
publicKey: process.env.VAPID_PUBLIC_KEY ?? "",
privateKey: process.env.VAPID_PRIVATE_KEY ?? ""
},
ttl: 60,
urgency: "high"
});
await channel.send("Deployment complete");
See Web Push setup for browser subscription and service-worker setup.
import { notify, whatsapp, telegram } from "callmebot-notifier";
await notify({
primary: whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" }),
fallback: telegram({
botToken: process.env.TELEGRAM_BOT_TOKEN ?? "",
chatId: process.env.TELEGRAM_CHAT_ID ?? ""
}),
message: "Server is down"
});
import { notify, whatsapp, telegram, email, gchat, teams } from "callmebot-notifier";
await notify({
routes: {
info: [
telegram({
botToken: process.env.TELEGRAM_BOT_TOKEN ?? "",
chatId: process.env.TELEGRAM_CHAT_ID ?? ""
})
],
warn: [gchat({ webhookUrl: process.env.GCHAT_WEBHOOK_URL ?? "" })],
critical: [
whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" }),
teams({ webhookUrl: process.env.TEAMS_WEBHOOK_URL ?? "" }),
email({
host: process.env.SMTP_HOST ?? "",
port: Number(process.env.SMTP_PORT || 587),
secure: process.env.SMTP_SECURE === "true",
user: process.env.SMTP_USER ?? undefined,
pass: process.env.SMTP_PASS ?? undefined,
from: process.env.EMAIL_FROM ?? "",
to: process.env.EMAIL_TO ?? ""
})
]
},
message: {
title: "CPU high",
message: "Load spike on api-1",
severity: "critical"
}
});
import { notify, whatsapp } from "callmebot-notifier";
await notify.alert(
{
title: "Deploy",
message: "Application deployed",
source: "GitHub Actions"
},
{
channels: [whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" })]
}
);
await notify.incident(
{
title: "Database down",
message: "Primary DB unavailable",
source: "api"
},
{
channels: [whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" })]
}
);
import { notify, whatsapp, telegram, email } from "callmebot-notifier";
await notify({
channels: [
whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" }),
telegram({
botToken: process.env.TELEGRAM_BOT_TOKEN ?? "",
chatId: process.env.TELEGRAM_CHAT_ID ?? ""
}),
email({
host: process.env.SMTP_HOST ?? "",
port: Number(process.env.SMTP_PORT || 587),
secure: process.env.SMTP_SECURE === "true",
user: process.env.SMTP_USER ?? undefined,
pass: process.env.SMTP_PASS ?? undefined,
from: process.env.EMAIL_FROM ?? "",
to: process.env.EMAIL_TO ?? ""
})
],
message: "Build failed",
retry: { attempts: 3, delayMs: 1000 }
});
import { notify, whatsapp } from "callmebot-notifier";
const channel = whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" });
await notify({
channels: [channel],
message: "Release done",
logLevel: "info",
onResult: (result) => {
console.log("notify.result", result);
},
onError: (error, context) => {
console.error("notify.error", { error, ...context });
}
});
import { createExpressApp, FallbackChannel, whatsapp, telegram } from "callmebot-notifier";
const app = createExpressApp(
new FallbackChannel([
whatsapp({ phone: process.env.PHONE ?? "", apikey: process.env.APIKEY ?? "" }),
telegram({
botToken: process.env.TELEGRAM_BOT_TOKEN ?? "",
chatId: process.env.TELEGRAM_CHAT_ID ?? ""
})
])
);
app.listen(3000);
Use published action:
- uses: F3rr1gn0/callmebot-notifier-action@v1
with:
message: "Build done"
channel: "telegram"
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
Secrets to set in consumer repo:
TELEGRAM_BOT_TOKEN
TELEGRAM_CHAT_ID
PHONE
APIKEY
DISCORD_WEBHOOK_URL
SLACK_WEBHOOK_URL
GCHAT_WEBHOOK_URL
TEAMS_WEBHOOK_URL
SMTP_HOST
SMTP_PORT
SMTP_SECURE
SMTP_USER
SMTP_PASS
EMAIL_FROM
EMAIL_TO
Smoke flow:
name: smoke-action
on:
workflow_dispatch:
jobs:
smoke:
runs-on: ubuntu-latest
steps:
- uses: F3rr1gn0/callmebot-notifier-action@v1
with:
message: "Smoke from GitHub Action"
channel: "telegram"
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
Failure flow:
name: smoke-action-failure
on:
workflow_dispatch:
jobs:
smoke:
runs-on: ubuntu-latest
steps:
- run: exit 1
- if: ${{ failure() }}
uses: F3rr1gn0/callmebot-notifier-action@v1
with:
message: "Build failed"
channel: "telegram"
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
Expose send_notification to Claude Desktop, Cursor, or another MCP client:
Common variables:
PHONEAPIKEYTELEGRAM_BOT_TOKENTELEGRAM_CHAT_IDVAPID_PUBLIC_KEYVAPID_PRIVATE_KEYDISCORD_WEBHOOK_URLSLACK_WEBHOOK_URLGCHAT_WEBHOOK_URLTEAMS_WEBHOOK_URLSIGNAL_API_URLSIGNAL_NUMBERSIGNAL_RECIPIENTSSMTP_HOSTSMTP_PORTSMTP_SECURESMTP_USERSMTP_PASSEMAIL_FROMEMAIL_TOnotify() returns:
type NotifyResult = {
ok: boolean;
deliveredBy?: string;
attempts: Array<{
channel: string;
ok: boolean;
attempt: number;
error?: string;
}>;
};
Helper:
import { summarizeNotifyResult } from "callmebot-notifier";
const summary = summarizeNotifyResult(result);
404 or 410fromEnv() is the quickest way to bootstrap a notifier from environment variablesnpm run test:coverageMIT
FAQs
Typed notification library for Node.js with WhatsApp, Telegram, Signal, Email, Discord, Slack, Google Chat, and Microsoft Teams.
The npm package callmebot-notifier receives a total of 29 weekly downloads. As such, callmebot-notifier popularity was classified as not popular.
We found that callmebot-notifier demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Ten malicious OpenAPI React Query Codegen versions were published to npm in the Mini Shai-Hulud attack, all with valid provenance.

Security News
Socket joins more than 100 technology, cybersecurity, and financial organizations calling for a global surge in cyber defense.

Product
Enterprise security teams can now detect malware, credential theft, suspicious network activity, and risky updates across Microsoft Edge extensions.