本文へ移動
cccskills
無料GitHub で公開

apollo-core-workflow-a

Implement Apollo.io lead search and enrichment workflow. Use when building lead generation features, searching for contacts, or enriching prospect data from Apollo. Trigger with phrases like "apollo lead search", "search apollo contacts", "find leads in apollo", "apollo people search", "enrich contacts apollo".

インストール方法を見る

含まれるファイル(2)

  • SKILL.md8.1 KB
  • references/implementation-guide.md6.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Apollo Core Workflow A: Lead Search & Enrichment

Overview

Build the core Apollo.io prospecting pipeline: search for people and organizations, then enrich the best leads. Key distinction — search is free (no credits), enrichment costs credits. This skill uses the correct endpoints and x-api-key header authentication.

Prerequisites

  • Completed apollo-install-auth setup
  • Valid Apollo API key with search + enrichment permissions
  • Understanding of your Ideal Customer Profile (ICP)

Instructions

Step 1: Search for People (Free — No Credits)

The People API Search endpoint (POST /mixed_people/api_search) searches Apollo's 275M+ database. It does not return emails or phone numbers — use enrichment for that.

// src/workflows/lead-search.ts
import axios from 'axios';

const client = axios.create({
  baseURL: 'https://api.apollo.io/api/v1',
  headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.APOLLO_API_KEY! },
});

interface PersonSearchParams {
  domains: string[];
  titles?: string[];
  seniorities?: string[];    // "c_suite", "vp", "director", "manager", "senior"
  locations?: string[];       // "United States", "San Francisco, California"
  page?: number;
  perPage?: number;
}

export async function searchPeople(params: PersonSearchParams) {
  const { data } = await client.post('/mixed_people/api_search', {
    q_organization_domains_list: params.domains,
    person_titles: params.titles,
    person_seniorities: params.seniorities,
    person_locations: params.locations,
    include_similar_titles: true,
    page: params.page ?? 1,
    per_page: params.perPage ?? 25,
  });

  return {
    people: data.people,
    total: data.pagination.total_entries,
    totalPages: data.pagination.total_pages,
    page: data.pagination.page,
  };
}

Step 2: Search for Organizations (Free)

// src/workflows/org-search.ts
interface OrgSearchParams {
  keywords?: string;
  locations?: string[];
  employeeRanges?: string[];  // ["1,10", "11,50", "51,200", "201,500"]
  industries?: string[];
  revenueRanges?: string[];   // ["0,1000000", "1000000,10000000"]
}

export async function searchOrganizations(params: OrgSearchParams) {
  const { data } = await client.post('/mixed_companies/search', {
    q_organization_keyword_tags: params.keywords ? [params.keywords] : undefined,
    organization_locations: params.locations,
    organization_num_employees_ranges: params.employeeRanges,
    organization_industry_tag_ids: params.industries,
    organization_revenue_ranges: params.revenueRanges,
    page: 1,
    per_page: 25,
  });

  return data.organizations.map((org: any) => ({
    id: org.id,
    name: org.name,
    domain: org.primary_domain,
    industry: org.industry,
    employees: org.estimated_num_employees,
    revenue: org.annual_revenue_printed,
    city: org.city,
    state: org.state,
  }));
}

Step 3: Enrich a Single Person (1 Credit)

// src/workflows/enrich.ts
export async function enrichPerson(params: {
  email?: string;
  linkedinUrl?: string;
  firstName?: string;
  lastName?: string;
  domain?: string;
}) {
  const { data } = await client.post('/people/match', {
    email: params.email,
    linkedin_url: params.linkedinUrl,
    first_name: params.firstName,
    last_name: params.lastName,
    organization_domain: params.domain,
    reveal_personal_emails: false,
    reveal_phone_number: true,
  });

  if (!data.person) return null;
  const p = data.person;

  return {
    id: p.id,
    name: p.name,
    title: p.title,
    email: p.email,
    phone: p.phone_numbers?.[0]?.sanitized_number,
    company: p.organization?.name,
    companyDomain: p.organization?.primary_domain,
    linkedinUrl: p.linkedin_url,
    seniority: p.seniority,
    city: p.city,
    state: p.state,
  };
}

Step 4: Bulk Enrich People (Up to 10 per Call)

