TypeScript SDK
@waveband/sdk is a typed client for the whole REST API v1 — the same Zod contracts that generate the OpenAPI spec type the SDK, so request and response shapes are always in sync with the platform.
pnpm add @waveband/sdk
Setup
import { WavebandClient } from "@waveband/sdk";
const waveband = new WavebandClient({
apiKey: process.env.WAVEBAND_API_KEY!, // wbk_...
baseUrl: "https://waveband.adwave.com", // or your white-label host
});Namespaces
One namespace per resource, mirroring the REST paths: workspaces, campaigns, lineItems, creatives, conversionEvents, reports, events, webhooks, apiKeys, audiences, marketplaceSegments, rateCards, packages, deals, and proposals.
Launch a campaign
const { items: workspaces } = await waveband.workspaces.list();
const workspaceId = workspaces[0].id;
// The second argument of every create call is an optional Idempotency-Key —
// pass one and retries can never double-create.
const campaign = await waveband.campaigns.create(
{
workspaceId,
name: "Spring CTV Launch",
channel: "ctv",
startDate: "2026-08-01",
budgetUsdMinor: 500_000, // $5,000 in cents
goalType: "impressions",
},
"spring-ctv-launch",
);
const lineItem = await waveband.lineItems.create(
{
campaignId: campaign.id,
name: "CTV — US prospecting",
startDate: "2026-08-01",
budgetUsdMinor: 250_000,
bid: { type: "fixed_cpm", cpmUsdMinor: 2_400 }, // $24 CPM
targeting: { geo: { countries: ["US"] } },
},
"spring-ctv-li-1",
);
await waveband.lineItems.attachCreative(lineItem.id, creativeId);
await waveband.campaigns.resume(campaign.id);Reports
const report = await waveband.reports.query({
workspaceId,
from: "2026-08-01",
to: "2026-08-07",
groupBy: "campaign",
});Error handling
Non-2xx responses throw WavebandApiError carrying status, code, and field-level details — check code against the error reference:
import { WavebandApiError } from "@waveband/sdk";
try {
await waveband.lineItems.update(id, { budgetUsdMinor: 50 });
} catch (err) {
if (err instanceof WavebandApiError && err.code === "WAVEBAND_BUDGET_BELOW_MINIMUM") {
// surface err.details to the user
} else {
throw err;
}
}Growth flow (agencies)
// Package your offering, instantiate it for a client, send the proposal.
const pkg = await waveband.packages.create({
name: "CTV Starter",
channel: "ctv",
cpmUsdMinor: 3_200, // client-facing CPM ($32)
budgetFloorUsdMinor: 250_000,
defaultDurationDays: 30,
targeting: { geo: { countries: ["US"] } },
});
// Draft campaign + line item from the package.
const draft = await waveband.packages.instantiate(pkg.id, {
workspaceId,
budgetUsdMinor: 750_000,
startDate: "2026-09-01",
});
const proposal = await waveband.proposals.create({
workspaceId,
title: "Q4 CTV Program",
clientName: "Acme Outdoors",
items: [
{
name: "CTV prospecting",
channel: "ctv",
budgetUsdMinor: 750_000,
cpmUsdMinor: 3_200,
estImpressions: 234_375,
packageId: pkg.id,
},
],
flightStartDate: "2026-09-01",
flightEndDate: "2026-09-30",
});
await waveband.proposals.send(proposal.id);Full request/response types ship with the package; your editor autocompletes every field.