universal-mcp-applications 0.1.30__py3-none-any.whl → 0.1.36rc1__py3-none-any.whl
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.
Potentially problematic release.
This version of universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/ahrefs/app.py +52 -198
- universal_mcp/applications/airtable/app.py +23 -122
- universal_mcp/applications/apollo/app.py +111 -464
- universal_mcp/applications/asana/app.py +417 -1567
- universal_mcp/applications/aws_s3/app.py +33 -100
- universal_mcp/applications/bill/app.py +546 -1957
- universal_mcp/applications/box/app.py +1068 -3981
- universal_mcp/applications/braze/app.py +364 -1430
- universal_mcp/applications/browser_use/app.py +2 -8
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +61 -200
- universal_mcp/applications/canva/app.py +45 -110
- universal_mcp/applications/clickup/app.py +207 -674
- universal_mcp/applications/coda/app.py +146 -426
- universal_mcp/applications/confluence/app.py +310 -1098
- universal_mcp/applications/contentful/app.py +36 -151
- universal_mcp/applications/crustdata/app.py +28 -107
- universal_mcp/applications/dialpad/app.py +283 -756
- universal_mcp/applications/digitalocean/app.py +1766 -5777
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +14 -64
- universal_mcp/applications/elevenlabs/app.py +9 -47
- universal_mcp/applications/exa/app.py +6 -17
- universal_mcp/applications/falai/app.py +23 -100
- universal_mcp/applications/figma/app.py +53 -137
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +51 -152
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +91 -528
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +52 -161
- universal_mcp/applications/github/app.py +19 -56
- universal_mcp/applications/gong/app.py +88 -248
- universal_mcp/applications/google_calendar/app.py +16 -68
- universal_mcp/applications/google_docs/app.py +88 -188
- universal_mcp/applications/google_drive/app.py +140 -462
- universal_mcp/applications/google_gemini/app.py +12 -64
- universal_mcp/applications/google_mail/app.py +28 -157
- universal_mcp/applications/google_searchconsole/app.py +15 -48
- universal_mcp/applications/google_sheet/app.py +101 -578
- universal_mcp/applications/google_sheet/helper.py +10 -37
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/app.py +44 -122
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/api_segments/crm_api.py +460 -1573
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +74 -262
- universal_mcp/applications/hubspot/app.py +23 -87
- universal_mcp/applications/jira/app.py +2071 -7986
- universal_mcp/applications/klaviyo/app.py +494 -1376
- universal_mcp/applications/linkedin/README.md +9 -2
- universal_mcp/applications/linkedin/app.py +392 -212
- universal_mcp/applications/mailchimp/app.py +450 -1605
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +217 -699
- universal_mcp/applications/ms_teams/app.py +64 -186
- universal_mcp/applications/neon/app.py +86 -192
- universal_mcp/applications/notion/app.py +21 -36
- universal_mcp/applications/onedrive/app.py +14 -36
- universal_mcp/applications/openai/app.py +42 -165
- universal_mcp/applications/outlook/app.py +16 -76
- universal_mcp/applications/perplexity/app.py +4 -19
- universal_mcp/applications/pipedrive/app.py +832 -3142
- universal_mcp/applications/posthog/app.py +163 -432
- universal_mcp/applications/reddit/app.py +40 -139
- universal_mcp/applications/resend/app.py +41 -107
- universal_mcp/applications/retell/app.py +14 -41
- universal_mcp/applications/rocketlane/app.py +221 -934
- universal_mcp/applications/scraper/README.md +7 -4
- universal_mcp/applications/scraper/app.py +216 -102
- universal_mcp/applications/semanticscholar/app.py +22 -64
- universal_mcp/applications/semrush/app.py +43 -77
- universal_mcp/applications/sendgrid/app.py +512 -1262
- universal_mcp/applications/sentry/app.py +271 -906
- universal_mcp/applications/serpapi/app.py +40 -143
- universal_mcp/applications/sharepoint/app.py +15 -37
- universal_mcp/applications/shopify/app.py +1551 -4287
- universal_mcp/applications/shortcut/app.py +155 -417
- universal_mcp/applications/slack/app.py +50 -101
- universal_mcp/applications/spotify/app.py +126 -325
- universal_mcp/applications/supabase/app.py +104 -213
- universal_mcp/applications/tavily/app.py +1 -1
- universal_mcp/applications/trello/app.py +693 -2656
- universal_mcp/applications/twilio/app.py +14 -50
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +70 -283
- universal_mcp/applications/wrike/app.py +45 -118
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +75 -261
- universal_mcp/applications/zenquotes/app.py +2 -2
- {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/METADATA +2 -2
- {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/RECORD +105 -105
- {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/WHEEL +0 -0
- {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
3
|
from typing import Any, Callable, Literal
|
|
4
|
-
|
|
5
4
|
from loguru import logger
|
|
6
5
|
from universal_mcp.applications.application import APIApplication
|
|
7
6
|
from universal_mcp.integrations import Integration
|
|
@@ -23,7 +22,6 @@ class LinkedinApp(APIApplication):
|
|
|
23
22
|
`{"headers": {"x-api-key": "YOUR_API_KEY"}}`.
|
|
24
23
|
"""
|
|
25
24
|
super().__init__(name="linkedin", integration=integration)
|
|
26
|
-
|
|
27
25
|
self._base_url = None
|
|
28
26
|
self.account_id = None
|
|
29
27
|
if self.integration:
|
|
@@ -36,12 +34,8 @@ class LinkedinApp(APIApplication):
|
|
|
36
34
|
if not self._base_url:
|
|
37
35
|
unipile_dsn = os.getenv("UNIPILE_DSN")
|
|
38
36
|
if not unipile_dsn:
|
|
39
|
-
logger.error(
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
raise ValueError(
|
|
43
|
-
"UnipileApp: UNIPILE_DSN environment variable is required."
|
|
44
|
-
)
|
|
37
|
+
logger.error("UnipileApp: UNIPILE_DSN environment variable is not set.")
|
|
38
|
+
raise ValueError("UnipileApp: UNIPILE_DSN environment variable is required.")
|
|
45
39
|
self._base_url = f"https://{unipile_dsn}"
|
|
46
40
|
return self._base_url
|
|
47
41
|
|
|
@@ -56,35 +50,46 @@ class LinkedinApp(APIApplication):
|
|
|
56
50
|
Overrides the base class method to use X-Api-Key.
|
|
57
51
|
"""
|
|
58
52
|
if not self.integration:
|
|
59
|
-
logger.warning(
|
|
60
|
-
"UnipileApp: No integration configured, returning empty headers."
|
|
61
|
-
)
|
|
53
|
+
logger.warning("UnipileApp: No integration configured, returning empty headers.")
|
|
62
54
|
return {}
|
|
63
|
-
|
|
64
55
|
api_key = os.getenv("UNIPILE_API_KEY")
|
|
65
56
|
if not api_key:
|
|
66
|
-
logger.error(
|
|
67
|
-
|
|
68
|
-
)
|
|
69
|
-
return { # Or return minimal headers if some calls might not need auth (unlikely for Unipile)
|
|
70
|
-
"Content-Type": "application/json",
|
|
71
|
-
"Cache-Control": "no-cache",
|
|
72
|
-
}
|
|
73
|
-
|
|
57
|
+
logger.error("UnipileApp: API key not found in integration credentials for Unipile.")
|
|
58
|
+
return {"Content-Type": "application/json", "Cache-Control": "no-cache"}
|
|
74
59
|
logger.debug("UnipileApp: Using X-Api-Key for authentication.")
|
|
75
|
-
return {
|
|
76
|
-
"x-api-key": api_key,
|
|
77
|
-
"Content-Type": "application/json",
|
|
78
|
-
"Cache-Control": "no-cache", # Often good practice for APIs
|
|
79
|
-
}
|
|
60
|
+
return {"x-api-key": api_key, "Content-Type": "application/json", "Cache-Control": "no-cache"}
|
|
80
61
|
|
|
81
|
-
def
|
|
62
|
+
def _get_search_parameter_id(self, param_type: str, keywords: str) -> str:
|
|
63
|
+
"""
|
|
64
|
+
Retrieves the ID for a given LinkedIn search parameter by its name.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
param_type: The type of parameter to search for (e.g., "LOCATION", "COMPANY").
|
|
68
|
+
keywords: The name of the parameter to find (e.g., "United States").
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The corresponding ID for the search parameter.
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
ValueError: If no exact match for the keywords is found.
|
|
75
|
+
httpx.HTTPError: If the API request fails.
|
|
76
|
+
"""
|
|
77
|
+
url = f"{self.base_url}/api/v1/linkedin/search/parameters"
|
|
78
|
+
params = {"account_id": self.account_id, "keywords": keywords, "type": param_type}
|
|
79
|
+
response = self._get(url, params=params)
|
|
80
|
+
results = self._handle_response(response)
|
|
81
|
+
items = results.get("items", [])
|
|
82
|
+
if items:
|
|
83
|
+
return items[0]["id"]
|
|
84
|
+
raise ValueError(f'Could not find a matching ID for {param_type}: "{keywords}"')
|
|
85
|
+
|
|
86
|
+
async def list_all_chats(
|
|
82
87
|
self,
|
|
83
88
|
unread: bool | None = None,
|
|
84
89
|
cursor: str | None = None,
|
|
85
|
-
before: str | None = None,
|
|
86
|
-
after: str | None = None,
|
|
87
|
-
limit: int | None = None,
|
|
90
|
+
before: str | None = None,
|
|
91
|
+
after: str | None = None,
|
|
92
|
+
limit: int | None = None,
|
|
88
93
|
account_type: str | None = None,
|
|
89
94
|
) -> dict[str, Any]:
|
|
90
95
|
"""
|
|
@@ -109,9 +114,7 @@ class LinkedinApp(APIApplication):
|
|
|
109
114
|
"""
|
|
110
115
|
url = f"{self.base_url}/api/v1/chats"
|
|
111
116
|
params: dict[str, Any] = {}
|
|
112
|
-
|
|
113
117
|
params["account_id"] = self.account_id
|
|
114
|
-
|
|
115
118
|
if unread is not None:
|
|
116
119
|
params["unread"] = unread
|
|
117
120
|
if cursor:
|
|
@@ -124,18 +127,16 @@ class LinkedinApp(APIApplication):
|
|
|
124
127
|
params["limit"] = limit
|
|
125
128
|
if account_type:
|
|
126
129
|
params["account_type"] = account_type
|
|
127
|
-
|
|
128
|
-
|
|
129
130
|
response = self._get(url, params=params)
|
|
130
131
|
return response.json()
|
|
131
132
|
|
|
132
|
-
def list_chat_messages(
|
|
133
|
+
async def list_chat_messages(
|
|
133
134
|
self,
|
|
134
135
|
chat_id: str,
|
|
135
136
|
cursor: str | None = None,
|
|
136
|
-
before: str | None = None,
|
|
137
|
-
after: str | None = None,
|
|
138
|
-
limit: int | None = None,
|
|
137
|
+
before: str | None = None,
|
|
138
|
+
after: str | None = None,
|
|
139
|
+
limit: int | None = None,
|
|
139
140
|
sender_id: str | None = None,
|
|
140
141
|
) -> dict[str, Any]:
|
|
141
142
|
"""
|
|
@@ -170,15 +171,10 @@ class LinkedinApp(APIApplication):
|
|
|
170
171
|
params["limit"] = limit
|
|
171
172
|
if sender_id:
|
|
172
173
|
params["sender_id"] = sender_id
|
|
173
|
-
|
|
174
174
|
response = self._get(url, params=params)
|
|
175
175
|
return response.json()
|
|
176
176
|
|
|
177
|
-
def send_chat_message(
|
|
178
|
-
self,
|
|
179
|
-
chat_id: str,
|
|
180
|
-
text: str,
|
|
181
|
-
) -> dict[str, Any]:
|
|
177
|
+
async def send_chat_message(self, chat_id: str, text: str) -> dict[str, Any]:
|
|
182
178
|
"""
|
|
183
179
|
Sends a text message to a specific chat conversation using its `chat_id`. This function creates a new message via a POST request, distinguishing it from read-only functions like `list_chat_messages`. It returns the API's response, which typically confirms the successful creation of the message.
|
|
184
180
|
|
|
@@ -198,11 +194,10 @@ class LinkedinApp(APIApplication):
|
|
|
198
194
|
"""
|
|
199
195
|
url = f"{self.base_url}/api/v1/chats/{chat_id}/messages"
|
|
200
196
|
payload: dict[str, Any] = {"text": text}
|
|
201
|
-
|
|
202
197
|
response = self._post(url, data=payload)
|
|
203
198
|
return response.json()
|
|
204
199
|
|
|
205
|
-
def retrieve_chat(self, chat_id: str) -> dict[str, Any]:
|
|
200
|
+
async def retrieve_chat(self, chat_id: str) -> dict[str, Any]:
|
|
206
201
|
"""
|
|
207
202
|
Retrieves a single chat's details using its Unipile or provider-specific ID. This function is distinct from `list_all_chats`, which returns a collection, by targeting one specific conversation.
|
|
208
203
|
|
|
@@ -222,16 +217,15 @@ class LinkedinApp(APIApplication):
|
|
|
222
217
|
params: dict[str, Any] = {}
|
|
223
218
|
if self.account_id:
|
|
224
219
|
params["account_id"] = self.account_id
|
|
225
|
-
|
|
226
220
|
response = self._get(url, params=params)
|
|
227
221
|
return response.json()
|
|
228
222
|
|
|
229
|
-
def list_all_messages(
|
|
223
|
+
async def list_all_messages(
|
|
230
224
|
self,
|
|
231
225
|
cursor: str | None = None,
|
|
232
|
-
before: str | None = None,
|
|
233
|
-
after: str | None = None,
|
|
234
|
-
limit: int | None = None,
|
|
226
|
+
before: str | None = None,
|
|
227
|
+
after: str | None = None,
|
|
228
|
+
limit: int | None = None,
|
|
235
229
|
sender_id: str | None = None,
|
|
236
230
|
) -> dict[str, Any]:
|
|
237
231
|
"""
|
|
@@ -267,64 +261,11 @@ class LinkedinApp(APIApplication):
|
|
|
267
261
|
params["sender_id"] = sender_id
|
|
268
262
|
if self.account_id:
|
|
269
263
|
params["account_id"] = self.account_id
|
|
270
|
-
|
|
271
264
|
response = self._get(url, params=params)
|
|
272
265
|
return response.json()
|
|
273
266
|
|
|
274
|
-
def
|
|
275
|
-
self,
|
|
276
|
-
cursor: str | None = None,
|
|
277
|
-
limit: int | None = None, # 1-259 according to spec
|
|
278
|
-
) -> dict[str, Any]:
|
|
279
|
-
"""
|
|
280
|
-
Retrieves a paginated list of all social media accounts linked to the Unipile service. This is crucial for obtaining the `account_id` required by other methods to specify which user account should perform an action, like sending a message or retrieving user-specific posts.
|
|
281
|
-
|
|
282
|
-
Args:
|
|
283
|
-
cursor: Pagination cursor.
|
|
284
|
-
limit: Number of items to return (1-259).
|
|
285
|
-
|
|
286
|
-
Returns:
|
|
287
|
-
A dictionary containing a list of account objects and a pagination cursor.
|
|
288
|
-
|
|
289
|
-
Raises:
|
|
290
|
-
httpx.HTTPError: If the API request fails.
|
|
291
|
-
|
|
292
|
-
Tags:
|
|
293
|
-
linkedin, account, list, unipile, api, important
|
|
294
|
-
"""
|
|
295
|
-
url = f"{self.base_url}/api/v1/accounts"
|
|
296
|
-
params: dict[str, Any] = {}
|
|
297
|
-
if cursor:
|
|
298
|
-
params["cursor"] = cursor
|
|
299
|
-
if limit:
|
|
300
|
-
params["limit"] = limit
|
|
301
|
-
|
|
302
|
-
response = self._get(url, params=params)
|
|
303
|
-
return response.json()
|
|
304
|
-
|
|
305
|
-
# def retrieve_linked_account(self) -> dict[str, Any]:
|
|
306
|
-
# """
|
|
307
|
-
# Retrieves details for the account linked to Unipile. It fetches metadata about the connection itself (e.g., a linked LinkedIn account), differentiating it from `retrieve_user_profile` which fetches a user's profile from the external platform.
|
|
308
|
-
|
|
309
|
-
# Returns:
|
|
310
|
-
# A dictionary containing the account object details.
|
|
311
|
-
|
|
312
|
-
# Raises:
|
|
313
|
-
# httpx.HTTPError: If the API request fails.
|
|
314
|
-
|
|
315
|
-
# Tags:
|
|
316
|
-
# linkedin, account, retrieve, get, unipile, api, important
|
|
317
|
-
# """
|
|
318
|
-
# url = f"{self.base_url}/api/v1/accounts/{self.account_id}"
|
|
319
|
-
# response = self._get(url)
|
|
320
|
-
# return response.json()
|
|
321
|
-
|
|
322
|
-
def list_profile_posts(
|
|
323
|
-
self,
|
|
324
|
-
identifier: str, # User or Company provider internal ID
|
|
325
|
-
cursor: str | None = None,
|
|
326
|
-
limit: int | None = None, # 1-100 (spec says max 250)
|
|
327
|
-
is_company: bool | None = None,
|
|
267
|
+
async def list_profile_posts(
|
|
268
|
+
self, identifier: str, cursor: str | None = None, limit: int | None = None, is_company: bool | None = None
|
|
328
269
|
) -> dict[str, Any]:
|
|
329
270
|
"""
|
|
330
271
|
Retrieves a paginated list of posts from a specific user or company profile using their provider ID. An authorizing `account_id` is required, and the `is_company` flag must specify the entity type, distinguishing this from `retrieve_post` which fetches a single post by its own ID.
|
|
@@ -352,11 +293,10 @@ class LinkedinApp(APIApplication):
|
|
|
352
293
|
params["limit"] = limit
|
|
353
294
|
if is_company is not None:
|
|
354
295
|
params["is_company"] = is_company
|
|
355
|
-
|
|
356
296
|
response = self._get(url, params=params)
|
|
357
297
|
return response.json()
|
|
358
298
|
|
|
359
|
-
def retrieve_own_profile(self) -> dict[str, Any]:
|
|
299
|
+
async def retrieve_own_profile(self) -> dict[str, Any]:
|
|
360
300
|
"""
|
|
361
301
|
Retrieves the profile details for the user associated with the Unipile account. This function targets the API's 'me' endpoint to fetch the authenticated user's profile, distinct from `retrieve_user_profile` which fetches profiles of other users by their public identifier.
|
|
362
302
|
|
|
@@ -374,7 +314,7 @@ class LinkedinApp(APIApplication):
|
|
|
374
314
|
response = self._get(url, params=params)
|
|
375
315
|
return response.json()
|
|
376
316
|
|
|
377
|
-
def retrieve_post(self, post_id: str) -> dict[str, Any]:
|
|
317
|
+
async def retrieve_post(self, post_id: str) -> dict[str, Any]:
|
|
378
318
|
"""
|
|
379
319
|
Fetches a specific post's details by its unique ID. Unlike `list_profile_posts`, which retrieves a collection of posts from a user or company profile, this function targets one specific post and returns its full object.
|
|
380
320
|
|
|
@@ -395,18 +335,14 @@ class LinkedinApp(APIApplication):
|
|
|
395
335
|
response = self._get(url, params=params)
|
|
396
336
|
return response.json()
|
|
397
337
|
|
|
398
|
-
def list_post_comments(
|
|
399
|
-
self,
|
|
400
|
-
post_id: str,
|
|
401
|
-
comment_id: str | None = None,
|
|
402
|
-
cursor: str | None = None,
|
|
403
|
-
limit: int | None = None,
|
|
338
|
+
async def list_post_comments(
|
|
339
|
+
self, post_id: str, comment_id: str | None = None, cursor: str | None = None, limit: int | None = None
|
|
404
340
|
) -> dict[str, Any]:
|
|
405
341
|
"""
|
|
406
|
-
Fetches comments for a specific post. Providing an optional `comment_id` retrieves threaded replies instead of top-level comments.
|
|
342
|
+
Fetches comments for a specific post. Providing an optional `comment_id` retrieves threaded replies instead of top-level comments. `retrieve_post` or `list_profile_posts` can be used to obtain the `post_id` which is the social_id in their response.
|
|
407
343
|
|
|
408
344
|
Args:
|
|
409
|
-
post_id: The social ID of the post.
|
|
345
|
+
post_id: The social ID of the post which you get from using `retrieve_post` or `list_profile_posts` tools.
|
|
410
346
|
comment_id: If provided, retrieves replies to this comment ID instead of top-level comments.
|
|
411
347
|
cursor: Pagination cursor.
|
|
412
348
|
limit: Number of comments to return. (OpenAPI spec shows type string, passed as string if provided).
|
|
@@ -428,15 +364,11 @@ class LinkedinApp(APIApplication):
|
|
|
428
364
|
params["limit"] = str(limit)
|
|
429
365
|
if comment_id:
|
|
430
366
|
params["comment_id"] = comment_id
|
|
431
|
-
|
|
432
367
|
response = self._get(url, params=params)
|
|
433
368
|
return response.json()
|
|
434
369
|
|
|
435
|
-
def create_post(
|
|
436
|
-
self,
|
|
437
|
-
text: str,
|
|
438
|
-
mentions: list[dict[str, Any]] | None = None,
|
|
439
|
-
external_link: str | None = None,
|
|
370
|
+
async def create_post(
|
|
371
|
+
self, text: str, mentions: list[dict[str, Any]] | None = None, external_link: str | None = None
|
|
440
372
|
) -> dict[str, Any]:
|
|
441
373
|
"""
|
|
442
374
|
Publishes a new top-level post from the account, including text, user mentions, and an external link. This function creates original content, distinguishing it from `create_post_comment` which adds replies to existing posts.
|
|
@@ -457,26 +389,16 @@ class LinkedinApp(APIApplication):
|
|
|
457
389
|
linkedin, post, create, share, content, api, important
|
|
458
390
|
"""
|
|
459
391
|
url = f"{self.base_url}/api/v1/posts"
|
|
460
|
-
|
|
461
|
-
params: dict[str, str] = {
|
|
462
|
-
"account_id": self.account_id,
|
|
463
|
-
"text": text,
|
|
464
|
-
}
|
|
465
|
-
|
|
392
|
+
params: dict[str, str] = {"account_id": self.account_id, "text": text}
|
|
466
393
|
if mentions:
|
|
467
394
|
params["mentions"] = mentions
|
|
468
395
|
if external_link:
|
|
469
396
|
params["external_link"] = external_link
|
|
470
|
-
|
|
471
397
|
response = self._post(url, data=params)
|
|
472
398
|
return response.json()
|
|
473
399
|
|
|
474
|
-
def list_content_reactions(
|
|
475
|
-
self,
|
|
476
|
-
post_id: str,
|
|
477
|
-
comment_id: str | None = None,
|
|
478
|
-
cursor: str | None = None,
|
|
479
|
-
limit: int | None = None,
|
|
400
|
+
async def list_content_reactions(
|
|
401
|
+
self, post_id: str, comment_id: str | None = None, cursor: str | None = None, limit: int | None = None
|
|
480
402
|
) -> dict[str, Any]:
|
|
481
403
|
"""
|
|
482
404
|
Retrieves a paginated list of reactions for a given post or, optionally, a specific comment. This read-only operation uses the account for the request, distinguishing it from the `create_reaction` function which adds new reactions.
|
|
@@ -504,16 +426,11 @@ class LinkedinApp(APIApplication):
|
|
|
504
426
|
params["limit"] = limit
|
|
505
427
|
if comment_id:
|
|
506
428
|
params["comment_id"] = comment_id
|
|
507
|
-
|
|
508
429
|
response = self._get(url, params=params)
|
|
509
430
|
return response.json()
|
|
510
431
|
|
|
511
|
-
def create_post_comment(
|
|
512
|
-
self,
|
|
513
|
-
post_social_id: str,
|
|
514
|
-
text: str,
|
|
515
|
-
comment_id: str | None = None, # If provided, replies to a specific comment
|
|
516
|
-
mentions_body: list[dict[str, Any]] | None = None,
|
|
432
|
+
async def create_post_comment(
|
|
433
|
+
self, post_social_id: str, text: str, comment_id: str | None = None, mentions_body: list[dict[str, Any]] | None = None
|
|
517
434
|
) -> dict[str, Any]:
|
|
518
435
|
"""
|
|
519
436
|
Publishes a comment on a specified post. By providing an optional `comment_id`, it creates a threaded reply to an existing comment instead of a new top-level one. This function's dual capability distinguishes it from `list_post_comments`, which only retrieves comments and their replies.
|
|
@@ -535,33 +452,21 @@ class LinkedinApp(APIApplication):
|
|
|
535
452
|
linkedin, post, comment, create, content, api, important
|
|
536
453
|
"""
|
|
537
454
|
url = f"{self.base_url}/api/v1/posts/{post_social_id}/comments"
|
|
538
|
-
params: dict[str, Any] = {
|
|
539
|
-
"account_id": self.account_id,
|
|
540
|
-
"text": text,
|
|
541
|
-
}
|
|
542
|
-
|
|
455
|
+
params: dict[str, Any] = {"account_id": self.account_id, "text": text}
|
|
543
456
|
if comment_id:
|
|
544
457
|
params["comment_id"] = comment_id
|
|
545
|
-
|
|
546
458
|
if mentions_body:
|
|
547
459
|
params = {"mentions": mentions_body}
|
|
548
|
-
|
|
549
460
|
response = self._post(url, data=params)
|
|
550
|
-
|
|
551
461
|
try:
|
|
552
462
|
return response.json()
|
|
553
463
|
except json.JSONDecodeError:
|
|
554
|
-
return {
|
|
555
|
-
"status": response.status_code,
|
|
556
|
-
"message": "Comment action processed.",
|
|
557
|
-
}
|
|
464
|
+
return {"status": response.status_code, "message": "Comment action processed."}
|
|
558
465
|
|
|
559
|
-
def create_reaction(
|
|
466
|
+
async def create_reaction(
|
|
560
467
|
self,
|
|
561
468
|
post_social_id: str,
|
|
562
|
-
reaction_type: Literal[
|
|
563
|
-
"like", "celebrate", "love", "insightful", "funny", "support"
|
|
564
|
-
],
|
|
469
|
+
reaction_type: Literal["like", "celebrate", "love", "insightful", "funny", "support"],
|
|
565
470
|
comment_id: str | None = None,
|
|
566
471
|
) -> dict[str, Any]:
|
|
567
472
|
"""
|
|
@@ -582,113 +487,382 @@ class LinkedinApp(APIApplication):
|
|
|
582
487
|
linkedin, post, reaction, create, like, content, api, important
|
|
583
488
|
"""
|
|
584
489
|
url = f"{self.base_url}/api/v1/posts/reaction"
|
|
585
|
-
|
|
586
|
-
params: dict[str, str] = {
|
|
587
|
-
"account_id": self.account_id,
|
|
588
|
-
"post_id": post_social_id,
|
|
589
|
-
"reaction_type": reaction_type,
|
|
590
|
-
}
|
|
591
|
-
|
|
490
|
+
params: dict[str, str] = {"account_id": self.account_id, "post_id": post_social_id, "reaction_type": reaction_type}
|
|
592
491
|
if comment_id:
|
|
593
492
|
params["comment_id"] = comment_id
|
|
594
|
-
|
|
595
493
|
response = self._post(url, data=params)
|
|
596
|
-
|
|
597
494
|
try:
|
|
598
495
|
return response.json()
|
|
599
496
|
except json.JSONDecodeError:
|
|
600
|
-
return {
|
|
601
|
-
"status": response.status_code,
|
|
602
|
-
"message": "Reaction action processed.",
|
|
603
|
-
}
|
|
497
|
+
return {"status": response.status_code, "message": "Reaction action processed."}
|
|
604
498
|
|
|
605
|
-
def
|
|
499
|
+
async def retrieve_user_profile(self, public_identifier: str) -> dict[str, Any]:
|
|
500
|
+
"""
|
|
501
|
+
Retrieves a specific LinkedIn user's profile using their public or internal ID. Unlike `retrieve_own_profile`, which fetches the authenticated user's details, this function targets and returns data for any specified third-party user profile on the platform.
|
|
502
|
+
|
|
503
|
+
Args:
|
|
504
|
+
public_identifier: Extract this value from the response of `search_people` tool. The response contains a public_identifier field.For example, for https://www.linkedin.com/in/manojbajaj95/, the identifier is "manojbajaj95".
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
A dictionary containing the user's profile details.
|
|
508
|
+
|
|
509
|
+
Raises:
|
|
510
|
+
httpx.HTTPError: If the API request fails.
|
|
511
|
+
|
|
512
|
+
Tags:
|
|
513
|
+
linkedin, user, profile, retrieve, get, api, important
|
|
514
|
+
"""
|
|
515
|
+
url = f"{self.base_url}/api/v1/users/{public_identifier}"
|
|
516
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
517
|
+
response = self._get(url, params=params)
|
|
518
|
+
return self._handle_response(response)
|
|
519
|
+
|
|
520
|
+
async def search_people(
|
|
606
521
|
self,
|
|
607
|
-
category: Literal["people", "companies", "posts", "jobs"],
|
|
608
522
|
cursor: str | None = None,
|
|
609
523
|
limit: int | None = None,
|
|
610
524
|
keywords: str | None = None,
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
525
|
+
location: str | None = None,
|
|
526
|
+
industry: str | None = None,
|
|
527
|
+
company: str | None = None,
|
|
614
528
|
) -> dict[str, Any]:
|
|
615
529
|
"""
|
|
616
|
-
|
|
617
|
-
Supports pagination and targets either the classic or Sales Navigator API for posts.
|
|
618
|
-
For people, companies, and jobs, it uses the classic API.
|
|
530
|
+
Searches for LinkedIn user profiles using keywords, with optional filters for location, industry, and company. This function specifically targets the 'people' category, distinguishing it from other search methods like `search_companies` or `search_jobs` that query different entity types through the same API endpoint.
|
|
619
531
|
|
|
620
532
|
Args:
|
|
621
|
-
category: Type of search to perform. Valid values are "people", "companies", "posts", or "jobs".
|
|
622
533
|
cursor: Pagination cursor for the next page of entries.
|
|
623
534
|
limit: Number of items to return (up to 50 for Classic search).
|
|
624
535
|
keywords: Keywords to search for.
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
536
|
+
location: The geographical location to filter people by (e.g., "United States").
|
|
537
|
+
industry: The industry to filter people by.(eg., "Information Technology and Services").
|
|
538
|
+
company: The company to filter people by.(e.g., "Google").
|
|
628
539
|
|
|
629
540
|
Returns:
|
|
630
541
|
A dictionary containing search results and pagination details.
|
|
631
542
|
|
|
632
543
|
Raises:
|
|
633
544
|
httpx.HTTPError: If the API request fails.
|
|
634
|
-
|
|
545
|
+
"""
|
|
546
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
547
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
548
|
+
if cursor:
|
|
549
|
+
params["cursor"] = cursor
|
|
550
|
+
if limit is not None:
|
|
551
|
+
params["limit"] = limit
|
|
552
|
+
payload: dict[str, Any] = {"api": "classic", "category": "people"}
|
|
553
|
+
if keywords:
|
|
554
|
+
payload["keywords"] = keywords
|
|
555
|
+
if location:
|
|
556
|
+
location_id = self._get_search_parameter_id("LOCATION", location)
|
|
557
|
+
payload["location"] = [location_id]
|
|
558
|
+
if industry:
|
|
559
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
560
|
+
payload["industry"] = [industry_id]
|
|
561
|
+
if company:
|
|
562
|
+
company_id = self._get_search_parameter_id("COMPANY", company)
|
|
563
|
+
payload["company"] = [company_id]
|
|
564
|
+
response = self._post(url, params=params, data=payload)
|
|
565
|
+
return self._handle_response(response)
|
|
635
566
|
|
|
636
|
-
|
|
637
|
-
|
|
567
|
+
async def search_companies(
|
|
568
|
+
self,
|
|
569
|
+
cursor: str | None = None,
|
|
570
|
+
limit: int | None = None,
|
|
571
|
+
keywords: str | None = None,
|
|
572
|
+
location: str | None = None,
|
|
573
|
+
industry: str | None = None,
|
|
574
|
+
) -> dict[str, Any]:
|
|
638
575
|
"""
|
|
639
|
-
|
|
640
|
-
raise ValueError("Category cannot be empty.")
|
|
576
|
+
Performs a paginated search for companies on LinkedIn using keywords, with optional location and industry filters. Its specific 'companies' search category distinguishes it from other methods like `search_people` or `search_posts`, ensuring that only company profiles are returned.
|
|
641
577
|
|
|
642
|
-
|
|
578
|
+
Args:
|
|
579
|
+
cursor: Pagination cursor for the next page of entries.
|
|
580
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
581
|
+
keywords: Keywords to search for.
|
|
582
|
+
location: The geographical location to filter companies by (e.g., "United States").
|
|
583
|
+
industry: The industry to filter companies by.(e.g., "Information Technology and Services").
|
|
643
584
|
|
|
585
|
+
Returns:
|
|
586
|
+
A dictionary containing search results and pagination details.
|
|
587
|
+
|
|
588
|
+
Raises:
|
|
589
|
+
httpx.HTTPError: If the API request fails.
|
|
590
|
+
"""
|
|
591
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
644
592
|
params: dict[str, Any] = {"account_id": self.account_id}
|
|
645
593
|
if cursor:
|
|
646
594
|
params["cursor"] = cursor
|
|
647
595
|
if limit is not None:
|
|
648
596
|
params["limit"] = limit
|
|
597
|
+
payload: dict[str, Any] = {"api": "classic", "category": "companies"}
|
|
598
|
+
if keywords:
|
|
599
|
+
payload["keywords"] = keywords
|
|
600
|
+
if location:
|
|
601
|
+
location_id = self._get_search_parameter_id("LOCATION", location)
|
|
602
|
+
payload["location"] = [location_id]
|
|
603
|
+
if industry:
|
|
604
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
605
|
+
payload["industry"] = [industry_id]
|
|
606
|
+
response = self._post(url, params=params, data=payload)
|
|
607
|
+
return self._handle_response(response)
|
|
608
|
+
|
|
609
|
+
async def search_posts(
|
|
610
|
+
self,
|
|
611
|
+
cursor: str | None = None,
|
|
612
|
+
limit: int | None = None,
|
|
613
|
+
keywords: str | None = None,
|
|
614
|
+
date_posted: Literal["past_day", "past_week", "past_month"] | None = None,
|
|
615
|
+
sort_by: Literal["relevance", "date"] = "relevance",
|
|
616
|
+
) -> dict[str, Any]:
|
|
617
|
+
"""
|
|
618
|
+
Performs a keyword-based search for LinkedIn posts, allowing filters for date and sorting by relevance. This function executes a general, platform-wide content search, distinguishing it from other search functions that target people, companies, or jobs, and from `list_profile_posts` which retrieves from a specific profile.
|
|
619
|
+
|
|
620
|
+
Args:
|
|
621
|
+
cursor: Pagination cursor for the next page of entries.
|
|
622
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
623
|
+
keywords: Keywords to search for.
|
|
624
|
+
date_posted: Filter by when the post was posted.
|
|
625
|
+
sort_by: How to sort the results.
|
|
649
626
|
|
|
650
|
-
|
|
627
|
+
Returns:
|
|
628
|
+
A dictionary containing search results and pagination details.
|
|
651
629
|
|
|
630
|
+
Raises:
|
|
631
|
+
httpx.HTTPError: If the API request fails.
|
|
632
|
+
"""
|
|
633
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
634
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
635
|
+
if cursor:
|
|
636
|
+
params["cursor"] = cursor
|
|
637
|
+
if limit is not None:
|
|
638
|
+
params["limit"] = limit
|
|
639
|
+
payload: dict[str, Any] = {"api": "classic", "category": "posts"}
|
|
652
640
|
if keywords:
|
|
653
641
|
payload["keywords"] = keywords
|
|
642
|
+
if date_posted:
|
|
643
|
+
payload["date_posted"] = date_posted
|
|
644
|
+
if sort_by:
|
|
645
|
+
payload["sort_by"] = sort_by
|
|
646
|
+
response = self._post(url, params=params, data=payload)
|
|
647
|
+
return self._handle_response(response)
|
|
648
|
+
|
|
649
|
+
async def search_jobs(
|
|
650
|
+
self,
|
|
651
|
+
cursor: str | None = None,
|
|
652
|
+
limit: int | None = None,
|
|
653
|
+
keywords: str | None = None,
|
|
654
|
+
region: str | None = None,
|
|
655
|
+
sort_by: Literal["relevance", "date"] = "relevance",
|
|
656
|
+
minimum_salary_value: int = 40,
|
|
657
|
+
industry: str | None = None,
|
|
658
|
+
) -> dict[str, Any]:
|
|
659
|
+
"""
|
|
660
|
+
Performs a LinkedIn search for jobs, filtering results by keywords, region, industry, and minimum salary. Unlike other search functions (`search_people`, `search_companies`), this method is specifically configured to query the 'jobs' category, providing a paginated list of relevant employment opportunities.
|
|
654
661
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
662
|
+
Args:
|
|
663
|
+
cursor: Pagination cursor for the next page of entries.
|
|
664
|
+
limit: Number of items to return (up to 50 for Classic search).
|
|
665
|
+
keywords: Keywords to search for.
|
|
666
|
+
region: The geographical region to filter jobs by (e.g., "United States").
|
|
667
|
+
sort_by: How to sort the results.(e.g., "relevance" or "date".)
|
|
668
|
+
minimum_salary_value: The minimum salary to filter for.
|
|
669
|
+
industry: The industry to filter jobs by.(e.g., "Software Development").
|
|
660
670
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
"currency": "USD",
|
|
664
|
-
"value": minimum_salary_value,
|
|
665
|
-
}
|
|
666
|
-
if sort_by:
|
|
667
|
-
payload["sort_by"] = sort_by
|
|
671
|
+
Returns:
|
|
672
|
+
A dictionary containing search results and pagination details.
|
|
668
673
|
|
|
674
|
+
Raises:
|
|
675
|
+
httpx.HTTPError: If the API request fails.
|
|
676
|
+
ValueError: If the specified location is not found.
|
|
677
|
+
"""
|
|
678
|
+
url = f"{self.base_url}/api/v1/linkedin/search"
|
|
679
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
680
|
+
if cursor:
|
|
681
|
+
params["cursor"] = cursor
|
|
682
|
+
if limit is not None:
|
|
683
|
+
params["limit"] = limit
|
|
684
|
+
payload: dict[str, Any] = {
|
|
685
|
+
"api": "classic",
|
|
686
|
+
"category": "jobs",
|
|
687
|
+
"minimum_salary": {"currency": "USD", "value": minimum_salary_value},
|
|
688
|
+
}
|
|
689
|
+
if keywords:
|
|
690
|
+
payload["keywords"] = keywords
|
|
691
|
+
if sort_by:
|
|
692
|
+
payload["sort_by"] = sort_by
|
|
693
|
+
if region:
|
|
694
|
+
location_id = self._get_search_parameter_id("LOCATION", region)
|
|
695
|
+
payload["region"] = location_id
|
|
696
|
+
if industry:
|
|
697
|
+
industry_id = self._get_search_parameter_id("INDUSTRY", industry)
|
|
698
|
+
payload["industry"] = [industry_id]
|
|
669
699
|
response = self._post(url, params=params, data=payload)
|
|
670
700
|
return self._handle_response(response)
|
|
671
701
|
|
|
672
|
-
def
|
|
702
|
+
async def send_invitation(self, provider_id: str, user_email: str | None = None, message: str | None = None) -> dict[str, Any]:
|
|
673
703
|
"""
|
|
674
|
-
|
|
704
|
+
Sends a connection invitation to a LinkedIn user specified by their provider ID. An optional message and the user's email can be included.
|
|
675
705
|
|
|
676
706
|
Args:
|
|
677
|
-
|
|
707
|
+
provider_id: The LinkedIn provider ID of the user to invite. This is available in response of `retrieve_user_profile` tool.
|
|
708
|
+
user_email: Optional. The email address of the user, which may be required by LinkedIn.
|
|
709
|
+
message: Optional. A personalized message to include with the invitation (max 300 characters).
|
|
678
710
|
|
|
679
711
|
Returns:
|
|
680
|
-
A dictionary
|
|
712
|
+
A dictionary confirming the invitation was sent.
|
|
681
713
|
|
|
682
714
|
Raises:
|
|
683
715
|
httpx.HTTPError: If the API request fails.
|
|
716
|
+
ValueError: If the message exceeds 300 characters.
|
|
684
717
|
|
|
685
718
|
Tags:
|
|
686
|
-
linkedin, user,
|
|
719
|
+
linkedin, user, invite, connect, contact, api, important
|
|
720
|
+
"""
|
|
721
|
+
url = f"{self.base_url}/api/v1/users/invite"
|
|
722
|
+
payload: dict[str, Any] = {"account_id": self.account_id, "provider_id": provider_id}
|
|
723
|
+
if user_email:
|
|
724
|
+
payload["user_email"] = user_email
|
|
725
|
+
if message:
|
|
726
|
+
if len(message) > 300:
|
|
727
|
+
raise ValueError("Message cannot exceed 300 characters.")
|
|
728
|
+
payload["message"] = message
|
|
729
|
+
response = self._post(url, data=payload)
|
|
730
|
+
try:
|
|
731
|
+
return response.json()
|
|
732
|
+
except json.JSONDecodeError:
|
|
733
|
+
return {"status": response.status_code, "message": "Invitation action processed."}
|
|
734
|
+
|
|
735
|
+
async def list_sent_invitations(self, cursor: str | None = None, limit: int | None = None) -> dict[str, Any]:
|
|
736
|
+
"""
|
|
737
|
+
Retrieves a paginated list of all sent connection invitations that are currently pending. This function allows for iterating through the history of outstanding connection requests made from the specified account.
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
cursor: A pagination cursor for retrieving the next page of entries.
|
|
741
|
+
limit: The number of items to return, ranging from 1 to 100. Defaults to 10 if not specified.
|
|
742
|
+
|
|
743
|
+
Returns:
|
|
744
|
+
A dictionary containing a list of sent invitation objects and pagination details.
|
|
745
|
+
|
|
746
|
+
Raises:
|
|
747
|
+
httpx.HTTPError: If the API request fails.
|
|
748
|
+
|
|
749
|
+
Tags:
|
|
750
|
+
linkedin, user, invite, sent, list, contacts, api
|
|
687
751
|
"""
|
|
688
|
-
url = f"{self.base_url}/api/v1/users/
|
|
752
|
+
url = f"{self.base_url}/api/v1/users/invite/sent"
|
|
689
753
|
params: dict[str, Any] = {"account_id": self.account_id}
|
|
754
|
+
if cursor:
|
|
755
|
+
params["cursor"] = cursor
|
|
756
|
+
if limit is not None:
|
|
757
|
+
params["limit"] = limit
|
|
690
758
|
response = self._get(url, params=params)
|
|
691
|
-
return
|
|
759
|
+
return response.json()
|
|
760
|
+
|
|
761
|
+
async def list_received_invitations(self, cursor: str | None = None, limit: int | None = None) -> dict[str, Any]:
|
|
762
|
+
"""
|
|
763
|
+
Retrieves a paginated list of all received connection invitations. This function allows for reviewing and processing incoming connection requests to the specified account.
|
|
764
|
+
|
|
765
|
+
Args:
|
|
766
|
+
cursor: A pagination cursor for retrieving the next page of entries.
|
|
767
|
+
limit: The number of items to return, ranging from 1 to 100. Defaults to 10 if not specified.
|
|
768
|
+
|
|
769
|
+
Returns:
|
|
770
|
+
A dictionary containing a list of received invitation objects and pagination details.
|
|
771
|
+
|
|
772
|
+
Raises:
|
|
773
|
+
httpx.HTTPError: If the API request fails.
|
|
774
|
+
|
|
775
|
+
Tags:
|
|
776
|
+
linkedin, user, invite, received, list, contacts, api
|
|
777
|
+
"""
|
|
778
|
+
url = f"{self.base_url}/api/v1/users/invite/received"
|
|
779
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
780
|
+
if cursor:
|
|
781
|
+
params["cursor"] = cursor
|
|
782
|
+
if limit is not None:
|
|
783
|
+
params["limit"] = limit
|
|
784
|
+
response = self._get(url, params=params)
|
|
785
|
+
return response.json()
|
|
786
|
+
|
|
787
|
+
async def handle_received_invitation(
|
|
788
|
+
self, invitation_id: str, action: Literal["accept", "decline"], shared_secret: str
|
|
789
|
+
) -> dict[str, Any]:
|
|
790
|
+
"""
|
|
791
|
+
Accepts or declines a received LinkedIn connection invitation using its ID and a required shared secret. This function performs a POST request to update the invitation's status, distinguishing it from read-only functions like `list_received_invitations`.
|
|
792
|
+
|
|
793
|
+
Args:
|
|
794
|
+
invitation_id: The ID of the invitation to handle.Get this ID from the 'list_received_invitations' tool.
|
|
795
|
+
action: The action to perform, either "accept" or "decline".
|
|
796
|
+
shared_secret: The token provided by LinkedIn, retrieved from the 'list_received_invitations' tool, which is mandatory for this action.
|
|
797
|
+
|
|
798
|
+
Returns:
|
|
799
|
+
A dictionary confirming the action was processed.
|
|
800
|
+
|
|
801
|
+
Raises:
|
|
802
|
+
httpx.HTTPError: If the API request fails.
|
|
803
|
+
|
|
804
|
+
Tags:
|
|
805
|
+
linkedin, user, invite, received, handle, accept, decline, api
|
|
806
|
+
"""
|
|
807
|
+
url = f"{self.base_url}/api/v1/users/invite/received/{invitation_id}"
|
|
808
|
+
payload: dict[str, Any] = {"provider": "LINKEDIN", "action": action, "shared_secret": shared_secret, "account_id": self.account_id}
|
|
809
|
+
response = self._post(url, data=payload)
|
|
810
|
+
try:
|
|
811
|
+
return response.json()
|
|
812
|
+
except json.JSONDecodeError:
|
|
813
|
+
return {"status": response.status_code, "message": f"Invitation action '{action}' processed."}
|
|
814
|
+
|
|
815
|
+
async def list_followers(self, cursor: str | None = None, limit: int | None = None) -> dict[str, Any]:
|
|
816
|
+
"""
|
|
817
|
+
Retrieves a paginated list of all followers for the current user's account. This function is distinct from `list_following` as it shows who follows the user, not who the user follows.
|
|
818
|
+
|
|
819
|
+
Args:
|
|
820
|
+
cursor: A pagination cursor for retrieving the next page of entries.
|
|
821
|
+
limit: The number of items to return, ranging from 1 to 1000.
|
|
822
|
+
|
|
823
|
+
Returns:
|
|
824
|
+
A dictionary containing a list of follower objects and pagination details.
|
|
825
|
+
|
|
826
|
+
Raises:
|
|
827
|
+
httpx.HTTPError: If the API request fails.
|
|
828
|
+
|
|
829
|
+
Tags:
|
|
830
|
+
linkedin, user, followers, list, contacts, api
|
|
831
|
+
"""
|
|
832
|
+
url = f"{self.base_url}/api/v1/users/followers"
|
|
833
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
834
|
+
if cursor:
|
|
835
|
+
params["cursor"] = cursor
|
|
836
|
+
if limit is not None:
|
|
837
|
+
params["limit"] = limit
|
|
838
|
+
response = self._get(url, params=params)
|
|
839
|
+
return response.json()
|
|
840
|
+
|
|
841
|
+
def list_following(self, cursor: str | None = None, limit: int | None = None) -> dict[str, Any]:
|
|
842
|
+
"""
|
|
843
|
+
Retrieves a paginated list of all accounts that the current user is following. This function is the counterpart to `list_followers`, focusing on the user's outgoing connections rather than incoming ones.
|
|
844
|
+
|
|
845
|
+
Args:
|
|
846
|
+
cursor: A pagination cursor for retrieving the next page of entries.
|
|
847
|
+
limit: The number of items to return, ranging from 1 to 1000.
|
|
848
|
+
|
|
849
|
+
Returns:
|
|
850
|
+
A dictionary containing a list of followed account objects and pagination details.
|
|
851
|
+
|
|
852
|
+
Raises:
|
|
853
|
+
httpx.HTTPError: If the API request fails.
|
|
854
|
+
|
|
855
|
+
Tags:
|
|
856
|
+
linkedin, user, following, list, contacts, api
|
|
857
|
+
"""
|
|
858
|
+
url = f"{self.base_url}/api/v1/users/following"
|
|
859
|
+
params: dict[str, Any] = {"account_id": self.account_id}
|
|
860
|
+
if cursor:
|
|
861
|
+
params["cursor"] = cursor
|
|
862
|
+
if limit is not None:
|
|
863
|
+
params["limit"] = limit
|
|
864
|
+
response = self._get(url, params=params)
|
|
865
|
+
return response.json()
|
|
692
866
|
|
|
693
867
|
def list_tools(self) -> list[Callable]:
|
|
694
868
|
return [
|
|
@@ -697,8 +871,6 @@ class LinkedinApp(APIApplication):
|
|
|
697
871
|
self.send_chat_message,
|
|
698
872
|
self.retrieve_chat,
|
|
699
873
|
self.list_all_messages,
|
|
700
|
-
self.list_all_accounts,
|
|
701
|
-
# self.retrieve_linked_account,
|
|
702
874
|
self.list_profile_posts,
|
|
703
875
|
self.retrieve_own_profile,
|
|
704
876
|
self.retrieve_user_profile,
|
|
@@ -708,5 +880,13 @@ class LinkedinApp(APIApplication):
|
|
|
708
880
|
self.list_content_reactions,
|
|
709
881
|
self.create_post_comment,
|
|
710
882
|
self.create_reaction,
|
|
711
|
-
self.
|
|
883
|
+
self.search_companies,
|
|
884
|
+
self.search_jobs,
|
|
885
|
+
self.search_people,
|
|
886
|
+
self.search_posts,
|
|
887
|
+
self.send_invitation,
|
|
888
|
+
self.list_sent_invitations,
|
|
889
|
+
self.list_received_invitations,
|
|
890
|
+
self.handle_received_invitation,
|
|
891
|
+
self.list_followers,
|
|
712
892
|
]
|