export async function bulkEnrichPeople(details: Array<{
  email?: string;
  linkedin_url?: string;
  first_name?: string;
  last_name?: string;
  organization_domain?: string;
}>) {
  const { data } = await client.post('/people/bulk_match', {
    details,
    reveal_personal_emails: false,
    reveal_phone_number: false,
  });

  return (data.matches ?? []).map((match: any) => ({
    id: match.id,
    name: match.name,
    email: match.email,
    title: match.title,
    company: match.organization?.name,
  }));
}

Step 5: Build a Combined Lead Pipeline

export async function buildLeadPipeline(targetDomains: string[]) {
  const leads: any[] = [];

  for (const domain of targetDomains) {
    // Step A: Search for decision-makers (free)
    const { people } = await searchPeople({
      domains: [domain],
      seniorities: ['vp', 'director', 'c_suite'],
    });

    // Step B: Score leads before enriching (save credits)
    const worthEnriching = people.filter((p: any) => scoreLead(p) >= 50);

    // Step C: Bulk enrich top leads (costs credits)
    if (worthEnriching.length > 0) {
      const enriched = await bulkEnrichPeople(
        worthEnriching.map((p: any) => ({
          first_name: p.first_name,
          last_name: p.last_name,
          organization_domain: domain,
        })),
      );
      leads.push(...enriched);
    }
  }

  return leads.sort((a, b) => scoreLead(b) - scoreLead(a));
}

function scoreLead(person: any): number {
  let score = 0;
  if (person.email) score += 30;
  if (person.phone_numbers?.length) score += 20;
  if (['c_suite', 'vp', 'founder', 'owner'].includes(person.seniority)) score += 30;
  else if (['director'].includes(person.seniority)) score += 20;
  if (person.linkedin_url) score += 10;
  if (person.city) score += 10;
  return score;
}

Output

  • People search via POST /mixed_people/api_search (free, no credits)
  • Organization search via POST /mixed_companies/search (free)
  • Single person enrichment via POST /people/match (1 credit)
  • Bulk enrichment via POST /people/bulk_match (up to 10 per call)
  • Lead scoring to minimize credit spend before enriching

Error Handling

ErrorCauseSolution
Empty people arrayToo narrow criteriaBroaden seniority levels, add include_similar_titles: true
null from enrichmentPerson not in Apollo databaseTry enriching via LinkedIn URL instead of name+domain
429 Rate LimitedToo many requests/minuteBatch requests with 500ms delays between calls
403 ForbiddenStandard key used for enrichmentUpgrade to master API key in Apollo dashboard

Examples

Quick ICP Search

// Find Series B SaaS companies with 50-500 employees
const companies = await searchOrganizations({
  keywords: 'SaaS',
  employeeRanges: ['51,200', '201,500'],
  locations: ['United States'],
});

// Find VPs of Sales at those companies
for (const company of companies.slice(0, 10)) {
  const { people, total } = await searchPeople({
    domains: [company.domain],
    titles: ['VP Sales', 'Head of Sales', 'VP Revenue'],
  });
  console.log(`${company.name} (${company.domain}): ${total} contacts`);
}

Resources

Next Steps

Proceed to apollo-core-workflow-b for email sequences and outreach.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Build a synthetic-data CI gate for customer-controlled Abridge integration code without calling undocumented vendor interfaces. Use when adding regression checks to an Abridge deployment repository. Trigger with "test the Abridge integration".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

Triage Abridge recording, note-review, Epic handoff, and access failures from observed evidence without inventing vendor error codes. Use when an Abridge clinical workflow is degraded. Trigger with "diagnose this Abridge issue".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

Design and verify the clinician workflow from consent through recording, draft review, Linked Evidence, and final note disposition. Use when implementing or auditing an Abridge clinical documentation pathway. Trigger with "map the Abridge note workflow".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

Verify the approved handoff of clinician-reviewed Abridge note sections into Epic templates and downstream workflows. Use when configuring or auditing Abridge-to-Epic documentation flow. Trigger with "verify the Abridge Epic handoff".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

Evaluate Abridge adoption, workflow value, and avoidable operational friction without inventing prices or vendor billing meters. Use when reviewing an Abridge rollout or renewal. Trigger with "analyze Abridge value".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

Produce a PHI-minimized Abridge support bundle with provenance, redaction, and protected escalation boundaries. Use when support needs reproducible evidence for an Abridge issue. Trigger with "build an Abridge debug bundle".

日本語の概要は準備中です。原文の説明を表示しています。

jeremylongshore/tons-of-skills-marketplace2,8322026年10月13日 更新

jeremylongshore のスキルをすべて見る

このスキルの問題を報告する