Minimal CLI for publishing LinkedIn text posts with the Posts API
Project description
lkdn
Small CLI for supported LinkedIn API workflows.
Scope
This project is intentionally narrow:
- publish a text post as a member or organization
- publish an image post as a member or organization
- publish a video post as a member or organization
- read employment data from official LinkedIn profile APIs when your app tier and scopes allow it
- use the current LinkedIn
Posts API - stay easy to read and easy to fork
It does not try to automate OAuth in a fragile way. You bring your own access token and author URN. It does not scrape LinkedIn pages or rely on undocumented web endpoints.
Install
uv sync
PyPI distribution: lkdn
Command aliases:
liclilkdnlinkedin
Usage
Set the required environment variables:
export LINKEDIN_ACCESS_TOKEN="..."
export LINKEDIN_AUTHOR_URN="urn:li:person:YOUR_ID"
export LINKEDIN_API_VERSION="YYYYMM"
Then publish a post:
uv run licli post "Hello from the new Posts API"
Publish a post with an image:
uv run licli post \
--image /absolute/path/to/banner.png \
--alt-text "Bitdevs BSB event banner" \
"Hello from the new Posts API"
Publish a post with a video:
uv run licli post \
--video /absolute/path/to/clip.mp4 \
--video-title "Linus on abstraction" \
"Hello from the new Posts API"
You can also pass values as flags:
uv run licli post \
--access-token "..." \
--author "urn:li:person:YOUR_ID" \
--api-version "YYYYMM" \
"Shipping a tiny CLI."
Read employment data through official profile APIs:
uv run licli profile employment-history
Use the Verified on LinkedIn identityMe endpoint instead:
uv run licli profile employment-history --source identity-me
Limit output to a different lookback window:
uv run licli profile employment-history --years 3
Docs
- docs/onboarding.md for the full step-by-step setup flow
- docs/credentials.md for the local env file layout and variable reference
- docs/pypi-publishing.md for the GitHub-to-PyPI release flow
LinkedIn requirements
According to the official LinkedIn docs, posting on behalf of a member requires:
- OAuth 2.0 member authentication
- the
w_member_socialscope - a valid
Linkedin-Versionheader inYYYYMMformat
For image posts, this project uses LinkedIn's Images API to initialize an upload, uploads the binary to the returned uploadUrl, and then creates the post with the returned urn:li:image:....
For video posts, this project uses LinkedIn's Videos API to initialize the upload, uploads each instructed part, finalizes the upload, waits for the asset to become AVAILABLE, and then creates the post with the returned urn:li:video:....
For employment data, the official API surface is constrained:
GET /rest/identityMecan return only the member's current position, and only on the Plus tier with ther_primary_current_experiencescope.positionson the Profile API are part of the olderr_fullprofilepermission set, and LinkedIn documents that access tor_fullprofileis closed.- This means
profile employment-historyis only useful if your app already has the required restricted profile access; otherwise LinkedIn will return limited data or a permission error.
Official docs:
- Getting access to LinkedIn APIs
- Sign In with LinkedIn
- Posts API
- Videos API
- Profile API
- Full Profile Fields
- Profile Details API (
/identityMe) - URNs and IDs
Development
Run tests:
uv run pytest
Run lint:
uv run ruff check
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lkdn-0.1.1.tar.gz.
File metadata
- Download URL: lkdn-0.1.1.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfbac6a6c789f96212514ad1c88190db7c6913c0419e1933cc7a9dd43571eaa5
|
|
| MD5 |
3d04cbae8d6a5809e83aec220ac584bf
|
|
| BLAKE2b-256 |
136c618169f0bc349bbd6194b1d6c343e3c68c95880ed2de27dea15eaa0607a2
|
Provenance
The following attestation bundles were made for lkdn-0.1.1.tar.gz:
Publisher:
release.yml on brenorb/linkedin-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lkdn-0.1.1.tar.gz -
Subject digest:
cfbac6a6c789f96212514ad1c88190db7c6913c0419e1933cc7a9dd43571eaa5 - Sigstore transparency entry: 2023664457
- Sigstore integration time:
-
Permalink:
brenorb/linkedin-cli@b11bff7879c96e04dc9c353684e0b91fcac06647 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brenorb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b11bff7879c96e04dc9c353684e0b91fcac06647 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lkdn-0.1.1-py3-none-any.whl.
File metadata
- Download URL: lkdn-0.1.1-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e810cdee42a331e8bfb5b80e830b78429aef9203570caa78e2b1bf881320224
|
|
| MD5 |
7e180cef1fa6f87b30b6606b1d0cfd1f
|
|
| BLAKE2b-256 |
38d2bdc7c2b1a72e7e643a79e35446d02c2e1ed64384a03f260b265ce15ff86d
|
Provenance
The following attestation bundles were made for lkdn-0.1.1-py3-none-any.whl:
Publisher:
release.yml on brenorb/linkedin-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lkdn-0.1.1-py3-none-any.whl -
Subject digest:
8e810cdee42a331e8bfb5b80e830b78429aef9203570caa78e2b1bf881320224 - Sigstore transparency entry: 2023664528
- Sigstore integration time:
-
Permalink:
brenorb/linkedin-cli@b11bff7879c96e04dc9c353684e0b91fcac06647 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brenorb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b11bff7879c96e04dc9c353684e0b91fcac06647 -
Trigger Event:
push
-
Statement type: