Overview
The official FoxReach TypeScript SDK gives you type-safe access to the entire FoxReach API. It has zero dependencies, uses native fetch, and works everywhere — Node.js, Deno, Bun, and edge runtimes.
Install it with npm:
npm install foxreach
Quick Start
import { FoxReach } from "foxreach";
const client = new FoxReach({ apiKey: "otr_your_key" });
// List all active leads
const leads = await client.leads.list({ status: "active" });
for (const lead of leads.data) {
console.log(`${lead.email} — ${lead.company}`);
}
// Create a new lead
const lead = await client.leads.create({
email: "jane@example.com",
firstName: "Jane",
lastName: "Smith",
company: "TechCorp",
});
console.log(`Created lead: ${lead.id}`);
What's Included
The SDK covers every FoxReach API endpoint:
- Leads —
client.leads.list(),create(),get(),update(),delete() - Campaigns —
create(),start(),pause(),resume(),delete() - Sequences —
client.campaigns.sequences.create(),update(),delete() - Templates —
client.templates.list(),create(),update(),delete() - Email Accounts —
client.emailAccounts.list(),get(),delete() - Inbox —
client.inbox.list(),get(),update(),reply() - Analytics —
client.analytics.overview(),campaign() - Webhooks —
client.webhooks.list(),create(),update(),delete()
Full Type Safety
Every request and response is fully typed. Your editor gives you autocomplete, inline docs, and compile-time error checking:
const campaign = await client.campaigns.create({
name: "Q1 Enterprise Outreach",
timezone: "America/New_York",
sendingDays: [1, 2, 3, 4, 5],
sendingStartHour: 9,
sendingEndHour: 17,
dailyLimit: 50,
});
// campaign is typed as Campaign with all fields
Auto-Pagination
List endpoints return paginated results. Use the built-in pagination helpers:
// Get a single page
const page = await client.leads.list({ page: 1, limit: 50 });
console.log(`Total: ${page.total}, Page: ${page.page}`);
// Iterate all pages with async iterator
for await (const lead of client.leads.listAll({ status: "active" })) {
console.log(lead.email);
}
Error Handling
API errors are thrown as typed exceptions:
import { FoxReachError, NotFoundError, ValidationError } from "foxreach";
try {
const lead = await client.leads.get("cld_nonexistent");
} catch (error) {
if (error instanceof NotFoundError) {
console.log("Lead not found");
} else if (error instanceof ValidationError) {
console.log(`Invalid request: ${error.message}`);
} else if (error instanceof FoxReachError) {
console.log(`API error ${error.statusCode}: ${error.message}`);
}
}
End-to-End Example: Campaign Setup
Here's a complete script that creates leads, builds a campaign, and starts it:
import { FoxReach } from "foxreach";
const client = new FoxReach({ apiKey: "otr_your_key" });
// 1. Create leads
const contacts = [
{ email: "sarah@techcorp.io", firstName: "Sarah", lastName: "Chen", company: "TechCorp" },
{ email: "mike@startupco.com", firstName: "Mike", lastName: "Johnson", company: "StartupCo" },
{ email: "lisa@enterprise.com", firstName: "Lisa", lastName: "Wang", company: "Enterprise Ltd" },
];
const leads = await Promise.all(
contacts.map((contact) => client.leads.create(contact))
);
console.log(`Created ${leads.length} leads`);
// 2. Create a campaign
const campaign = await client.campaigns.create({
name: "Q1 Outreach",
timezone: "America/New_York",
sendingDays: [1, 2, 3, 4, 5],
sendingStartHour: 9,
sendingEndHour: 17,
dailyLimit: 50,
});
// 3. Add sequence steps
await client.campaigns.sequences.create(campaign.id, {
subject: "Quick question about {{company}}",
body: "Hi {{firstName}},\n\nI noticed {{company}} is growing fast...",
delayDays: 0,
});
await client.campaigns.sequences.create(campaign.id, {
subject: "Re: Quick question about {{company}}",
body: "Hi {{firstName}},\n\nJust following up...",
delayDays: 3,
});
// 4. Add leads to campaign
await client.campaigns.addLeads(campaign.id, leads.map((l) => l.id));
// 5. Assign email account
const accounts = await client.emailAccounts.list();
await client.campaigns.addAccounts(campaign.id, [accounts.data[0].id]);
// 6. Start the campaign
await client.campaigns.start(campaign.id);
console.log(`Campaign '${campaign.name}' is now active!`);
Use with Express for Webhook Handling
The SDK pairs well with Express for receiving webhook events:
import express from "express";
import crypto from "crypto";
const app = express();
const WEBHOOK_SECRET = "your_webhook_secret";
app.post("/webhooks/foxreach", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-webhook-signature"] as string;
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body.toString());
console.log(`Received event: ${event.event}`);
// Handle events
switch (event.event) {
case "reply.received":
console.log(`New reply from ${event.data.leadEmail}`);
break;
case "email.bounced":
console.log(`Bounce: ${event.data.leadEmail}`);
break;
}
res.sendStatus(200);
});
app.listen(3000);