Plan and run campaigns
Use a configured WhatsAppClient from Install and verify. Examples below assume it is named whatsapp. Application callbacks such as db, myDatabase, and queue are supplied by your app; fileBlob is the Blob you intend to upload.
Campaigns
Campaigns are side-effect-free until you call run. You bring the database, queue, and logging.
const plan = whatsapp.campaigns.createPlan({
template: {
name: "order_update",
language: { code: "en_US" },
},
recipients: [
{ id: "1", phone: "201234567890", lastContactedAt: Date.now() - 48 * 60 * 60 * 1000 },
{ id: "2", phone: "201111111111", lastContactedAt: Date.now() },
],
rules: {
messagesPerSecond: 10,
skipRecentlyContacted: true,
recentContactWindowMs: 24 * 60 * 60 * 1000,
maxRetries: 3,
},
});
const summary = await whatsapp.campaigns.run(plan, {
async logResult(result) {
await db.campaignLogs.insert(result);
},
async markContacted(recipient, timestamp) {
await db.contacts.update(recipient.id, { lastContactedAt: timestamp });
},
});Bring Your Own Database
This package intentionally does not ship database tables or storage assumptions. Use adapters and callbacks to connect your own stack:
await whatsapp.campaigns.run(plan, {
sendTemplate: (recipient, template) => whatsapp.messages.sendTemplate(recipient.phone, template),
logResult: (result) => myDatabase.writeCampaignResult(result),
markContacted: (recipient, timestamp) => myDatabase.updateContact(recipient.id, { timestamp }),
wait: (ms) => queue.sleep(ms),
});Webhook handlers follow the same model: save inbound messages, statuses, media IDs, and template updates wherever your application stores them.
Execution boundary
createPlan prepares work without sending messages. run executes sends. The package does not provide durable queue storage or database transactions. Persist results and contact timestamps in the callbacks, and make your application’s retry processing idempotent.
Source captured: 2026-10-11