Send WhatsApp messages with Node.js
Node.js 18+ ships with fetch, so you can send WhatsApp messages without installing anything. Works with Express, NestJS, Next.js API routes and serverless functions.
Before you start
- Create a free account and copy your API key from Settings.
- Add a WhatsApp number and scan the QR code; copy its instance id.
- Replace
YOUR_API_KEYandYOUR_INSTANCE_IDin the examples below.
1. Setup
# Node.js 18+ β no packages needed
2. Send a WhatsApp text message with Node.js
The recipient goes in to with the country code (for India, 91 followed by the 10-digit number). The response contains the message id and status.
const API_KEY = "YOUR_API_KEY";
const INSTANCE_ID = "YOUR_INSTANCE_ID";
const BASE = "https://powerapiwa.com/api/v1";
const res = await fetch(`${BASE}/instances/${INSTANCE_ID}/send`, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ to: "919876543210", type: "text", message: "Hello from Node.js π" }),
});
const data = await res.json();
console.log(data.message.status); // "sent"
3. Send an image, PDF or location
Change the type: media_url for files from a URL, media for base64 uploads, location, poll or contact.
await fetch(`${BASE}/instances/${INSTANCE_ID}/send`, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
to: "919876543210",
type: "media_url",
url: "https://example.com/offer.jpg",
caption: "Weekend offer π",
}),
});
4. Receive messages with a webhook
Set your endpoint URL on the WhatsApp number in the dashboard. Always verify the X-PowerAPI-Signature header before trusting the payload.
import crypto from "node:crypto";
import express from "express";
const app = express();
const WEBHOOK_SECRET = "YOUR_WEBHOOK_SECRET";
// keep the raw body: the signature is computed over the exact bytes we sent
app.post("/whatsapp/webhook", express.raw({ type: "application/json" }), (req, res) => {
const expected = crypto.createHmac("sha256", WEBHOOK_SECRET).update(req.body).digest("hex");
const given = req.get("X-PowerAPI-Signature") || "";
if (given.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
if (event.event === "message") console.log(event.data.message.from, event.data.message.body);
res.json({ ok: true });
});
app.listen(3000);
Response and errors
Successful calls return {"success": true, ...}. Errors return {"success": false, "error": "..."} with a status code: 401 invalid key, 402 plan expired, 422 invalid payload, 429 daily limit reached. See the full API documentation.