Publishes text/link posts to a user's LinkedIn personal feed via the LinkedIn Posts API. Useful when the user wants to share updates or cross-post articles to LinkedIn.
How this skill is triggered — by the user, by Claude, or both
Slash command
/acedatacloud-ai-media:linkedinWhen to use
Trigger when the user wants to publish a text or link share to their own LinkedIn feed. Posting is public on their profile — confirm the text (and link, if any) before publishing. Requires the w_member_social scope (granted by the connector at install).
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Call the **LinkedIn API** with `curl + jq`. The user's bearer token is in
Call the LinkedIn API with curl + jq. The user's bearer token is in
$LINKEDIN_TOKEN; every call needs Authorization: Bearer $LINKEDIN_TOKEN.
LinkedIn posts must be authored by the member's URN. Get the member id from the
OpenID userinfo endpoint, then build urn:li:person:{sub}.
SUB=$(curl -sS -H "Authorization: Bearer $LINKEDIN_TOKEN" \
"https://api.linkedin.com/v2/userinfo" | jq -r .sub)
AUTHOR="urn:li:person:$SUB"
echo "$AUTHOR"
Errors are JSON with message / serviceErrorCode — show them verbatim.
401 → token expired (tokens last ~60 days), re-connect the LinkedIn connector.
Confirm the text with the user first. Use the versioned Posts API; set the
LinkedIn-Version header to a recent YYYYMM (LinkedIn requires a valid recent
version — if you get 426/version errors, bump to the current month).
jq -n --arg a "$AUTHOR" --arg t "My update text. Check out https://studio.acedata.cloud" \
'{author:$a, commentary:$t, visibility:"PUBLIC",
distribution:{feedDistribution:"MAIN_FEED", targetEntities:[], thirdPartyDistributionChannels:[]},
lifecycleState:"PUBLISHED", isReshareDisabledByAuthor:false}' \
| curl -sS -X POST "https://api.linkedin.com/rest/posts" \
-H "Authorization: Bearer $LINKEDIN_TOKEN" \
-H "Content-Type: application/json" \
-H "LinkedIn-Version: 202401" \
-H "X-Restli-Protocol-Version: 2.0.0" \
-d @- -D - -o /dev/null | tr -d '\r' | awk '/^[Xx]-[Rr]estli-[Ii]d:|^[Ll]ocation:/{print}'
A successful create returns 201 with the post URN in the x-restli-id
(or Location) response header — report that URN / the resulting post URL.
Link posts: put the URL inline in
commentary(LinkedIn auto-unfurls it). Rich article attachments need the assets/images API — out of scope for a simple text/link share; keep links inline.
If the versioned endpoint is unavailable for the app, the older
POST https://api.linkedin.com/v2/ugcPosts with a
specificContent."com.linkedin.ugc.ShareContent" body also works with
w_member_social. Prefer /rest/posts above.
urn:li:person:{sub}) — you
can't post as someone else.w_member_social only allows posting to the member's own feed; company
Page posts need w_organization_social + an admin role (not in this connector).LinkedIn-Version header is mandatory for /rest/*; a stale value
returns a version error — bump to the current YYYYMM.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub acedatacloud/skills --plugin acedatacloud-ai-tools