Saltar al contenido principal

Cómo Programar Mensajes de WhatsApp con Node.js Cómo Programar Mensajes de WhatsApp con Node.js

Cómo Programar Mensajes de WhatsApp con Node.js

WhatsApp no tiene una API de programación incorporada, pero puedes construir una con whatsmeow-node y herramientas estándar de programación de Node.js — setTimeout para delays únicos, node-cron para mensajes recurrentes, o una cola respaldada por base de datos para persistencia.

Requisitos Previos

  • Una sesión vinculada de whatsmeow-node (Cómo Vincular)
  • Para programaciones recurrentes: npm install node-cron

Enviar un Mensaje Diferido

El enfoque más simple — envía un mensaje después de un delay:

function sendLater(jid: string, message: string, delayMs: number) {
setTimeout(async () => {
await client.sendMessage(jid, { conversation: message });
console.log(`Sent scheduled message to ${jid}`);
}, delayMs);
}

// Send in 30 minutes
sendLater("5512345678@s.whatsapp.net", "Time's up!", 30 * 60 * 1000);

Programar a una Hora Específica

Calcula el delay desde ahora hasta la hora objetivo:

function sendAt(jid: string, message: string, date: Date) {
const delay = date.getTime() - Date.now();

if (delay <= 0) {
console.error("Scheduled time is in the past");
return;
}

console.log(`Scheduled for ${date.toLocaleString()} (in ${Math.round(delay / 1000)}s)`);

setTimeout(async () => {
await client.sendMessage(jid, { conversation: message });
}, delay);
}

// Send tomorrow at 9 AM
const tomorrow9am = new Date();
tomorrow9am.setDate(tomorrow9am.getDate() + 1);
tomorrow9am.setHours(9, 0, 0, 0);

sendAt("5512345678@s.whatsapp.net", "Good morning! Don't forget the meeting at 10.", tomorrow9am);

Configurar Mensajes Recurrentes con Cron

Usa node-cron para programaciones recurrentes:

npm install node-cron
import cron from "node-cron";

// Every weekday at 8:55 AM — "standup in 5 minutes"
cron.schedule("55 8 * * 1-5", async () => {
const groupJid = "120363XXXXX@g.us";
await client.sendMessage(groupJid, {
conversation: "Standup in 5 minutes!",
});
});

// Every Monday at 9 AM — weekly report
cron.schedule("0 9 * * 1", async () => {
const reportChat = "5512345678@s.whatsapp.net";
await client.sendMessage(reportChat, {
conversation: "Weekly report is ready: https://example.com/reports/latest",
});
});

// First day of every month — billing reminder
cron.schedule("0 10 1 * *", async () => {
const billingGroup = "120363YYYYY@g.us";
await client.sendMessage(billingGroup, {
conversation: "Reminder: invoices are due by the 5th",
});
});
Sintaxis cron

node-cron usa el formato estándar de cron: minuto hora día-del-mes mes día-de-la-semana. Usa crontab.guru para construir expresiones.

Crear un Programador para Usuarios

Permite que los usuarios programen recordatorios vía comandos de WhatsApp:

client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;

const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (!text?.startsWith("!remind")) return;

// Parse: !remind 30m Take a break
const match = text.match(/^!remind\s+(\d+)(m|h|s)\s+(.+)$/);
if (!match) {
await client.sendMessage(info.chat, {
conversation: "Usage: !remind <number><m|h|s> <message>\nExample: !remind 30m Take a break",
});
return;
}

const [, amount, unit, reminder] = match;
const multiplier = { s: 1000, m: 60_000, h: 3_600_000 }[unit]!;
const delayMs = parseInt(amount) * multiplier;

setTimeout(async () => {
await client.sendRawMessage(info.chat, {
extendedTextMessage: {
text: `Reminder: ${reminder}`,
contextInfo: {
mentionedJid: [info.sender],
},
},
});
}, delayMs);

const delayText = `${amount}${unit}`;
await client.sendMessage(info.chat, {
conversation: `Got it! I'll remind you in ${delayText}: "${reminder}"`,
});
});

Ejemplo Completo

Un bot programador con comandos !remind y un cron diario:

import { createClient } from "@whatsmeow-node/whatsmeow-node";
import cron from "node-cron";

const client = createClient({ store: "session.db" });

// Daily standup reminder
cron.schedule("55 8 * * 1-5", async () => {
const group = "120363XXXXX@g.us";
await client.sendMessage(group, {
conversation: "Standup in 5 minutes!",
});
});

// User-facing !remind command
client.on("message", async ({ info, message }) => {
if (info.isFromMe) return;

const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
if (!text?.startsWith("!remind")) return;

const match = text.match(/^!remind\s+(\d+)(m|h|s)\s+(.+)$/);
if (!match) {
await client.sendMessage(info.chat, {
conversation: "Usage: !remind <number><m|h|s> <message>\nExample: !remind 30m Take a break",
});
return;
}

const [, amount, unit, reminder] = match;
const multiplier = { s: 1000, m: 60_000, h: 3_600_000 }[unit]!;
const delayMs = parseInt(amount) * multiplier;

setTimeout(async () => {
await client.sendRawMessage(info.chat, {
extendedTextMessage: {
text: `Reminder: ${reminder}`,
contextInfo: {
mentionedJid: [info.sender],
},
},
});
}, delayMs);

await client.sendMessage(info.chat, {
conversation: `I'll remind you in ${amount}${unit}: "${reminder}"`,
});
});

async function main() {
const { jid } = await client.init();
if (!jid) {
console.error("Not paired!");
process.exit(1);
}
await client.connect();
await client.sendPresence("available");
console.log("Scheduler bot is online!");

process.on("SIGINT", async () => {
await client.sendPresence("unavailable");
await client.disconnect();
client.close();
process.exit(0);
});
}

main().catch(console.error);

Errores Comunes

Las programaciones en memoria se pierden al reiniciar

Las programaciones de setTimeout y node-cron viven en memoria. Si el proceso se reinicia, los recordatorios pendientes se pierden. Para producción, persiste las programaciones en una base de datos y recárgalas al iniciar.

Zonas horarias

node-cron usa la zona horaria del servidor por defecto. Configúrala explícitamente con la opción timezone si tus usuarios están en diferentes zonas horarias: cron.schedule("0 9 * * *", fn, { timezone: "America/Sao_Paulo" }).

Límites de tasa

Si un cron job envía a muchos destinatarios, espacia los envíos. Consulta Límites de Tasa.