linkedin-secret-sauce 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +339 -31
- package/dist/cosiall-client.d.ts +1 -1
- package/dist/cosiall-client.js +1 -1
- package/dist/enrichment/index.d.ts +23 -2
- package/dist/enrichment/index.js +38 -22
- package/dist/enrichment/matching.d.ts +16 -2
- package/dist/enrichment/matching.js +387 -65
- package/dist/enrichment/providers/bounceban.d.ts +82 -0
- package/dist/enrichment/providers/bounceban.js +447 -0
- package/dist/enrichment/providers/bouncer.d.ts +1 -1
- package/dist/enrichment/providers/bouncer.js +19 -21
- package/dist/enrichment/providers/construct.d.ts +1 -1
- package/dist/enrichment/providers/construct.js +22 -38
- package/dist/enrichment/providers/cosiall.d.ts +1 -1
- package/dist/enrichment/providers/cosiall.js +3 -4
- package/dist/enrichment/providers/dropcontact.d.ts +15 -9
- package/dist/enrichment/providers/dropcontact.js +188 -19
- package/dist/enrichment/providers/hunter.d.ts +8 -1
- package/dist/enrichment/providers/hunter.js +52 -28
- package/dist/enrichment/providers/index.d.ts +2 -0
- package/dist/enrichment/providers/index.js +10 -1
- package/dist/enrichment/providers/ldd.d.ts +1 -10
- package/dist/enrichment/providers/ldd.js +20 -97
- package/dist/enrichment/providers/smartprospect.js +28 -48
- package/dist/enrichment/providers/snovio.d.ts +1 -1
- package/dist/enrichment/providers/snovio.js +29 -31
- package/dist/enrichment/providers/trykitt.d.ts +63 -0
- package/dist/enrichment/providers/trykitt.js +210 -0
- package/dist/enrichment/types.d.ts +220 -7
- package/dist/enrichment/types.js +16 -8
- package/dist/enrichment/utils/candidate-parser.d.ts +107 -0
- package/dist/enrichment/utils/candidate-parser.js +173 -0
- package/dist/enrichment/utils/noop-provider.d.ts +39 -0
- package/dist/enrichment/utils/noop-provider.js +37 -0
- package/dist/enrichment/utils/rate-limiter.d.ts +103 -0
- package/dist/enrichment/utils/rate-limiter.js +204 -0
- package/dist/enrichment/utils/validation.d.ts +75 -3
- package/dist/enrichment/utils/validation.js +164 -11
- package/dist/linkedin-api.d.ts +40 -1
- package/dist/linkedin-api.js +160 -27
- package/dist/types.d.ts +50 -1
- package/dist/utils/lru-cache.d.ts +105 -0
- package/dist/utils/lru-cache.js +175 -0
- package/docs/COSIALL_PROFILE_EMAILS.md +342 -0
- package/docs/ENRICHMENT.md +622 -0
- package/docs/INTEGRATION.md +405 -0
- package/docs/PLAYGROUND.md +558 -0
- package/docs/SALES_SEARCH.md +171 -0
- package/docs/api/.nojekyll +1 -0
- package/docs/api/assets/hierarchy.js +1 -0
- package/docs/api/assets/highlight.css +92 -0
- package/docs/api/assets/icons.js +18 -0
- package/docs/api/assets/icons.svg +1 -0
- package/docs/api/assets/main.js +60 -0
- package/docs/api/assets/navigation.js +1 -0
- package/docs/api/assets/search.js +1 -0
- package/docs/api/assets/style.css +1633 -0
- package/docs/api/classes/LinkedInClientError.html +37 -0
- package/docs/api/functions/_testGetAccountCookies.html +4 -0
- package/docs/api/functions/_testGetAccountEntry.html +4 -0
- package/docs/api/functions/_testGetAllAccountIds.html +3 -0
- package/docs/api/functions/_testGetPoolState.html +3 -0
- package/docs/api/functions/adminResetAccount.html +1 -0
- package/docs/api/functions/adminSetCooldown.html +1 -0
- package/docs/api/functions/buildCookieHeader.html +1 -0
- package/docs/api/functions/clearAllSmartLeadTokens.html +2 -0
- package/docs/api/functions/clearRequestHistory.html +1 -0
- package/docs/api/functions/clearSessionAccount.html +1 -0
- package/docs/api/functions/clearSmartLeadToken.html +2 -0
- package/docs/api/functions/createEnrichmentClient.html +8 -0
- package/docs/api/functions/extractCsrfToken.html +1 -0
- package/docs/api/functions/extractLinkedInHandle.html +7 -0
- package/docs/api/functions/fetchCookiesFromCosiall.html +14 -0
- package/docs/api/functions/fetchProfileEmailsFromCosiall.html +18 -0
- package/docs/api/functions/forceRefreshCookies.html +1 -0
- package/docs/api/functions/getAccountForSession.html +1 -0
- package/docs/api/functions/getAccountsSummary.html +1 -0
- package/docs/api/functions/getCompaniesBatch.html +5 -0
- package/docs/api/functions/getCompanyById.html +9 -0
- package/docs/api/functions/getCompanyByUrl.html +1 -0
- package/docs/api/functions/getConfig.html +1 -0
- package/docs/api/functions/getCookiePoolHealth.html +1 -0
- package/docs/api/functions/getProfileByUrn.html +17 -0
- package/docs/api/functions/getProfileByVanity.html +10 -0
- package/docs/api/functions/getProfilesBatch.html +1 -0
- package/docs/api/functions/getRequestHistory.html +1 -0
- package/docs/api/functions/getSalesNavigatorProfileDetails.html +1 -0
- package/docs/api/functions/getSalesNavigatorProfileFull.html +16 -0
- package/docs/api/functions/getSmartLeadToken.html +1 -0
- package/docs/api/functions/getSmartLeadTokenCacheStats.html +2 -0
- package/docs/api/functions/getSmartLeadUser.html +2 -0
- package/docs/api/functions/getSnapshot.html +1 -0
- package/docs/api/functions/getYearsAtCompanyOptions.html +2 -0
- package/docs/api/functions/getYearsInPositionOptions.html +2 -0
- package/docs/api/functions/getYearsOfExperienceOptions.html +2 -0
- package/docs/api/functions/incrementMetric.html +1 -0
- package/docs/api/functions/initializeCookiePool.html +1 -0
- package/docs/api/functions/initializeLinkedInClient.html +1 -0
- package/docs/api/functions/isBusinessEmail.html +4 -0
- package/docs/api/functions/isDisposableDomain.html +4 -0
- package/docs/api/functions/isDisposableEmail.html +4 -0
- package/docs/api/functions/isPersonalDomain.html +4 -0
- package/docs/api/functions/isPersonalEmail.html +4 -0
- package/docs/api/functions/isRoleAccount.html +4 -0
- package/docs/api/functions/isValidEmailSyntax.html +4 -0
- package/docs/api/functions/parseFullProfile.html +15 -0
- package/docs/api/functions/parseSalesSearchResults.html +1 -0
- package/docs/api/functions/reportAccountFailure.html +1 -0
- package/docs/api/functions/reportAccountSuccess.html +1 -0
- package/docs/api/functions/resolveCompanyUniversalName.html +1 -0
- package/docs/api/functions/searchSalesLeads.html +16 -0
- package/docs/api/functions/selectAccountForRequest.html +1 -0
- package/docs/api/functions/setAccountForSession.html +1 -0
- package/docs/api/functions/typeahead.html +1 -0
- package/docs/api/functions/verifyEmailMx.html +1 -0
- package/docs/api/hierarchy.html +1 -0
- package/docs/api/index.html +12 -0
- package/docs/api/interfaces/AccountCookies.html +4 -0
- package/docs/api/interfaces/BatchEnrichmentOptions.html +14 -0
- package/docs/api/interfaces/CacheAdapter.html +6 -0
- package/docs/api/interfaces/CanonicalEmail.html +14 -0
- package/docs/api/interfaces/Company.html +17 -0
- package/docs/api/interfaces/ConstructConfig.html +8 -0
- package/docs/api/interfaces/CosiallProfileEmailsResponse.html +11 -0
- package/docs/api/interfaces/DropcontactConfig.html +3 -0
- package/docs/api/interfaces/EnrichmentCandidate.html +34 -0
- package/docs/api/interfaces/EnrichmentClient.html +10 -0
- package/docs/api/interfaces/EnrichmentClientConfig.html +12 -0
- package/docs/api/interfaces/EnrichmentLogger.html +6 -0
- package/docs/api/interfaces/EnrichmentOptions.html +10 -0
- package/docs/api/interfaces/HunterConfig.html +3 -0
- package/docs/api/interfaces/LddConfig.html +4 -0
- package/docs/api/interfaces/LddProfileData.html +6 -0
- package/docs/api/interfaces/LinkedInClientConfig.html +20 -0
- package/docs/api/interfaces/LinkedInCookie.html +9 -0
- package/docs/api/interfaces/LinkedInPosition.html +14 -0
- package/docs/api/interfaces/LinkedInProfile.html +21 -0
- package/docs/api/interfaces/LinkedInSpotlightBadge.html +5 -0
- package/docs/api/interfaces/LinkedInTenure.html +3 -0
- package/docs/api/interfaces/Metrics.html +22 -0
- package/docs/api/interfaces/MetricsSnapshot.html +23 -0
- package/docs/api/interfaces/ProfileEducation.html +8 -0
- package/docs/api/interfaces/ProfileEmailsLookupOptions.html +9 -0
- package/docs/api/interfaces/ProfilePosition.html +12 -0
- package/docs/api/interfaces/ProfileSkill.html +3 -0
- package/docs/api/interfaces/ProviderResult.html +11 -0
- package/docs/api/interfaces/ProvidersConfig.html +17 -0
- package/docs/api/interfaces/RequestHistoryEntry.html +8 -0
- package/docs/api/interfaces/SalesLeadSearchResult.html +31 -0
- package/docs/api/interfaces/SalesNavigatorContactInfo.html +5 -0
- package/docs/api/interfaces/SalesNavigatorPosition.html +11 -0
- package/docs/api/interfaces/SalesNavigatorProfile.html +9 -0
- package/docs/api/interfaces/SalesNavigatorProfileFull.html +24 -0
- package/docs/api/interfaces/SearchSalesResult.html +5 -0
- package/docs/api/interfaces/SmartLeadAuthConfig.html +6 -0
- package/docs/api/interfaces/SmartLeadCredentials.html +3 -0
- package/docs/api/interfaces/SmartLeadLoginResponse.html +3 -0
- package/docs/api/interfaces/SmartLeadUser.html +8 -0
- package/docs/api/interfaces/SmartProspectConfig.html +19 -0
- package/docs/api/interfaces/SmartProspectContact.html +24 -0
- package/docs/api/interfaces/SmartProspectSearchFilters.html +42 -0
- package/docs/api/interfaces/TypeaheadItem.html +3 -0
- package/docs/api/interfaces/TypeaheadResult.html +3 -0
- package/docs/api/interfaces/VerificationResult.html +16 -0
- package/docs/api/types/CostCallback.html +2 -0
- package/docs/api/types/Geo.html +4 -0
- package/docs/api/types/LddApiResponse.html +1 -0
- package/docs/api/types/ProviderFunc.html +2 -0
- package/docs/api/types/ProviderName.html +2 -0
- package/docs/api/types/SalesSearchFilters.html +7 -0
- package/docs/api/types/TypeaheadType.html +1 -0
- package/docs/api/variables/COMPANY_SIZE_OPTIONS.html +1 -0
- package/docs/api/variables/DEFAULT_PROVIDER_ORDER.html +20 -0
- package/docs/api/variables/DISPOSABLE_DOMAINS.html +2 -0
- package/docs/api/variables/FUNCTION_OPTIONS.html +1 -0
- package/docs/api/variables/INDUSTRY_OPTIONS.html +1 -0
- package/docs/api/variables/LANGUAGE_OPTIONS.html +1 -0
- package/docs/api/variables/PERSONAL_DOMAINS.html +2 -0
- package/docs/api/variables/PROVIDER_COSTS.html +15 -0
- package/docs/api/variables/REGION_OPTIONS.html +1 -0
- package/docs/api/variables/SENIORITY_OPTIONS.html +3 -0
- package/docs/api/variables/YEARS_OPTIONS.html +1 -0
- package/docs/index.html +98 -0
- package/package.json +16 -5
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
# Email Enrichment Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to using the email enrichment module in LinkedIn Secret Sauce.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The enrichment module finds and verifies business emails using multiple providers in an optimized 3-phase strategy. It automatically balances cost, speed, and accuracy.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { createEnrichmentClient } from 'linkedin-secret-sauce';
|
|
13
|
+
|
|
14
|
+
const enrichment = createEnrichmentClient({
|
|
15
|
+
providers: {
|
|
16
|
+
// FREE providers (Phase 1)
|
|
17
|
+
ldd: { apiUrl: process.env.LDD_API_URL, apiToken: process.env.LDD_API_TOKEN },
|
|
18
|
+
smartprospect: { email: process.env.SMARTLEAD_EMAIL, password: process.env.SMARTLEAD_PASSWORD },
|
|
19
|
+
trykitt: { apiKey: process.env.TRYKITT_API_KEY },
|
|
20
|
+
// construct and cosiall are enabled by default (no config needed)
|
|
21
|
+
|
|
22
|
+
// Verification (Phase 2)
|
|
23
|
+
bounceban: { apiKey: process.env.BOUNCEBAN_API_KEY },
|
|
24
|
+
|
|
25
|
+
// Paid finders (Phase 3 - only if needed)
|
|
26
|
+
hunter: { apiKey: process.env.HUNTER_API_KEY },
|
|
27
|
+
snovio: { clientId: process.env.SNOVIO_CLIENT_ID, clientSecret: process.env.SNOVIO_CLIENT_SECRET },
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = await enrichment.enrich({
|
|
32
|
+
firstName: 'John',
|
|
33
|
+
lastName: 'Doe',
|
|
34
|
+
company: 'Acme Corp',
|
|
35
|
+
domain: 'acme.com',
|
|
36
|
+
linkedinUrl: 'https://linkedin.com/in/johndoe',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(result.business_email); // john.doe@acme.com
|
|
40
|
+
console.log(result.business_email_source); // 'trykitt'
|
|
41
|
+
console.log(result.business_email_verified); // true
|
|
42
|
+
console.log(result.business_email_confidence); // 95
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3-Phase Enrichment Strategy
|
|
48
|
+
|
|
49
|
+
The default provider order optimizes for cost and accuracy:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
PHASE 1 - Free Lookups (Parallel)
|
|
53
|
+
┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐
|
|
54
|
+
│ LDD │ SmartProspect │ Cosiall │ TryKitt │
|
|
55
|
+
│ (Database) │ (Database) │ (LinkedIn API) │ (AI Finder) │
|
|
56
|
+
│ FREE │ FREE* │ FREE │ FREE** │
|
|
57
|
+
└─────────────────┴─────────────────┴─────────────────┴─────────────────┘
|
|
58
|
+
↓
|
|
59
|
+
If no verified email found (confidence < 80%)
|
|
60
|
+
↓
|
|
61
|
+
PHASE 2 - Pattern + Verification
|
|
62
|
+
┌─────────────────────────────┬─────────────────────────────┐
|
|
63
|
+
│ Construct │ BounceBan │
|
|
64
|
+
│ (Pattern Guessing + MX) │ (Catch-all Verification) │
|
|
65
|
+
│ FREE │ FREE single / $0.003 │
|
|
66
|
+
└─────────────────────────────┴─────────────────────────────┘
|
|
67
|
+
↓
|
|
68
|
+
If still no verified email found
|
|
69
|
+
↓
|
|
70
|
+
PHASE 3 - Paid Finders (Only if needed)
|
|
71
|
+
┌─────────────────────────────┬─────────────────────────────┐
|
|
72
|
+
│ Hunter │ Snov.io │
|
|
73
|
+
│ $0.005/email │ $0.02/email │
|
|
74
|
+
└─────────────────────────────┴─────────────────────────────┘
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
*FREE with SmartLead subscription
|
|
78
|
+
**FREE for individuals with unlimited searches
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Supported Providers (11 Total)
|
|
83
|
+
|
|
84
|
+
### FREE Providers
|
|
85
|
+
|
|
86
|
+
| Provider | Type | Description | Required Config |
|
|
87
|
+
|----------|------|-------------|-----------------|
|
|
88
|
+
| **Construct** | Pattern | Email pattern guessing + MX verification | None (always enabled) |
|
|
89
|
+
| **Cosiall** | Lookup | Emails from LinkedIn profiles | None (uses global config) |
|
|
90
|
+
| **LDD** | Database | LinkedIn Data Dump (~500M verified emails) | `apiUrl`, `apiToken` |
|
|
91
|
+
| **SmartProspect** | Database | SmartLead's prospect database | `email`, `password` |
|
|
92
|
+
| **TryKitt.ai** | AI Finder | AI-powered email finder with catch-all verification | `apiKey` |
|
|
93
|
+
|
|
94
|
+
### PAID Providers
|
|
95
|
+
|
|
96
|
+
| Provider | Cost | Description | Required Config |
|
|
97
|
+
|----------|------|-------------|-----------------|
|
|
98
|
+
| **BounceBan** | FREE single / $0.003 bulk | Catch-all specialist (85-95% accuracy) | `apiKey` |
|
|
99
|
+
| **Hunter** | $0.005/email | Domain search + email finder | `apiKey` |
|
|
100
|
+
| **Bouncer** | $0.006/email | SMTP verification (99%+ accuracy) | `apiKey` |
|
|
101
|
+
| **Dropcontact** | $0.01/email | Email finder API | `apiKey` |
|
|
102
|
+
| **Snov.io** | $0.02/email | Email finding + verification | `clientId`, `clientSecret` |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Provider Configuration
|
|
107
|
+
|
|
108
|
+
### LDD (LinkedIn Data Dump)
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
ldd: {
|
|
112
|
+
apiUrl: process.env.LDD_API_URL, // Required: API endpoint
|
|
113
|
+
apiToken: process.env.LDD_API_TOKEN, // Required: Bearer token
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### SmartProspect
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
smartprospect: {
|
|
121
|
+
// Option 1: Email/password (recommended)
|
|
122
|
+
email: process.env.SMARTLEAD_EMAIL,
|
|
123
|
+
password: process.env.SMARTLEAD_PASSWORD,
|
|
124
|
+
|
|
125
|
+
// Option 2: Direct token
|
|
126
|
+
apiToken: process.env.SMARTLEAD_TOKEN,
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### TryKitt.ai
|
|
131
|
+
|
|
132
|
+
AI-powered email finding with enterprise identity server verification. FREE for individuals.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
trykitt: {
|
|
136
|
+
apiKey: process.env.TRYKITT_API_KEY, // Required
|
|
137
|
+
apiUrl: 'https://api.trykitt.ai', // Optional override
|
|
138
|
+
timeoutMs: 30000, // Optional (default: 30s)
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Get your API key at: https://trykitt.ai
|
|
143
|
+
|
|
144
|
+
### BounceBan
|
|
145
|
+
|
|
146
|
+
Specializes in catch-all email verification with 85-95% accuracy WITHOUT sending emails.
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
bounceban: {
|
|
150
|
+
apiKey: process.env.BOUNCEBAN_API_KEY, // Required
|
|
151
|
+
useDeepVerify: true, // +15-25% accuracy for pattern-guessed emails
|
|
152
|
+
useWaterfall: true, // Recommended: includes 30-min free retry window
|
|
153
|
+
apiUrl: 'https://api.bounceban.com', // Optional override
|
|
154
|
+
waterfallApiUrl: 'https://api-waterfall.bounceban.com', // Optional
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Get your API key at: https://bounceban.com
|
|
159
|
+
|
|
160
|
+
### Hunter
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
hunter: {
|
|
164
|
+
apiKey: process.env.HUNTER_API_KEY, // Required
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Get your API key at: https://hunter.io
|
|
169
|
+
|
|
170
|
+
### Bouncer
|
|
171
|
+
|
|
172
|
+
SMTP verification with 99%+ accuracy.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
bouncer: {
|
|
176
|
+
apiKey: process.env.BOUNCER_API_KEY, // Required
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Get your API key at: https://bouncer.io
|
|
181
|
+
|
|
182
|
+
### Snov.io
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
snovio: {
|
|
186
|
+
clientId: process.env.SNOVIO_CLIENT_ID, // Required
|
|
187
|
+
clientSecret: process.env.SNOVIO_CLIENT_SECRET, // Required
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Get your credentials at: https://snov.io
|
|
192
|
+
|
|
193
|
+
### Dropcontact
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
dropcontact: {
|
|
197
|
+
apiKey: process.env.DROPCONTACT_API_KEY, // Required
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Get your API key at: https://dropcontact.com
|
|
202
|
+
|
|
203
|
+
### Cosiall
|
|
204
|
+
|
|
205
|
+
Enabled by default using global Cosiall configuration. To disable:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
cosiall: {
|
|
209
|
+
enabled: false,
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Construct
|
|
214
|
+
|
|
215
|
+
Pattern guessing + MX verification. Always enabled, no API key needed.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
construct: {
|
|
219
|
+
maxAttempts: 8, // Max patterns to try (default: 8)
|
|
220
|
+
timeoutMs: 5000, // MX verification timeout (default: 5s)
|
|
221
|
+
smtpVerifyDelayMs: 2000, // Delay between SMTP checks (default: 2s)
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Environment Variables
|
|
228
|
+
|
|
229
|
+
Complete reference:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# LinkedIn API (required for Cosiall)
|
|
233
|
+
COSIALL_API_URL=https://...
|
|
234
|
+
COSIALL_API_KEY=...
|
|
235
|
+
|
|
236
|
+
# LDD
|
|
237
|
+
LDD_API_URL=https://...
|
|
238
|
+
LDD_API_TOKEN=...
|
|
239
|
+
|
|
240
|
+
# SmartProspect/SmartLead
|
|
241
|
+
SMARTLEAD_EMAIL=...
|
|
242
|
+
SMARTLEAD_PASSWORD=...
|
|
243
|
+
# OR
|
|
244
|
+
SMARTLEAD_TOKEN=...
|
|
245
|
+
|
|
246
|
+
# TryKitt.ai (FREE for individuals)
|
|
247
|
+
TRYKITT_API_KEY=...
|
|
248
|
+
|
|
249
|
+
# BounceBan (FREE single verification)
|
|
250
|
+
BOUNCEBAN_API_KEY=...
|
|
251
|
+
|
|
252
|
+
# Hunter ($0.005/email)
|
|
253
|
+
HUNTER_API_KEY=...
|
|
254
|
+
|
|
255
|
+
# Bouncer ($0.006/email)
|
|
256
|
+
BOUNCER_API_KEY=...
|
|
257
|
+
|
|
258
|
+
# Snov.io ($0.02/email)
|
|
259
|
+
SNOVIO_CLIENT_ID=...
|
|
260
|
+
SNOVIO_CLIENT_SECRET=...
|
|
261
|
+
|
|
262
|
+
# Dropcontact ($0.01/email)
|
|
263
|
+
DROPCONTACT_API_KEY=...
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## API Reference
|
|
269
|
+
|
|
270
|
+
### `createEnrichmentClient(config)`
|
|
271
|
+
|
|
272
|
+
Creates an enrichment client instance.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const enrichment = createEnrichmentClient({
|
|
276
|
+
providers: { /* provider configs */ },
|
|
277
|
+
options: {
|
|
278
|
+
providerOrder: ['ldd', 'trykitt', 'construct', 'hunter'], // Custom order
|
|
279
|
+
maxCostPerEmail: 0.05, // Max USD to spend per email
|
|
280
|
+
confidenceThreshold: 70, // Min confidence to accept (0-100)
|
|
281
|
+
retryMs: 200, // Retry delay on transient errors
|
|
282
|
+
},
|
|
283
|
+
cache: myRedisCache, // Optional cache adapter
|
|
284
|
+
onCost: (provider, cost) => { /* track costs */ },
|
|
285
|
+
logger: myLogger, // Optional logger
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### `enrichment.enrich(candidate)`
|
|
290
|
+
|
|
291
|
+
Find a single business email. Returns first verified match.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const result = await enrichment.enrich({
|
|
295
|
+
firstName: 'John',
|
|
296
|
+
lastName: 'Doe',
|
|
297
|
+
company: 'Acme Corp',
|
|
298
|
+
domain: 'acme.com', // Optional but improves accuracy
|
|
299
|
+
linkedinUrl: 'linkedin.com/in/johndoe', // For LDD/Cosiall lookups
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Result
|
|
303
|
+
{
|
|
304
|
+
business_email: 'john.doe@acme.com',
|
|
305
|
+
business_email_source: 'trykitt',
|
|
306
|
+
business_email_verified: true,
|
|
307
|
+
business_email_confidence: 95,
|
|
308
|
+
last_checked_at: '2024-01-15T10:30:00.000Z',
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### `enrichment.enrichAll(candidate)`
|
|
313
|
+
|
|
314
|
+
Get ALL emails from ALL providers (doesn't stop at first match).
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
const result = await enrichment.enrichAll({
|
|
318
|
+
firstName: 'John',
|
|
319
|
+
lastName: 'Doe',
|
|
320
|
+
domain: 'acme.com',
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Result
|
|
324
|
+
{
|
|
325
|
+
emails: [
|
|
326
|
+
{ email: 'john.doe@acme.com', source: 'trykitt', confidence: 95, verified: true, type: 'business' },
|
|
327
|
+
{ email: 'j.doe@acme.com', source: 'construct', confidence: 70, verified: false, type: 'business' },
|
|
328
|
+
{ email: 'johndoe@gmail.com', source: 'cosiall', confidence: 100, verified: true, type: 'personal' },
|
|
329
|
+
],
|
|
330
|
+
totalCost: 0.005,
|
|
331
|
+
providersQueried: ['ldd', 'smartprospect', 'cosiall', 'trykitt', 'construct', 'hunter'],
|
|
332
|
+
completedAt: '2024-01-15T10:30:00.000Z',
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### `enrichment.enrichBatch(candidates, options)`
|
|
337
|
+
|
|
338
|
+
Process multiple candidates efficiently.
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const results = await enrichment.enrichBatch(candidates, {
|
|
342
|
+
batchSize: 50, // Process 50 at a time
|
|
343
|
+
delayMs: 200, // Delay between batches
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### `enrichment.enrichAllBatch(candidates, options)`
|
|
348
|
+
|
|
349
|
+
Batch version of `enrichAll()`.
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
const results = await enrichment.enrichAllBatch(candidates, {
|
|
353
|
+
batchSize: 50,
|
|
354
|
+
delayMs: 200,
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Standalone Provider Functions
|
|
361
|
+
|
|
362
|
+
For advanced use cases, you can call providers directly:
|
|
363
|
+
|
|
364
|
+
### TryKitt.ai
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import { findEmailWithTryKitt, verifyEmailWithTryKitt } from 'linkedin-secret-sauce';
|
|
368
|
+
|
|
369
|
+
// Find email
|
|
370
|
+
const result = await findEmailWithTryKitt(
|
|
371
|
+
'John Doe',
|
|
372
|
+
'acme.com',
|
|
373
|
+
{ apiKey: process.env.TRYKITT_API_KEY },
|
|
374
|
+
'https://linkedin.com/in/johndoe' // Optional LinkedIn URL
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
// Verify email
|
|
378
|
+
const verification = await verifyEmailWithTryKitt(
|
|
379
|
+
'john@acme.com',
|
|
380
|
+
{ apiKey: process.env.TRYKITT_API_KEY }
|
|
381
|
+
);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### BounceBan
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
import {
|
|
388
|
+
verifyEmailWithBounceBan,
|
|
389
|
+
verifyEmailsBatchWithBounceBan,
|
|
390
|
+
checkCatchAllWithBounceBan
|
|
391
|
+
} from 'linkedin-secret-sauce';
|
|
392
|
+
|
|
393
|
+
// Verify single email (FREE)
|
|
394
|
+
const result = await verifyEmailWithBounceBan('john@acme.com', {
|
|
395
|
+
apiKey: process.env.BOUNCEBAN_API_KEY,
|
|
396
|
+
useDeepVerify: true,
|
|
397
|
+
useWaterfall: true,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// Check catch-all domain
|
|
401
|
+
const isCatchAll = await checkCatchAllWithBounceBan('acme.com', config);
|
|
402
|
+
|
|
403
|
+
// Batch verification
|
|
404
|
+
const results = await verifyEmailsBatchWithBounceBan(emails, config);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Bouncer
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
import { verifyEmailWithBouncer, checkCatchAllDomain, verifyEmailsBatch } from 'linkedin-secret-sauce';
|
|
411
|
+
|
|
412
|
+
const result = await verifyEmailWithBouncer('john@acme.com', {
|
|
413
|
+
apiKey: process.env.BOUNCER_API_KEY,
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Snov.io
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import { findEmailsWithSnovio, verifyEmailWithSnovio } from 'linkedin-secret-sauce';
|
|
421
|
+
|
|
422
|
+
const emails = await findEmailsWithSnovio('John', 'Doe', 'acme.com', {
|
|
423
|
+
clientId: process.env.SNOVIO_CLIENT_ID,
|
|
424
|
+
clientSecret: process.env.SNOVIO_CLIENT_SECRET,
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Email Validation Utilities
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
import {
|
|
434
|
+
isValidEmailSyntax,
|
|
435
|
+
isPersonalEmail,
|
|
436
|
+
isBusinessEmail,
|
|
437
|
+
isDisposableEmail,
|
|
438
|
+
isRoleAccount,
|
|
439
|
+
verifyEmailMx,
|
|
440
|
+
checkDomainCatchAll,
|
|
441
|
+
PERSONAL_DOMAINS,
|
|
442
|
+
DISPOSABLE_DOMAINS,
|
|
443
|
+
} from 'linkedin-secret-sauce';
|
|
444
|
+
|
|
445
|
+
// Syntax validation
|
|
446
|
+
isValidEmailSyntax('john@example.com'); // true
|
|
447
|
+
|
|
448
|
+
// Domain classification
|
|
449
|
+
isPersonalEmail('john@gmail.com'); // true
|
|
450
|
+
isBusinessEmail('john@acme.com'); // true
|
|
451
|
+
isDisposableEmail('x@mailinator.com'); // true
|
|
452
|
+
isRoleAccount('info@company.com'); // true
|
|
453
|
+
|
|
454
|
+
// MX verification
|
|
455
|
+
const hasMx = await verifyEmailMx('john@acme.com');
|
|
456
|
+
|
|
457
|
+
// Catch-all detection
|
|
458
|
+
const isCatchAll = await checkDomainCatchAll('acme.com');
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Cost Tracking
|
|
464
|
+
|
|
465
|
+
Track costs across providers:
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
let totalCost = 0;
|
|
469
|
+
|
|
470
|
+
const enrichment = createEnrichmentClient({
|
|
471
|
+
providers: { /* ... */ },
|
|
472
|
+
onCost: (provider, cost) => {
|
|
473
|
+
totalCost += cost;
|
|
474
|
+
console.log(`${provider}: $${cost.toFixed(4)}`);
|
|
475
|
+
},
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// After enrichment
|
|
479
|
+
console.log(`Total spent: $${totalCost.toFixed(4)}`);
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Provider costs are also available as constants:
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
import { PROVIDER_COSTS } from 'linkedin-secret-sauce';
|
|
486
|
+
|
|
487
|
+
console.log(PROVIDER_COSTS);
|
|
488
|
+
// {
|
|
489
|
+
// construct: 0,
|
|
490
|
+
// ldd: 0,
|
|
491
|
+
// smartprospect: 0,
|
|
492
|
+
// cosiall: 0,
|
|
493
|
+
// trykitt: 0,
|
|
494
|
+
// bounceban: 0.003,
|
|
495
|
+
// hunter: 0.005,
|
|
496
|
+
// dropcontact: 0.01,
|
|
497
|
+
// bouncer: 0.006,
|
|
498
|
+
// snovio: 0.02,
|
|
499
|
+
// }
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## Caching
|
|
505
|
+
|
|
506
|
+
Implement a cache adapter to avoid duplicate lookups:
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
const enrichment = createEnrichmentClient({
|
|
510
|
+
providers: { /* ... */ },
|
|
511
|
+
cache: {
|
|
512
|
+
async get(key: string) {
|
|
513
|
+
return redis.get(key);
|
|
514
|
+
},
|
|
515
|
+
async set(key: string, value: any, ttlMs?: number) {
|
|
516
|
+
await redis.set(key, value, 'PX', ttlMs || 30 * 24 * 60 * 60 * 1000);
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Default cache TTL is 30 days.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## Custom Provider Order
|
|
527
|
+
|
|
528
|
+
Override the default 3-phase strategy:
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
const enrichment = createEnrichmentClient({
|
|
532
|
+
providers: { /* ... */ },
|
|
533
|
+
options: {
|
|
534
|
+
providerOrder: [
|
|
535
|
+
'ldd', // Check database first
|
|
536
|
+
'trykitt', // Then AI finder
|
|
537
|
+
'construct', // Pattern guess
|
|
538
|
+
'bounceban', // Verify patterns
|
|
539
|
+
'hunter', // Paid finder last
|
|
540
|
+
],
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Error Handling
|
|
548
|
+
|
|
549
|
+
The enrichment client handles errors gracefully - providers that fail return `null` and the next provider is tried. To get visibility:
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
const enrichment = createEnrichmentClient({
|
|
553
|
+
providers: { /* ... */ },
|
|
554
|
+
logger: {
|
|
555
|
+
debug: (msg, data) => console.debug(msg, data),
|
|
556
|
+
info: (msg, data) => console.info(msg, data),
|
|
557
|
+
warn: (msg, data) => console.warn(msg, data),
|
|
558
|
+
error: (msg, data) => console.error(msg, data),
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## LinkedIn Contact Matching
|
|
566
|
+
|
|
567
|
+
For workflows that start with LinkedIn data:
|
|
568
|
+
|
|
569
|
+
```typescript
|
|
570
|
+
import {
|
|
571
|
+
getEmailsForLinkedInContact,
|
|
572
|
+
salesLeadToContact,
|
|
573
|
+
searchSalesLeads,
|
|
574
|
+
} from 'linkedin-secret-sauce';
|
|
575
|
+
|
|
576
|
+
// Search LinkedIn
|
|
577
|
+
const results = await searchSalesLeads('cto fintech', { count: 25 });
|
|
578
|
+
|
|
579
|
+
// Enrich each lead
|
|
580
|
+
for (const lead of results.items) {
|
|
581
|
+
const contact = salesLeadToContact(lead);
|
|
582
|
+
|
|
583
|
+
const emailResult = await getEmailsForLinkedInContact(contact, {
|
|
584
|
+
smartprospect: { email: '...', password: '...' },
|
|
585
|
+
trykitt: { apiKey: '...' },
|
|
586
|
+
bounceban: { apiKey: '...' },
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
console.log(emailResult.bestEmail);
|
|
590
|
+
console.log(emailResult.emails);
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## Troubleshooting
|
|
597
|
+
|
|
598
|
+
### No emails found
|
|
599
|
+
|
|
600
|
+
1. Ensure at least one provider is configured correctly
|
|
601
|
+
2. Check that the candidate has enough data (name + domain/company)
|
|
602
|
+
3. Try `enrichAll()` to see what each provider returns
|
|
603
|
+
4. Check logs for provider errors
|
|
604
|
+
|
|
605
|
+
### Low confidence scores
|
|
606
|
+
|
|
607
|
+
1. Provide more candidate data (LinkedIn URL improves accuracy)
|
|
608
|
+
2. Enable BounceBan verification for pattern-guessed emails
|
|
609
|
+
3. Consider using TryKitt for AI-powered finding
|
|
610
|
+
|
|
611
|
+
### High costs
|
|
612
|
+
|
|
613
|
+
1. Ensure FREE providers are configured first
|
|
614
|
+
2. Use `maxCostPerEmail` option to set a budget
|
|
615
|
+
3. Use `confidenceThreshold` to accept lower confidence results from free providers
|
|
616
|
+
4. Monitor costs with `onCost` callback
|
|
617
|
+
|
|
618
|
+
### Rate limiting
|
|
619
|
+
|
|
620
|
+
1. Use `delayMs` in batch operations
|
|
621
|
+
2. Check provider-specific rate limits in their documentation
|
|
622
|
+
3. Implement caching to avoid duplicate lookups
|