Tutorial: Build a Lead Scoring Engine with Enrichment Data

Turn raw signups into scored leads by combining B2B Enrichment API data with your ideal customer profile (ICP). This tutorial shows you how to request the right fields and build a scoring function that ranks leads automatically.

What You'll Build

A scoring function that enriches a company and assigns a 0-100 score based on industry fit, company size, and technology overlap.

Define Your ICP

Before writing code, define what makes a lead valuable. Here's an example for a developer tools company:

SignalHigh ScoreMedium ScoreLow Score
IndustrySaaS, Developer Tools, FintechE-commerce, Marketing TechEducation, Government
Size51-500 employees11-50 or 501-10001-10 or 10000+
Tech StackUses React, Next.js, or TypeScriptUses Node.js or PythonNo tech signals

The Scoring Function

JavaScript

const ICP = {
  highValueIndustries: ["SaaS", "Developer Tools", "Fintech", "Software"],
  mediumValueIndustries: ["E-commerce", "Marketing", "Data Analytics"],
  idealSizeRanges: ["51-200", "201-500"],
  goodSizeRanges: ["11-50", "501-1000"],
  targetTech: ["React", "Next.js", "TypeScript", "Node.js"],
};

async function scoreCompany(domain) {
  const response = await fetch(
    "https://b2b-enrichment.p.rapidapi.com/api/enrich",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": process.env.RAPIDAPI_KEY,
      },
      body: JSON.stringify({
        company: domain,
        fields: ["name", "industry", "size", "techStack"],
      }),
    }
  );

  if (!response.ok) return { domain, score: 0, reason: "enrichment_failed" };

  const { data } = await response.json();
  let score = 0;
  const signals = [];

  // Industry scoring (0-40 points)
  const industry = (data.industry || "").toLowerCase();
  if (ICP.highValueIndustries.some((i) => industry.includes(i.toLowerCase()))) {
    score += 40;
    signals.push("high-value industry");
  } else if (
    ICP.mediumValueIndustries.some((i) => industry.includes(i.toLowerCase()))
  ) {
    score += 20;
    signals.push("medium-value industry");
  }

  // Size scoring (0-30 points)
  if (ICP.idealSizeRanges.includes(data.size)) {
    score += 30;
    signals.push("ideal company size");
  } else if (ICP.goodSizeRanges.includes(data.size)) {
    score += 15;
    signals.push("acceptable company size");
  }

  // Tech stack scoring (0-30 points)
  const techStack = (data.techStack || []).map((t) => t.toLowerCase());
  const techMatches = ICP.targetTech.filter((t) =>
    techStack.includes(t.toLowerCase())
  );
  const techScore = Math.min(techMatches.length * 10, 30);
  score += techScore;
  if (techMatches.length > 0) {
    signals.push(`tech match: ${techMatches.join(", ")}`);
  }

  return {
    domain,
    company: data.name,
    score,
    tier: score >= 70 ? "hot" : score >= 40 ? "warm" : "cold",
    signals,
  };
}

Python

import os
import requests

ICP = {
    "high_industries": ["saas", "developer tools", "fintech", "software"],
    "medium_industries": ["e-commerce", "marketing", "data analytics"],
    "ideal_sizes": ["51-200", "201-500"],
    "good_sizes": ["11-50", "501-1000"],
    "target_tech": ["react", "next.js", "typescript", "node.js"],
}

def score_company(domain: str) -> dict:
    response = requests.post(
        "https://b2b-enrichment.p.rapidapi.com/api/enrich",
        headers={
            "Content-Type": "application/json",
            "X-API-Key": os.environ["RAPIDAPI_KEY"],
        },
        json={
            "company": domain,
            "fields": ["name", "industry", "size", "techStack"],
        },
        timeout=30,
    )

    if not response.ok:
        return {"domain": domain, "score": 0, "reason": "enrichment_failed"}

    data = response.json()["data"]
    score = 0
    signals = []

    # Industry (0-40)
    industry = (data.get("industry") or "").lower()
    if any(i in industry for i in ICP["high_industries"]):
        score += 40
        signals.append("high-value industry")
    elif any(i in industry for i in ICP["medium_industries"]):
        score += 20
        signals.append("medium-value industry")

    # Size (0-30)
    size = data.get("size")
    if size in ICP["ideal_sizes"]:
        score += 30
        signals.append("ideal size")
    elif size in ICP["good_sizes"]:
        score += 15
        signals.append("acceptable size")

    # Tech stack (0-30)
    tech = [t.lower() for t in (data.get("techStack") or [])]
    matches = [t for t in ICP["target_tech"] if t in tech]
    score += min(len(matches) * 10, 30)
    if matches:
        signals.append(f"tech: {', '.join(matches)}")

    tier = "hot" if score >= 70 else "warm" if score >= 40 else "cold"
    return {
        "domain": domain,
        "company": data.get("name"),
        "score": score,
        "tier": tier,
        "signals": signals,
    }

Score a Batch of Leads

const leads = ["vercel.com", "stripe.com", "notion.so", "shopify.com"];

const scored = [];
for (const domain of leads) {
  scored.push(await scoreCompany(domain));
  await new Promise((r) => setTimeout(r, 6000)); // rate limit
}

// Sort by score, highest first
scored.sort((a, b) => b.score - a.score);

console.table(scored.map(({ company, score, tier, signals }) => ({
  company,
  score,
  tier,
  signals: signals.join("; "),
})));

Using Scores in Your Pipeline

Once you have scores, route leads based on tier:

TierScoreAction
Hot (70-100)Strong ICP matchRoute to sales immediately. Assign to AE.
Warm (40-69)Partial matchAdd to nurture sequence. Auto-assign SDR follow-up.
Cold (0-39)Low fitAdd to long-term nurture. No outbound.

Tips

  • Request only scoring fields. You need industry, size, and techStack — skip description, socialLinks, and founded to keep requests fast.
  • Cache enrichment results. Company data doesn't change daily. Store results keyed by domain and re-enrich monthly.
  • Combine with first-party signals. Enrichment scores get more powerful when combined with behavioral data — page visits, email opens, feature usage.
  • Tune your ICP weights. Start with the 40/30/30 split above, then adjust based on which scored leads actually convert.