Loading...
Loading...
Prospecting hub. Opens by asking your GOAL, then routes to 7 sub-skills - find new companies, lookalikes of best customers, rank my accounts, event prospecting, expansion radar, TAM builder, champion tracker (with live watcher). Iterative Crustdata search, FIT x TIMING x WARMTH scoring, opt-in enrichment, handoff to sheet or CSV. Use for "build me a list", "find companies like <customer>", "who should I prospect", "rank my accounts", "who's hot in my book", "list for <conference>", "upsell targets", "how big is this market", "track champions who leave customers".
npx skill4agent add crustdata/skills sales-prospectingconfig/gtm-config.mdconfig/persona-profile.mdexecute({ code })get_schema: Typeas// user query: ...// model query: ...const r = await callTool(name, params){ ok: true, data }{ ok: false, status, errorType, message }r.okfieldsundefinedawait parallelMap(items, fn)chunk(list, 25)checkpoint(acc)company_autocompleteperson_autocompletebasic_info.industriestaxonomy.professional_network_industryfunding.last_round_typebasic_info.company_typeEntry LevelEntry Level ManagerExperienced ManagerSeniorDirectorVice PresidentCXOOwner / PartnerIn TrainingStrategicperson_autocompleteprofessional_network.followersmetadataprofessional_network.connectionsgte(..., 100)...current.company_name...current[].name...current.company_id...current[].crustdata_company_id...current.company_website_domain...current[].company_websitesocial_handles.professional_network_identifier.profile_urlprofileUrl(p)locations.countryUSA"USA"basic_profile.location.countryUnited Statesstripe.comseries_ainnot_in=and_experience.*and_all_ofall_of{ op: "all_of", conditions: [ {...}, {...} ] }has_alltrajectorypost_processing: { exclude_profiles: [...], exclude_names: [...] }// model query: resolve exact industry and funding-stage values before filtering
const probes = [
["basic_info.industries", "software"],
["funding.last_round_type", "series a"],
];
const values = await parallelMap(probes, async ([field, query]) => {
const r = await callTool("company_autocomplete", { field, query });
return { field, values: r.ok ? r.data : r.message };
});
return values;company_searchfunding.last_round_typefunding.total_investment_usdfunding.last_round_amount_usdbasic_info.year_foundedgt("headcount.growth_percent.12m", N)headcount.totalfunding.last_fundraise_date// model query: US software companies 51-1000, raised $5M+, growing >20% — refine round 2
const r = await callTool("company_search", {
filters: and_(
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
gt("funding.total_investment_usd", 5000000),
gt("headcount.growth_percent.12m", 20)
),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding"],
sorts: [{ field: "funding.last_fundraise_date", order: "desc" }],
limit: 25,
});
if (!r.ok) return { error: r.message };
return {
total: r.data.total_count,
rows: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
domain: c.basic_info?.primary_domain,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
})),
};person_searchperson_autocompleteexcludes()// model query: buyer-title people at the shortlisted companies
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.ids),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"]),
gte("professional_network.connections", 100),
excludes("experience.employment_details.current.title", "advisor"),
excludes("experience.employment_details.current.title", "investor")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => ({
name: p.basic_profile?.name,
title: p.basic_profile?.current_title,
company: p.experience?.employment_details?.current?.[0]?.name,
url: profileUrl(p),
}));company_identifydomainsnamesconfidence_scorecompany_searchin_("crustdata_company_id", seedIds)// model query: resolve seed customers and read the traits they share
const idr = await callTool("company_identify", {
domains: inputs.seedDomains,
fields: ["crustdata_company_id", "basic_info"],
});
if (!idr.ok) return { error: idr.message };
const ids = idr.data
.map(m => m.matches?.[0]?.company_data?.crustdata_company_id)
.filter(Boolean);
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "headcount", "funding", "taxonomy", "locations"],
limit: ids.length,
});
if (!r.ok) return { error: r.message };
return r.data.companies.map(c => ({
name: c.basic_info?.name,
industries: c.basic_info?.industries,
hc: c.headcount?.total,
growth12m: c.headcount?.growth_percent?.["12m"],
stage: c.funding?.last_round_type,
country: c.locations?.country,
}));nin_("crustdata_company_id", excludeIds)company_identifychunk(domains, 25)parallelMapconfidence_scorecompany_searchin_("crustdata_company_id", ids)fields: ["crustdata_company_id", "basic_info", "funding", "headcount"]headcountheadcount.growth_percent.{1m,3m,6m,12m}fields// user query: rank my account list — who do I work first?
const batches = chunk(inputs.domains, 25);
const identified = await parallelMap(batches, async (batch) => {
const r = await callTool("company_identify", {
domains: batch,
fields: ["crustdata_company_id", "basic_info"],
});
return r.ok ? r.data : batch.map(d => ({ matched_on: d, matches: [], error: r.message }));
});
const rows = identified.flat();
const unresolved = rows.filter(m => !m.matches?.length).map(m => m.matched_on);
const ids = rows.map(m => m.matches?.[0]?.company_data?.crustdata_company_id).filter(Boolean);
checkpoint({ ids, unresolved });
const r = await callTool("company_search", {
filters: in_("crustdata_company_id", ids),
fields: ["crustdata_company_id", "basic_info", "funding", "headcount"],
limit: ids.length,
});
if (!r.ok) return { error: r.message, unresolved };
return {
unresolved,
accounts: r.data.companies.map(c => ({
id: c.crustdata_company_id,
name: c.basic_info?.name,
lastRound: c.funding?.last_round_type,
lastRaise: c.funding?.last_fundraise_date,
raisedUsd: c.funding?.total_investment_usd,
hc: c.headcount?.total,
growth3m: c.headcount?.growth_percent?.["3m"],
growth12m: c.headcount?.growth_percent?.["12m"],
})),
};job_searchaggregationslimit: 0web_search_liveweb_enrich_live// model query: find the official sponsor page for the event and pull the roster
const s = await callTool("web_search_live", { query: `${inputs.event} sponsors exhibitors` });
if (!s.ok) return { error: s.message };
const page = s.data.results.find(x => /sponsor|exhibitor/i.test(x.url));
if (!page) return { candidates: s.data.results.map(x => ({ title: x.title, url: x.url })) };
const f = await callTool("web_enrich_live", { urls: [page.url] });
if (!f.ok) return { error: f.message };
return { url: page.url, page: f.data };company_identifychunk(25)parallelMapcompany_searchsocial_post_search_liveexact_keyword_matchlimitcompany_searchperson_searchin_("experience.employment_details.current.company_id", customerIds)current[].start_datejob_searchperson_searchfunction_category// model query: new senior hires in the last 6 months across customer accounts
const cutoff = new Date(Date.now() - 183 * 24 * 3600 * 1000).toISOString().slice(0, 10);
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.current.company_id", inputs.customerIds),
in_("experience.employment_details.current.seniority_level", ["Director", "Vice President", "CXO"])
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 100,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
return {
name: p.basic_profile?.name,
title: cur?.title,
company: cur?.name,
started: cur?.start_date,
url: profileUrl(p),
};
}).filter(x => x.started && x.started >= cutoff);// model query: open-role counts per customer account (hiring signal, counts only)
const r = await callTool("job_search", {
filters: in_("company.basic_info.company_id", inputs.customerIds),
aggregations: [{ type: "group_by", field: "company.basic_info.crustdata_company_id", agg: "count", size: 100 }],
limit: 0,
});
if (!r.ok) return { error: r.message };
return r.data.aggregations;content.description[.](.)metadata.date_addedcompany_searchlimit: 1total_countcompany_searchcountlimit: 1total_countperson_searchcountlimit// user query: how big is my market — TAM/SAM with real counts
const base = [
in_("basic_info.industries", ["Software Development"]),
eq("locations.country", "USA"),
between("headcount.total", 51, 1000),
];
const layers = [
{ name: "TAM", extra: [] },
{ name: "SAM", extra: [gt("funding.total_investment_usd", 5000000)] },
{ name: "SAM-growing", extra: [gt("funding.total_investment_usd", 5000000), gt("headcount.growth_percent.12m", 20)] },
];
const counts = await parallelMap(layers, async (l) => {
const r = await callTool("company_search", {
filters: and_(...base, ...l.extra),
fields: ["crustdata_company_id"],
limit: 1,
});
return { layer: l.name, count: r.ok ? r.data.total_count : null, error: r.ok ? undefined : r.message };
});
return counts;web_search_liveparallelMapperson_searchrecently_changed_jobs// user query: champions who recently left my customer accounts
const r = await callTool("person_search", {
filters: and_(
in_("experience.employment_details.past.company_website_domain", inputs.customerDomains),
eq("recently_changed_jobs", true),
gte("professional_network.connections", 100),
excludes("experience.employment_details.past.title", "advisor"),
excludes("experience.employment_details.past.title", "investor"),
excludes("experience.employment_details.past.title", "board")
),
fields: ["basic_profile", "experience", "social_handles"],
limit: 50,
});
if (!r.ok) return { error: r.message };
return r.data.profiles.map(p => {
const cur = p.experience?.employment_details?.current?.[0];
const past = p.experience?.employment_details?.past?.[0];
return {
name: p.basic_profile?.name,
was: past?.title,
at: past?.name,
now: cur?.title,
nowAt: cur?.name,
landed: cur?.start_date,
url: profileUrl(p),
};
});experience.employment_details.past.end_daterecently_changed_jobs = truecurrent[].start_dateexcludes()current[].namecompany_namenamecurl -X POST https://api.crustdata.com/watch/person/search \
-H "authorization: Bearer YOUR_API_KEY" \
-H "x-api-version: 2025-11-01" \
-H "content-type: application/json" \
-d '{
"filters": {
"op": "and",
"conditions": [
{ "field": "experience.employment_details.past.company_website_domain", "type": "in", "value": ["customer1.com", "customer2.com"] },
{ "field": "recently_changed_jobs", "type": "=", "value": true }
]
},
"config": { "trigger": { "type": "interval", "every_hours": 168 } },
"notifications": [{ "type": "webhook", "url": "https://your-endpoint.example.com/champions" }]
}'content.description[.]social_post_search_liveweb_search_liveperson_contact_enrichchunkparallelMapfieldscredits_remainingcrustdata_company_idsexact_match: truecurrentColorbasic_profile.profile_picture_permalinkbasic_profileperson_searchbasic_info.logo_permalinkcompany_identifycompany_searchbasic_infodata:image/jpeg;base64,...binary/octet-stream<img src>assets/crustdata-logo-light.pngcrustdata-logo-dark.png#5547E2#8387FFcreditscredits_remainingaccount_credits| Call | Cost |
|---|---|
| Free |
| ~0.03 cr/result |
Count query ( | ~0.03-0.04 cr |
| counts only, ~free |
| 1 cr/query |
| 1 cr/page |
| 1 cr/post — 3 cr/post with |
| no base; cap 5 cr/person |
| 2 cr/returned match; +2 if technographics requested and returned (2-4/match) |
| Person Discovery Watcher | first run free baseline, then 0.5 cr/new person |
list_toolsget_schemaexecuteexecute({ code })await callTool(name, params)company_searchperson_searchcompany_identifycompany_autocompleteperson_autocompletejob_searchweb_search_liveweb_enrich_livesocial_post_search_liveperson_contact_enrichcompany_enrichaccount_creditsapi.crustdata.com