linkedin-secret-sauce 0.12.2 → 0.12.4
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 +276 -40
- package/dist/enrichment/index.d.ts +22 -3
- package/dist/enrichment/index.js +29 -38
- package/dist/enrichment/matching.d.ts +4 -8
- package/dist/enrichment/matching.js +6 -5
- package/dist/enrichment/orchestrator.d.ts +1 -1
- package/dist/enrichment/orchestrator.js +51 -44
- package/dist/enrichment/providers/index.d.ts +0 -2
- package/dist/enrichment/providers/index.js +1 -8
- package/dist/enrichment/providers/snovio.d.ts +4 -4
- package/dist/enrichment/providers/snovio.js +14 -14
- package/dist/enrichment/types.d.ts +18 -71
- package/dist/enrichment/types.js +3 -8
- package/dist/enrichment/utils/rate-limiter.js +0 -2
- package/dist/index.d.ts +2 -4
- package/dist/index.js +2 -2
- package/docs/COSIALL_PROFILE_EMAILS.md +342 -0
- package/docs/ENRICHMENT.md +580 -0
- package/docs/INTEGRATION.md +403 -0
- package/docs/PLAYGROUND.md +553 -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/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 +14 -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 +19 -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 +13 -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 +40 -28
- package/dist/enrichment/providers/apollo.d.ts +0 -11
- package/dist/enrichment/providers/apollo.js +0 -181
- package/dist/enrichment/providers/bouncer.d.ts +0 -67
- package/dist/enrichment/providers/bouncer.js +0 -231
- package/dist/enrichment/providers/dropcontact.d.ts +0 -22
- package/dist/enrichment/providers/dropcontact.js +0 -206
package/dist/enrichment/types.js
CHANGED
|
@@ -21,10 +21,9 @@ exports.SMARTPROSPECT_SUB_INDUSTRIES = exports.PROVIDER_COSTS = exports.DEFAULT_
|
|
|
21
21
|
* - bounceban: BounceBan catch-all verification (FREE single, $0.003/bulk)
|
|
22
22
|
*
|
|
23
23
|
* PHASE 3 - Paid finders (only if Phase 2 inconclusive):
|
|
24
|
-
* - hunter: Hunter.io email finder ($0.
|
|
24
|
+
* - hunter: Hunter.io email finder ($0.015/email)
|
|
25
25
|
* - snovio: Snov.io email finder ($0.02/email)
|
|
26
26
|
*
|
|
27
|
-
* Note: bouncer, dropcontact available but not in default order
|
|
28
27
|
*/
|
|
29
28
|
exports.DEFAULT_PROVIDER_ORDER = [
|
|
30
29
|
"ldd",
|
|
@@ -46,10 +45,8 @@ exports.DEFAULT_PROVIDER_ORDER = [
|
|
|
46
45
|
* - trykitt: FREE (unlimited for individuals, $0.005/email high volume)
|
|
47
46
|
* - construct: FREE (pattern guessing + MX check)
|
|
48
47
|
* - bounceban: FREE single / $0.003/email bulk (catch-all specialist)
|
|
49
|
-
* -
|
|
48
|
+
* - hunter: $0.015/email (Growth tier)
|
|
50
49
|
* - snovio: $0.02/email (email finding + verification)
|
|
51
|
-
* - hunter: $0.005/email
|
|
52
|
-
* - dropcontact: $0.01/email (not in default order)
|
|
53
50
|
*/
|
|
54
51
|
exports.PROVIDER_COSTS = {
|
|
55
52
|
construct: 0,
|
|
@@ -58,9 +55,7 @@ exports.PROVIDER_COSTS = {
|
|
|
58
55
|
cosiall: 0,
|
|
59
56
|
trykitt: 0, // FREE for individuals
|
|
60
57
|
bounceban: 0.003, // FREE single, $0.003 bulk
|
|
61
|
-
hunter: 0.
|
|
62
|
-
dropcontact: 0.01,
|
|
63
|
-
bouncer: 0.006,
|
|
58
|
+
hunter: 0.015,
|
|
64
59
|
snovio: 0.02,
|
|
65
60
|
};
|
|
66
61
|
/**
|
|
@@ -26,8 +26,6 @@ exports.DEFAULT_RATE_LIMITS = {
|
|
|
26
26
|
hunter: { maxRequests: 10, windowMs: 1000, minDelayMs: 100 },
|
|
27
27
|
snovio: { maxRequests: 60, windowMs: 60000, minDelayMs: 1000 },
|
|
28
28
|
bounceban: { maxRequests: 10, windowMs: 1000, minDelayMs: 100 },
|
|
29
|
-
bouncer: { maxRequests: 10, windowMs: 1000, minDelayMs: 100 },
|
|
30
|
-
dropcontact: { maxRequests: 5, windowMs: 1000, minDelayMs: 200 },
|
|
31
29
|
smartprospect: { maxRequests: 2, windowMs: 1000, minDelayMs: 500 },
|
|
32
30
|
// Free providers have no external limits
|
|
33
31
|
construct: { maxRequests: 100, windowMs: 1000, minDelayMs: 0 },
|
package/dist/index.d.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* const enrichment = createEnrichmentClient({
|
|
31
31
|
* providers: {
|
|
32
32
|
* hunter: { apiKey: process.env.HUNTER_API_KEY },
|
|
33
|
-
*
|
|
33
|
+
* bounceban: { apiKey: process.env.BOUNCEBAN_API_KEY },
|
|
34
34
|
* },
|
|
35
35
|
* });
|
|
36
36
|
*
|
|
@@ -68,7 +68,7 @@ export * from "./constants";
|
|
|
68
68
|
* providers: {
|
|
69
69
|
* construct: {}, // FREE pattern matching
|
|
70
70
|
* hunter: { apiKey: 'xxx' },
|
|
71
|
-
*
|
|
71
|
+
* bounceban: { apiKey: 'xxx' },
|
|
72
72
|
* },
|
|
73
73
|
* onCost: (provider, cost) => console.log(`${provider}: $${cost}`),
|
|
74
74
|
* });
|
|
@@ -108,8 +108,6 @@ HunterConfig,
|
|
|
108
108
|
SmartProspectConfig,
|
|
109
109
|
/** LinkedIn Data Dump configuration */
|
|
110
110
|
LddConfig,
|
|
111
|
-
/** Dropcontact configuration */
|
|
112
|
-
DropcontactConfig,
|
|
113
111
|
/** Construct provider configuration */
|
|
114
112
|
ConstructConfig,
|
|
115
113
|
/** Cache adapter interface */
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* const enrichment = createEnrichmentClient({
|
|
32
32
|
* providers: {
|
|
33
33
|
* hunter: { apiKey: process.env.HUNTER_API_KEY },
|
|
34
|
-
*
|
|
34
|
+
* bounceban: { apiKey: process.env.BOUNCEBAN_API_KEY },
|
|
35
35
|
* },
|
|
36
36
|
* });
|
|
37
37
|
*
|
|
@@ -115,7 +115,7 @@ __exportStar(require("./constants"), exports);
|
|
|
115
115
|
* providers: {
|
|
116
116
|
* construct: {}, // FREE pattern matching
|
|
117
117
|
* hunter: { apiKey: 'xxx' },
|
|
118
|
-
*
|
|
118
|
+
* bounceban: { apiKey: 'xxx' },
|
|
119
119
|
* },
|
|
120
120
|
* onCost: (provider, cost) => console.log(`${provider}: $${cost}`),
|
|
121
121
|
* });
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Cosiall Profile Emails API
|
|
2
|
+
|
|
3
|
+
This document describes how to use the Cosiall Profile Emails API to retrieve email addresses associated with LinkedIn profiles.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Profile Emails endpoint retrieves all email addresses associated with a LinkedIn profile from the Cosiall database. It provides flexible lookup options using ObjectURN, LinkedIn URL, or vanity name.
|
|
8
|
+
|
|
9
|
+
## API Endpoint
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
GET /api/flexiq/profile-emails
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Authentication
|
|
16
|
+
|
|
17
|
+
| Header | Value | Required |
|
|
18
|
+
|--------|-------|----------|
|
|
19
|
+
| `X-API-Key` | Your FlexIQ API key | Yes |
|
|
20
|
+
|
|
21
|
+
### Query Parameters
|
|
22
|
+
|
|
23
|
+
At least one of the following parameters must be provided:
|
|
24
|
+
|
|
25
|
+
| Parameter | Type | Description | Example |
|
|
26
|
+
|-----------|------|-------------|---------|
|
|
27
|
+
| `objectUrn` | string | LinkedIn ObjectURN identifier | `urn:li:member:129147375` |
|
|
28
|
+
| `linkedInUrl` | string | Full LinkedIn profile URL | `https://www.linkedin.com/in/john-doe/` |
|
|
29
|
+
| `vanity` | string | LinkedIn username/vanity name | `john-doe` |
|
|
30
|
+
|
|
31
|
+
**Priority**: If multiple parameters are provided, the lookup follows this order:
|
|
32
|
+
1. `objectUrn` (most precise)
|
|
33
|
+
2. `linkedInUrl`
|
|
34
|
+
3. `vanity`
|
|
35
|
+
|
|
36
|
+
### Response
|
|
37
|
+
|
|
38
|
+
#### Success (200 OK)
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"profileId": 12345,
|
|
43
|
+
"objectUrn": "urn:li:member:129147375",
|
|
44
|
+
"linkedInUrl": "https://www.linkedin.com/in/john-doe/",
|
|
45
|
+
"emails": [
|
|
46
|
+
"john.doe@company.com",
|
|
47
|
+
"johndoe@gmail.com"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Field | Type | Description |
|
|
53
|
+
|-------|------|-------------|
|
|
54
|
+
| `profileId` | integer | Cosiall internal profile ID |
|
|
55
|
+
| `objectUrn` | string | LinkedIn ObjectURN |
|
|
56
|
+
| `linkedInUrl` | string | LinkedIn profile URL |
|
|
57
|
+
| `emails` | array | List of email addresses (may be empty) |
|
|
58
|
+
|
|
59
|
+
#### Error Responses
|
|
60
|
+
|
|
61
|
+
| Status | Description | Response Body |
|
|
62
|
+
|--------|-------------|---------------|
|
|
63
|
+
| 400 Bad Request | No search parameters provided | `{ "error": "At least one of 'objectUrn', 'linkedInUrl', or 'vanity' must be provided." }` |
|
|
64
|
+
| 401 Unauthorized | Invalid or missing API key | - |
|
|
65
|
+
| 404 Not Found | Profile not found in database | `{ "error": "No LinkedIn profile found matching the provided parameters." }` |
|
|
66
|
+
| 500 Internal Server Error | Server error | `{ "error": "An internal server error occurred while retrieving profile emails." }` |
|
|
67
|
+
|
|
68
|
+
## Usage Examples
|
|
69
|
+
|
|
70
|
+
### cURL
|
|
71
|
+
|
|
72
|
+
**Using ObjectURN:**
|
|
73
|
+
```bash
|
|
74
|
+
curl -X GET "https://api.cosiall.com/api/flexiq/profile-emails?objectUrn=urn:li:member:129147375" \
|
|
75
|
+
-H "X-API-Key: your-api-key"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Using LinkedIn URL:**
|
|
79
|
+
```bash
|
|
80
|
+
curl -X GET "https://api.cosiall.com/api/flexiq/profile-emails?linkedInUrl=https://www.linkedin.com/in/john-doe/" \
|
|
81
|
+
-H "X-API-Key: your-api-key"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Using Vanity/Username:**
|
|
85
|
+
```bash
|
|
86
|
+
curl -X GET "https://api.cosiall.com/api/flexiq/profile-emails?vanity=john-doe" \
|
|
87
|
+
-H "X-API-Key: your-api-key"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Python
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import requests
|
|
94
|
+
|
|
95
|
+
API_KEY = "your-api-key"
|
|
96
|
+
BASE_URL = "https://api.cosiall.com/api/flexiq"
|
|
97
|
+
|
|
98
|
+
def get_profile_emails(object_urn=None, linkedin_url=None, vanity=None):
|
|
99
|
+
headers = {"X-API-Key": API_KEY}
|
|
100
|
+
params = {}
|
|
101
|
+
|
|
102
|
+
if object_urn:
|
|
103
|
+
params["objectUrn"] = object_urn
|
|
104
|
+
if linkedin_url:
|
|
105
|
+
params["linkedInUrl"] = linkedin_url
|
|
106
|
+
if vanity:
|
|
107
|
+
params["vanity"] = vanity
|
|
108
|
+
|
|
109
|
+
response = requests.get(f"{BASE_URL}/profile-emails", headers=headers, params=params)
|
|
110
|
+
|
|
111
|
+
if response.status_code == 200:
|
|
112
|
+
return response.json()
|
|
113
|
+
elif response.status_code == 404:
|
|
114
|
+
return None # Profile not found
|
|
115
|
+
else:
|
|
116
|
+
response.raise_for_status()
|
|
117
|
+
|
|
118
|
+
# Usage examples
|
|
119
|
+
emails_data = get_profile_emails(vanity="john-doe")
|
|
120
|
+
if emails_data:
|
|
121
|
+
print(f"Found {len(emails_data['emails'])} email(s): {emails_data['emails']}")
|
|
122
|
+
|
|
123
|
+
# Or by ObjectURN (most precise)
|
|
124
|
+
emails_data = get_profile_emails(object_urn="urn:li:member:129147375")
|
|
125
|
+
|
|
126
|
+
# Or by LinkedIn URL
|
|
127
|
+
emails_data = get_profile_emails(linkedin_url="https://www.linkedin.com/in/john-doe/")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### JavaScript/Node.js
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
const axios = require('axios');
|
|
134
|
+
|
|
135
|
+
const API_KEY = 'your-api-key';
|
|
136
|
+
const BASE_URL = 'https://api.cosiall.com/api/flexiq';
|
|
137
|
+
|
|
138
|
+
async function getProfileEmails({ objectUrn, linkedInUrl, vanity }) {
|
|
139
|
+
try {
|
|
140
|
+
const response = await axios.get(`${BASE_URL}/profile-emails`, {
|
|
141
|
+
headers: { 'X-API-Key': API_KEY },
|
|
142
|
+
params: { objectUrn, linkedInUrl, vanity }
|
|
143
|
+
});
|
|
144
|
+
return response.data;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error.response?.status === 404) {
|
|
147
|
+
return null; // Profile not found
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Usage examples
|
|
154
|
+
const data = await getProfileEmails({ vanity: 'john-doe' });
|
|
155
|
+
if (data) {
|
|
156
|
+
console.log(`Found ${data.emails.length} email(s):`, data.emails);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Or by ObjectURN
|
|
160
|
+
const dataByUrn = await getProfileEmails({ objectUrn: 'urn:li:member:129147375' });
|
|
161
|
+
|
|
162
|
+
// Or by LinkedIn URL
|
|
163
|
+
const dataByUrl = await getProfileEmails({ linkedInUrl: 'https://www.linkedin.com/in/john-doe/' });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### C#
|
|
167
|
+
|
|
168
|
+
```csharp
|
|
169
|
+
using System.Net.Http;
|
|
170
|
+
using System.Text.Json;
|
|
171
|
+
|
|
172
|
+
public class FlexIQClient
|
|
173
|
+
{
|
|
174
|
+
private readonly HttpClient _client;
|
|
175
|
+
private const string BaseUrl = "https://api.cosiall.com/api/flexiq";
|
|
176
|
+
|
|
177
|
+
public FlexIQClient(string apiKey)
|
|
178
|
+
{
|
|
179
|
+
_client = new HttpClient();
|
|
180
|
+
_client.DefaultRequestHeaders.Add("X-API-Key", apiKey);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public async Task<ProfileEmailsResponse?> GetProfileEmailsAsync(
|
|
184
|
+
string? objectUrn = null,
|
|
185
|
+
string? linkedInUrl = null,
|
|
186
|
+
string? vanity = null)
|
|
187
|
+
{
|
|
188
|
+
var queryParams = new List<string>();
|
|
189
|
+
if (!string.IsNullOrEmpty(objectUrn))
|
|
190
|
+
queryParams.Add($"objectUrn={Uri.EscapeDataString(objectUrn)}");
|
|
191
|
+
if (!string.IsNullOrEmpty(linkedInUrl))
|
|
192
|
+
queryParams.Add($"linkedInUrl={Uri.EscapeDataString(linkedInUrl)}");
|
|
193
|
+
if (!string.IsNullOrEmpty(vanity))
|
|
194
|
+
queryParams.Add($"vanity={Uri.EscapeDataString(vanity)}");
|
|
195
|
+
|
|
196
|
+
var url = $"{BaseUrl}/profile-emails?{string.Join("&", queryParams)}";
|
|
197
|
+
var response = await _client.GetAsync(url);
|
|
198
|
+
|
|
199
|
+
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
200
|
+
return null;
|
|
201
|
+
|
|
202
|
+
response.EnsureSuccessStatusCode();
|
|
203
|
+
var json = await response.Content.ReadAsStringAsync();
|
|
204
|
+
return JsonSerializer.Deserialize<ProfileEmailsResponse>(json);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public class ProfileEmailsResponse
|
|
209
|
+
{
|
|
210
|
+
public int ProfileId { get; set; }
|
|
211
|
+
public string? ObjectUrn { get; set; }
|
|
212
|
+
public string? LinkedInUrl { get; set; }
|
|
213
|
+
public List<string> Emails { get; set; } = new();
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Using the LinkedIn Secret Sauce Library
|
|
218
|
+
|
|
219
|
+
The library provides a convenient wrapper function for this endpoint.
|
|
220
|
+
|
|
221
|
+
### Installation
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
npm install linkedin-secret-sauce
|
|
225
|
+
# or
|
|
226
|
+
pnpm add linkedin-secret-sauce
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Usage
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import {
|
|
233
|
+
initializeLinkedInClient,
|
|
234
|
+
fetchProfileEmailsFromCosiall
|
|
235
|
+
} from 'linkedin-secret-sauce';
|
|
236
|
+
|
|
237
|
+
// Initialize the client (required once at startup)
|
|
238
|
+
initializeLinkedInClient({
|
|
239
|
+
cosiallApiUrl: process.env.COSIALL_API_URL,
|
|
240
|
+
cosiallApiKey: process.env.COSIALL_API_KEY,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Lookup by ObjectURN (most precise)
|
|
244
|
+
const result = await fetchProfileEmailsFromCosiall({
|
|
245
|
+
objectUrn: 'urn:li:member:129147375'
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Lookup by LinkedIn URL
|
|
249
|
+
const result = await fetchProfileEmailsFromCosiall({
|
|
250
|
+
linkedInUrl: 'https://www.linkedin.com/in/john-doe/'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Lookup by vanity name
|
|
254
|
+
const result = await fetchProfileEmailsFromCosiall({
|
|
255
|
+
vanity: 'john-doe'
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
console.log(`Profile ID: ${result.profileId}`);
|
|
259
|
+
console.log(`Found ${result.emails.length} emails:`, result.emails);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Error Handling
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import {
|
|
266
|
+
fetchProfileEmailsFromCosiall,
|
|
267
|
+
LinkedInClientError
|
|
268
|
+
} from 'linkedin-secret-sauce';
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const result = await fetchProfileEmailsFromCosiall({ vanity: 'john-doe' });
|
|
272
|
+
console.log(result.emails);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (error instanceof LinkedInClientError) {
|
|
275
|
+
switch (error.code) {
|
|
276
|
+
case 'NOT_FOUND':
|
|
277
|
+
console.log('Profile not found in database');
|
|
278
|
+
break;
|
|
279
|
+
case 'AUTH_ERROR':
|
|
280
|
+
console.log('Invalid API key');
|
|
281
|
+
break;
|
|
282
|
+
case 'INVALID_REQUEST':
|
|
283
|
+
console.log('Missing required parameters');
|
|
284
|
+
break;
|
|
285
|
+
default:
|
|
286
|
+
console.log('API error:', error.message);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### TypeScript Types
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import type {
|
|
296
|
+
CosiallProfileEmailsResponse,
|
|
297
|
+
ProfileEmailsLookupOptions
|
|
298
|
+
} from 'linkedin-secret-sauce';
|
|
299
|
+
|
|
300
|
+
// Response type
|
|
301
|
+
interface CosiallProfileEmailsResponse {
|
|
302
|
+
profileId: number;
|
|
303
|
+
objectUrn: string;
|
|
304
|
+
linkedInUrl: string;
|
|
305
|
+
emails: string[];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Options type
|
|
309
|
+
interface ProfileEmailsLookupOptions {
|
|
310
|
+
objectUrn?: string;
|
|
311
|
+
linkedInUrl?: string;
|
|
312
|
+
vanity?: string;
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Notes
|
|
317
|
+
|
|
318
|
+
- **Empty Emails Array**: A 200 OK response with an empty `emails` array means the profile exists but no emails are stored for it.
|
|
319
|
+
|
|
320
|
+
- **URL Normalization**: The endpoint handles various URL formats:
|
|
321
|
+
- With or without trailing slash: `linkedin.com/in/john-doe` or `linkedin.com/in/john-doe/`
|
|
322
|
+
- With or without `https://` prefix
|
|
323
|
+
|
|
324
|
+
- **Data Freshness**: Emails are retrieved from Cosiall's database and reflect the data collected during profile enrichment.
|
|
325
|
+
|
|
326
|
+
- **Deduplication**: Email addresses are automatically deduplicated in the response.
|
|
327
|
+
|
|
328
|
+
## Related Endpoints
|
|
329
|
+
|
|
330
|
+
| Endpoint | Description |
|
|
331
|
+
|----------|-------------|
|
|
332
|
+
| `GET /api/flexiq/linkedin-cookies/all` | Retrieve Sales Navigator session cookies |
|
|
333
|
+
|
|
334
|
+
## Playground Testing
|
|
335
|
+
|
|
336
|
+
The LinkedIn Secret Sauce Playground includes a dedicated "Cosiall" tab for testing the Profile Emails API. Start the playground with:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
pnpm dev:playground
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Then navigate to the "Cosiall" tab to interactively test lookups by vanity, URL, or ObjectURN.
|