Getting started
Configuration
Everything the Whatsapp constructor accepts, runtime token management, rate limit monitoring, and multi-tenant setup.
import { Whatsapp } from "wapi-cloud";
const whatsapp = new Whatsapp({
accessToken: process.env.WA_TOKEN!,
phoneNumberId: process.env.WA_PHONE_ID!,
businessAccountId: process.env.WA_WABA_ID,
appId: process.env.WA_APP_ID,
appSecret: process.env.WA_APP_SECRET,
businessId: process.env.WA_BUSINESS_ID,
apiVersion: "v21.0",
maxRetries: 3,
timeoutMs: 15000,
onRequest: ({ method, url }) => {
console.log("[WA API]", method, url);
},
onResponse: ({ method, url, status }) => {
console.log("[WA API]", method, url, "→", status);
},
});Constructor options
| Parameter | Type | Description |
|---|---|---|
| accessToken* | string | Permanent or System User access token with whatsapp_business_messaging and whatsapp_business_management permissions. |
| phoneNumberId* | string | Default Phone Number ID used for sending messages and uploading media. |
| businessAccountId | string | WhatsApp Business Account (WABA) ID. Required for templates, flows, qrCodes, analytics, and phoneNumbers.list(). |
| appSecret | string | Meta App Secret. Required for webhook signature verification (X-Hub-Signature-256) and Embedded Signup code exchange. |
| appId | string | Meta App ID. Required for Embedded Signup code exchange and script generation. |
| businessId | string | Meta Business Manager ID. Required only for whatsapp.catalogs.list(). Distinct from businessAccountId. |
| apiVersion | string | Graph API version to target (e.g. "v21.0"). Defaults to a pinned stable version. |
| baseUrl | string | Base Graph API URL. Defaults to "https://graph.facebook.com". Useful for mocking or proxying requests. |
| fetch | typeof fetch | Custom fetch implementation (e.g. undici, node-fetch, or a testing stub). |
| maxRetries | number | Maximum automatic retries with exponential backoff and jitter for 429 rate limits and 5xx server errors. Default: 3. |
| timeoutMs | number | Per-request timeout in milliseconds before failing with a TimeoutError. Default: 15000. |
| onRequest | (info) => void | Optional callback invoked before each HTTP request for logging/tracing. |
| onResponse | (info) => void | Optional callback invoked after each HTTP response for metrics/logging. |
Runtime token management
If you rotate or refresh access tokens dynamically (e.g. using short-lived tokens), you can swap in a new token on an existing client instance without creating a new object:
// Update token on the fly
whatsapp.setAccessToken(freshlyRefreshedToken);Rate limit monitoring
The Graph API returns business use-case usage headers on responses. You can inspect the last seen header value at any time:
const usageHeader = whatsapp.getRateLimitStatus();
if (usageHeader) {
console.log("Current rate limit header:", usageHeader);
}Partial configuration is supported
You don't need every option to start using wapi-cloud — only the modules you call check their corresponding config parameters. If you call a module that requires a missing value, it will not throw an exception; it returns a typed configuration error:
const whatsapp = new Whatsapp({
accessToken: process.env.WA_TOKEN!,
phoneNumberId: process.env.WA_PHONE_ID!,
// businessAccountId omitted
});
const { data, error } = await whatsapp.templates.list();
// data === null
// error.type === "ConfigError"
// error.message === "businessAccountId is required in the Whatsapp client config to use whatsapp.templates.*"accessToken and appSecret in secure environment variables or a secrets manager. Never expose them to client-side code.Multi-tenant applications
Because configuration is scoped per instance, you can safely create multiple Whatsapp instances in multi-tenant or agency setups:
export function getTenantClient(tenant: {
token: string;
phoneId: string;
wabaId: string;
}) {
return new Whatsapp({
accessToken: tenant.token,
phoneNumberId: tenant.phoneId,
businessAccountId: tenant.wabaId,
});
}