linkdapi 1.0.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.
package/dist/client.js ADDED
@@ -0,0 +1,1008 @@
1
+ "use strict";
2
+ /**
3
+ * LinkdAPI Node.js SDK
4
+ *
5
+ * A high-level client for interacting with the LinkdAPI service.
6
+ *
7
+ * This client provides:
8
+ * - Automatic retry mechanism for failed requests
9
+ * - Type-annotated methods for better IDE support
10
+ * - Connection pooling for improved performance
11
+ * - Comprehensive error handling
12
+ *
13
+ * Basic Usage:
14
+ * ```typescript
15
+ * const api = new LinkdAPI({ apiKey: "your_api_key" });
16
+ * const profile = await api.getProfileOverview("ryanroslansky");
17
+ * console.log(profile);
18
+ * ```
19
+ *
20
+ * @see https://linkdapi.com/?p=signup - Get your API key (100 free credits)
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.LinkdAPI = exports.TimeoutError = exports.NetworkError = exports.HTTPError = exports.LinkdAPIError = void 0;
24
+ const DEFAULT_BASE_URL = 'https://linkdapi.com';
25
+ const DEFAULT_TIMEOUT = 30000;
26
+ const DEFAULT_MAX_RETRIES = 3;
27
+ const DEFAULT_RETRY_DELAY = 1000;
28
+ class LinkdAPIError extends Error {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = 'LinkdAPIError';
32
+ }
33
+ }
34
+ exports.LinkdAPIError = LinkdAPIError;
35
+ class HTTPError extends LinkdAPIError {
36
+ statusCode;
37
+ statusText;
38
+ responseBody;
39
+ constructor(statusCode, statusText, responseBody) {
40
+ super(`API request failed with status ${statusCode}: ${statusText}`);
41
+ this.name = 'HTTPError';
42
+ this.statusCode = statusCode;
43
+ this.statusText = statusText;
44
+ this.responseBody = responseBody;
45
+ }
46
+ }
47
+ exports.HTTPError = HTTPError;
48
+ class NetworkError extends LinkdAPIError {
49
+ cause;
50
+ constructor(message, cause) {
51
+ super(message);
52
+ this.name = 'NetworkError';
53
+ this.cause = cause;
54
+ }
55
+ }
56
+ exports.NetworkError = NetworkError;
57
+ class TimeoutError extends LinkdAPIError {
58
+ constructor(message = 'Request timed out') {
59
+ super(message);
60
+ this.name = 'TimeoutError';
61
+ }
62
+ }
63
+ exports.TimeoutError = TimeoutError;
64
+ class LinkdAPI {
65
+ apiKey;
66
+ baseUrl;
67
+ timeout;
68
+ maxRetries;
69
+ retryDelay;
70
+ constructor(config) {
71
+ if (!config.apiKey) {
72
+ throw new Error('API key is required');
73
+ }
74
+ this.apiKey = config.apiKey;
75
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, '');
76
+ this.timeout = config.timeout || DEFAULT_TIMEOUT;
77
+ this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
78
+ this.retryDelay = config.retryDelay || DEFAULT_RETRY_DELAY;
79
+ }
80
+ getHeaders() {
81
+ return {
82
+ 'X-linkdapi-apikey': this.apiKey,
83
+ 'Accept': 'application/json',
84
+ 'Content-Type': 'application/json',
85
+ 'User-Agent': 'LinkdAPI-Node-Client/1.0',
86
+ };
87
+ }
88
+ async sendRequest(method, endpoint, params) {
89
+ let url = `${this.baseUrl}/${endpoint.replace(/^\//, '')}`;
90
+ if (params) {
91
+ const queryParams = new URLSearchParams();
92
+ for (const [key, value] of Object.entries(params)) {
93
+ if (value !== undefined && value !== null && value !== '') {
94
+ queryParams.append(key, String(value));
95
+ }
96
+ }
97
+ const queryString = queryParams.toString();
98
+ if (queryString) {
99
+ url += `?${queryString}`;
100
+ }
101
+ }
102
+ let lastError = null;
103
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
104
+ try {
105
+ const controller = new AbortController();
106
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
107
+ const response = await fetch(url, {
108
+ method,
109
+ headers: this.getHeaders(),
110
+ signal: controller.signal,
111
+ });
112
+ clearTimeout(timeoutId);
113
+ if (!response.ok) {
114
+ const responseBody = await response.text();
115
+ throw new HTTPError(response.status, response.statusText, responseBody);
116
+ }
117
+ return await response.json();
118
+ }
119
+ catch (error) {
120
+ lastError = error;
121
+ if (error instanceof Error && error.name === 'AbortError') {
122
+ lastError = new TimeoutError(`Request timed out after ${this.timeout}ms`);
123
+ }
124
+ // Don't retry on client errors (4xx)
125
+ if (error instanceof HTTPError && error.statusCode >= 400 && error.statusCode < 500) {
126
+ throw error;
127
+ }
128
+ // Wait before retrying
129
+ if (attempt < this.maxRetries) {
130
+ await new Promise((resolve) => setTimeout(resolve, this.retryDelay * (attempt + 1)));
131
+ }
132
+ }
133
+ }
134
+ if (lastError instanceof HTTPError || lastError instanceof TimeoutError) {
135
+ throw lastError;
136
+ }
137
+ throw new NetworkError(`Request failed after ${this.maxRetries + 1} attempts: ${lastError?.message || 'Unknown error'}`, lastError || undefined);
138
+ }
139
+ // ==================== Profile Endpoints ====================
140
+ /**
141
+ * Get basic profile information by username.
142
+ *
143
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/overview
144
+ *
145
+ * @param username - The LinkedIn username to look up
146
+ * @returns Profile overview data
147
+ */
148
+ async getProfileOverview(username) {
149
+ return this.sendRequest('GET', 'api/v1/profile/overview', { username });
150
+ }
151
+ /**
152
+ * Get profile details information by URN.
153
+ *
154
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/details
155
+ *
156
+ * @param urn - The LinkedIn URN (Uniform Resource Name) for the profile
157
+ * @returns Detailed profile information
158
+ */
159
+ async getProfileDetails(urn) {
160
+ return this.sendRequest('GET', 'api/v1/profile/details', { urn });
161
+ }
162
+ /**
163
+ * Get contact details for a profile by username.
164
+ *
165
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/contact-info
166
+ *
167
+ * @param username - The LinkedIn username to look up
168
+ * @returns Contact information including email, phone, and websites
169
+ */
170
+ async getContactInfo(username) {
171
+ return this.sendRequest('GET', 'api/v1/profile/contact-info', { username });
172
+ }
173
+ /**
174
+ * Get complete work experience by URN.
175
+ *
176
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/full-experience
177
+ *
178
+ * @param urn - The LinkedIn URN for the profile
179
+ * @returns Complete work experience information
180
+ */
181
+ async getFullExperience(urn) {
182
+ return this.sendRequest('GET', 'api/v1/profile/full-experience', { urn });
183
+ }
184
+ /**
185
+ * Get lists of professional certifications by URN.
186
+ *
187
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/certifications
188
+ *
189
+ * @param urn - The LinkedIn URN for the profile
190
+ * @returns Certification information
191
+ */
192
+ async getCertifications(urn) {
193
+ return this.sendRequest('GET', 'api/v1/profile/certifications', { urn });
194
+ }
195
+ /**
196
+ * Get full education information by URN.
197
+ *
198
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/education
199
+ *
200
+ * @param urn - The LinkedIn URN for the profile
201
+ * @returns Education history
202
+ */
203
+ async getEducation(urn) {
204
+ return this.sendRequest('GET', 'api/v1/profile/education', { urn });
205
+ }
206
+ /**
207
+ * Get profile skills by URN.
208
+ *
209
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/skills
210
+ *
211
+ * @param urn - The LinkedIn URN for the profile
212
+ * @returns Skills information
213
+ */
214
+ async getSkills(urn) {
215
+ return this.sendRequest('GET', 'api/v1/profile/skills', { urn });
216
+ }
217
+ /**
218
+ * Get social network metrics by username.
219
+ *
220
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/social-matrix
221
+ *
222
+ * @param username - The LinkedIn username to look up
223
+ * @returns Social metrics including connections and followers count
224
+ */
225
+ async getSocialMatrix(username) {
226
+ return this.sendRequest('GET', 'api/v1/profile/social-matrix', { username });
227
+ }
228
+ /**
229
+ * Get profile given and received recommendations by URN.
230
+ *
231
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/recommendations
232
+ *
233
+ * @param urn - The LinkedIn URN for the profile
234
+ * @returns Recommendations data
235
+ */
236
+ async getRecommendations(urn) {
237
+ return this.sendRequest('GET', 'api/v1/profile/recommendations', { urn });
238
+ }
239
+ /**
240
+ * Get similar profiles for a given profile using its URN.
241
+ *
242
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/similar
243
+ *
244
+ * @param urn - The LinkedIn URN for the profile
245
+ * @returns List of similar profiles
246
+ */
247
+ async getSimilarProfiles(urn) {
248
+ return this.sendRequest('GET', 'api/v1/profile/similar', { urn });
249
+ }
250
+ /**
251
+ * Get about this profile such as last update and verification info.
252
+ *
253
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/about
254
+ *
255
+ * @param urn - The LinkedIn URN for the profile
256
+ * @returns Profile about information
257
+ */
258
+ async getProfileAbout(urn) {
259
+ return this.sendRequest('GET', 'api/v1/profile/about', { urn });
260
+ }
261
+ /**
262
+ * Get all reactions for given profile by URN.
263
+ *
264
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/reactions
265
+ *
266
+ * @param urn - The LinkedIn URN for the profile
267
+ * @param cursor - Pagination cursor (optional)
268
+ * @returns Reactions data with pagination information
269
+ */
270
+ async getProfileReactions(urn, cursor = '') {
271
+ const params = { urn };
272
+ if (cursor) {
273
+ params.cursor = cursor;
274
+ }
275
+ return this.sendRequest('GET', 'api/v1/profile/reactions', params);
276
+ }
277
+ /**
278
+ * Get profile interests by URN.
279
+ *
280
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/interests
281
+ *
282
+ * @param urn - The LinkedIn URN for the profile
283
+ * @returns Profile interests information
284
+ */
285
+ async getProfileInterests(urn) {
286
+ return this.sendRequest('GET', 'api/v1/profile/interests', { urn });
287
+ }
288
+ /**
289
+ * Get full profile data in 1 request (everything included).
290
+ *
291
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/full
292
+ *
293
+ * @param options - Either username or urn must be provided
294
+ * @param options.username - The LinkedIn username
295
+ * @param options.urn - The LinkedIn URN for the profile
296
+ * @returns Complete profile data including all information
297
+ */
298
+ async getFullProfile(options) {
299
+ if (!options.username && !options.urn) {
300
+ throw new Error('Either username or urn must be provided');
301
+ }
302
+ const params = {};
303
+ if (options.username)
304
+ params.username = options.username;
305
+ if (options.urn)
306
+ params.urn = options.urn;
307
+ return this.sendRequest('GET', 'api/v1/profile/full', params);
308
+ }
309
+ /**
310
+ * Get profile services by URN.
311
+ *
312
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/services
313
+ *
314
+ * @param urn - The LinkedIn URN for the profile
315
+ * @returns Profile services information
316
+ */
317
+ async getProfileServices(urn) {
318
+ return this.sendRequest('GET', 'api/v1/profile/services', { urn });
319
+ }
320
+ /**
321
+ * Get profile URN by username.
322
+ *
323
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/profile/username-to-urn
324
+ *
325
+ * @param username - The LinkedIn username for the profile
326
+ * @returns Profile URN
327
+ */
328
+ async getProfileUrn(username) {
329
+ return this.sendRequest('GET', 'api/v1/profile/username-to-urn', { username });
330
+ }
331
+ // ==================== Posts Endpoints ====================
332
+ /**
333
+ * Get all featured posts for a given profile using its URN.
334
+ *
335
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/posts/featured
336
+ *
337
+ * @param urn - The LinkedIn URN for the profile
338
+ * @returns List of featured posts
339
+ */
340
+ async getFeaturedPosts(urn) {
341
+ return this.sendRequest('GET', 'api/v1/posts/featured', { urn });
342
+ }
343
+ /**
344
+ * Retrieve all posts for a given profile URN.
345
+ *
346
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/posts/all
347
+ *
348
+ * @param urn - The LinkedIn URN of the profile
349
+ * @param cursor - Pagination cursor (default is empty)
350
+ * @param start - Start index for pagination (default is 0)
351
+ * @returns List of posts with pagination info
352
+ */
353
+ async getAllPosts(urn, cursor = '', start = 0) {
354
+ return this.sendRequest('GET', 'api/v1/posts/all', { urn, cursor, start });
355
+ }
356
+ /**
357
+ * Retrieve information about a specific post using its URN.
358
+ *
359
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/posts/info
360
+ *
361
+ * @param urn - The URN of the LinkedIn post
362
+ * @returns Detailed post information
363
+ */
364
+ async getPostInfo(urn) {
365
+ return this.sendRequest('GET', 'api/v1/posts/info', { urn });
366
+ }
367
+ /**
368
+ * Get comments for a specific LinkedIn post.
369
+ *
370
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/posts/comments
371
+ *
372
+ * @param urn - The URN of the post
373
+ * @param start - Starting index for pagination (default is 0)
374
+ * @param count - Number of comments to fetch per request (default is 10)
375
+ * @param cursor - Cursor for pagination (default is empty)
376
+ * @returns A list of comments and pagination metadata
377
+ */
378
+ async getPostComments(urn, start = 0, count = 10, cursor = '') {
379
+ return this.sendRequest('GET', 'api/v1/posts/comments', { urn, start, count, cursor });
380
+ }
381
+ /**
382
+ * Retrieve all users who liked or reacted to a given post.
383
+ *
384
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/posts/likes
385
+ *
386
+ * @param urn - The URN of the LinkedIn post
387
+ * @param start - Pagination start index (default is 0)
388
+ * @returns List of users who liked/reacted to the post
389
+ */
390
+ async getPostLikes(urn, start = 0) {
391
+ return this.sendRequest('GET', 'api/v1/posts/likes', { urn, start });
392
+ }
393
+ // ==================== Comments Endpoints ====================
394
+ /**
395
+ * Retrieve all comments made by a profile using their URN.
396
+ *
397
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/comments/all
398
+ *
399
+ * @param urn - The LinkedIn profile URN
400
+ * @param cursor - Pagination cursor (default is empty)
401
+ * @returns List of comments made by the user
402
+ */
403
+ async getAllComments(urn, cursor = '') {
404
+ return this.sendRequest('GET', 'api/v1/comments/all', { urn, cursor });
405
+ }
406
+ /**
407
+ * Get all users who reacted to one or more comment URNs.
408
+ *
409
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/comments/likes
410
+ *
411
+ * @param urns - Comma-separated URNs of comments
412
+ * @param start - Pagination start index (default is 0)
413
+ * @returns List of users who liked or reacted to the comments
414
+ */
415
+ async getCommentLikes(urns, start = 0) {
416
+ return this.sendRequest('GET', 'api/v1/comments/likes', { urn: urns, start });
417
+ }
418
+ // ==================== Service Status Endpoint ====================
419
+ /**
420
+ * Get API service status.
421
+ *
422
+ * @returns Service status information
423
+ */
424
+ async getServiceStatus() {
425
+ return this.sendRequest('GET', 'status/');
426
+ }
427
+ // ==================== Companies Endpoints ====================
428
+ /**
429
+ * Search companies by name.
430
+ *
431
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/name-lookup
432
+ *
433
+ * @param query - The search query (can be 1 character or multiple)
434
+ * @returns List of matching companies
435
+ */
436
+ async companyNameLookup(query) {
437
+ return this.sendRequest('GET', 'api/v1/companies/name-lookup', { query });
438
+ }
439
+ /**
440
+ * Get company details either by ID or name.
441
+ *
442
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/info
443
+ *
444
+ * @param options - Either companyId or name must be provided
445
+ * @param options.companyId - Company ID
446
+ * @param options.name - Company name
447
+ * @returns Company details information
448
+ */
449
+ async getCompanyInfo(options) {
450
+ if (!options.companyId && !options.name) {
451
+ throw new Error('Either companyId or name must be provided');
452
+ }
453
+ const params = {};
454
+ if (options.companyId)
455
+ params.id = options.companyId;
456
+ if (options.name)
457
+ params.name = options.name;
458
+ return this.sendRequest('GET', 'api/v1/companies/company/info', params);
459
+ }
460
+ /**
461
+ * Get similar companies by ID.
462
+ *
463
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/similar
464
+ *
465
+ * @param companyId - Company ID
466
+ * @returns List of similar companies
467
+ */
468
+ async getSimilarCompanies(companyId) {
469
+ return this.sendRequest('GET', 'api/v1/companies/company/similar', { id: companyId });
470
+ }
471
+ /**
472
+ * Get company employees data by ID.
473
+ *
474
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/employees-data
475
+ *
476
+ * @param companyId - Company ID
477
+ * @returns Company employees data
478
+ */
479
+ async getCompanyEmployeesData(companyId) {
480
+ return this.sendRequest('GET', 'api/v1/companies/company/employees-data', { id: companyId });
481
+ }
482
+ /**
483
+ * Get available job listings for given companies by ID.
484
+ *
485
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/jobs
486
+ *
487
+ * @param companyIds - Company ID(s) - can be a single ID or array of IDs
488
+ * @param start - Pagination start index (default is 0)
489
+ * @returns List of job listings for the specified companies
490
+ */
491
+ async getCompanyJobs(companyIds, start = 0) {
492
+ const ids = Array.isArray(companyIds) ? companyIds.join(',') : companyIds;
493
+ return this.sendRequest('GET', 'api/v1/companies/jobs', { companyIDs: ids, start });
494
+ }
495
+ /**
496
+ * Get affiliated pages/subsidiaries of a company by ID.
497
+ *
498
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/affiliated-pages
499
+ *
500
+ * @param companyId - Company ID
501
+ * @returns List of affiliated pages and subsidiaries
502
+ */
503
+ async getCompanyAffiliatedPages(companyId) {
504
+ return this.sendRequest('GET', 'api/v1/companies/company/affiliated-pages', { id: companyId });
505
+ }
506
+ /**
507
+ * Get Posts of a company by ID.
508
+ *
509
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/posts
510
+ *
511
+ * @param companyId - Company ID
512
+ * @param start - Pagination start index (default is 0)
513
+ * @returns List of posts
514
+ */
515
+ async getCompanyPosts(companyId, start = 0) {
516
+ return this.sendRequest('GET', 'api/v1/companies/company/posts', { id: companyId, start });
517
+ }
518
+ /**
519
+ * Get ID of a company by universal_name (username).
520
+ *
521
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/universal-name-to-id
522
+ *
523
+ * @param universalName - Company universalName (username)
524
+ * @returns Company ID
525
+ */
526
+ async getCompanyId(universalName) {
527
+ return this.sendRequest('GET', 'api/v1/companies/company/universal-name-to-id', { universalName });
528
+ }
529
+ /**
530
+ * Get company details V2 with extended information by company ID.
531
+ * This endpoint returns more information about the company including
532
+ * peopleAlsoFollow, affiliatedByJobs, etc.
533
+ *
534
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/companies/company/info-v2
535
+ *
536
+ * @param companyId - Company ID
537
+ * @returns Extended company details information
538
+ */
539
+ async getCompanyDetailsV2(companyId) {
540
+ return this.sendRequest('GET', 'api/v1/companies/company/info-v2', { id: companyId });
541
+ }
542
+ // ==================== Jobs Endpoints ====================
543
+ /**
544
+ * Search for jobs with various filters.
545
+ *
546
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/search
547
+ *
548
+ * @param options - Search options
549
+ * @param options.keyword - Job title, skills, or keywords
550
+ * @param options.location - City, state, or region
551
+ * @param options.geoId - LinkedIn's internal geographic identifier
552
+ * @param options.companyIds - Specific company LinkedIn IDs (string or array)
553
+ * @param options.jobTypes - Employment types: full_time, part_time, contract, temporary, internship, volunteer
554
+ * @param options.experience - Experience levels: internship, entry_level, associate, mid_senior, director
555
+ * @param options.regions - Specific region codes (string or array)
556
+ * @param options.timePosted - How recently posted: any, 24h, 1week, 1month
557
+ * @param options.salary - Minimum salary: any, 40k, 60k, 80k, 100k, 120k
558
+ * @param options.workArrangement - Work arrangement: onsite, remote, hybrid
559
+ * @param options.start - Pagination start index (default is 0)
560
+ * @returns List of job search results
561
+ */
562
+ async searchJobs(options = {}) {
563
+ const params = { start: options.start ?? 0 };
564
+ if (options.keyword)
565
+ params.keyword = options.keyword;
566
+ if (options.location)
567
+ params.location = options.location;
568
+ if (options.geoId)
569
+ params.geoId = options.geoId;
570
+ if (options.companyIds) {
571
+ params.companyIds = Array.isArray(options.companyIds) ? options.companyIds.join(',') : options.companyIds;
572
+ }
573
+ if (options.jobTypes) {
574
+ params.jobTypes = Array.isArray(options.jobTypes) ? options.jobTypes.join(',') : options.jobTypes;
575
+ }
576
+ if (options.experience) {
577
+ params.experience = Array.isArray(options.experience) ? options.experience.join(',') : options.experience;
578
+ }
579
+ if (options.regions) {
580
+ params.regions = Array.isArray(options.regions) ? options.regions.join(',') : options.regions;
581
+ }
582
+ if (options.timePosted)
583
+ params.timePosted = options.timePosted;
584
+ if (options.salary)
585
+ params.salary = options.salary;
586
+ if (options.workArrangement) {
587
+ params.workArrangement = Array.isArray(options.workArrangement) ? options.workArrangement.join(',') : options.workArrangement;
588
+ }
589
+ return this.sendRequest('GET', 'api/v1/jobs/search', params);
590
+ }
591
+ /**
592
+ * Get job details by job ID.
593
+ *
594
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/job/details
595
+ *
596
+ * @param jobId - Job ID (must be open and actively hiring)
597
+ * @returns Detailed job information
598
+ */
599
+ async getJobDetails(jobId) {
600
+ return this.sendRequest('GET', 'api/v1/jobs/job/details', { jobId });
601
+ }
602
+ /**
603
+ * Get similar jobs by job ID.
604
+ *
605
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/job/similar
606
+ *
607
+ * @param jobId - Job ID
608
+ * @returns List of similar jobs
609
+ */
610
+ async getSimilarJobs(jobId) {
611
+ return this.sendRequest('GET', 'api/v1/jobs/job/similar', { jobId });
612
+ }
613
+ /**
614
+ * Get related jobs that people also viewed.
615
+ *
616
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/job/people-also-viewed
617
+ *
618
+ * @param jobId - Job ID
619
+ * @returns List of related jobs
620
+ */
621
+ async getPeopleAlsoViewedJobs(jobId) {
622
+ return this.sendRequest('GET', 'api/v1/jobs/job/people-also-viewed', { jobId });
623
+ }
624
+ /**
625
+ * Get job details V2 by job ID. This endpoint supports all job statuses
626
+ * (open, closed, expired, etc.) and provides detailed information about the job.
627
+ *
628
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/job/details-v2
629
+ *
630
+ * @param jobId - Job ID (supports all job statuses)
631
+ * @returns Detailed job information
632
+ */
633
+ async getJobDetailsV2(jobId) {
634
+ return this.sendRequest('GET', 'api/v1/jobs/job/details-v2', { jobId });
635
+ }
636
+ /**
637
+ * Get hiring team members for a specific job.
638
+ *
639
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/job/hiring-team
640
+ *
641
+ * @param jobId - Job ID
642
+ * @param start - Pagination start index (default is 0)
643
+ * @returns List of hiring team members
644
+ */
645
+ async getHiringTeam(jobId, start = 0) {
646
+ return this.sendRequest('GET', 'api/v1/jobs/job/hiring-team', { jobId, start });
647
+ }
648
+ /**
649
+ * Get jobs posted by a specific profile.
650
+ *
651
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/jobs/posted-by-profile
652
+ *
653
+ * @param profileUrn - Profile URN
654
+ * @param start - Pagination start index (default is 0)
655
+ * @param count - Number of jobs to retrieve (default is 25)
656
+ * @returns List of jobs posted by the profile
657
+ */
658
+ async getProfilePostedJobs(profileUrn, start = 0, count = 25) {
659
+ return this.sendRequest('GET', 'api/v1/jobs/posted-by-profile', { profileUrn, start, count });
660
+ }
661
+ /**
662
+ * Search for jobs V2 with comprehensive filters (all filters available).
663
+ *
664
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/jobs
665
+ *
666
+ * @param options - Search options
667
+ * @param options.keyword - Search keyword
668
+ * @param options.start - Pagination offset (default: 0, increment by 25)
669
+ * @param options.sortBy - Sort by "relevance" (default) or "date_posted"
670
+ * @param options.datePosted - Filter by "24h", "1week", or "1month"
671
+ * @param options.experience - Experience levels: internship, entry_level, associate, mid_senior, director, executive
672
+ * @param options.jobTypes - Employment types: full_time, part_time, contract, temporary, internship, volunteer, other
673
+ * @param options.workplaceTypes - Work arrangement: onsite, remote, hybrid
674
+ * @param options.salary - Minimum annual salary: 20k, 30k, 40k, 50k, 60k, 70k, 80k, 90k, 100k
675
+ * @param options.companies - Company IDs (string or array)
676
+ * @param options.industries - Industry IDs (string or array)
677
+ * @param options.locations - LinkedIn's internal geographic identifiers (string or array)
678
+ * @param options.functions - Job function codes (string or array, e.g., "it,sales,eng")
679
+ * @param options.titles - Job title IDs (string or array)
680
+ * @param options.benefits - Benefits: medical_ins, dental_ins, vision_ins, 401k, pension, paid_maternity, paid_paternity, commuter, student_loan, tuition, disability_ins
681
+ * @param options.commitments - Company values: dei, environmental, work_life, social_impact, career_growth
682
+ * @param options.easyApply - Show only LinkedIn Easy Apply jobs
683
+ * @param options.verifiedJob - Show only verified job postings
684
+ * @param options.under10Applicants - Show jobs with fewer than 10 applicants
685
+ * @param options.fairChance - Show jobs from fair chance employers
686
+ * @returns List of job search results
687
+ */
688
+ async searchJobsV2(options = {}) {
689
+ const params = { start: options.start ?? 0 };
690
+ if (options.keyword)
691
+ params.keyword = options.keyword;
692
+ if (options.sortBy)
693
+ params.sortBy = options.sortBy;
694
+ if (options.datePosted)
695
+ params.datePosted = options.datePosted;
696
+ if (options.experience) {
697
+ params.experience = Array.isArray(options.experience) ? options.experience.join(',') : options.experience;
698
+ }
699
+ if (options.jobTypes) {
700
+ params.jobTypes = Array.isArray(options.jobTypes) ? options.jobTypes.join(',') : options.jobTypes;
701
+ }
702
+ if (options.workplaceTypes) {
703
+ params.workplaceTypes = Array.isArray(options.workplaceTypes) ? options.workplaceTypes.join(',') : options.workplaceTypes;
704
+ }
705
+ if (options.salary)
706
+ params.salary = options.salary;
707
+ if (options.companies) {
708
+ params.companies = Array.isArray(options.companies) ? options.companies.join(',') : options.companies;
709
+ }
710
+ if (options.industries) {
711
+ params.industries = Array.isArray(options.industries) ? options.industries.join(',') : options.industries;
712
+ }
713
+ if (options.locations) {
714
+ params.locations = Array.isArray(options.locations) ? options.locations.join(',') : options.locations;
715
+ }
716
+ if (options.functions) {
717
+ params.functions = Array.isArray(options.functions) ? options.functions.join(',') : options.functions;
718
+ }
719
+ if (options.titles) {
720
+ params.titles = Array.isArray(options.titles) ? options.titles.join(',') : options.titles;
721
+ }
722
+ if (options.benefits) {
723
+ params.Benefits = Array.isArray(options.benefits) ? options.benefits.join(',') : options.benefits;
724
+ }
725
+ if (options.commitments) {
726
+ params.commitments = Array.isArray(options.commitments) ? options.commitments.join(',') : options.commitments;
727
+ }
728
+ if (options.easyApply !== undefined)
729
+ params.easyApply = String(options.easyApply).toLowerCase();
730
+ if (options.verifiedJob !== undefined)
731
+ params.verifiedJob = String(options.verifiedJob).toLowerCase();
732
+ if (options.under10Applicants !== undefined)
733
+ params.under10Applicants = String(options.under10Applicants).toLowerCase();
734
+ if (options.fairChance !== undefined)
735
+ params.fairChance = String(options.fairChance).toLowerCase();
736
+ return this.sendRequest('GET', 'api/v1/search/jobs', params);
737
+ }
738
+ // ==================== Geos Lookup Endpoints ====================
739
+ /**
740
+ * Search locations and get geo IDs.
741
+ *
742
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/geos/name-lookup
743
+ *
744
+ * @param query - The search query (can be 1 character or multiple)
745
+ * @returns List of matching locations with geo IDs
746
+ */
747
+ async geoNameLookup(query) {
748
+ return this.sendRequest('GET', 'api/v1/geos/name-lookup', { query });
749
+ }
750
+ // ==================== Search Endpoints ====================
751
+ /**
752
+ * Search for people with various filters.
753
+ *
754
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/people
755
+ *
756
+ * @param options - Search options
757
+ * @param options.keyword - Search keyword (e.g., "software engineer")
758
+ * @param options.start - Pagination start index (default is 0)
759
+ * @param options.currentCompany - Current company IDs (string or array)
760
+ * @param options.firstName - First name filter
761
+ * @param options.geoUrn - Geographic URNs (string or array)
762
+ * @param options.industry - Industry IDs (string or array)
763
+ * @param options.lastName - Last name filter
764
+ * @param options.profileLanguage - Profile language (e.g., "en" for English)
765
+ * @param options.pastCompany - Past company IDs (string or array)
766
+ * @param options.school - School IDs (string or array)
767
+ * @param options.serviceCategory - Service category ID
768
+ * @param options.title - Job title (e.g., "founder")
769
+ * @returns List of people matching the search criteria
770
+ */
771
+ async searchPeople(options = {}) {
772
+ const params = { start: options.start ?? 0 };
773
+ if (options.keyword)
774
+ params.keyword = options.keyword;
775
+ if (options.currentCompany) {
776
+ params.currentCompany = Array.isArray(options.currentCompany) ? options.currentCompany.join(',') : options.currentCompany;
777
+ }
778
+ if (options.firstName)
779
+ params.firstName = options.firstName;
780
+ if (options.geoUrn) {
781
+ params.geoUrn = Array.isArray(options.geoUrn) ? options.geoUrn.join(',') : options.geoUrn;
782
+ }
783
+ if (options.industry) {
784
+ params.industry = Array.isArray(options.industry) ? options.industry.join(',') : options.industry;
785
+ }
786
+ if (options.lastName)
787
+ params.lastName = options.lastName;
788
+ if (options.profileLanguage)
789
+ params.profileLanguage = options.profileLanguage;
790
+ if (options.pastCompany) {
791
+ params.pastCompany = Array.isArray(options.pastCompany) ? options.pastCompany.join(',') : options.pastCompany;
792
+ }
793
+ if (options.school) {
794
+ params.school = Array.isArray(options.school) ? options.school.join(',') : options.school;
795
+ }
796
+ if (options.serviceCategory)
797
+ params.serviceCategory = options.serviceCategory;
798
+ if (options.title)
799
+ params.title = options.title;
800
+ return this.sendRequest('GET', 'api/v1/search/people', params);
801
+ }
802
+ /**
803
+ * Search for companies with various filters.
804
+ *
805
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/companies
806
+ *
807
+ * @param options - Search options
808
+ * @param options.keyword - Search keyword (e.g., "software")
809
+ * @param options.start - Pagination start index (default is 0)
810
+ * @param options.geoUrn - Geographic URNs (string or array)
811
+ * @param options.companySize - Company sizes: "1-10", "11-50", "51-200", "201-500", "501-1000", "1001-5000", "5001-10,000", "10,001+"
812
+ * @param options.hasJobs - Filter companies with job listings
813
+ * @param options.industry - Industry IDs (string or array)
814
+ * @returns List of companies matching the search criteria
815
+ */
816
+ async searchCompanies(options = {}) {
817
+ const params = { start: options.start ?? 0 };
818
+ if (options.keyword)
819
+ params.keyword = options.keyword;
820
+ if (options.geoUrn) {
821
+ params.geoUrn = Array.isArray(options.geoUrn) ? options.geoUrn.join(',') : options.geoUrn;
822
+ }
823
+ if (options.companySize) {
824
+ params.companySize = Array.isArray(options.companySize) ? options.companySize.join(',') : options.companySize;
825
+ }
826
+ if (options.hasJobs !== undefined)
827
+ params.hasJobs = String(options.hasJobs).toLowerCase();
828
+ if (options.industry) {
829
+ params.industry = Array.isArray(options.industry) ? options.industry.join(',') : options.industry;
830
+ }
831
+ return this.sendRequest('GET', 'api/v1/search/companies', params);
832
+ }
833
+ /**
834
+ * Search for services offered by LinkedIn members.
835
+ *
836
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/services
837
+ *
838
+ * @param options - Search options
839
+ * @param options.keyword - Search keyword (e.g., "software")
840
+ * @param options.start - Pagination start index (default is 0)
841
+ * @param options.geoUrn - Geographic URNs (string or array)
842
+ * @param options.profileLanguage - Profile language (e.g., "en,ch")
843
+ * @param options.serviceCategory - Service category IDs (string or array)
844
+ * @returns List of services matching the search criteria
845
+ */
846
+ async searchServices(options = {}) {
847
+ const params = { start: options.start ?? 0 };
848
+ if (options.keyword)
849
+ params.keyword = options.keyword;
850
+ if (options.geoUrn) {
851
+ params.geoUrn = Array.isArray(options.geoUrn) ? options.geoUrn.join(',') : options.geoUrn;
852
+ }
853
+ if (options.profileLanguage)
854
+ params.profileLanguage = options.profileLanguage;
855
+ if (options.serviceCategory) {
856
+ params.serviceCategory = Array.isArray(options.serviceCategory) ? options.serviceCategory.join(',') : options.serviceCategory;
857
+ }
858
+ return this.sendRequest('GET', 'api/v1/search/services', params);
859
+ }
860
+ /**
861
+ * Search for educational institutions/schools.
862
+ *
863
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/schools
864
+ *
865
+ * @param keyword - Search keyword (e.g., "stanford")
866
+ * @param start - Pagination start index (default is 0)
867
+ * @returns List of schools matching the search criteria
868
+ */
869
+ async searchSchools(keyword, start = 0) {
870
+ const params = { start };
871
+ if (keyword)
872
+ params.keyword = keyword;
873
+ return this.sendRequest('GET', 'api/v1/search/schools', params);
874
+ }
875
+ /**
876
+ * Search for LinkedIn posts with various filters.
877
+ *
878
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/search/posts
879
+ *
880
+ * @param options - Search options
881
+ * @param options.keyword - Search keyword (e.g., "google")
882
+ * @param options.start - Pagination start index (default is 10)
883
+ * @param options.authorCompany - Company ID of the post author
884
+ * @param options.authorIndustry - Industry ID of the post author
885
+ * @param options.authorJobTitle - Job title of the post author (e.g., "founder")
886
+ * @param options.contentType - Content type: videos, photos, jobs, liveVideos, documents, collaborativeArticles
887
+ * @param options.datePosted - Date filter: past-24h, past-week, past-month, past-year
888
+ * @param options.fromMember - Profile URN of the post author
889
+ * @param options.fromOrganization - Company IDs (string or array)
890
+ * @param options.mentionsMember - Profile URN mentioned in posts
891
+ * @param options.mentionsOrganization - Company IDs mentioned (string or array)
892
+ * @param options.sortBy - Sort order: relevance, date_posted (default is "relevance")
893
+ * @returns List of posts matching the search criteria
894
+ */
895
+ async searchPosts(options = {}) {
896
+ const params = {
897
+ start: options.start ?? 10,
898
+ sortBy: options.sortBy ?? 'relevance',
899
+ };
900
+ if (options.keyword)
901
+ params.keyword = options.keyword;
902
+ if (options.authorCompany)
903
+ params.authorCompany = options.authorCompany;
904
+ if (options.authorIndustry)
905
+ params.authorIndustry = options.authorIndustry;
906
+ if (options.authorJobTitle)
907
+ params.authorJobTitle = options.authorJobTitle;
908
+ if (options.contentType)
909
+ params.contentType = options.contentType;
910
+ if (options.datePosted)
911
+ params.datePosted = options.datePosted;
912
+ if (options.fromMember)
913
+ params.fromMember = options.fromMember;
914
+ if (options.fromOrganization) {
915
+ params.fromOrganization = Array.isArray(options.fromOrganization) ? options.fromOrganization.join(',') : options.fromOrganization;
916
+ }
917
+ if (options.mentionsMember)
918
+ params.mentionsMember = options.mentionsMember;
919
+ if (options.mentionsOrganization) {
920
+ params.mentionsOrganization = Array.isArray(options.mentionsOrganization) ? options.mentionsOrganization.join(',') : options.mentionsOrganization;
921
+ }
922
+ return this.sendRequest('GET', 'api/v1/search/posts', params);
923
+ }
924
+ // ==================== Skills & Titles Lookup Endpoints ====================
925
+ /**
926
+ * Search for keywords and get relevant skills and titles with their IDs.
927
+ *
928
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/g/title-skills-lookup
929
+ *
930
+ * @param query - Search query
931
+ * @returns List of relevant skills and titles with IDs
932
+ */
933
+ async titleSkillsLookup(query) {
934
+ return this.sendRequest('GET', 'api/v1/g/title-skills-lookup', { query });
935
+ }
936
+ /**
937
+ * Look up service categories and return matching services.
938
+ *
939
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/g/services-lookup
940
+ *
941
+ * @param query - Search query for services (e.g., "software")
942
+ * @returns List of matching service categories with IDs
943
+ */
944
+ async servicesLookup(query) {
945
+ return this.sendRequest('GET', 'api/v1/g/services-lookup', { query });
946
+ }
947
+ // ==================== Services Endpoints ====================
948
+ /**
949
+ * Get service by VanityName.
950
+ *
951
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/services/service/details
952
+ *
953
+ * @param vanityname - The service vanity name identifier
954
+ * @returns Service details information
955
+ */
956
+ async getServiceDetails(vanityname) {
957
+ return this.sendRequest('GET', 'api/v1/services/service/details', { vanityname });
958
+ }
959
+ /**
960
+ * Get similar services by VanityName.
961
+ *
962
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/services/service/similar
963
+ *
964
+ * @param vanityname - The service vanity name identifier
965
+ * @returns List of similar services
966
+ */
967
+ async getSimilarServices(vanityname) {
968
+ return this.sendRequest('GET', 'api/v1/services/service/similar', { vanityname });
969
+ }
970
+ // ==================== Articles Endpoints ====================
971
+ /**
972
+ * Get all articles published by a specific LinkedIn profile.
973
+ *
974
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/articles/all
975
+ *
976
+ * @param urn - The LinkedIn profile URN
977
+ * @param start - Pagination start index (default is 0)
978
+ * @returns List of articles published by the profile
979
+ */
980
+ async getAllArticles(urn, start = 0) {
981
+ return this.sendRequest('GET', 'api/v1/articles/all', { urn, start });
982
+ }
983
+ /**
984
+ * Get detailed information about a specific LinkedIn article.
985
+ *
986
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/articles/article/info
987
+ *
988
+ * @param url - Full LinkedIn article URL (e.g., "https://www.linkedin.com/pulse/...")
989
+ * @returns Detailed article information
990
+ */
991
+ async getArticleInfo(url) {
992
+ return this.sendRequest('GET', 'api/v1/articles/article/info', { url });
993
+ }
994
+ /**
995
+ * Get reactions (likes, comments, etc.) for a specific LinkedIn article.
996
+ *
997
+ * Documentation: https://linkdapi.com/docs?endpoint=/api/v1/articles/article/reactions
998
+ *
999
+ * @param urn - Article/thread URN (obtained from getArticleInfo)
1000
+ * @param start - Pagination start index (default is 0)
1001
+ * @returns Reactions data for the article
1002
+ */
1003
+ async getArticleReactions(urn, start = 0) {
1004
+ return this.sendRequest('GET', 'api/v1/articles/article/reactions', { urn, start });
1005
+ }
1006
+ }
1007
+ exports.LinkdAPI = LinkdAPI;
1008
+ //# sourceMappingURL=client.js.map