wi-api
v0.1.2
Published
Official Node.js SDK for the wi-api WhatsApp platform
Maintainers
Readme
wi-api Node.js SDK
Node.js and TypeScript SDK for wi-api. Send and receive WhatsApp messages in a few lines of code.
Works on Node 18+, Bun, Deno, and Cloudflare Workers. No runtime dependencies.
Install
npm install wi-apibun add wi-apipnpm add wi-apiQuick start
import { Wi } from "wi-api"
const wi = new Wi({ apiKey: process.env.WI_API_KEY! })
const msg = await wi.session("my-instance").sendText({
to: "5511999999999",
text: "Hello from wi-api",
})
console.log(msg.messageId)Sessions
const session = wi.session("my-instance")
// Start the connection flow
await session.connect()
// Poll for QR code (base64 PNG)
const { qr } = await session.qr()
// Or pair by phone number
const { pairCode } = await session.pairPhone("5511999999999")
// Check status
const { connected, phone } = await session.status()
await session.disconnect() // keeps session keys
await session.logout() // removes session keysSending messages
// Text
await session.sendText({ to: "5511999999999", text: "Hello!" })
// Reply
await session.sendText({ to: "5511999999999", text: "Got it", quoted: messageId })
// Image
await session.sendImage({ to: "5511999999999", url: "https://example.com/photo.jpg", caption: "Look" })
// Voice note
await session.sendAudio({ to: "5511999999999", url: "https://example.com/audio.ogg", ptt: true })
// Document
await session.sendDocument({ to: "5511999999999", url: "https://example.com/file.pdf", filename: "report.pdf" })
// Location
await session.sendLocation({ to: "5511999999999", latitude: -23.5505, longitude: -46.6333 })
// Poll
await session.sendPoll({ to: "5511999999999", question: "Best stack?", options: ["Bun", "Node", "Deno"] })
// Reaction
await session.react({ to: "5511999999999", messageId, emoji: "" })Webhooks
wi-api signs every webhook payload with x-wi-signature: sha256=<hex>.
import { createWebhookHandler } from "wi-api"
// Next.js App Router
export const POST = createWebhookHandler({
secret: process.env.WI_WEBHOOK_SECRET!,
async onMessage({ data }) {
console.log(data.from, data.text)
},
async onConnected({ data }) {
console.log("connected:", data.phone)
},
})// Hono / Elysia / any Web API runtime
const handler = createWebhookHandler({ secret: "...", onMessage: ... })
app.post("/webhook", (c) => handler(c.req.raw))Verify manually:
import { verifyWebhookSignature, parseWebhookEvent } from "wi-api"
const valid = await verifyWebhookSignature(rawBody, req.headers["x-wi-signature"], secret)
if (!valid) return new Response(null, { status: 401 })
const event = parseWebhookEvent(rawBody)Error handling
import { WiError } from "wi-api"
try {
await session.sendText({ to: "5511999999999", text: "Hello" })
} catch (err) {
if (err instanceof WiError) {
console.error(err.status, err.message)
}
}Configuration
const wi = new Wi({
apiKey: process.env.WI_API_KEY!,
baseUrl: "https://endpoint.wi.api.br", // default
timeout: 30_000, // ms, default 30s
})