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.

TypeScript SDK — Waveband Docs