sales-prospecting について
sales-prospectingは、営業リサーチの依頼を7種類のプロスペクティング手順に振り分け、Crustdataで企業、連絡先、シグナルを調査・優先順位付けするスキルです。営業チームのリスト作成や機会発見を支援します。
主な機能
- 017種類のプロスペクティング手順への振り分け
- 02企業と類似アカウントの検索
- 03企業データによるアカウントリストの順位付け
- 04イベント関連の見込み客と購買担当者の特定
- 05拡大機会と離職するキーパーソンの把握
活用シーン
- 01ICPに基づく新規企業リストの作成
- 02テリトリーやCRM出力のアカウント優先順位付け
- 03イベントに関連する見込み客の発見
- 04顧客内の拡大機会と離職するキーパーソンの追跡
MCP 対応
このスキルはCode Mode MCPを介してCrustdataのデータツールを呼び出し、JavaScriptのexecuteスクリプトとcallToolを使用します。企業、人物、イベント、アカウントのシグナル検索を扱います。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ crustdata/ skills --skill sales-prospectingインストール後、Claude Code で/sales-prospectingを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonREADME.md
詳細
営業プロスペクティング
プロスペクティングの拠点です。必ず「目標は何ですか?」から始めてください。 7つのサブスキルを表示します。適切なサブスキルに振り分け、そのレシピを正確に実行します。以下のレシピはすべて実環境でテスト済みです。注意点も含めて、そのとおりに進めてください。
ステップ 0:コンテキスト(処理を止めない)
- 作業ディレクトリに
config/gtm-config.mdまたはconfig/persona-profile.mdがある場合は読み込み、ICP、販売する製品、購入者の役職、顧客リスト、技術スタックを確認します。 - ファイルがない場合は、その場で簡単な質問を1~2個します(「どの業界・規模・地域のお客様に販売していますか?購入するのはどの役職ですか?」)。または、設定を適切に作成するために icp-builder スキルを案内します。設定がなくても、実行を決して止めてはいけません。
- クレジットを消費する前に、依頼内容を一文で確認します。
目標メニュー(最初に表示)
- 新しい企業を探す — 「ICPはあります。新しいリストを作成してください」
- 類似企業を探す — 「最も優良な顧客に似た企業を探してください」
- アカウントをランク付けする — 「担当アカウント(ブック/テリトリー/CSV)はこちらです。どこから対応すべきですか?」
- イベントでのプロスペクティング — 「には誰が参加しますか?誰と会うべきですか?」
- 顧客内の拡大余地を探す — 「既存顧客のどこで事業を拡大できますか?」
- TAM ビルダー — 「実際の数値で、市場規模を教えてください」
- チャンピオントラッカー — 「チャンピオンが顧客企業を離れたら通知してください」(ライブ監視)
すべての検索の実行方法(Code Mode の基本ルール)
Crustdata のデータツールはすべて execute({ code }) 内で実行します。これはプレーンな JavaScript スクリプトです(get_schema の型付きインターフェースを参考にしてコードを作成しますが、型注釈は一切記述しません。: Type、as、ジェネリックを使うと構文解析エラーになり、実行全体が開始前に失敗して、費用も発生しません)。
- すべてのスクリプトはクエリコメントから始めます — ユーザーの文字どおりの依頼には
// user query: ...、そこから導き出した手順には// model query: ...を使います。コメントのないスクリプトは実行前に拒否されます。 - I/O プリミティブは 1 つだけです:
const r = await callTool(name, params)は{ ok: true, data }または{ ok: false, status, errorType, message }を返します。必ずr.okに応じて分岐してください — 呼び出しに失敗してもスクリプトは中断されないため、失敗を確認しないまま処理を続けると、空のデータが使われて「結果なし」のように見えてしまいます。 fieldsはレスポンスの許可リストです。 結果には指定したグループ/パスだけが含まれます。指定していないグループは後でundefinedとなり、データが欠けているように見えます。読み取るグループはすべて指定してください。- 返すデータは必要最小限にします。 スクリプトが返したデータだけがモデルに渡されます。生のプロフィールではなく、名前/ID/URL/シグナルの行にマッピングしてください。
- 独立した呼び出しは並列実行します。
await parallelMap(items, fn)を使い、最初にchunk(list, 25)で分割してください。カーソルページネーションや依存する段階は並列化しないでください。時間のかかる段階の後にはcheckpoint(acc)を呼び出し、タイムアウトしても途中までの進捗が返るようにします。 - カテゴリ値は有限の選択肢です。 もっともらしくても誤った値を使うと、エラーにならずに結果が 0 件になります。フィルタリングの前に、無料の
company_autocomplete/person_autocompleteで正確な保存値を確認してください。対象:basic_info.industries、taxonomy.professional_network_industry、funding.last_round_type、basic_info.company_type、役職、シニアリティ、function_category。 - シニアリティの語彙(person_search):
Entry Level、Entry Level Manager、Experienced Manager、Senior、Director、Vice President、CXO、Owner / Partner、In Training、Strategic。フィルタリング前に必ずperson_autocompleteで確認してください。 - プランで制限されるフィールドを指定すると、フィールド名を含む 403 エラーが呼び出し全体で発生します。そのフィールドを外して再実行してください。既知の対象:person_search の
professional_network.followersとmetadata。followers は投影しないでください。代わりにprofessional_network.connectionsでフィルタリングします(gte(..., 100)が使えます)。 - フィルターパスとレスポンスパスは異なります(person_search):
...current.company_nameでフィルタリングすると...current[].nameに返され、...current.company_idでフィルタリングすると...current[].crustdata_company_idに返され、...current.company_website_domainでフィルタリングすると...current[].company_websiteに返されます。プロフィール URL はsocial_handles.professional_network_identifier.profile_urlに返されます(profileUrl(p)アクセサーを使用)。このフィールドはフィルタリングできません。 - 値の形式:会社の
locations.countryはフィルターとして ISO-3(USA)を受け付けますが、返される値は正規化された正式名称です。レスポンスの値を"USA"と比較しないでください。雇用主の本社所在国は ISO-3 です。人物のbasic_profile.location.countryは正式名称(United States)です。ドメインは裸の形式(stripe.com)です。資金調達ステージは小文字のスネークケース(series_a)です。in/not_inは保存された文字列と完全一致し、=は大文字と小文字を区別しません。 - ネストされた配列での AND(person_search):ネストされた配列のフィールド(
experience.*)に対する通常のand_は、配列の同じ要素がすべての条件を満たす必要があります。そのため、「企業 X のエンジニア」はデフォルトでこの動作となり、問題なく機能します。異なる要素をまたぐ条件(「企業 A ではエンジニアであり、企業 B ではマネージャーだった」のように、異なる職歴を対象とする場合)では、通常のand_は結果を返しません。代わりにall_ofグループを使ってください。クエリビルダーにはall_ofヘルパーがないため、生のフィルターオブジェクトを記述します:{ op: "all_of", conditions: [ {...}, {...} ] }。1 つのフィールドに複数の必須値を指定する場合は、has_allが同じ動作をします。 - 結果が 0 件でも、一致するものがないとは限りません。 正しい形式のクエリでも、適切でない依頼を表現している場合があります。条件を分解し、低コストの件数確認で各述語の選択性をテストしてください。複数段階の結果を信頼する前に、実行レスポンスの
trajectory(呼び出しごとのフィルターと件数)を確認してください。 - ラウンドをまたいで重複を排除するには、person_search の
post_processing: { exclude_profiles: [...], exclude_names: [...] }を使います。
サブスキルのレシピ
1. 新規企業の検索(新規開拓)
入力:ICP(業界/規模/地域/ステージ)+シグナル(以下の一覧)+対象役職+希望件数。
ステップ 1 — カテゴリー値はすべてオートコンプリートで検証します。 値が間違っていると、何も返されないままになります。
// 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;
ステップ 2 — 広範な company_search を実行し、上位 10 件を確認して、2~4 回に分けて条件を絞り込みます。 絞り込みの軸:ステージを固定(funding.last_round_type)、金額帯(funding.total_investment_usd、funding.last_round_amount_usd)、basic_info.year_founded、成長率の下限 gt("headcount.growth_percent.12m", N) — フィルターには使えますが、ソートには使えません。成長率で順位付けするには、成長率をフィルターに使い、headcount.total または funding.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,
})),
};
ステップ 3 — 人物を取得します。 候補企業の ID と対象役職/職位レベルで絞り込んだ person_search を 1 回実行します(職位レベルの値は、まず person_autocomplete で解決します)。ノイズを除くフィルターも同じクエリに含めます:コネクション数の下限、アドバイザー/投資家の除外(excludes() は値ごとにあいまいな否定条件を 1 つ作成するため、複数の値には AND を指定します)。
// 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),
}));
ステップ 4 — FIT × TIMING × WARMTH をスコアリングします → 🔥/🟡/⚪。各行には、判断の決め手となったシグナルとその日付を表示します。無料データのみを使用し、連絡先のエンリッチメントはオプトインのままにします(共通ルールを参照)。
2. 類似企業
- 顧客候補を
company_identifyで特定します — 無料です。1 回の呼び出しで指定できる識別子の種類は 1 つだけです(domainsまたはnamesを配列で指定)。特定結果はあいまいです。1 つのドメインから複数の企業が一致する場合があります — 識別子ごとにconfidence_scoreが最も高い一致を選びます。 - 共通する特性(業界の値、規模の範囲、ステージ、成長率、地域)を確認するため、
in_("crustdata_company_id", seedIds)を指定したcompany_searchを 1 回実行します。
// 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,
}));
- これらの共通特性をフィルターにして、手順 2 からレシピ 1 を実行します。
nin_("crustdata_company_id", excludeIds)でシード企業と既存顧客を除外します。
3. 担当アカウントの順位付け(顧客リスト、テリトリー、貼り付けた CSV — 1 つのサブスキル)
入力:任意の場所から取得したアカウント名/ドメイン/CSV。
company_identifyで全行を解決します(無料。chunk(domains, 25)+parallelMapでバッチ処理し、1 回の呼び出しにつき識別子の種類は 1 つだけ)。解決できなかった行は正直に明記します — 黙って除外してはいけません。あいまいな一致が複数ある場合は、行ごとにconfidence_scoreが最も高いものを選びます。in_("crustdata_company_id", ids)を指定し、fields: ["crustdata_company_id", "basic_info", "funding", "headcount"]としたcompany_searchを 1 回実行します。成長率はheadcountグループ内で取得できます(headcount.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"],
})),
};
- ホットアカウントの詳細を追加する場合は、任意で
aggregationsとlimit: 0を指定したjob_searchを実行し、募集中の職種数を確認します(手軽な採用シグナルです。スニペットは拡大予測レーダーを参照)。 - スコアリング:TIMING を重視します。資金調達が 3 か月未満前なら 🔥、3~9 か月なら 🟡、12 か月超なら ⚪ です。従業員数の増加または採用の急増があれば、ランクを 1 段階上げます。出力:順位付きの表、各行の「理由」、今週の上位 5 件。
4. イベントでの見込み顧客開拓
- 参加企業のリストは実際の情報源から取得します。参加者を捏造してはいけません。
web_search_liveで「<イベント名> sponsors exhibitors」を検索します(公式の /sponsors ページには通常、スニペット内にティアが記載されています)。次に、web_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_identifyで特定します(無料。chunk(25)+parallelMap)。続いて、ICP に合う企業に絞るため、スコープを指定したcompany_searchを 1 回実行し、レシピ 1 のステップ 3 に従って人物を取得します。イベントについてすでに投稿している人物を優先します。イベント名でsocial_post_search_liveを実行してください。投稿 1 件につき 1 クレジット(exact_keyword_matchを指定すると 3 クレジット)を消費するため、limitは慎重に設定します(10~20)。 - 提出物:ICP への適合度順に並べた面談リスト。ブース/ティアと、イベントに言及した最初の声かけ案を添えます(以下の「手抜き禁止」ルールに従って作成します)。
5. 拡大機会のレーダー(見過ごされがちな収益機会)
入力:顧客リスト(CRM のエクスポート、または営業担当者から提供されたもの)。4 つの拡大領域を調査します。3 つの対象を絞った検索で顧客全体をカバーできるため、アカウントごとに 1 回呼び出す必要はありません。
- 新たな資金 — 対象を絞った
rank-my-accountsのcompany_search(資金調達フィールド):新たな資金調達は予算を意味します。 - 新たな人材 —
in_("experience.employment_details.current.company_id", customerIds)とシニアレベルを指定して、person_searchを 1 回だけ実行します。current[].start_dateを確認し、直近約 6 か月の人材に絞ります。販売対象の職能に新しい幹部が加わることは、最も有力な拡大のきっかけです。また、job_searchの求人も確認します(下記)。 - 新たな領域 — まだ関わりのないチーム、地域、職能:同じ対象を絞った
person_searchをスクリプト内でfunction_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_added で投稿を並べ替えます。
顧客ごとの出力:機会 — 領域 — 根拠(日付付き)— 推定規模(シート数/チーム数)— 温かいつながり — 推奨するアプローチ。顧客全体を拡大準備度で順位付けします。
6. TAM の算出(調査に基づく手法 — 適切に実施する)
ボトムアップで実際の企業数を数える方法は、トップダウンの推測に勝ります(実在する企業数 x ACV を数えます)。3 つのレイヤーを構築します。それぞれ company_search の件数クエリを 1 回実行します。limit: 1 を指定し、total_count を読み取ります。1 回あたり約 0.03 クレジットと安価なので、必要な内訳をすべて実行できます。注:company_search に count パラメーターはありません。limit: 1 + total_count が件数クエリになります(person_search には count があり、limit とは併用できません)。
- TAM — 最も広い条件を満たす市場(将来的に購入する可能性があるすべての企業)。検証済みの例:米国の「ソフトウェア開発」、従業員数 51~1000 人 = 8,244。
- SAM — 現在の製品/GTM で対応できる市場(資金調達状況/ステージ/地域の条件を追加)。検証済み:さらに 500 万ドル以上の資金調達を条件に追加 = 3,132。(さらに直近 12 か月の成長率 20% 超を加えると 1,245 に絞られます。有用な「成長中の SAM」の切り口です。)
- SOM — 現実的に獲得可能な市場:SAM x 信頼性のある成約率、または営業担当者数 x 年間成約数で算出します。
// 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;
次に、$ = 件数 x ACV(ACV は設定または営業担当者から取得)。トップダウンでも照合します。web_search_live でアナリストによる市場規模の数値を検索し、両方の数値を並べて示します。フィルターを明示してください。数値を検証できるよう、各件数の根拠となる正確なフィルターセットを必ず表示します。規模別/地域別/ステージ別などの内訳も、追加の件数クエリとして提示します。1 回あたり約 0.03 クレジットなので、parallelMap で気軽に実行できます。
7. チャンピオントラッカー(今すぐリストを作成+継続監視)
ステップ 1 — 今日のリスト。 過去の勤務先と recently_changed_jobs を使って person_search を実行します。
// 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_dateはフィルターに使用できません。試さないでください。対応している方法は、過去の勤務先とrecently_changed_jobs = trueを指定し、その後current[].start_dateを確認して候補を選別することです。- 生のリストにはノイズが多いため、各行を確認して除外してください: 「新しい」会社が依然として顧客(またはそのリブランド後の会社)である社内異動者、子会社化・買収による異動(会社名が変更された、または吸収されただけで、実際に退職した人はいないケース)、在籍期間がずっと前に終わったアドバイザー・投資家・LP、最近の転職が顧客と無関係な古い退職者。「おめでとうございます」と連絡する前に、顧客が直近の勤務先だったことを確認してください。
excludes()を使うと、アドバイザーや投資家の肩書の大半を最初に除外できます。条件ごとに値は 1 つ指定し、複数の条件を AND で組み合わせます。残りは各行を確認して除外してください。- 新しい会社名は
current[].nameから取得します(フィルターではcompany_nameを指定しますが、レスポンスのキーはnameです)。 - つながりの最低条件は維持してください。フォロワー数は投影しないでください。
ステップ 2 — ウォッチャー(継続実行)。 ウォッチャーは Code Mode ではなく、通常の REST です。Person Discovery Watcher は、検証したばかりのフィルターとまったく同じものを継続的なフィードに変換し、毎週、実行ごとに新たに一致した人のみを、任意の Webhook に配信します。初回実行は無料のベースライン(最大 5 件)で、その後は新しい人 1 人につき 0.5 クレジットです。
手順:まずステップ 1 の検索を実行して、リストが適切に見えることをユーザーと確認します → 同じフィルターで curl を作成します → 内容を提示します → 明示的な承認があった場合に限り作成します。
curl -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" }]
}'
ステップ 3 — 出力行: 人物 — [顧客] で [役職] — 現在は [新しい会社] で [役職] — [日付] に入社。「おめでとうございます。以前からお付き合いがありますね」という連絡をするため、アウトリーチツールに引き継ぎます。
シグナルの選択肢(ヒアリング時に提示、組み合わせ可能)
成長(従業員数の増加率、職種構成の成長、売上規模)— 資金調達(時期、ステージ、規模、投資家)— 採用(解決する課題に関わる職種、求人掲載の急増、求人情報内で言及された技術 content.description [.])— コンテンツとインテント(social_post_search_live による、キーワードを投稿した人物/会社の検索、競合への言及)— 人物と異動(チャンピオンの転職、新任幹部、競合からの転職者、顧客企業の元従業員、同じ学校の出身者)— 企業イベント(web_search_live によるニュース、ローンチ、新オフィス)— 技術とプレゼンス(テクノグラフィクス、ソフトウェアレビューの件数/評価)— 親近性(共通の知人、共通の投資家、アクセラレーター)— 除外条件(解雇、既存顧客、競合)— カスタム AND ルール。
UNIVERSAL RULES
- まず目標を尋ね、範囲を1行で確認してから、手順を実行し、各ステップを説明してください。
- 1回目の結果をそのまま出さず、反復してください。 絞り込みの各ラウンドで除外したものと、その理由を示してください。
- まず無料データを使ってください。 コンタクト情報のエンリッチメントはオプトインとし、実行前に費用を確認してください。連絡先情報には、基本料金なしの
person_contact_enrichをデフォルトで使用します。ビジネスメールは約1クレジット、個人メールは約2クレジット、電話番号は約2クレジットで、1人あたり最大5クレジットです。1回の呼び出しにつきURLは25件までです(chunkとparallelMapを使用)。費用を抑えるためにfieldsを絞り、実際の残高はcredits_remainingを確認してください。必ず上限を先に伝えてください:「20人分のメールアドレスで最大約100クレジットです。進めてよいですか?」 - 会社のエンリッチメント(返された一致1件につき2クレジット、technographicsをリクエストして返された場合は一致1件につきさらに2クレジット、つまり一致1件あたり2~4クレジット)は、無料の特定処理を行った後に限り、
crustdata_company_idsとexact_match: trueを使って実行してください。 - 常にジャンクを除外してください: コネクションが100件未満のプロフィール、プレースホルダーの見出し、アドバイザー/投資家/取締役、地域や役職の不一致。
- ウォッチャーの追加や外部への書き込みには、必ず明示的な承認を得てください。
- 引き渡し方法は必ず確認してください: スプレッドシート、CSVエクスポート(シーケンサーまたはCRMへのインポート用)、上位アカウントの詳細調査を account-research スキルに引き継ぐ、または表のみ。
- 作成するテキスト(最初の連絡文、施策、紹介依頼の文面など)では、emダッシュ、「delve」「leverage」「streamline」、埋め草の表現を使わないでください。そのアカウントに詳しい同僚のように書いてください。
- コンテンツに合わせてレイアウトを調整し、隠さないでください。 ブランドシステムは固定ですが、レイアウトは固定ではありません。実際のコンテンツが収まらない場合(会社名や人名が長い、タイトルが12語ある、行数が200件あるなど)は、コンテンツではなくレイアウトを変更してください。カードを伸ばす、切り詰めずに折り返す、1列にする、列幅を広げる、上限を引き上げる、横に広い要素専用のスクロール領域を設ける、といった方法があります。カードを切り抜く、名前を省略記号で短縮する、行を黙って削除することで、表示上の問題を解決してはいけません。上限をどうしても設ける場合は、読者が表示されていない内容を把握できるよう、UIに「214件中、上位50件を表示」と明記してください。引き渡す前にレンダリング結果を確認し、切れている部分を修正してください。
- レンダリング出力のアイコン: ダッシュボードのアイコンセットであるLucideを、
currentColorのストロークを使ったインラインSVGとして使用してください。成果物のUIに絵文字は使わないでください。🔥/🟡/⚪の評価段階はチャット用です。レンダリングされた成果物では、色付きピルまたはLucideグリフに置き換えてください。 - ロゴと写真は無料です。レンダリング出力に使ってください。 人物の写真も使用してください。
basic_profile.profile_picture_permalinkは、person_searchがすでに返すbasic_profileグループに含まれているため、レンダリングされた人物一覧ではモノグラムではなく顔写真を表示できます。basic_info.logo_permalinkは、各行の解決にすでに使用しているcompany_identifyと、company_searchのbasic_infoグループから返されます。Base64でインライン化し、data:image/jpeg;base64,...URIとして指定してください。メディアCDNはこれらをbinary/octet-streamとして配信するため、リモートの<img src>は空白で表示されます。会社にロゴがない場合は、モノグラムを代わりに表示してください。 - 成果物のブランド表示: 納品物は原則としてチャット内で扱える形式(表、CSV)にし、成果物をレンダリングすること自体を目的にしてはいけません。ただし、ユーザーがレンダリングされたページやドキュメント(HTMLリスト、TAMレポート、文書など)を希望する場合は、ヘッダーまたはフッターにCrustdataのブランドロックアップを含めてください。小さな大文字の「Powered by」という肩書きと、crustdata.comへのリンクを設定した公式Crustdataワードマークを配置します。ワードマークの2種類のファイルは、このスキルの
assets/にあります。crustdata-logo-light.png(明るい背景用の濃色テキスト)とcrustdata-logo-dark.png(暗い背景用の白色テキスト)で、どちらもapp.crustdata.comのヘッダーで使われているものと同じファイルです。テーマに合ったバリアントを高さ約17pxでBase64インライン化してください(ダークモードがあるページでは、テーマに応じて切り替えます)。ホットリンクは使わないでください。レンダリングされた成果物からリモート画像は取得できません。ブランドアクセントカラーは#5547E2(製品のプライマリーカラー。暗い背景では#8387FF)です。埋め込み可能な場合は本文フォントにGeistを使用し、それ以外の場合はシステムフォントスタックを使ってください。 - すべての実行レスポンスには
creditsとcredits_remainingが含まれます。account_creditsは無料で、必要に応じて残高を返します。
コスト早見表
| 呼び出し | コスト |
|---|---|
company_identify、オートコンプリート、get_schema | 無料 |
company_search / person_search / job_search | 結果 1 件あたり約 0.03 cr |
件数クエリ(limit: 1、total_count を読み取る) | 約 0.03~0.04 cr |
limit: 0 を指定した job_search の集計 | 件数のみ、ほぼ無料 |
web_search_live | クエリあたり 1 cr |
web_enrich_live | ページあたり 1 cr |
social_post_search_live | 投稿あたり 1 cr — exact_keyword_match を指定すると投稿あたり 3 cr。limit は意図的に設定してください |
person_contact_enrich | 基本料金なし。1 人あたり上限 5 cr |
company_enrich | 返された一致 1 件あたり 2 cr。テクノグラフィック情報が要求され、返された場合はさらに 2 cr(1 件あたり 2~4 cr) |
| Person Discovery Watcher | 初回実行時は無料でベースラインを取得し、その後は新規の人物 1 人あたり 0.5 cr |
ツールの依存関係
このスキルには以下が必要です。
- Crustdata MCP サーバー (install.crustdata.com/mcp):
list_tools、get_schema、executeを公開する単一の Code Mode MCP です。Crustdata のすべてのデータツールには、await callTool(name, params)を使うプレーンな JavaScript スクリプトをexecute({ code })内で実行してアクセスします。ここで使用するツール:company_search、person_search、company_identify、company_autocomplete、person_autocomplete、job_search、web_search_live、web_enrich_live、social_post_search_live、person_contact_enrich(オプトイン)、company_enrich(オプトイン)、account_credits - Crustdata REST API(
api.crustdata.com):champion-tracker watcher 専用です。このスキルはすぐに実行できる curl を出力します。ユーザーは API キーを指定し、明示的に承諾した後に実行します