The WhatsApp Business API, without the BSP runaround.
Official Meta Business Solution Provider since the API existed. Template approval, session windows, media, interactive messages — all handled. Two billion-plus monthly WhatsApp users, addressable from a single endpoint that looks like every other Bird channel.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.whatsapp.send({
to: "+15005550009",
template: "order_shipped",
locale: "en_US",
variables: {
customer_name: "Ada",
order_id: "BRD-49217",
tracking_url: "https://track.bird.dev/49217",
eta: "Thursday, May 21",
},
}).safe();
if (error) throw error;
console.log(data.id);
// → "wa_msg_8nB91Yk3p..."5 minutes from npm install to first send
Send a WhatsApp from the language you already use.
SDKs in every major runtime. The first send goes to a sanctioned test recipient (+15005550009) with a pre-approved template, so you can ship a CI check before you submit your first template for approval.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.whatsapp.send({
to: "+15005550009",
template: "hello_world",
locale: "en_US",
}).safe();Ten things the BSP gate hides from you. We don't.
WhatsApp is gated by Meta. The choice of BSP is whether the gates show up in your code or get smuggled into a dashboard. We chose code.
- 01
Official Meta Business Solution Provider (BSP)
Direct relationship with Meta since the API existed. No resold transit, no third-party hop.
- 02
Template management
Submit, track approval state, and get a webhook the moment Meta approves or rejects.
- 03
Session-window awareness
The SDK tells you whether free-form or template is allowed before you send.
- 04
Interactive messages
Buttons, lists, product cards, and WhatsApp Flows — declared in the same payload.
- 05
Media and rich content
Images, video, documents, location, contacts, link previews, reactions, and replies.
- 06
WhatsApp Flows
Multi-step in-app forms with backend validation, defined as JSON, executed by Meta.
- 07
Click-to-WhatsApp Ads
Integration with Meta Ads Manager so ad clicks land in a conversation you can answer.
- 08
Cross-channel fallback
Add fallback: "sms" to any send — session expiry routes through SMS automatically.
- 09
Inbound message webhooks
HMAC-signed events for inbound messages, read receipts, reactions, and template state.
- 10
2B+ users on one endpoint
Two billion-plus monthly WhatsApp users addressable from a single bird.whatsapp.send call.
Why we build WhatsApp
We were one of the first WhatsApp BSPs. We're still one of the few that ship code with you.
WhatsApp is gated. You need an approved template; you need an opted-in session window; you need a Meta business verification. That part doesn't change — and won't. What changes is whether your BSP makes those gates easier or harder to walk through — by exposing them in your code, on webhooks you can subscribe to, in errors that say exactly what's wrong. We chose the first.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.whatsapp.send({
to: "+15005550009",
template: "order_shipped",
locale: "en_US",
variables: {
customer_name: "Ada",
order_id: "BRD-49217",
tracking_url: "https://track.bird.dev/49217",
eta: "Thursday, May 21",
},
}).safe();
if (error) throw error;
console.log(data.id);
// → "wa_msg_8nB91Yk3p..."Every state change is a webhook.
HMAC-signed payloads, replay-protected, idempotent. The same envelope on every Bird channel — learn one, you've learned them all.
{
"type": "whatsapp.read",
"id": "evt_7kQ02v...",
"created_at": "2026-05-19T15:42:08.114Z",
"data": {
"wa_msg_id": "wa_msg_8nB91Yk3p",
"from": "+15551234567",
"to": "+15005550009",
"conversation_id": "wa_conv_3pX1g7t",
"template": "order_shipped",
"delivered_at": "2026-05-19T15:42:01.802Z",
"read_at": "2026-05-19T15:42:08.020Z"
}
}Retry schedule: 5s, 30s, 5m, 30m, 2h, 6h, 12h. Dead-letter after the final attempt; every dead-lettered event is replayable from the dashboard or API.
whatsapp.queuedAccepted by the API and queued for send to Meta.whatsapp.sentHanded off to Meta's Cloud API.whatsapp.deliveredMeta reports the message landed on the recipient's device.whatsapp.readRecipient opened the message (if read receipts are on).whatsapp.failedPermanent failure — reason code in the payload.whatsapp.receivedInbound message from a user inside the 24h session window.whatsapp.template.approvedMeta approved a template you submitted.whatsapp.template.rejectedMeta rejected a template — rejection reason in the payload.
Fallback to SMS is one attribute, not a second integration.
If WhatsApp can't deliver — session expired, recipient never opted in, template not yet approved — Bird routes the same message over SMS in the same request. Same auth, same idempotency contract, same webhook shape on the other end.
WhatsApp with fallback.
await bird.whatsapp.send({
to: "+15005550009",
template: "order_shipped",
variables: { order_id: "BRD-49217" },
fallback: "sms",
});One payload, one auth. Session expiry, opt-in gap, unapproved template — all route through SMS automatically.
SMS direct.
await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your order BRD-49217 has shipped.`,
});The same wires, addressed directly. Use it when you want the SMS path explicitly.