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.
Files changed (184) hide show
  1. package/README.md +339 -31
  2. package/dist/cosiall-client.d.ts +1 -1
  3. package/dist/cosiall-client.js +1 -1
  4. package/dist/enrichment/index.d.ts +23 -2
  5. package/dist/enrichment/index.js +38 -22
  6. package/dist/enrichment/matching.d.ts +16 -2
  7. package/dist/enrichment/matching.js +387 -65
  8. package/dist/enrichment/providers/bounceban.d.ts +82 -0
  9. package/dist/enrichment/providers/bounceban.js +447 -0
  10. package/dist/enrichment/providers/bouncer.d.ts +1 -1
  11. package/dist/enrichment/providers/bouncer.js +19 -21
  12. package/dist/enrichment/providers/construct.d.ts +1 -1
  13. package/dist/enrichment/providers/construct.js +22 -38
  14. package/dist/enrichment/providers/cosiall.d.ts +1 -1
  15. package/dist/enrichment/providers/cosiall.js +3 -4
  16. package/dist/enrichment/providers/dropcontact.d.ts +15 -9
  17. package/dist/enrichment/providers/dropcontact.js +188 -19
  18. package/dist/enrichment/providers/hunter.d.ts +8 -1
  19. package/dist/enrichment/providers/hunter.js +52 -28
  20. package/dist/enrichment/providers/index.d.ts +2 -0
  21. package/dist/enrichment/providers/index.js +10 -1
  22. package/dist/enrichment/providers/ldd.d.ts +1 -10
  23. package/dist/enrichment/providers/ldd.js +20 -97
  24. package/dist/enrichment/providers/smartprospect.js +28 -48
  25. package/dist/enrichment/providers/snovio.d.ts +1 -1
  26. package/dist/enrichment/providers/snovio.js +29 -31
  27. package/dist/enrichment/providers/trykitt.d.ts +63 -0
  28. package/dist/enrichment/providers/trykitt.js +210 -0
  29. package/dist/enrichment/types.d.ts +220 -7
  30. package/dist/enrichment/types.js +16 -8
  31. package/dist/enrichment/utils/candidate-parser.d.ts +107 -0
  32. package/dist/enrichment/utils/candidate-parser.js +173 -0
  33. package/dist/enrichment/utils/noop-provider.d.ts +39 -0
  34. package/dist/enrichment/utils/noop-provider.js +37 -0
  35. package/dist/enrichment/utils/rate-limiter.d.ts +103 -0
  36. package/dist/enrichment/utils/rate-limiter.js +204 -0
  37. package/dist/enrichment/utils/validation.d.ts +75 -3
  38. package/dist/enrichment/utils/validation.js +164 -11
  39. package/dist/linkedin-api.d.ts +40 -1
  40. package/dist/linkedin-api.js +160 -27
  41. package/dist/types.d.ts +50 -1
  42. package/dist/utils/lru-cache.d.ts +105 -0
  43. package/dist/utils/lru-cache.js +175 -0
  44. package/docs/COSIALL_PROFILE_EMAILS.md +342 -0
  45. package/docs/ENRICHMENT.md +622 -0
  46. package/docs/INTEGRATION.md +405 -0
  47. package/docs/PLAYGROUND.md +558 -0
  48. package/docs/SALES_SEARCH.md +171 -0
  49. package/docs/api/.nojekyll +1 -0
  50. package/docs/api/assets/hierarchy.js +1 -0
  51. package/docs/api/assets/highlight.css +92 -0
  52. package/docs/api/assets/icons.js +18 -0
  53. package/docs/api/assets/icons.svg +1 -0
  54. package/docs/api/assets/main.js +60 -0
  55. package/docs/api/assets/navigation.js +1 -0
  56. package/docs/api/assets/search.js +1 -0
  57. package/docs/api/assets/style.css +1633 -0
  58. package/docs/api/classes/LinkedInClientError.html +37 -0
  59. package/docs/api/functions/_testGetAccountCookies.html +4 -0
  60. package/docs/api/functions/_testGetAccountEntry.html +4 -0
  61. package/docs/api/functions/_testGetAllAccountIds.html +3 -0
  62. package/docs/api/functions/_testGetPoolState.html +3 -0
  63. package/docs/api/functions/adminResetAccount.html +1 -0
  64. package/docs/api/functions/adminSetCooldown.html +1 -0
  65. package/docs/api/functions/buildCookieHeader.html +1 -0
  66. package/docs/api/functions/clearAllSmartLeadTokens.html +2 -0
  67. package/docs/api/functions/clearRequestHistory.html +1 -0
  68. package/docs/api/functions/clearSessionAccount.html +1 -0
  69. package/docs/api/functions/clearSmartLeadToken.html +2 -0
  70. package/docs/api/functions/createEnrichmentClient.html +8 -0
  71. package/docs/api/functions/extractCsrfToken.html +1 -0
  72. package/docs/api/functions/extractLinkedInHandle.html +7 -0
  73. package/docs/api/functions/fetchCookiesFromCosiall.html +14 -0
  74. package/docs/api/functions/fetchProfileEmailsFromCosiall.html +18 -0
  75. package/docs/api/functions/forceRefreshCookies.html +1 -0
  76. package/docs/api/functions/getAccountForSession.html +1 -0
  77. package/docs/api/functions/getAccountsSummary.html +1 -0
  78. package/docs/api/functions/getCompaniesBatch.html +5 -0
  79. package/docs/api/functions/getCompanyById.html +9 -0
  80. package/docs/api/functions/getCompanyByUrl.html +1 -0
  81. package/docs/api/functions/getConfig.html +1 -0
  82. package/docs/api/functions/getCookiePoolHealth.html +1 -0
  83. package/docs/api/functions/getProfileByUrn.html +17 -0
  84. package/docs/api/functions/getProfileByVanity.html +10 -0
  85. package/docs/api/functions/getProfilesBatch.html +1 -0
  86. package/docs/api/functions/getRequestHistory.html +1 -0
  87. package/docs/api/functions/getSalesNavigatorProfileDetails.html +1 -0
  88. package/docs/api/functions/getSalesNavigatorProfileFull.html +16 -0
  89. package/docs/api/functions/getSmartLeadToken.html +1 -0
  90. package/docs/api/functions/getSmartLeadTokenCacheStats.html +2 -0
  91. package/docs/api/functions/getSmartLeadUser.html +2 -0
  92. package/docs/api/functions/getSnapshot.html +1 -0
  93. package/docs/api/functions/getYearsAtCompanyOptions.html +2 -0
  94. package/docs/api/functions/getYearsInPositionOptions.html +2 -0
  95. package/docs/api/functions/getYearsOfExperienceOptions.html +2 -0
  96. package/docs/api/functions/incrementMetric.html +1 -0
  97. package/docs/api/functions/initializeCookiePool.html +1 -0
  98. package/docs/api/functions/initializeLinkedInClient.html +1 -0
  99. package/docs/api/functions/isBusinessEmail.html +4 -0
  100. package/docs/api/functions/isDisposableDomain.html +4 -0
  101. package/docs/api/functions/isDisposableEmail.html +4 -0
  102. package/docs/api/functions/isPersonalDomain.html +4 -0
  103. package/docs/api/functions/isPersonalEmail.html +4 -0
  104. package/docs/api/functions/isRoleAccount.html +4 -0
  105. package/docs/api/functions/isValidEmailSyntax.html +4 -0
  106. package/docs/api/functions/parseFullProfile.html +15 -0
  107. package/docs/api/functions/parseSalesSearchResults.html +1 -0
  108. package/docs/api/functions/reportAccountFailure.html +1 -0
  109. package/docs/api/functions/reportAccountSuccess.html +1 -0
  110. package/docs/api/functions/resolveCompanyUniversalName.html +1 -0
  111. package/docs/api/functions/searchSalesLeads.html +16 -0
  112. package/docs/api/functions/selectAccountForRequest.html +1 -0
  113. package/docs/api/functions/setAccountForSession.html +1 -0
  114. package/docs/api/functions/typeahead.html +1 -0
  115. package/docs/api/functions/verifyEmailMx.html +1 -0
  116. package/docs/api/hierarchy.html +1 -0
  117. package/docs/api/index.html +12 -0
  118. package/docs/api/interfaces/AccountCookies.html +4 -0
  119. package/docs/api/interfaces/BatchEnrichmentOptions.html +14 -0
  120. package/docs/api/interfaces/CacheAdapter.html +6 -0
  121. package/docs/api/interfaces/CanonicalEmail.html +14 -0
  122. package/docs/api/interfaces/Company.html +17 -0
  123. package/docs/api/interfaces/ConstructConfig.html +8 -0
  124. package/docs/api/interfaces/CosiallProfileEmailsResponse.html +11 -0
  125. package/docs/api/interfaces/DropcontactConfig.html +3 -0
  126. package/docs/api/interfaces/EnrichmentCandidate.html +34 -0
  127. package/docs/api/interfaces/EnrichmentClient.html +10 -0
  128. package/docs/api/interfaces/EnrichmentClientConfig.html +12 -0
  129. package/docs/api/interfaces/EnrichmentLogger.html +6 -0
  130. package/docs/api/interfaces/EnrichmentOptions.html +10 -0
  131. package/docs/api/interfaces/HunterConfig.html +3 -0
  132. package/docs/api/interfaces/LddConfig.html +4 -0
  133. package/docs/api/interfaces/LddProfileData.html +6 -0
  134. package/docs/api/interfaces/LinkedInClientConfig.html +20 -0
  135. package/docs/api/interfaces/LinkedInCookie.html +9 -0
  136. package/docs/api/interfaces/LinkedInPosition.html +14 -0
  137. package/docs/api/interfaces/LinkedInProfile.html +21 -0
  138. package/docs/api/interfaces/LinkedInSpotlightBadge.html +5 -0
  139. package/docs/api/interfaces/LinkedInTenure.html +3 -0
  140. package/docs/api/interfaces/Metrics.html +22 -0
  141. package/docs/api/interfaces/MetricsSnapshot.html +23 -0
  142. package/docs/api/interfaces/ProfileEducation.html +8 -0
  143. package/docs/api/interfaces/ProfileEmailsLookupOptions.html +9 -0
  144. package/docs/api/interfaces/ProfilePosition.html +12 -0
  145. package/docs/api/interfaces/ProfileSkill.html +3 -0
  146. package/docs/api/interfaces/ProviderResult.html +11 -0
  147. package/docs/api/interfaces/ProvidersConfig.html +17 -0
  148. package/docs/api/interfaces/RequestHistoryEntry.html +8 -0
  149. package/docs/api/interfaces/SalesLeadSearchResult.html +31 -0
  150. package/docs/api/interfaces/SalesNavigatorContactInfo.html +5 -0
  151. package/docs/api/interfaces/SalesNavigatorPosition.html +11 -0
  152. package/docs/api/interfaces/SalesNavigatorProfile.html +9 -0
  153. package/docs/api/interfaces/SalesNavigatorProfileFull.html +24 -0
  154. package/docs/api/interfaces/SearchSalesResult.html +5 -0
  155. package/docs/api/interfaces/SmartLeadAuthConfig.html +6 -0
  156. package/docs/api/interfaces/SmartLeadCredentials.html +3 -0
  157. package/docs/api/interfaces/SmartLeadLoginResponse.html +3 -0
  158. package/docs/api/interfaces/SmartLeadUser.html +8 -0
  159. package/docs/api/interfaces/SmartProspectConfig.html +19 -0
  160. package/docs/api/interfaces/SmartProspectContact.html +24 -0
  161. package/docs/api/interfaces/SmartProspectSearchFilters.html +42 -0
  162. package/docs/api/interfaces/TypeaheadItem.html +3 -0
  163. package/docs/api/interfaces/TypeaheadResult.html +3 -0
  164. package/docs/api/interfaces/VerificationResult.html +16 -0
  165. package/docs/api/types/CostCallback.html +2 -0
  166. package/docs/api/types/Geo.html +4 -0
  167. package/docs/api/types/LddApiResponse.html +1 -0
  168. package/docs/api/types/ProviderFunc.html +2 -0
  169. package/docs/api/types/ProviderName.html +2 -0
  170. package/docs/api/types/SalesSearchFilters.html +7 -0
  171. package/docs/api/types/TypeaheadType.html +1 -0
  172. package/docs/api/variables/COMPANY_SIZE_OPTIONS.html +1 -0
  173. package/docs/api/variables/DEFAULT_PROVIDER_ORDER.html +20 -0
  174. package/docs/api/variables/DISPOSABLE_DOMAINS.html +2 -0
  175. package/docs/api/variables/FUNCTION_OPTIONS.html +1 -0
  176. package/docs/api/variables/INDUSTRY_OPTIONS.html +1 -0
  177. package/docs/api/variables/LANGUAGE_OPTIONS.html +1 -0
  178. package/docs/api/variables/PERSONAL_DOMAINS.html +2 -0
  179. package/docs/api/variables/PROVIDER_COSTS.html +15 -0
  180. package/docs/api/variables/REGION_OPTIONS.html +1 -0
  181. package/docs/api/variables/SENIORITY_OPTIONS.html +3 -0
  182. package/docs/api/variables/YEARS_OPTIONS.html +1 -0
  183. package/docs/index.html +98 -0
  184. package/package.json +16 -5
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Simple LRU (Least Recently Used) Cache
3
+ *
4
+ * A memory-bounded cache that evicts the least recently used entries
5
+ * when the maximum size is exceeded. Prevents unbounded memory growth.
6
+ *
7
+ * Features:
8
+ * - O(1) get and set operations
9
+ * - Automatic eviction of stale entries
10
+ * - Optional TTL support
11
+ * - Size limit enforcement
12
+ */
13
+ /**
14
+ * Cache entry with data and timestamp
15
+ */
16
+ export interface CacheEntry<T> {
17
+ data: T;
18
+ ts: number;
19
+ }
20
+ /**
21
+ * LRU Cache implementation using Map's insertion order
22
+ *
23
+ * JavaScript Map maintains insertion order, so we can implement LRU
24
+ * by deleting and re-inserting on access (moving to end).
25
+ */
26
+ export declare class LRUCache<T> {
27
+ private cache;
28
+ private readonly maxSize;
29
+ private readonly ttlMs;
30
+ /**
31
+ * Create a new LRU cache
32
+ *
33
+ * @param maxSize - Maximum number of entries to store (default: 1000)
34
+ * @param ttlMs - Optional TTL in milliseconds (default: null = no expiry)
35
+ */
36
+ constructor(maxSize?: number, ttlMs?: number | null);
37
+ /**
38
+ * Get a value from the cache
39
+ *
40
+ * @param key - Cache key
41
+ * @param ttlOverride - Optional TTL override in milliseconds (for dynamic TTL from config)
42
+ * @returns The cached value or null if not found/expired
43
+ */
44
+ get(key: string, ttlOverride?: number): T | null;
45
+ /**
46
+ * Set a value in the cache
47
+ *
48
+ * @param key - Cache key
49
+ * @param data - Value to cache
50
+ */
51
+ set(key: string, data: T): void;
52
+ /**
53
+ * Delete a key from the cache
54
+ *
55
+ * @param key - Cache key to delete
56
+ * @returns true if the key existed
57
+ */
58
+ delete(key: string): boolean;
59
+ /**
60
+ * Check if a key exists in the cache (without updating access time)
61
+ *
62
+ * @param key - Cache key
63
+ * @returns true if key exists and is not expired
64
+ */
65
+ has(key: string): boolean;
66
+ /**
67
+ * Clear all entries from the cache
68
+ */
69
+ clear(): void;
70
+ /**
71
+ * Get the current number of entries in the cache
72
+ */
73
+ get size(): number;
74
+ /**
75
+ * Get all keys in the cache (for debugging/testing)
76
+ */
77
+ keys(): IterableIterator<string>;
78
+ /**
79
+ * Prune expired entries (useful for periodic cleanup)
80
+ *
81
+ * @returns Number of entries removed
82
+ */
83
+ prune(): number;
84
+ /**
85
+ * Get cache statistics
86
+ */
87
+ stats(): {
88
+ size: number;
89
+ maxSize: number;
90
+ ttlMs: number | null;
91
+ };
92
+ }
93
+ /**
94
+ * Create a new LRU cache with the specified options
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // Cache up to 500 profiles for 15 minutes
99
+ * const profileCache = createLRUCache<LinkedInProfile>(500, 15 * 60 * 1000);
100
+ *
101
+ * profileCache.set('johndoe', profile);
102
+ * const cached = profileCache.get('johndoe');
103
+ * ```
104
+ */
105
+ export declare function createLRUCache<T>(maxSize?: number, ttlMs?: number | null): LRUCache<T>;
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /**
3
+ * Simple LRU (Least Recently Used) Cache
4
+ *
5
+ * A memory-bounded cache that evicts the least recently used entries
6
+ * when the maximum size is exceeded. Prevents unbounded memory growth.
7
+ *
8
+ * Features:
9
+ * - O(1) get and set operations
10
+ * - Automatic eviction of stale entries
11
+ * - Optional TTL support
12
+ * - Size limit enforcement
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.LRUCache = void 0;
16
+ exports.createLRUCache = createLRUCache;
17
+ /**
18
+ * LRU Cache implementation using Map's insertion order
19
+ *
20
+ * JavaScript Map maintains insertion order, so we can implement LRU
21
+ * by deleting and re-inserting on access (moving to end).
22
+ */
23
+ class LRUCache {
24
+ cache;
25
+ maxSize;
26
+ ttlMs;
27
+ /**
28
+ * Create a new LRU cache
29
+ *
30
+ * @param maxSize - Maximum number of entries to store (default: 1000)
31
+ * @param ttlMs - Optional TTL in milliseconds (default: null = no expiry)
32
+ */
33
+ constructor(maxSize = 1000, ttlMs = null) {
34
+ this.cache = new Map();
35
+ this.maxSize = maxSize;
36
+ this.ttlMs = ttlMs;
37
+ }
38
+ /**
39
+ * Get a value from the cache
40
+ *
41
+ * @param key - Cache key
42
+ * @param ttlOverride - Optional TTL override in milliseconds (for dynamic TTL from config)
43
+ * @returns The cached value or null if not found/expired
44
+ */
45
+ get(key, ttlOverride) {
46
+ const entry = this.cache.get(key);
47
+ if (!entry) {
48
+ return null;
49
+ }
50
+ // Check TTL expiration (use override if provided, otherwise instance TTL)
51
+ const effectiveTtl = ttlOverride ?? this.ttlMs;
52
+ if (effectiveTtl !== null && Date.now() - entry.ts > effectiveTtl) {
53
+ this.cache.delete(key);
54
+ return null;
55
+ }
56
+ // Move to end (most recently used) by delete + set
57
+ this.cache.delete(key);
58
+ this.cache.set(key, entry);
59
+ return entry.data;
60
+ }
61
+ /**
62
+ * Set a value in the cache
63
+ *
64
+ * @param key - Cache key
65
+ * @param data - Value to cache
66
+ */
67
+ set(key, data) {
68
+ // If key exists, delete it first (will be re-added at end)
69
+ if (this.cache.has(key)) {
70
+ this.cache.delete(key);
71
+ }
72
+ // Evict oldest entries if at capacity
73
+ while (this.cache.size >= this.maxSize) {
74
+ const oldestKey = this.cache.keys().next().value;
75
+ if (oldestKey !== undefined) {
76
+ this.cache.delete(oldestKey);
77
+ }
78
+ else {
79
+ break;
80
+ }
81
+ }
82
+ // Add new entry
83
+ this.cache.set(key, { data, ts: Date.now() });
84
+ }
85
+ /**
86
+ * Delete a key from the cache
87
+ *
88
+ * @param key - Cache key to delete
89
+ * @returns true if the key existed
90
+ */
91
+ delete(key) {
92
+ return this.cache.delete(key);
93
+ }
94
+ /**
95
+ * Check if a key exists in the cache (without updating access time)
96
+ *
97
+ * @param key - Cache key
98
+ * @returns true if key exists and is not expired
99
+ */
100
+ has(key) {
101
+ const entry = this.cache.get(key);
102
+ if (!entry) {
103
+ return false;
104
+ }
105
+ // Check TTL expiration
106
+ if (this.ttlMs !== null && Date.now() - entry.ts > this.ttlMs) {
107
+ this.cache.delete(key);
108
+ return false;
109
+ }
110
+ return true;
111
+ }
112
+ /**
113
+ * Clear all entries from the cache
114
+ */
115
+ clear() {
116
+ this.cache.clear();
117
+ }
118
+ /**
119
+ * Get the current number of entries in the cache
120
+ */
121
+ get size() {
122
+ return this.cache.size;
123
+ }
124
+ /**
125
+ * Get all keys in the cache (for debugging/testing)
126
+ */
127
+ keys() {
128
+ return this.cache.keys();
129
+ }
130
+ /**
131
+ * Prune expired entries (useful for periodic cleanup)
132
+ *
133
+ * @returns Number of entries removed
134
+ */
135
+ prune() {
136
+ if (this.ttlMs === null) {
137
+ return 0;
138
+ }
139
+ const now = Date.now();
140
+ let removed = 0;
141
+ for (const [key, entry] of this.cache) {
142
+ if (now - entry.ts > this.ttlMs) {
143
+ this.cache.delete(key);
144
+ removed++;
145
+ }
146
+ }
147
+ return removed;
148
+ }
149
+ /**
150
+ * Get cache statistics
151
+ */
152
+ stats() {
153
+ return {
154
+ size: this.cache.size,
155
+ maxSize: this.maxSize,
156
+ ttlMs: this.ttlMs,
157
+ };
158
+ }
159
+ }
160
+ exports.LRUCache = LRUCache;
161
+ /**
162
+ * Create a new LRU cache with the specified options
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * // Cache up to 500 profiles for 15 minutes
167
+ * const profileCache = createLRUCache<LinkedInProfile>(500, 15 * 60 * 1000);
168
+ *
169
+ * profileCache.set('johndoe', profile);
170
+ * const cached = profileCache.get('johndoe');
171
+ * ```
172
+ */
173
+ function createLRUCache(maxSize = 1000, ttlMs = null) {
174
+ return new LRUCache(maxSize, ttlMs);
175
+ }
@@ -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.