The SMS API for developers who actually need to ship.
150+ countries, 240 direct-to-carrier connections, one auth model. About 40% of the world's commercial SMS volume transits the Bird network — we've been at this a decade. 95% of messages delivered in under 2.5 seconds.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const code = generateOtp();
const { data, error } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your Bird verification code is ${code}. Reply STOP to opt out.`,
}).safe();
if (error) throw error;
console.log(data.id);
// → "sms_4kT01Lq2m..."5 minutes from npm install to first send
Send an SMS from the language you already use.
SDKs in every major runtime. The first send goes to a sanctioned test recipient (+15005550006) so you can ship a CI check before you provision a number.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: "Hello from Node.",
}).safe();Ten things we file, configure, and route so you don't.
Routing, compliance, and inbound primitives, named and audit-able.
- 01
150+ country coverage
One unified API, one billing relationship — no per-region contracts to chase down.
- 02
240 direct-to-carrier links
No middleman aggregator skimming margin or dropping receipts between us and the MNO.
- 03
Operator-grade routing
Real-time route reselection when a carrier path degrades; failover happens before you notice.
- 04
Two-way SMS inbound
Inbound messages arrive as HMAC-signed webhooks on the number you provisioned.
- 05
Numbers of every shape
Long codes, short codes, toll-free, and alphanumeric sender IDs — provisioned via one endpoint.
- 06
A2P 10DLC in-dashboard
Brand and campaign registration handled in the console; status is queryable from the API.
- 07
MNP lookup before send
We resolve the recipient's current carrier on every send so the route is always right.
- 08
STOP / HELP compliance
Opt-out keywords honored automatically per recipient; suppression list is queryable.
- 09
Delivery receipts as webhooks
Every state transition fires a signed event — sms.queued through sms.delivered or sms.failed.
- 10
Segment and Unicode safety
The SDK counts segments before send and warns on encoding flips that would split a message.
Why we build SMS
SMS is the messy channel. We built the API that makes it boring.
Every country has different rules, every carrier has different routes, every region has different sender-ID conventions. We've been running SMS for ten years, so that knowledge lives behind one endpoint, one auth model, one webhook contract. Whatever changes upstream, the call you wrote against bird.sms.send doesn't.
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const code = generateOtp();
const { data, error } = await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your Bird verification code is ${code}. Reply STOP to opt out.`,
}).safe();
if (error) throw error;
console.log(data.id);
// → "sms_4kT01Lq2m..."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": "sms.delivered",
"id": "evt_7jR42x...",
"created_at": "2026-05-19T15:42:01.221Z",
"data": {
"sms_id": "sms_4kT01Lq2m",
"from": "Bird",
"to": "+15005550006",
"mcc_mnc": "310-260",
"country": "US",
"segments": 1,
"latency_ms": 1284
}
}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.
sms.queuedAccepted by the API and queued for the carrier hand-off.sms.sentSubmitted to the destination carrier's SMSC.sms.deliveredDelivery receipt received from the carrier (DLR).sms.failedPermanent failure — carrier rejection, invalid number, suppression hit.sms.receivedInbound message on one of your provisioned numbers.sms.opted_outRecipient sent a STOP keyword; future sends to this number will be suppressed.
If you've integrated SMS, you've integrated WhatsApp.
Same auth model, same idempotency contract, same error envelope, same webhook shape. The difference is what each one does — not how you call it.
SMS.
await bird.sms.send({
from: "Bird",
to: "+15005550006",
text: `Your code is ${code}.`,
});One verb. Plain text. Numeric to/from. The shape every developer already has muscle memory for.
WhatsApp.
await bird.whatsapp.send({
from: "+15551234567",
to: "+15005550006",
template: { name: "otp", variables: { code } },
});Same verb. Different payload — templated, opted-in, in the channel two billion people open daily.