Skip to content
Preview: outbound-sdk is not on npm yet and its repository is private. Instantly and HeyReach are beta, Smartlead is unverified.What is verified
outbound-sdk
Esc
↑↓navigate↵open⌘Jpreview
On this page

Usage

Construct an Outbound instance with an adapter, list and read records, follow a campaign down to its sequence, stats and leads, and handle the one error class.

Create one instance per adapter, then call the same methods on it whichever vendor is behind it.

Construct an instance

import { createOutbound } from "outbound-sdk";
import { instantly } from "outbound-sdk/instantly";

// Reads INSTANTLY_API_KEY. Or pass it: instantly({ apiKey }).
const outbound = createOutbound({ adapter: instantly() });

console.log(outbound.provider, outbound.maturity);

console.log(outbound.capabilities["replies.category"]);
instantly beta
vendor

Constructing an instance makes no request. maturity says how far the adapter has been checked against the live API (see what is verified), and capabilities says what it can do before you ask.

To try the SDK without a key, use the in-memory adapter. The rest of this page does.

Read

import { createOutbound } from "outbound-sdk";
import { demoData, memory } from "outbound-sdk/memory";

const outbound = createOutbound({ adapter: memory({ data: demoData() }) });

// One page, with a cursor for the next.
const page = await outbound.campaigns.list({ limit: 1, status: "active" });

console.log(
  page.items.length,
  "campaign on this page; complete:",
  page.complete
);

// A handle is one record and everything under it.
const [first] = page.items;
const campaign = outbound.campaign(first?.ref ?? "");

const sequence = await campaign.sequence();

console.log("steps:", sequence.steps.length);

const stats = await campaign.stats({ from: "2026-10-01", to: "2026-10-31" });

console.log("sent:", stats.rows[0]?.sent);

for await (const lead of campaign.leads.listAll()) {
  console.log(lead.email, lead.status);
}

// Every result says how it was obtained.
console.log(stats.meta.evidence, stats.meta.provider, stats.meta.complete);
1 campaign on this page; complete: true
steps: 2
sent: 90
person1@example.com replied
person2@example.com active
exact memory true
  • Collections (campaigns, senders, leads, messages, replies, lists, tags, blocklist, webhooks, workspaces) have list for one page and listAll for every page, fetched under the vendor’s rate limit as you iterate. See collections.
  • Handles (campaign(id), sender(id), lead(id), list(id), thread(id)) are one record and what hangs off it. See handles.
  • Every result carries meta: how it was obtained (exact, sampled or derived), when, how many vendor requests it cost and whether it is complete. See results.

An id can be the vendor’s own id or a ref from any record. On an instance that combines several adapters, use the ref.

Handle errors

There is one error class, OutboundError, with a code.

import { createOutbound, OutboundError } from "outbound-sdk";
import { demoData, memory } from "outbound-sdk/memory";

const outbound = createOutbound({
  // An adapter that, like HeyReach, cannot read campaign settings.
  adapter: memory({
    capabilities: { "campaigns.settings": false },
    data: demoData(),
  }),
});

try {
  await outbound.campaigns.get("no-such-campaign");
} catch (error) {
  if (OutboundError.is(error)) {
    console.log(error.code, error.permanent);
  }
}

try {
  await outbound.campaign("cmp_founders").settings();
} catch (error) {
  if (OutboundError.is(error)) {
    console.log(error.code, "-", error.message);
  }
}

console.log(await outbound.campaigns.exists("no-such-campaign"));
NotFound true
Unsupported - Reading a campaign's settings is not available: the memory adapter does not support it (campaigns.settings)
false

A missing record is NotFound. A read the adapter cannot serve is Unsupported, thrown before any request. exists never throws for a missing record. The full list of codes is on the errors page.

Next

Was this page helpful?