linkedin-secret-sauce 0.5.1 → 0.6.0

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.
@@ -8,9 +8,14 @@
8
8
  * Supports two authentication methods:
9
9
  * 1. Direct token: Pass `apiToken` directly (for pre-authenticated scenarios)
10
10
  * 2. Credentials: Pass `email` and `password` for automatic login with token caching
11
+ *
12
+ * Exports:
13
+ * - createSmartProspectProvider: For email enrichment (waterfall pattern)
14
+ * - createSmartProspectClient: Full client with search/fetch capabilities
11
15
  */
12
16
  Object.defineProperty(exports, "__esModule", { value: true });
13
17
  exports.createSmartProspectProvider = createSmartProspectProvider;
18
+ exports.createSmartProspectClient = createSmartProspectClient;
14
19
  const smartlead_auth_1 = require("../auth/smartlead-auth");
15
20
  const DEFAULT_API_URL = "https://prospect-api.smartlead.ai/api/search-email-leads";
16
21
  /**
@@ -252,6 +257,22 @@ function createSmartProspectProvider(config) {
252
257
  };
253
258
  }
254
259
  }
260
+ /**
261
+ * Calculate confidence score for a contact
262
+ */
263
+ function calculateConfidence(contact) {
264
+ const isVerified = contact.verificationStatus === "valid";
265
+ const isCatchAll = contact.verificationStatus === "catch_all";
266
+ const deliverability = contact.emailDeliverability || 0;
267
+ let confidence = deliverability * 100;
268
+ if (isVerified) {
269
+ confidence = Math.max(confidence, 90);
270
+ }
271
+ else if (isCatchAll) {
272
+ confidence = Math.min(confidence, 75);
273
+ }
274
+ return confidence;
275
+ }
255
276
  async function fetchEmail(candidate) {
256
277
  const { firstName, lastName } = extractNames(candidate);
257
278
  if (!firstName) {
@@ -270,64 +291,399 @@ function createSmartProspectProvider(config) {
270
291
  candidate.companyDomain ||
271
292
  candidate.company_domain ||
272
293
  undefined;
273
- // Build search filters
294
+ // Build search filters using correct API field names
274
295
  const filters = {
275
296
  name: [fullName],
276
- limit: 5, // Get top 5 to find best match
297
+ limit: 10, // Get more results to return multiple emails
277
298
  };
278
299
  if (company) {
279
- filters.company = [company];
300
+ filters.companyName = [company];
280
301
  }
281
302
  if (domain) {
282
- filters.domain = [domain];
303
+ filters.companyDomain = [domain];
283
304
  }
284
305
  // Step 1: Search for contacts (FREE)
285
306
  const searchResult = await searchContacts(filters);
286
307
  if (!searchResult.success || searchResult.data.list.length === 0) {
287
308
  return null;
288
309
  }
289
- // Find best match by scoring
310
+ // Score and sort all matches
290
311
  const matches = searchResult.data.list;
291
- let bestMatch = null;
292
- let bestScore = 0;
293
- for (const contact of matches) {
294
- const score = calculateMatchScore(contact, fullName, company, title);
295
- if (score > bestScore) {
296
- bestScore = score;
297
- bestMatch = contact;
298
- }
299
- }
300
- if (!bestMatch) {
312
+ const scoredMatches = matches
313
+ .map((contact) => ({
314
+ contact,
315
+ score: calculateMatchScore(contact, fullName, company, title),
316
+ }))
317
+ .filter((m) => m.score > 0) // Only include matches with some relevance
318
+ .sort((a, b) => b.score - a.score);
319
+ if (scoredMatches.length === 0) {
301
320
  return null;
302
321
  }
303
- // Step 2: Fetch email for best match (COSTS CREDITS)
304
- const fetchResult = await fetchContacts([bestMatch.id]);
322
+ // Step 2: Fetch emails for ALL matching contacts (COSTS CREDITS)
323
+ // Note: This costs more credits but gives us all available emails
324
+ const contactIds = scoredMatches.map((m) => m.contact.id);
325
+ const fetchResult = await fetchContacts(contactIds);
305
326
  if (!fetchResult.success || fetchResult.data.list.length === 0) {
306
327
  return null;
307
328
  }
308
- const enrichedContact = fetchResult.data.list[0];
309
- const email = enrichedContact?.email;
310
- if (!email) {
329
+ // Build multi-result with all found emails
330
+ const emails = [];
331
+ const seenEmails = new Set();
332
+ for (const enrichedContact of fetchResult.data.list) {
333
+ const email = enrichedContact?.email;
334
+ if (!email)
335
+ continue;
336
+ const emailLower = email.toLowerCase();
337
+ if (seenEmails.has(emailLower))
338
+ continue;
339
+ seenEmails.add(emailLower);
340
+ const isVerified = enrichedContact.verificationStatus === "valid";
341
+ const isCatchAll = enrichedContact.verificationStatus === "catch_all";
342
+ emails.push({
343
+ email,
344
+ verified: isVerified || isCatchAll,
345
+ confidence: calculateConfidence(enrichedContact),
346
+ isCatchAll,
347
+ metadata: {
348
+ fullName: enrichedContact.fullName,
349
+ title: enrichedContact.title,
350
+ company: enrichedContact.company?.name,
351
+ linkedin: enrichedContact.linkedin,
352
+ verificationStatus: enrichedContact.verificationStatus,
353
+ matchScore: scoredMatches.find((m) => m.contact.id === enrichedContact.id)?.score,
354
+ },
355
+ });
356
+ }
357
+ if (emails.length === 0) {
311
358
  return null;
312
359
  }
313
- // Calculate verification confidence
314
- const isVerified = enrichedContact.verificationStatus === "valid";
315
- const isCatchAll = enrichedContact.verificationStatus === "catch_all";
316
- const deliverability = enrichedContact.emailDeliverability || 0;
317
- let confidence = deliverability * 100;
318
- if (isVerified) {
319
- confidence = Math.max(confidence, 90);
360
+ // Sort by confidence (highest first)
361
+ emails.sort((a, b) => (b.confidence ?? 0) - (a.confidence ?? 0));
362
+ // Return multi-result format
363
+ return { emails };
364
+ }
365
+ // Mark provider name for orchestrator
366
+ fetchEmail.__name = "smartprospect";
367
+ return fetchEmail;
368
+ }
369
+ /**
370
+ * Create a SmartProspect client for direct API access
371
+ *
372
+ * This provides access to the full SmartProspect API for:
373
+ * - Searching contacts with comprehensive filters (FREE)
374
+ * - Fetching/enriching contact emails (COSTS CREDITS)
375
+ * - Combined search + fetch operations
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * const client = createSmartProspectClient({
380
+ * email: 'user@example.com',
381
+ * password: 'password123'
382
+ * });
383
+ *
384
+ * // Search only (FREE)
385
+ * const results = await client.search({
386
+ * title: ['CEO', 'CTO'],
387
+ * company: ['Google', 'Microsoft'],
388
+ * level: ['C-Level'],
389
+ * companyHeadCount: ['1001-5000', '5001-10000'],
390
+ * limit: 25
391
+ * });
392
+ *
393
+ * // Fetch specific contacts (COSTS CREDITS)
394
+ * const enriched = await client.fetch(['contact-id-1', 'contact-id-2']);
395
+ * ```
396
+ */
397
+ function createSmartProspectClient(config) {
398
+ const { apiToken, email, password, apiUrl = DEFAULT_API_URL, loginUrl, eagerInit = true, } = config;
399
+ // Check if we have valid auth config
400
+ const hasDirectToken = !!apiToken;
401
+ const hasCredentials = !!email && !!password;
402
+ if (!hasDirectToken && !hasCredentials) {
403
+ return null;
404
+ }
405
+ /**
406
+ * Get the current auth token
407
+ */
408
+ async function getAuthToken() {
409
+ if (hasDirectToken) {
410
+ return apiToken;
320
411
  }
321
- else if (isCatchAll) {
322
- confidence = Math.min(confidence, 75);
412
+ return (0, smartlead_auth_1.getSmartLeadToken)({
413
+ credentials: { email: email, password: password },
414
+ loginUrl,
415
+ });
416
+ }
417
+ /**
418
+ * Handle 401 errors
419
+ */
420
+ async function handleAuthError() {
421
+ if (hasCredentials) {
422
+ (0, smartlead_auth_1.clearSmartLeadToken)(email);
423
+ }
424
+ }
425
+ // Eager initialization
426
+ if (eagerInit && hasCredentials) {
427
+ getAuthToken().catch(() => { });
428
+ }
429
+ /**
430
+ * Build the request payload with proper defaults
431
+ * Field names match the actual SmartProspect API
432
+ */
433
+ function buildSearchPayload(filters) {
434
+ const payload = {};
435
+ // Contact-based filters
436
+ if (filters.name?.length)
437
+ payload.name = filters.name;
438
+ if (filters.firstName?.length)
439
+ payload.firstName = filters.firstName;
440
+ if (filters.lastName?.length)
441
+ payload.lastName = filters.lastName;
442
+ // Title filters
443
+ if (filters.title?.length)
444
+ payload.title = filters.title;
445
+ payload.titleExactMatch = filters.titleExactMatch ?? false;
446
+ // Department & Level
447
+ if (filters.department?.length)
448
+ payload.department = filters.department;
449
+ if (filters.level?.length)
450
+ payload.level = filters.level;
451
+ // Company filters (note: API uses companyName and companyDomain)
452
+ if (filters.companyName?.length)
453
+ payload.companyName = filters.companyName;
454
+ if (filters.companyDomain?.length)
455
+ payload.companyDomain = filters.companyDomain;
456
+ // Industry filters (note: API uses companyIndustry and companySubIndustry)
457
+ if (filters.companyIndustry?.length)
458
+ payload.companyIndustry = filters.companyIndustry;
459
+ if (filters.companySubIndustry?.length)
460
+ payload.companySubIndustry = filters.companySubIndustry;
461
+ // Company size filters
462
+ if (filters.companyHeadCount?.length)
463
+ payload.companyHeadCount = filters.companyHeadCount;
464
+ if (filters.companyRevenue?.length)
465
+ payload.companyRevenue = filters.companyRevenue;
466
+ // Location filters
467
+ if (filters.country?.length)
468
+ payload.country = filters.country;
469
+ if (filters.state?.length)
470
+ payload.state = filters.state;
471
+ if (filters.city?.length)
472
+ payload.city = filters.city;
473
+ // Workflow options
474
+ payload.dontDisplayOwnedContact = filters.dontDisplayOwnedContact ?? true;
475
+ // Pagination
476
+ payload.limit = filters.limit ?? 25;
477
+ if (filters.scroll_id)
478
+ payload.scroll_id = filters.scroll_id;
479
+ return payload;
480
+ }
481
+ /**
482
+ * Search for contacts (FREE - no credits)
483
+ */
484
+ async function search(filters) {
485
+ const payload = buildSearchPayload(filters);
486
+ const makeRequest = async (token) => {
487
+ return requestWithRetry(`${apiUrl}/search-contacts`, {
488
+ method: "POST",
489
+ headers: {
490
+ Authorization: `Bearer ${token}`,
491
+ "Content-Type": "application/json",
492
+ Accept: "application/json",
493
+ },
494
+ body: JSON.stringify(payload),
495
+ });
496
+ };
497
+ try {
498
+ const token = await getAuthToken();
499
+ return await makeRequest(token);
500
+ }
501
+ catch (err) {
502
+ if (err instanceof Error &&
503
+ err.message.includes("401") &&
504
+ hasCredentials) {
505
+ await handleAuthError();
506
+ try {
507
+ const freshToken = await getAuthToken();
508
+ return await makeRequest(freshToken);
509
+ }
510
+ catch {
511
+ // Retry failed
512
+ }
513
+ }
514
+ return {
515
+ success: false,
516
+ message: err instanceof Error ? err.message : "Search failed",
517
+ data: { list: [], total_count: 0 },
518
+ };
519
+ }
520
+ }
521
+ /**
522
+ * Fetch/enrich emails for specific contact IDs (COSTS CREDITS)
523
+ */
524
+ async function fetch(contactIds) {
525
+ if (!contactIds.length) {
526
+ return {
527
+ success: true,
528
+ message: "No contacts to fetch",
529
+ data: {
530
+ list: [],
531
+ total_count: 0,
532
+ metrics: {
533
+ totalContacts: 0,
534
+ totalEmails: 0,
535
+ noEmailFound: 0,
536
+ invalidEmails: 0,
537
+ catchAllEmails: 0,
538
+ verifiedEmails: 0,
539
+ completed: 0,
540
+ },
541
+ leads_found: 0,
542
+ email_fetched: 0,
543
+ verification_status_list: [],
544
+ },
545
+ };
546
+ }
547
+ const makeRequest = async (token) => {
548
+ return requestWithRetry(`${apiUrl}/fetch-contacts`, {
549
+ method: "POST",
550
+ headers: {
551
+ Authorization: `Bearer ${token}`,
552
+ "Content-Type": "application/json",
553
+ Accept: "application/json",
554
+ },
555
+ body: JSON.stringify({ contactIds }),
556
+ });
557
+ };
558
+ try {
559
+ const token = await getAuthToken();
560
+ return await makeRequest(token);
561
+ }
562
+ catch (err) {
563
+ if (err instanceof Error &&
564
+ err.message.includes("401") &&
565
+ hasCredentials) {
566
+ await handleAuthError();
567
+ try {
568
+ const freshToken = await getAuthToken();
569
+ return await makeRequest(freshToken);
570
+ }
571
+ catch {
572
+ // Retry failed
573
+ }
574
+ }
575
+ return {
576
+ success: false,
577
+ message: err instanceof Error ? err.message : "Fetch failed",
578
+ data: {
579
+ list: [],
580
+ total_count: 0,
581
+ metrics: {
582
+ totalContacts: 0,
583
+ totalEmails: 0,
584
+ noEmailFound: 0,
585
+ invalidEmails: 0,
586
+ catchAllEmails: 0,
587
+ verifiedEmails: 0,
588
+ completed: 0,
589
+ },
590
+ leads_found: 0,
591
+ email_fetched: 0,
592
+ verification_status_list: [],
593
+ },
594
+ };
595
+ }
596
+ }
597
+ /**
598
+ * Search and immediately fetch all results
599
+ */
600
+ async function searchAndFetch(filters) {
601
+ const searchResponse = await search(filters);
602
+ if (!searchResponse.success || searchResponse.data.list.length === 0) {
603
+ return {
604
+ searchResponse,
605
+ fetchResponse: null,
606
+ contacts: [],
607
+ };
323
608
  }
609
+ const contactIds = searchResponse.data.list.map((c) => c.id);
610
+ const fetchResponse = await fetch(contactIds);
324
611
  return {
325
- email,
326
- verified: isVerified || isCatchAll, // Accept catch-all as semi-verified
327
- score: confidence,
612
+ searchResponse,
613
+ fetchResponse,
614
+ contacts: fetchResponse.success ? fetchResponse.data.list : [],
328
615
  };
329
616
  }
330
- // Mark provider name for orchestrator
331
- fetchEmail.__name = "smartprospect";
332
- return fetchEmail;
617
+ /**
618
+ * Generic location lookup (countries, states, cities)
619
+ */
620
+ async function getLocations(type, options = {}) {
621
+ const { search: searchQuery, limit = 20, offset = 0 } = options;
622
+ const params = new URLSearchParams();
623
+ params.set('limit', String(limit));
624
+ if (offset > 0)
625
+ params.set('offset', String(offset));
626
+ if (searchQuery)
627
+ params.set('search', searchQuery);
628
+ const makeRequest = async (token) => {
629
+ return requestWithRetry(`${apiUrl}/${type}?${params.toString()}`, {
630
+ method: "GET",
631
+ headers: {
632
+ Authorization: `Bearer ${token}`,
633
+ Accept: "application/json",
634
+ },
635
+ });
636
+ };
637
+ try {
638
+ const token = await getAuthToken();
639
+ return await makeRequest(token);
640
+ }
641
+ catch (err) {
642
+ if (err instanceof Error &&
643
+ err.message.includes("401") &&
644
+ hasCredentials) {
645
+ await handleAuthError();
646
+ try {
647
+ const freshToken = await getAuthToken();
648
+ return await makeRequest(freshToken);
649
+ }
650
+ catch {
651
+ // Retry failed
652
+ }
653
+ }
654
+ return {
655
+ success: false,
656
+ message: err instanceof Error ? err.message : "Lookup failed",
657
+ data: [],
658
+ pagination: { limit, offset, page: 1, count: 0 },
659
+ search: searchQuery || null,
660
+ };
661
+ }
662
+ }
663
+ /**
664
+ * Lookup countries (for typeahead)
665
+ */
666
+ async function getCountries(options) {
667
+ return getLocations('countries', options);
668
+ }
669
+ /**
670
+ * Lookup states (for typeahead)
671
+ */
672
+ async function getStates(options) {
673
+ return getLocations('states', options);
674
+ }
675
+ /**
676
+ * Lookup cities (for typeahead)
677
+ */
678
+ async function getCities(options) {
679
+ return getLocations('cities', options);
680
+ }
681
+ return {
682
+ search,
683
+ fetch,
684
+ searchAndFetch,
685
+ getCountries,
686
+ getStates,
687
+ getCities,
688
+ };
333
689
  }
@@ -30,10 +30,62 @@ export interface ProviderResult {
30
30
  score?: number;
31
31
  confidence?: number;
32
32
  }
33
+ /**
34
+ * Extended provider result that can return multiple emails
35
+ */
36
+ export interface ProviderMultiResult {
37
+ emails: Array<{
38
+ email: string;
39
+ verified?: boolean;
40
+ confidence?: number;
41
+ isCatchAll?: boolean;
42
+ metadata?: Record<string, unknown>;
43
+ }>;
44
+ }
45
+ /**
46
+ * Email type classification
47
+ */
48
+ export type EmailType = 'business' | 'personal' | 'disposable' | 'role' | 'unknown';
49
+ /**
50
+ * Individual enriched email with full metadata
51
+ */
52
+ export interface EnrichedEmail {
53
+ /** The email address */
54
+ email: string;
55
+ /** Which provider found this email */
56
+ source: ProviderName;
57
+ /** Confidence score (0-100) */
58
+ confidence: number;
59
+ /** Whether the email was verified */
60
+ verified: boolean;
61
+ /** Email type classification */
62
+ type: EmailType;
63
+ /** Whether this is a catch-all domain */
64
+ isCatchAll?: boolean;
65
+ /** ISO timestamp of when this was found */
66
+ foundAt: string;
67
+ /** Additional provider-specific metadata */
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+ /**
71
+ * Result containing all found emails from all providers
72
+ */
73
+ export interface MultiEmailResult {
74
+ /** All found emails, sorted by confidence (highest first) */
75
+ emails: EnrichedEmail[];
76
+ /** The original candidate */
77
+ candidate: EnrichmentCandidate;
78
+ /** Total cost incurred across all providers */
79
+ totalCost: number;
80
+ /** List of providers that were queried */
81
+ providersQueried: ProviderName[];
82
+ /** ISO timestamp of when enrichment completed */
83
+ completedAt: string;
84
+ }
33
85
  /**
34
86
  * Provider function signature
35
87
  */
36
- export type ProviderFunc = (candidate: EnrichmentCandidate) => Promise<ProviderResult | null>;
88
+ export type ProviderFunc = (candidate: EnrichmentCandidate) => Promise<ProviderResult | ProviderMultiResult | null>;
37
89
  /**
38
90
  * Input candidate for enrichment - flexible to accept various naming conventions
39
91
  */
@@ -193,12 +245,16 @@ export interface EnrichmentClientConfig {
193
245
  * Enrichment client interface
194
246
  */
195
247
  export interface EnrichmentClient {
196
- /** Enrich a single candidate */
248
+ /** Enrich a single candidate - returns first valid business email (original behavior) */
197
249
  enrich: (candidate: EnrichmentCandidate) => Promise<CanonicalEmail>;
198
- /** Enrich multiple candidates in batches */
250
+ /** Enrich multiple candidates in batches - returns first valid business email per candidate */
199
251
  enrichBatch: (candidates: EnrichmentCandidate[], options?: BatchEnrichmentOptions) => Promise<Array<{
200
252
  candidate: EnrichmentCandidate;
201
253
  } & CanonicalEmail>>;
254
+ /** Enrich a single candidate - returns ALL found emails from ALL providers */
255
+ enrichAll: (candidate: EnrichmentCandidate) => Promise<MultiEmailResult>;
256
+ /** Enrich multiple candidates - returns ALL found emails for each candidate */
257
+ enrichAllBatch: (candidates: EnrichmentCandidate[], options?: BatchEnrichmentOptions) => Promise<MultiEmailResult[]>;
202
258
  }
203
259
  /**
204
260
  * Available provider names
@@ -260,26 +316,77 @@ export interface SmartProspectContact {
260
316
  verificationStatus?: string;
261
317
  catchAllStatus?: string;
262
318
  }
319
+ /**
320
+ * SmartProspect Search Filters
321
+ *
322
+ * Comprehensive filter interface matching SmartProspect/Smartlead's actual API.
323
+ * Field names and values match their exact API structure.
324
+ */
263
325
  export interface SmartProspectSearchFilters {
326
+ /** Full name (searches across first + last) */
264
327
  name?: string[];
328
+ /** First name only */
265
329
  firstName?: string[];
330
+ /** Last name only */
266
331
  lastName?: string[];
332
+ /** Job titles to search (free text, e.g., "CEO", "Software Engineer") */
267
333
  title?: string[];
268
- company?: string[];
269
- domain?: string[];
270
- department?: string[];
271
- level?: string[];
272
- industry?: string[];
334
+ /** Whether to match titles exactly (default: false) */
335
+ titleExactMatch?: boolean;
336
+ /** Departments - must use exact API values */
337
+ department?: SmartProspectDepartment[];
338
+ /** Seniority levels - must use exact API values */
339
+ level?: SmartProspectLevel[];
340
+ /** Company names (e.g., "Google", "Microsoft") */
341
+ companyName?: string[];
342
+ /** Company domains (e.g., "google.com", "microsoft.com") */
343
+ companyDomain?: string[];
344
+ /** Industries - must use exact API values */
345
+ companyIndustry?: SmartProspectIndustry[];
346
+ /** Sub-industries - must use exact API values */
347
+ companySubIndustry?: string[];
348
+ /** Headcount ranges - must use exact API values */
349
+ companyHeadCount?: SmartProspectHeadcount[];
350
+ /** Revenue ranges - must use exact API values */
351
+ companyRevenue?: SmartProspectRevenue[];
352
+ /** Countries (e.g., "United States", "United Kingdom", "Germany") */
273
353
  country?: string[];
354
+ /** States with country (e.g., "California, United States", "Bavaria, Germany") */
274
355
  state?: string[];
356
+ /** Cities with state and country (e.g., "San Francisco, California, United States") */
275
357
  city?: string[];
276
- companyHeadCount?: string[];
277
- companyRevenue?: string[];
358
+ /** Don't include contacts already owned/in campaigns (default: true) */
278
359
  dontDisplayOwnedContact?: boolean;
360
+ /** Number of results to return (default: 25, max: 100) */
279
361
  limit?: number;
280
- titleExactMatch?: boolean;
362
+ /** Scroll ID for cursor-based pagination (from previous response) */
281
363
  scroll_id?: string;
282
364
  }
365
+ /**
366
+ * SmartProspect Department values (exact API values)
367
+ */
368
+ export type SmartProspectDepartment = 'Engineering' | 'Finance & Administration' | 'Human Resources' | 'IT & IS' | 'Marketing' | 'Operations' | 'Other' | 'Support' | 'Sales';
369
+ /**
370
+ * SmartProspect Level/Seniority values (exact API values)
371
+ */
372
+ export type SmartProspectLevel = 'Staff' | 'Manager-Level' | 'Director-Level' | 'VP-Level' | 'C-Level';
373
+ /**
374
+ * SmartProspect Headcount ranges (exact API values)
375
+ */
376
+ export type SmartProspectHeadcount = '0 - 25' | '25 - 100' | '100 - 250' | '250 - 1000' | '1K - 10K' | '10K - 50K' | '50K - 100K' | '> 100K';
377
+ /**
378
+ * SmartProspect Revenue ranges (exact API values)
379
+ */
380
+ export type SmartProspectRevenue = '$0 - 1M' | '$1 - 10M' | '$10 - 50M' | '$50 - 100M' | '$100 - 250M' | '$250 - 500M' | '$500M - 1B' | '> $1B';
381
+ /**
382
+ * SmartProspect Industry values (exact API values)
383
+ */
384
+ export type SmartProspectIndustry = 'Software & Internet' | 'Business Services' | 'Real Estate & Construction' | 'Financial Services' | 'Healthcare, Pharmaceuticals, & Biotech' | 'Retail' | 'Consumer Services' | 'Education' | 'Media & Entertainment' | 'Travel, Recreation, and Leisure' | 'Transportation & Storage' | 'Manufacturing' | 'Wholesale & Distribution' | 'Non-Profit' | 'Energy & Utilities' | 'Government' | 'Agriculture & Mining' | 'Computers & Electronics' | 'Telecommunications' | 'Other';
385
+ /**
386
+ * SmartProspect Sub-Industry values (exact API values - partial list)
387
+ * Note: This is a subset of available sub-industries. The API accepts many more.
388
+ */
389
+ export declare const SMARTPROSPECT_SUB_INDUSTRIES: readonly ["Internet", "Information Technology and Services", "Information Services", "Computer Software", "Computer & Network Security", "Computer Games", "Glass, Ceramics & Concrete", "Construction", "Commercial Real Estate", "Civil Engineering", "Building Materials", "Architecture & Planning", "Writing and Editing", "Translation and Localization", "Think Tanks", "Staffing and Recruiting", "Security and Investigations", "Public Safety", "Public Relations and Communications", "Program Development", "Professional Training & Coaching", "Market Research", "Marketing and Advertising", "Management Consulting", "Legal Services", "Law Practice", "Law Enforcement", "International Trade and Development", "Import and Export", "Human Resources", "Graphic Design", "Facilities Services", "Executive Office", "Events Services", "Environmental Services", "Design", "Business Supplies and Equipment", "Animation", "Alternative Dispute Resolution", "Outsourcing/Offshoring"];
283
390
  export interface SmartProspectSearchResponse {
284
391
  success: boolean;
285
392
  message: string;
@@ -290,6 +397,27 @@ export interface SmartProspectSearchResponse {
290
397
  total_count: number;
291
398
  };
292
399
  }
400
+ /**
401
+ * SmartProspect Location lookup response (countries, states, cities)
402
+ */
403
+ export interface SmartProspectLocationItem {
404
+ id: number;
405
+ country_name?: string;
406
+ state_name?: string;
407
+ city_name?: string;
408
+ }
409
+ export interface SmartProspectLocationResponse {
410
+ success: boolean;
411
+ message: string;
412
+ data: SmartProspectLocationItem[];
413
+ pagination: {
414
+ limit: number;
415
+ offset: number;
416
+ page: number;
417
+ count: number;
418
+ };
419
+ search: string | null;
420
+ }
293
421
  export interface SmartProspectFetchResponse {
294
422
  success: boolean;
295
423
  message: string;