Skip to content

Commit e42756a

Browse files
Release
0 parents  commit e42756a

82 files changed

Lines changed: 4438 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/publish.yaml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: PR Merged -> main
2+
3+
on:
4+
push:
5+
branches: ['main']
6+
7+
jobs:
8+
quality:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v4
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v5
17+
with:
18+
python-version: '3.12'
19+
20+
- name: Install dependencies
21+
run: pip install -e '.[dev]'
22+
23+
- name: Lint
24+
run: ruff check .
25+
26+
- name: Type check
27+
run: mypy linkedapi
28+
29+
- name: Test
30+
run: pytest -q
31+
32+
publish:
33+
needs: [quality]
34+
runs-on: ubuntu-latest
35+
environment: pypi
36+
permissions:
37+
id-token: write
38+
39+
steps:
40+
- name: Checkout code
41+
uses: actions/checkout@v4
42+
43+
- name: Set up Python
44+
uses: actions/setup-python@v5
45+
with:
46+
python-version: '3.12'
47+
48+
- name: Check if version changed
49+
id: version-check
50+
run: |
51+
PACKAGE_NAME=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['name'])")
52+
PACKAGE_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
53+
PYPI_VERSION=$(curl -fsSL "https://pypi.org/pypi/${PACKAGE_NAME}/json" | python -c "import json,sys; print(json.load(sys.stdin)['info']['version'])" 2>/dev/null || echo "none")
54+
if [ "$PACKAGE_VERSION" != "$PYPI_VERSION" ]; then
55+
echo "should_publish=true" >> "$GITHUB_OUTPUT"
56+
echo "Version changed: $PYPI_VERSION -> $PACKAGE_VERSION"
57+
else
58+
echo "should_publish=false" >> "$GITHUB_OUTPUT"
59+
echo "Version unchanged: $PACKAGE_VERSION"
60+
fi
61+
62+
- name: Build distributions
63+
if: steps.version-check.outputs.should_publish == 'true'
64+
run: |
65+
pip install build
66+
python -m build
67+
68+
- name: Publish to PyPI
69+
if: steps.version-check.outputs.should_publish == 'true'
70+
uses: pypa/gh-action-pypi-publish@release/v1

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
__pycache__/
2+
*.py[cod]
3+
dist/
4+
*.egg-info/
5+
.mypy_cache/
6+
.ruff_cache/
7+
.pytest_cache/
8+
.venv/
9+
build/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Linked API <https://linkedapi.io>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
This official Python SDK is the synchronous way to integrate with Linked API. It provides pre-defined workflow operations, direct account/statistics methods, admin APIs, authentication headers, polling, and structured error responses.
2+
3+
## Get started
4+
5+
To get started with Linked API Python SDK, read these essential guides first:
6+
7+
1. [Core concepts](https://linkedapi.io/sdks/core-concepts-0/) - understand how Linked API works.
8+
2. [Installation & authorization](https://linkedapi.io/sdks/installation-authorization/) - install the SDK and authorize it.
9+
3. [Predefined vs. custom workflows](https://linkedapi.io/sdks/predefined-vs-custom-workflows/) - choose ready-made operations or custom workflow definitions.
10+
4. [Handling results and errors](https://linkedapi.io/sdks/handling-results-and-errors/) - process successful data and action errors.
11+
5. [Persisting and cancelling workflows](https://linkedapi.io/sdks/persisting-and-cancelling-workflows/) - save, resume, and cancel workflows.
12+
13+
Install the package:
14+
15+
```bash
16+
pip install linkedapi
17+
```
18+
19+
Initialize the client:
20+
21+
```python
22+
from linkedapi import LinkedApi, LinkedApiConfig
23+
24+
linkedapi = LinkedApi(
25+
LinkedApiConfig(
26+
linked_api_token="your-linked-api-token",
27+
identification_token="your-identification-token",
28+
)
29+
)
30+
```
31+
32+
Run a predefined workflow and poll the result:
33+
34+
```python
35+
from linkedapi import FetchPersonParams
36+
37+
workflow = linkedapi.fetch_person.execute(
38+
FetchPersonParams(
39+
person_url="https://www.linkedin.com/in/john-doe",
40+
retrieve_experience=True,
41+
retrieve_posts=True,
42+
posts_retrieval_config={"limit": 10},
43+
)
44+
)
45+
46+
result = linkedapi.fetch_person.result(workflow.workflow_id)
47+
if result.data:
48+
print(result.data.name)
49+
for error in result.errors:
50+
print(error.type, error.message)
51+
```
52+
53+
Execute a custom workflow:
54+
55+
```python
56+
workflow = linkedapi.custom_workflow.execute(
57+
{
58+
"actionType": "st.searchCompanies",
59+
"term": "Tech Inc",
60+
"filter": {
61+
"sizes": ["51-200", "2001-5000"],
62+
"locations": ["San Francisco", "New York"],
63+
"industries": ["Software Development"],
64+
},
65+
"then": {"actionType": "st.openCompanyPage", "basicInfo": True},
66+
}
67+
)
68+
69+
result = linkedapi.custom_workflow.result(workflow.workflow_id)
70+
print(result.data)
71+
```
72+
73+
Continue polling after a workflow timeout:
74+
75+
```python
76+
from linkedapi import LinkedApiWorkflowTimeoutError
77+
78+
try:
79+
result = linkedapi.fetch_person.result(workflow.workflow_id, timeout=30.0)
80+
except LinkedApiWorkflowTimeoutError as error:
81+
result = linkedapi.fetch_person.result(error.workflow_id)
82+
```
83+
84+
Cancel a workflow:
85+
86+
```python
87+
cancelled = linkedapi.fetch_person.cancel(workflow.workflow_id)
88+
print(cancelled)
89+
```
90+
91+
## License
92+
93+
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.

linkedapi/__init__.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
from linkedapi.admin import (
2+
AdminAccounts,
3+
AdminHttpClient,
4+
AdminLimits,
5+
AdminSubscription,
6+
LinkedApiAdmin,
7+
)
8+
from linkedapi.client import LinkedApi
9+
from linkedapi.config import LinkedApiConfig
10+
from linkedapi.core import Operation, poll_workflow_result
11+
from linkedapi.errors import (
12+
LINKED_API_ACTION_ERROR_TYPES,
13+
LINKED_API_ERROR_TYPES,
14+
LinkedApiActionErrorType,
15+
LinkedApiError,
16+
LinkedApiErrorType,
17+
LinkedApiWorkflowTimeoutError,
18+
)
19+
from linkedapi.http import HttpClient, LinkedApiHttpClient
20+
from linkedapi.mappers import (
21+
ActionConfig,
22+
ArrayWorkflowMapper,
23+
BaseMapper,
24+
MappedResponse,
25+
ResponseMapping,
26+
SimpleWorkflowMapper,
27+
ThenWorkflowMapper,
28+
VoidWorkflowMapper,
29+
)
30+
from linkedapi.operations import (
31+
CheckConnectionStatus,
32+
CommentOnPost,
33+
CreatePost,
34+
CustomWorkflow,
35+
FetchCompany,
36+
FetchCompanyMapper,
37+
FetchPerson,
38+
FetchPersonMapper,
39+
FetchPost,
40+
FetchPostMapper,
41+
NvFetchCompany,
42+
NvFetchCompanyMapper,
43+
NvFetchPerson,
44+
NvFetchPersonMapper,
45+
NvSearchCompanies,
46+
NvSearchPeople,
47+
NvSendMessage,
48+
NvSyncConversation,
49+
ReactToPost,
50+
RemoveConnection,
51+
RetrieveConnections,
52+
RetrievePendingRequests,
53+
RetrievePerformance,
54+
RetrieveSSI,
55+
SearchCompanies,
56+
SearchPeople,
57+
SendConnectionRequest,
58+
SendMessage,
59+
SyncConversation,
60+
WithdrawConnectionRequest,
61+
)
62+
from linkedapi.types import * # noqa: F403
63+
from linkedapi.types import __all__ as _types_all
64+
65+
__version__ = "1.0.0"
66+
PredefinedOperation = Operation
67+
68+
__all__ = [
69+
*_types_all,
70+
"AdminAccounts",
71+
"AdminHttpClient",
72+
"AdminLimits",
73+
"AdminSubscription",
74+
"ActionConfig",
75+
"ArrayWorkflowMapper",
76+
"BaseMapper",
77+
"CheckConnectionStatus",
78+
"CommentOnPost",
79+
"CreatePost",
80+
"CustomWorkflow",
81+
"FetchCompany",
82+
"FetchCompanyMapper",
83+
"FetchPerson",
84+
"FetchPersonMapper",
85+
"FetchPost",
86+
"FetchPostMapper",
87+
"HttpClient",
88+
"LINKED_API_ACTION_ERROR_TYPES",
89+
"LINKED_API_ERROR_TYPES",
90+
"LinkedApi",
91+
"LinkedApiActionErrorType",
92+
"LinkedApiAdmin",
93+
"LinkedApiConfig",
94+
"LinkedApiError",
95+
"LinkedApiErrorType",
96+
"LinkedApiHttpClient",
97+
"LinkedApiWorkflowTimeoutError",
98+
"MappedResponse",
99+
"NvFetchCompany",
100+
"NvFetchCompanyMapper",
101+
"NvFetchPerson",
102+
"NvFetchPersonMapper",
103+
"NvSearchCompanies",
104+
"NvSearchPeople",
105+
"NvSendMessage",
106+
"NvSyncConversation",
107+
"Operation",
108+
"PredefinedOperation",
109+
"ReactToPost",
110+
"RemoveConnection",
111+
"ResponseMapping",
112+
"RetrieveConnections",
113+
"RetrievePendingRequests",
114+
"RetrievePerformance",
115+
"RetrieveSSI",
116+
"SearchCompanies",
117+
"SearchPeople",
118+
"SendConnectionRequest",
119+
"SendMessage",
120+
"SimpleWorkflowMapper",
121+
"SyncConversation",
122+
"ThenWorkflowMapper",
123+
"VoidWorkflowMapper",
124+
"WithdrawConnectionRequest",
125+
"__version__",
126+
"poll_workflow_result",
127+
]

linkedapi/admin/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from linkedapi.admin.accounts import AdminAccounts
2+
from linkedapi.admin.admin import LinkedApiAdmin
3+
from linkedapi.admin.http_client import AdminHttpClient
4+
from linkedapi.admin.limits import AdminLimits
5+
from linkedapi.admin.subscription import AdminSubscription
6+
7+
__all__ = [
8+
"AdminAccounts",
9+
"AdminHttpClient",
10+
"AdminLimits",
11+
"AdminSubscription",
12+
"LinkedApiAdmin",
13+
]

0 commit comments

Comments
 (0)