
Email Search
- 57 installs
- 104 repo stars
- Updated July 1, 2026
- extruct-ai/gtm-skills
Helps with ai & agent building tasks.
About
email-search is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- email-search
- AI & Agent Building
- AI-coding skill
Email Search by the numbers
- 57 all-time installs (skills.sh)
- Ranked #6,669 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/extruct-ai/gtm-skills --skill email-searchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 57 |
|---|---|
| repo stars | ★ 104 |
| Last updated | July 1, 2026 |
| Repository | extruct-ai/gtm-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Email Finder
Turn LinkedIn profiles into verified emails and phones. Takes the output of people-search and runs it through contact enrichment providers like Prospeo or Fullenrich.
Related Skills
list-segmentation → people-search → email-search → email-generation → email-response-simulation → campaign-sendingAfter people-search finds WHO to contact (with LinkedIn URLs), this skill gets their verified contact info.
Extruct API Operations
This skill delegates all Extruct API calls to the extruct-api skill.
For all Extruct API operations, read and follow the instructions in skills/extruct-api/SKILL.md.
The only Extruct operation in this skill is reading people table data. Contact enrichment uses separate providers (Prospeo, Fullenrich, etc.) with their own APIs.
Inputs
| Input | Source | Required |
|---|---|---|
| People table ID | Child table from people-search | yes (or CSV) |
| People CSV | claude-code-gtm/csv/input/{campaign}/people_linkedin.csv | yes (or table) |
| Provider preference | User choice | yes |
| Include mobile phones | User choice | no (default: no) |
Choosing a Provider
Ask the user which contact enrichment provider they want to use. If they need guidance, consider:
- Have LinkedIn URLs? → providers with LinkedIn enrichment work best
- Need highest email hit rate? → waterfall providers try multiple sources
- Budget-conscious? → check credit costs per match
- Need mobile phones? → confirm the provider covers phone data
- Want maximum coverage? → run one provider first, then a second for misses
If the user doesn't know where to start, pre-configured options with local reference docs are available in references/.
Workflow
Step 0: Confirm provider and learn API
1. Ask the user which contact enrichment provider they want to use 2. Fetch or read the provider's API documentation and identify:
- Enrichment endpoint (single and bulk)
- Required input fields (LinkedIn URL, name, domain, etc.)
- Authentication method and credentials
- Throughput limits and request constraints
- Response format (email, phone, verification status)
- Credit/pricing model
3. Ask for their API credentials and confirm access 4. Plan the implementation and confirm with the user before proceeding
Step 1: Load people data
Option A: From Extruct people table (recommended) — Use the extruct-api skill to fetch data from the people table. Extract full_name, profile_url, role, and parent_row_id from each row. Split full name into first/last.
Option B: From CSV — Read claude-code-gtm/csv/input/{campaign}/people_linkedin.csv.
Step 2: Check credits
Before running enrichment, check the user's available credits or quota with the chosen provider (using the endpoint identified in Step 0). Present a cost estimate based on the number of contacts to enrich.
Step 3: Run enrichment
Using the chosen provider's API (from Step 0):
1. Prepare contact data in the format the provider expects (LinkedIn URL, name + domain, etc.) 2. Submit contacts in batches according to the provider's rate limits 3. Handle async responses if the provider uses polling 4. Collect results: emails, phone numbers, verification status 5. Track matched vs. unmatched contacts
If the user wants a waterfall (two providers), run the first provider, collect misses, then run misses through the second.
Step 4: Deduplicate and clean
Deduplicate by email. Filter out:
- Entries with no email
- Results where the provider marks verification as invalid
Step 5: Output contact CSV
Save enriched contacts to claude-code-gtm/csv/input/{campaign}/contacts.csv with columns:
first_name,last_name,email,email_verified,job_title,company_name,domain,linkedin_url,phone,location,source
Step 6: Review with user
Present summary:
Enrichment Results:
- Contacts submitted: N
- Emails found: N (X% hit rate)
- Emails verified: N
- Phones found: N
- No match: N
- Provider: [chosen provider]Show a sample of 10 contacts for spot-checking:
| Name | Title | Company | Phone | Source | |
|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... |
Ask:
- "Hit rate look acceptable? (>60% is good, >80% is great)"
- "Want to run the misses through another provider?"
- "Ready to proceed to
email-generation?"
API References
Pre-configured provider docs in references/ directory. For other providers, docs are fetched during Step 0.
Fullenrich API Reference
Waterfall contact enrichment — tries multiple data providers to maximize hit rate on emails and phones.
Base URL: https://api.fullenrich.com/api/v1 Auth: Authorization: Bearer YOUR_API_KEY API Key: https://app.fullenrich.com/app/api
Credit Costs
| Data point | Credits |
|---|---|
| Work email found | 1 |
| Personal email found | 3 |
| Mobile phone found | 10 |
| Search result returned | 0.25 per contact/company |
| No result found | 0 (no charge) |
| Duplicate (enriched within 3 months) | 0 (no charge) |
Endpoints
Check Credits
GET /account/creditsResponse: { "credits": 1234 }
Verify API Key
GET /account/keys/verifyBulk Enrich Contacts (async)
POST /contact/enrich/bulkBatch size: Up to 100 contacts per request.
Request body:
{
"contacts": [
{
"first_name": "Jane",
"last_name": "Doe",
"domain": "acme.com",
"linkedin_url": "https://www.linkedin.com/in/janedoe/"
}
],
"webhook_url": "https://your-server.com/webhook",
"webhook_events": ["contact_finished"]
}Required fields (at least one combo):
first_name+last_name+domain(orcompany_name)linkedin_url(improves accuracy 5-20% for emails, 10-60% for phones)
Optional fields:
company_name— company name (usedomainwhen possible for better accuracy)webhook_url— URL for async result delivery (recommended over polling)webhook_events—["contact_finished"]for per-contact notificationssilentFail— query param,trueto skip invalid contacts quietly
Response:
{
"enrichment_id": "uuid",
"status": "processing",
"total_contacts": 5
}Get Enrichment Results
GET /contact/enrich/bulk/{enrichment_id}Response:
{
"enrichment_id": "uuid",
"status": "completed",
"results": [
{
"input": { "first_name": "Jane", "last_name": "Doe", "domain": "acme.com" },
"work_email": {
"email": "jane.doe@acme.com",
"verification_status": "DELIVERABLE"
},
"personal_email": {
"email": "jane@gmail.com",
"verification_status": "DELIVERABLE"
},
"mobile_phone": {
"number": "+14155551234",
"region": "US"
},
"profile": {
"full_name": "Jane Doe",
"title": "VP of Sales",
"location": "San Francisco, CA",
"linkedin_url": "https://linkedin.com/in/janedoe",
"employment_history": [...],
"education": [...]
},
"company": {
"name": "Acme Corp",
"domain": "acme.com",
"industry": "Software",
"employee_count": 250
}
}
]
}Email verification statuses:
| Status | Bounce rate | Use |
|---|---|---|
DELIVERABLE | ~2% | Safe to email |
HIGH_PROBABILITY | ~9% | Safe (catch-all validated) |
CATCH_ALL | Higher | Use with caution |
INVALID | Likely bounces | Do not email |
Reverse Email Lookup (async)
POST /contact/reverse/email/bulk{
"emails": ["jane@acme.com", "john@example.com"],
"webhook_url": "https://your-server.com/webhook"
}Cost: 1 credit per match. Works with work and personal emails.
GET /contact/reverse/email/bulk/{enrichment_id}People Search (sync)
POST /people/search{
"filters": {
"job_title": ["VP of Sales", "Head of Sales"],
"seniority": ["VP", "Director"],
"location": ["United States"],
"company_size": ["51-200", "201-500"],
"industry": ["Software"]
},
"page": 1
}Cost: 0.25 credits per result returned. Synchronous response.
Company Search (sync)
POST /company/searchSimilar filter structure to people search but with company-level filters.
Rate Limits
- 60 API calls per minute (default, can be increased on request)
- 100 contacts per bulk enrichment request
- 100 concurrent enrichments in queue
- 100 concurrent reverse lookups in queue
- Search API is synchronous (no queue)
- Effective throughput: ~6,000 contacts/minute
Processing Time
- Average: 30-90 seconds per contact
- Varies by data availability and waterfall depth
- Use webhooks (recommended) instead of polling for results
Webhook Integration (recommended)
Set webhook_url in bulk requests. Fullenrich will POST results as they complete:
- Per-contact:
webhook_events: ["contact_finished"] - Retries: up to 5 times on delivery failure
- Verify delivery using a test endpoint
Test Contact (0 credits)
{
"first_name": "Grégoire",
"last_name": "Démogé",
"domain": "fullenrich.com",
"linkedin_url": "https://www.linkedin.com/in/demoge/"
}Data Retention
Results retained for 3 months (GDPR). Re-enrichment within window costs 0 credits.
Prospeo API Reference
Person and company enrichment with 200M+ contact database and 30+ search filters.
Base URL: https://api.prospeo.io Auth header: X-KEY: your_api_key Content-Type: application/json Method: All endpoints use POST API Key: https://app.prospeo.io/api
Credit Costs
| Endpoint | Credits |
|---|---|
| Enrich Person (email only) | 1 per match |
| Enrich Person (with mobile) | 10 per match |
| Bulk Enrich Person | Same as single, per matched record |
| Search Person | 1 per page (up to 25 results) |
| No match found | 0 (no charge) |
| Duplicate enrichment | 0 (no charge, lifetime dedup) |
Rate Limits
Tier-based. Check response headers:
x-daily-request-left— remaining daily requestsx-minute-request-left— remaining per-minute requestsx-second-rate-limit— per-second limitx-daily-reset-seconds— seconds until daily resetx-minute-reset-seconds— seconds until minute reset
Returns 429 when exceeded.
Endpoints
Search Person
POST /search-personSearch 200M+ contacts with 30+ filters. Returns person + company data but no email/mobile — use Enrich Person for that.
Request:
{
"filters": {
"job_title": {
"v": ["VP of Sales", "Head of Sales"],
"condition": "or"
},
"seniority": {
"v": ["VP", "Director", "C-Suite"],
"condition": "or"
},
"department": {
"v": ["Sales"],
"condition": "or"
},
"person_location": {
"v": ["United States"],
"condition": "or"
},
"industry": {
"v": ["Software", "Information Technology"],
"condition": "or"
},
"employee_range": {
"v": ["51-200", "201-500"],
"condition": "or"
},
"company_website": {
"v": ["acme.com", "example.com"],
"condition": "or"
}
},
"page": 1
}Available filters:
| Filter | Type | Notes |
|---|---|---|
job_title | string[] | Free text, use Search Suggestions for exact values |
seniority | enum[] | C-Suite, VP, Director, Manager, Senior, Entry, Training, Intern |
department | enum[] | Sales, Marketing, Engineering, Finance, HR, Operations, etc. |
person_location | string[] | Country, state, or city names |
industry | enum[] | 150+ industries |
employee_range | enum[] | 1-10, 11-20, 21-50, 51-100, 101-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+ |
company_website | string[] | Up to 500 domains per request |
company_name | string[] | Company names |
company_location | string[] | Country, state, or city |
funding_stage | enum[] | Seed, Series A, Series B, Series C, etc. |
technologies | enum[] | Salesforce, HubSpot, etc. |
mx_provider | enum[] | Gmail, Outlook, etc. |
years_of_experience | range | Min/max years |
All filters use "condition": "or" (match any) or "condition": "and" (match all) within the same filter field.
Response:
{
"error": false,
"results": [
{
"person": {
"id": "person-uuid",
"first_name": "Jane",
"last_name": "Doe",
"full_name": "Jane Doe",
"linkedin_url": "https://linkedin.com/in/janedoe",
"title": "VP of Sales",
"seniority": "VP",
"department": "Sales",
"location": "San Francisco, CA, US",
"skills": ["B2B Sales", "SaaS", "Revenue Operations"]
},
"company": {
"name": "Acme Corp",
"website": "acme.com",
"linkedin_url": "https://linkedin.com/company/acme",
"industry": "Software",
"headcount": 250,
"founded_year": 2018,
"location": "San Francisco, CA, US"
}
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total_page": 40,
"total_count": 1000
}
}Pagination: 25 results per page, max 1000 pages (25,000 results).
Enrich Person
POST /enrich-personGet verified email and optional mobile for a specific person.
Request:
{
"data": {
"first_name": "Jane",
"last_name": "Doe",
"company_website": "acme.com"
},
"only_verified_email": true,
"enrich_mobile": true,
"only_verified_mobile": false
}Required fields (at least one combo):
first_name+last_name+ (company_website|company_name|company_linkedin_url)full_name+ company infolinkedin_urlaloneemailaloneperson_id(from Search Person results)
Optional params:
only_verified_email(bool) — only return if email is verifiedenrich_mobile(bool) — include mobile lookup (costs 10 credits instead of 1)only_verified_mobile(bool) — only return if mobile is verified
Response:
{
"error": false,
"free_enrichment": false,
"person": {
"first_name": "Jane",
"last_name": "Doe",
"full_name": "Jane Doe",
"linkedin_url": "https://linkedin.com/in/janedoe",
"title": "VP of Sales",
"email": "jane.doe@acme.com",
"email_verified": true,
"mobile": "+14155551234",
"mobile_verified": true,
"location": "San Francisco, CA, US",
"skills": ["B2B Sales", "SaaS"]
},
"company": {
"name": "Acme Corp",
"website": "acme.com",
"industry": "Software",
"headcount": 250
}
}Error codes: NO_MATCH, INVALID_DATAPOINTS, INSUFFICIENT_CREDITS, INVALID_API_KEY, RATE_LIMITED
Bulk Enrich Person
POST /bulk-enrich-personEnrich up to 50 records at once. Same matching rules as single enrich.
Request:
{
"only_verified_email": true,
"enrich_mobile": false,
"only_verified_mobile": false,
"data": [
{
"first_name": "Jane",
"last_name": "Doe",
"company_website": "acme.com"
},
{
"linkedin_url": "https://linkedin.com/in/johndoe"
}
]
}Batch size: Max 50 records per request.
Response:
{
"error": false,
"total_cost": 5,
"matched": [
{
"person": { ... },
"company": { ... }
}
],
"not_matched": [
{ "first_name": "Unknown", "last_name": "Person", "company_website": "none.com" }
],
"invalid_datapoints": []
}Search Suggestions
POST /search-suggestionsGet exact filter values for job titles, locations, etc. Use before Search Person to get precise values.
Enrich Company
POST /enrich-companyGet verified company data including funding and technology details.
Search Company
POST /search-companySearch 30M+ company records.
Removed Endpoints (removed March 1, 2026)
These endpoints have been removed. Use the replacements listed:
- ~~Email Finder~~ → use Enrich Person
- ~~Mobile Finder~~ → use Enrich Person with
enrich_mobile: true - ~~Email Verifier~~ → use Enrich Person with
only_verified_email: true - ~~Domain Search~~ → use Search Person with
company_websitefilter - ~~Social URL Enrichment~~ → use Enrich Person with
linkedin_url