Quickstart · Next.js
Send your first email from a Next.js 15 App Router app. Server action posts to Bird, webhook route receives the delivery event.
Prerequisites
- Node 20 or later
- pnpm 9 or later (npm, yarn, bun all work too)
- A Bird test API key from the dashboard — it looks like
bird_test_xxxxxxxx
Install the SDK
pnpm add @bird/sdk
# npm install @bird/sdk
# yarn add @bird/sdk
# bun add @bird/sdk
Set the env var
Add the key to .env.local at the project root:
BIRD_API_KEY=bird_test_xxxxxxxx
Send from a server action
Create app/actions/send-welcome.ts:
"use server";
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
export async function sendWelcome(to: string) {
const { data, error } = await bird.email.send({
from: "Bird <onboarding@bird.dev>",
to: [to],
subject: "Welcome",
html: "<p>It works.</p>",
});
if (error) throw error;
return data.id;
}
Call it from a client component or a route handler with to: 'delivered@bird.dev' — a sanctioned test recipient that always accepts and emits events without touching a real inbox.
Receive the delivery webhook
Create app/api/webhooks/bird/route.ts:
import { NextRequest, NextResponse } from "next/server";
import { BirdClient } from "@bird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
export async function POST(req: NextRequest) {
const raw = await req.text();
const signature = req.headers.get("bird-signature") ?? "";
try {
const event = bird.webhooks.verify({
body: raw,
signature,
secret: process.env.BIRD_WEBHOOK_SECRET!,
});
// event.type === 'email.delivered' | 'email.bounced' | ...
return NextResponse.json({ received: true, id: event.data.id }, { status: 200 });
} catch {
return NextResponse.json({ error: "invalid_signature" }, { status: 401 });
}
}
What just happened
The server action hit POST /v1/emails and Bird returned an email_* id. Within a second, the dashboard logs show the send, and Bird re-emits the delivery event to your webhook with an HMAC-SHA256 Bird-Signature header.
Next steps
- Verify a sending domain — graduate from test keys to production sends.
- Send an SMS — same auth, same response envelope.
- Webhooks deep-dive — the full event catalog and retry schedule.
- Drop the MCP server in your IDE — let Claude and Cursor send through Bird.