Misar IO Docs

TypeScript SDK

Install and use the @misar/reach-sdk to search leads, verify emails, score leads, and manage deals from Node.js or the browser.

Installation

pnpm add @misar/reach-sdk

Setup

lib/reach.ts
import { MisarReachClient } from "@misar/reach-sdk";

export const reach = new MisarReachClient({
  apiKey: process.env.MISARREACH_API_KEY!,
  // baseUrl defaults to "https://api.misar.io/reach"
});

Lead Finder

Search leads

client.leads.search() creates an async search job and returns a jobId. The search processes in the background — poll client.leads.getJob() for results.

const { jobId } = await reach.leads.search({
  query: "CTOs at B2B SaaS startups with 10-50 employees in India",
  filters: {
    location: "India",
    industry: "B2B SaaS",
    companySize: "10-50",
  },
  useAI: true, // enable AI enrichment
});

Poll for job completion

async function waitForJob(jobId: string) {
  let job = await reach.leads.getJob(jobId);

  while (job.status === "pending" || job.status === "running") {
    await new Promise((r) => setTimeout(r, 2000));
    job = await reach.leads.getJob(jobId);
  }

  if (job.status === "failed") {
    throw new Error(`Search job failed: ${jobId}`);
  }

  return job;
}

const job = await waitForJob(jobId);
console.log(`Found ${job.result_count} leads`);

List leads

const { leads, total } = await reach.leads.list({
  jobId,        // filter by job
  page: 1,
  limit: 50,
  search: "CTO", // optional text filter
});

for (const lead of leads) {
  console.log(`${lead.name} <${lead.email}> — ${lead.company} (score: ${lead.score})`);
}

Discover companies

Synchronous endpoint — returns results immediately.

const { companies, leads } = await reach.leads.discover({
  industry: ["SaaS", "Fintech"],
  location: ["India", "Singapore"],
  headcount_min: 10,
  headcount_max: 100,
  fetch_emails: true,
  limit: 20,
});

Verify emails

Verify up to 20 emails per call. Returns deliverability status and confidence score.

const { results, verified } = await reach.leads.verify({
  emails: ["[email protected]", "[email protected]"],
});

const validEmails = results.filter((r) => r.status === "valid" && !r.pending);
console.log(`${verified} verified, ${validEmails.length} valid`);

Verification result shape:

interface VerifyResult {
  email: string;
  status: "valid" | "risky" | "invalid" | "unknown" | null;
  score: number | null;  // 0–100
  pending: boolean;      // true if Hunter.io is still processing
}

Score leads

Background scoring — returns immediately. Fetch updated score and score_reason from leads.list() after a few seconds.

// Score all unscored leads for a job
const { scored } = await reach.leads.score({ jobId });
console.log(`Scoring ${scored} leads...`);

// Or score specific leads
await reach.leads.score({ leadIds: ["uuid-1", "uuid-2"] });

Manage lead lists

// List all saved lists
const { lists } = await reach.lists.list();

// Create a new list
const { list } = await reach.lists.create({ name: "India CTOs — May 2026" });
console.log(`Created list ${list.id}`);

Deals

Create a deal

const { deal } = await reach.deals.create({
  leadEmail: "[email protected]",
  leadName: "Priya Sharma",
  value: 15000,      // in currency's base unit
  currency: "USD",
  notes: "Responded positively to cold email. Demo scheduled.",
  conversationId: "uuid", // optional — links deal to conversation
});

console.log(`Deal ${deal.id} created with status: ${deal.status}`);

List deals

const { deals, total, revenue } = await reach.deals.list({
  status: "proposal", // optional filter
  limit: 20,
  offset: 0,
});

console.log(`Pipeline value: $${revenue.pipeline}`);
console.log(`Closed revenue: $${revenue.closed}`);

Update a deal

// Move to next stage
await reach.deals.update(dealId, { status: "meeting" });

// Mark closed
await reach.deals.update(dealId, {
  status: "closed",
  notes: "Contract signed — $15,000.",
});

Pipeline

Get the board

Returns all deals grouped by stage.

const { board, revenue, stages } = await reach.pipeline.get();

for (const stage of stages) {
  const deals = board[stage];
  console.log(`${stage}: ${deals.length} deals`);
}

Move a deal

await reach.pipeline.move({
  dealId: "uuid",
  newStage: "meeting",
});

Full example — lead-to-deal workflow

scripts/find-and-track-leads.ts
import { MisarReachClient } from "@misar/reach-sdk";

const reach = new MisarReachClient({
  apiKey: process.env.MISARREACH_API_KEY!,
});

async function main() {
  // 1. Search for leads
  const { jobId } = await reach.leads.search({
    query: "Founders at fintech startups in Southeast Asia",
    filters: { location: "Southeast Asia", industry: "Fintech" },
    useAI: true,
  });

  console.log(`Search started: ${jobId}`);

  // 2. Wait for results
  let job = await reach.leads.getJob(jobId);
  while (job.status === "pending" || job.status === "running") {
    await new Promise((r) => setTimeout(r, 2000));
    job = await reach.leads.getJob(jobId);
  }

  console.log(`Found ${job.result_count} leads`);

  // 3. Get leads
  const { leads } = await reach.leads.list({ jobId, limit: 20 });

  // 4. Verify top 10 emails
  const emailsToVerify = leads.slice(0, 10).map((l) => l.email);
  const { results } = await reach.leads.verify({ emails: emailsToVerify });
  const validEmails = new Set(
    results.filter((r) => r.status === "valid").map((r) => r.email)
  );

  // 5. Create deals for verified leads
  const validLeads = leads.filter((l) => validEmails.has(l.email));
  for (const lead of validLeads) {
    const { deal } = await reach.deals.create({
      leadEmail: lead.email,
      leadName: lead.name ?? undefined,
      value: 0,
      currency: "USD",
      notes: `Lead from: ${lead.company} (score: ${lead.score})`,
    });
    console.log(`Deal created: ${deal.id} for ${lead.email}`);
  }

  console.log(`Created ${validLeads.length} deals from ${leads.length} leads`);
}

main().catch(console.error);

Error handling

The SDK throws typed errors for HTTP failures:

import { MisarReachError } from "@misar/reach-sdk";

try {
  const result = await reach.leads.search({ query: "..." });
} catch (err) {
  if (err instanceof MisarReachError) {
    console.error(`API error ${err.status}: ${err.message}`);
    if (err.status === 429 && err.data.upgrade) {
      console.log("Credit limit reached — upgrade at dashboard.misar.io");
    }
  }
}

TypeScript types

All request and response types are exported from @misar/reach-sdk:

import type {
  LeadSearchRequest,
  LeadSearchJob,
  Lead,
  VerifyResult,
  Deal,
  PipelineBoard,
  PipelineDeal,
} from "@misar/reach-sdk";