Skip to content

Commit 66ff2c7

Browse files
1.1.0
1 parent 80fdb72 commit 66ff2c7

36 files changed

+810
-310
lines changed

README.md

Lines changed: 76 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
- [Quick Start](#-quick-start)
55
- [Linked API](#-linked-api)
66
- [Best Practices](#-best-practices)
7-
- [Workflow Consistency & State Management](#-workflow-consistency--state-management)
87
- [Error Handling](#-error-handling)
98
- [TypeScript Support](#-typescript-support)
109
- [License](#-license)
@@ -26,7 +25,7 @@ import LinkedApi from "linkedapi-node";
2625

2726
// Initialize with your API tokens
2827
const linkedapi = new LinkedApi({
29-
apiToken: "your-api-token",
28+
linkedApiToken: "your-linked-api-token",
3029
identificationToken: "your-identification-token",
3130
});
3231

@@ -57,7 +56,7 @@ const companies = await searchCompaniesWorkflow.result();
5756
const companyWorkflow = await linkedapi.fetchCompany({
5857
companyUrl: "https://www.linkedin.com/company/company1",
5958
retrieveEmployees: true,
60-
employeeRetrievalConfig: {
59+
employeesRetrievalConfig: {
6160
filter: {
6261
schools: ["Harvard University", "Stanford University"],
6362
},
@@ -74,20 +73,20 @@ Linked API lets you manage LinkedIn accounts programmatically through an API int
7473

7574
To use Linked API you must initialize with:
7675

77-
- `apiToken` – your main token that enables overall Linked API access.
76+
- `linkedApiToken` – your main token that enables overall Linked API access.
7877
- `identificationToken` – unique token specific to each managed LinkedIn account.
7978

8079
```typescript
8180
const linkedapi = new LinkedApi({
82-
apiToken: "your-api-token",
81+
linkedApiToken: "your-linked-api-token",
8382
identificationToken: "your-identification-token",
8483
});
8584
```
8685

87-
You can obtain these tokens through [Linked API Platform](https://app.linkedapi.io/account-api?ref=linkedapi-node), as demonstrated below:
86+
You can obtain these tokens through [Linked API Platform](https://app.linkedapi.io?ref=linkedapi-node), as demonstrated below:
8887
![API Tokens](https://linkedapi.io/content/images/size/w1600/2025/07/tokens-1.webp)
8988

90-
**📖 Documentation:** [Documentation](https://linkedapi.io/docs/account-api/)
89+
**📖 Documentation:** [Documentation](https://linkedapi.io/docs)
9190

9291
---
9392

@@ -97,7 +96,7 @@ Execute custom LinkedIn automation workflows with raw workflow definitions.
9796

9897
- **Parameters:** `TWorkflowDefinition` - Custom workflow definition
9998
- **Returns:** `Promise<WorkflowHandler>` - Workflow handler for result management
100-
- **Documentation:** [Building Workflows](https://linkedapi.io/docs/account-api/building-workflows/) | [Executing Workflows](https://linkedapi.io/docs/account-api/executing-workflows/) | [Actions Overview](https://linkedapi.io/docs/account-api/actions-overview/)
99+
- **Documentation:** [Building Workflows](https://linkedapi.io/docs/building-workflows/) | [Executing Workflows](https://linkedapi.io/docs/executing-workflows/) | [Actions Overview](https://linkedapi.io/docs/actions-overview/)
101100

102101
```typescript
103102
const workflow = await linkedapi.executeCustomWorkflow({
@@ -115,14 +114,43 @@ Retrieve the result of a previously started workflow by its ID.
115114

116115
- **Parameters:** `string` - Workflow ID
117116
- **Returns:** `Promise<TWorkflowResponse>` - Workflow response with completion data
118-
- **Documentation:** [Executing Workflows](https://linkedapi.io/docs/account-api/executing-workflows/)
117+
- **Documentation:** [Executing Workflows](https://linkedapi.io/docs/executing-workflows/)
119118

120119
```typescript
121120
const result = await linkedapi.getWorkflowResult("workflow-id-123");
122121
```
123122

124123
---
125124

125+
### `restoreWorkflow(workflowId, functionName)`
126+
127+
Restore a WorkflowHandler for a previously started workflow using its ID and function name with type safety.
128+
129+
- **Parameters:**
130+
- `workflowId: string` - The unique identifier of the workflow to restore
131+
- `functionName: TSupportedFunctionName` - The name of the function that was used to create the workflow
132+
- **Returns:** `Promise<WorkflowHandler<TRestoreResultType<TFunction>>>` - WorkflowHandler with exact result type based on the function name
133+
- **Type Safety:** Full TypeScript inference for exact return types based on the function name
134+
- **Documentation:** [Executing Workflows](https://linkedapi.io/docs/executing-workflows/)
135+
136+
```typescript
137+
// Restore a person fetching workflow with full type safety
138+
const personHandler = await linkedapi.restoreWorkflow(
139+
"workflow-id-123",
140+
"fetchPerson"
141+
);
142+
const personData = await personHandler.result();
143+
144+
// Restore a company fetching workflow
145+
const companyHandler = await linkedapi.restoreWorkflow(
146+
"workflow-id-456",
147+
"fetchCompany"
148+
);
149+
const companyData = await companyHandler.result();
150+
```
151+
152+
---
153+
126154
### `fetchPerson(params)`
127155

128156
Retrieve comprehensive LinkedIn person profile data including experience, education, skills, and posts.
@@ -144,11 +172,11 @@ const personWorkflow = await linkedapi.fetchPerson({
144172
limit: 20, // Maximum number of posts to retrieve (1-20)
145173
since: "2024-01-01", // Retrieve posts since this date (YYYY-MM-DD)
146174
},
147-
commentRetrievalConfig: {
175+
commentsRetrievalConfig: {
148176
limit: 10, // Maximum number of comments to retrieve (1-20)
149177
since: "2024-01-01", // Retrieve comments since this date
150178
},
151-
reactionRetrievalConfig: {
179+
reactionsRetrievalConfig: {
152180
limit: 15, // Maximum number of reactions to retrieve (1-20)
153181
since: "2024-01-01", // Retrieve reactions since this date
154182
},
@@ -185,8 +213,8 @@ const companyWorkflow = await linkedapi.fetchCompany({
185213
companyUrl: "https://www.linkedin.com/company/microsoft",
186214
retrieveEmployees: true, // Get company employees with their profiles
187215
retrievePosts: true, // Get recent company posts and updates
188-
retrieveDms: true, // Get decision makers and key personnel
189-
employeeRetrievalConfig: {
216+
retrieveDMs: true, // Get decision makers and key personnel
217+
employeesRetrievalConfig: {
190218
limit: 25, // Maximum number of employees to retrieve (1-500)
191219
filter: {
192220
firstName: "John", // Filter by employee first name
@@ -199,11 +227,11 @@ const companyWorkflow = await linkedapi.fetchCompany({
199227
schools: ["Stanford University", "MIT"], // Filter by educational background
200228
},
201229
},
202-
postRetrievalConfig: {
230+
postsRetrievalConfig: {
203231
limit: 10, // Maximum number of posts to retrieve (1-20)
204232
since: "2024-01-01", // Retrieve posts since this date (YYYY-MM-DD)
205233
},
206-
dmRetrievalConfig: {
234+
dmsRetrievalConfig: {
207235
limit: 5, // Maximum number of decision makers to retrieve
208236
},
209237
});
@@ -222,9 +250,9 @@ Retrieve company data through Sales Navigator with advanced filtering and prospe
222250
```typescript
223251
const nvCompanyWorkflow = await linkedapi.salesNavigatorFetchCompany({
224252
companyHashedUrl: "https://www.linkedin.com/sales/company/1035",
225-
retrieveEmployees: true, // Get company employees with Sales Navigator data
226-
retrieveDms: true, // Get decision makers and key personnel
227-
employeeRetrievalConfig: {
253+
retrieveEmployees: true, // Get company employees with Sales Navigator
254+
retrieveDMs: true, // Get decision makers
255+
employeesRetrievalConfig: {
228256
limit: 25, // Maximum number of employees to retrieve (1-500)
229257
filter: {
230258
firstName: "John",
@@ -236,7 +264,7 @@ const nvCompanyWorkflow = await linkedapi.salesNavigatorFetchCompany({
236264
yearsOfExperiences: ["threeToFive", "sixToTen"],
237265
},
238266
},
239-
dmRetrievalConfig: {
267+
dmsRetrievalConfig: {
240268
limit: 10, // Maximum number of decision makers to retrieve (1-20)
241269
},
242270
});
@@ -364,7 +392,7 @@ const nvPeopleSearch = await linkedapi.salesNavigatorSearchPeople({
364392
Send connection requests to LinkedIn users with optional personalized messages.
365393

366394
- **Parameters:** `TSendConnectionRequestParams` - Person URL and optional message
367-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
395+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
368396

369397
```typescript
370398
await linkedapi.sendConnectionRequest({
@@ -397,7 +425,7 @@ console.log("Connection status:", status.connectionStatus); // 'connected', 'pen
397425
Withdraw previously sent connection requests.
398426

399427
- **Parameters:** `TWithdrawConnectionRequestParams` - Person URL
400-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
428+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
401429

402430
```typescript
403431
await linkedapi.withdrawConnectionRequest({
@@ -447,7 +475,7 @@ const connectionsWorkflow = await linkedapi.retrieveConnections({
447475
Remove existing connections from your LinkedIn network.
448476

449477
- **Parameters:** `TRemoveConnectionParams` - Person URL
450-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
478+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
451479

452480
```typescript
453481
await linkedapi.removeConnection({
@@ -462,7 +490,7 @@ await linkedapi.removeConnection({
462490
React to LinkedIn posts with various reaction types (like, love, support, etc.).
463491

464492
- **Parameters:** `TReactToPostParams` - Post URL and reaction type
465-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
493+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
466494

467495
```typescript
468496
await linkedapi.reactToPost({
@@ -478,7 +506,7 @@ await linkedapi.reactToPost({
478506
Comment on LinkedIn posts to engage with your network.
479507

480508
- **Parameters:** `TCommentOnPostParams` - Post URL and comment text
481-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
509+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
482510

483511
```typescript
484512
await linkedapi.commentOnPost({
@@ -522,7 +550,7 @@ console.log("Post views:", metrics.postViewsLast7Days);
522550

523551
### `getApiUsageStats(params)`
524552

525-
Retrieve Account API usage statistics for monitoring and optimization.
553+
Retrieve Linked API usage statistics for monitoring and optimization.
526554

527555
- **Parameters:** `TApiUsageStatsParams` - Start and end timestamps (max 30 days apart)
528556
- **Returns:** `Promise<TApiUsageStatsResponse>` - Array of executed actions with success/failure data
@@ -554,7 +582,7 @@ if (statsResponse.success) {
554582
Send messages to LinkedIn users through standard LinkedIn messaging.
555583

556584
- **Parameters:** `TSendMessageParams` - Person URL and message text
557-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
585+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
558586

559587
```typescript
560588
await linkedapi.sendMessage({
@@ -570,7 +598,7 @@ await linkedapi.sendMessage({
570598
Sync conversation history with a LinkedIn user for message polling.
571599

572600
- **Parameters:** `TSyncConversationParams` - Person URL
573-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
601+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
574602
- **Related Methods:** Use with `pollConversations()` to retrieve message history
575603

576604
```typescript
@@ -586,7 +614,7 @@ await linkedapi.syncConversation({
586614
Send messages through Sales Navigator with enhanced messaging capabilities.
587615

588616
- **Parameters:** `TNvSendMessageParams` - Person URL, message text, and optional subject
589-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
617+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
590618

591619
```typescript
592620
await linkedapi.salesNavigatorSendMessage({
@@ -603,7 +631,7 @@ await linkedapi.salesNavigatorSendMessage({
603631
Sync Sales Navigator conversation for message polling.
604632

605633
- **Parameters:** `TNvSyncConversationParams` - Person URL
606-
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (no result data)
634+
- **Returns:** `Promise<WorkflowHandler<void>>` - Workflow handler (void)
607635

608636
```typescript
609637
await linkedapi.salesNavigatorSyncConversation({
@@ -698,7 +726,7 @@ try {
698726
try {
699727
const companyEmployeesWorkflow = await linkedapi.fetchCompany({
700728
retrieveEmployees: true,
701-
employeeRetrievalConfig: {
729+
employeesRetrievalConfig: {
702730
limit: 5,
703731
filter: {
704732
position: "manager"
@@ -727,7 +755,7 @@ try {
727755
}
728756
```
729757

730-
**📖 Learn more:** [Building Custom Workflows](https://linkedapi.io/docs/account-api/building-workflows/) | [Actions Overview](https://linkedapi.io/docs/account-api/actions-overview/)
758+
**📖 Learn more:** [Building Custom Workflows](https://linkedapi.io/docs/building-workflows/) | [Actions Overview](https://linkedapi.io/docs/actions-overview/)
731759

732760
### Workflow Consistency & State Management
733761

@@ -749,7 +777,7 @@ const workflowId = personWorkflow.workflowId;
749777
console.log("Workflow started with ID:", workflowId);
750778

751779
// Store in database/file/memory for later retrieval
752-
await saveWorkflowToDatabase(workflowId);
780+
await saveWorkflowToDatabase(workflowId, "fetchPerson");
753781
try {
754782
const person = await personWorkflow.result();
755783
} finally {
@@ -759,37 +787,31 @@ try {
759787

760788
#### Retrieving Results After App Restart
761789

762-
If your application restarts or you need to check workflow status later, use `getWorkflowResult(workflowId)`:
790+
If your application restarts or you need to check workflow status later, you can:
791+
- Restore a `WorkflowHandler` using `restoreWorkflow(workflowId, functionName)` with full type safety
763792

764793
```typescript
765-
// Account API - retrieve workflow result by ID
766-
const savedWorkflows = await getWorkflowsFromDatabase();
767-
for (workflowId of runningWorkflows) {
768-
try {
769-
const result = await linkedapi.getWorkflowResult(workflowId);
794+
// 1) Raw handler
795+
const rawHandler = await linkedapi.restoreWorkflow(savedWorkflowId);
770796

771-
if (result.completion) {
772-
console.log("Workflow completed:", result.completion.data);
773-
await deleteWorkflowFromDatabase(workflowId);
774-
} else {
775-
console.log("Workflow still running...");
776-
// Continue polling or set up periodic checks
777-
}
778-
} catch (error) {
779-
console.error("Workflow failed:", error);
780-
await deleteWorkflowFromDatabase(workflowId);
781-
}
782-
}
797+
// 2) Streamlined restoration with function name (wide result type with full type safety)
798+
const handler = await linkedapi.restoreWorkflow(savedWorkflowId, "fetchPerson");
799+
const result = await handler.result();
800+
console.log("Person name:", result.name);
801+
console.log("Experience count:", result.experiences?.length);
783802
```
784803

804+
See `examples/restore-workflow.ts` for a full example.
805+
785806
---
786807

787808
## 🚨 Error Handling
788809

789810
Linked API provides structured error handling for different failure scenarios.
790811

791-
- **`LinkedApiError`** - throws if a [common error](https://linkedapi.io/docs/account-api/making-requests/#common-errors) occurs
792-
- **`LinkedApiWorkflowError`** - throws in case of the [workflow execution](https://linkedapi.io/docs/account-api/actions-overview/#result-options) error (like invalid URL or messaging not allowed)
812+
- **`LinkedApiError`** - throws if a [common error](https://linkedapi.io/docs/making-requests/#common-errors) occurs
813+
- **`LinkedApiWorkflowError`** - throws in case of the [workflow execution](https://linkedapi.io/docs/actions-overview/#result-options) error (like invalid URL or messaging not allowed)
814+
- **`LinkedApiWorkflowTimeoutError`** - throws in case of timeout. Contains `workflowId` and `functionName` for future restoration
793815

794816
```typescript
795817
import LinkedApi from "linkedapi-node";
@@ -815,8 +837,8 @@ try {
815837

816838
### Common Error Types
817839

818-
- **`accountApiTokenRequired`** - Missing API token
819-
- **`invalidAccountApiToken`** - Invalid API token
840+
- **`linkedApiTokenRequired`** - Missing API token
841+
- **`invalidLinkedApiToken`** - Invalid API token
820842
- **`identificationTokenRequired`** - Missing Indentification token
821843
- **`invalidIdentificationToken`** - Invalid Identification Token
822844
- **`subscriptionRequired`** - No purchased subscription seats available for this LinkedIn account.

examples/connections.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import LinkedApi, { LinkedApiError, LinkedApiWorkflowError } from 'linkedapi-nod
33
async function connectionsExample(): Promise<void> {
44

55
const linkedapi = new LinkedApi({
6-
apiToken: process.env.API_TOKEN!,
6+
linkedApiToken: process.env.LINKED_API_TOKEN!,
77
identificationToken: process.env.IDENTIFICATION_TOKEN!,
88
});
99

examples/custom-workflow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import LinkedApi, { LinkedApiError, LinkedApiWorkflowError } from 'linkedapi-nod
33
async function customWorkflowExample(): Promise<void> {
44

55
const linkedapi = new LinkedApi({
6-
apiToken: process.env.API_TOKEN!,
6+
linkedApiToken: process.env.LINKED_API_TOKEN!,
77
identificationToken: process.env.IDENTIFICATION_TOKEN!,
88
});
99

0 commit comments

Comments
 (0)