@kody/linkedin
Identity, generic requests, and guarded posting through the saved LinkedIn OAuth integration.
AGENTS.md
117 lines · 4.0 KB · Markdown@kody/linkedin — agent notes
Human setup and intent live in README.md. This file is for
agents: imports, smoke/dryRun execute snippets, and edge cases. Auth is the
saved OAuth integration named linkedin — never paste tokens. Do not
disable live webhooks or jobs. No /account/secrets/new token path for this
package.
Auth
- Integration id:
linkedin(createAuthenticatedFetch('linkedin')) - API origin:
https://api.linkedin.com - Scopes expected:
openid,profile,email,w_member_social - Author URN comes from
/v2/userinfo(urn:li:person:{sub}) unless overridden
Import paths
| Export | Import |
|---|---|
| overview / safety metadata | kody:@kody/linkedin |
| smoke-test | kody:@kody/linkedin/smoke-test |
| get-user-info | kody:@kody/linkedin/get-user-info |
| get-person-urn | kody:@kody/linkedin/get-person-urn |
| request | kody:@kody/linkedin/request |
| create-post | kody:@kody/linkedin/create-post |
| create-text-post | kody:@kody/linkedin/create-text-post |
| create-article-post | kody:@kody/linkedin/create-article-post |
| create-image-post | kody:@kody/linkedin/create-image-post |
| create-video-post | kody:@kody/linkedin/create-video-post |
| delete-post | kody:@kody/linkedin/delete-post |
| register-image-upload | kody:@kody/linkedin/register-image-upload |
| register-video-upload | kody:@kody/linkedin/register-video-upload |
| upload-video-part | kody:@kody/linkedin/upload-video-part |
| finalize-video-upload | kody:@kody/linkedin/finalize-video-upload |
Prefer static kody:@kody/linkedin/... imports from execute. Do not lead with
packages.invoke. For smoke against a forked package runtime that must bind
the caller's OAuth grant, a dynamic invoke of bare kody id linkedin is
acceptable — prefer the fork's published export once connected.
Smoke test (read-only)
import smokeTest from 'kody:@kody/linkedin/smoke-test'
export default async function main() {
return await smokeTest()
// => { ok: true, integration: 'linkedin', hasSubject: true, personUrnPresent: true }
}Identity helpers:
import getPersonUrn from 'kody:@kody/linkedin/get-person-urn'
export default async function main() {
return await getPersonUrn()
}import request from 'kody:@kody/linkedin/request'
export default async function main() {
return await request({ path: '/v2/userinfo', dryRun: true })
}dryRun / confirm (writes)
Posting and upload helpers never mutate LinkedIn when dryRun: true. A live
write requires a fresh confirm: true after the user approved the exact payload.
import createTextPost from 'kody:@kody/linkedin/create-text-post'
export default async function main() {
return await createTextPost({ text: 'Draft text', dryRun: true })
}import createArticlePost from 'kody:@kody/linkedin/create-article-post'
export default async function main() {
return await createArticlePost({
text: 'Read this',
url: 'https://example.com',
title: 'Example article',
description: 'A useful article.',
thumbnailUrl: 'https://example.com/thumbnail.jpg',
dryRun: true,
})
}LinkedIn does not scrape Open Graph metadata for API-created article posts.
Pass title, description, and either an existing LinkedIn image thumbnail
URN or an HTTPS thumbnailUrl.
Native video: register-video-upload → upload-video-part (each part) →
finalize-video-upload → create-video-post.
Edge cases / fork notes
- Fork first; connect the caller's LinkedIn app. Do not treat the live
@kody/linkedinintegration as theirs. - No refresh token without LinkedIn partner access — on 401, reconnect at
/connect/oauth?provider=linkedin. - HTTP 403 on posting: Share on LinkedIn product +
w_member_social, then reconnect. redirect_urimust be exactlyhttps://kody.codes/connect/oauth.- Do not hard-code a member URN. Do not use this as an org-page poster.
- Never treat smoke success as permission to post.
- Keep
LICENSE(MIT),## Intent, andcommunity-icon.svgfor community listing.