How to Post on LinkedIn Using the API: Complete 2026 Guide
A practical LinkedIn posting API guide covering OAuth, required permissions, profile versus company posts, media, scheduling, rate limits, and working examples.
The LinkedIn posting API is powerful, but most teams discover quickly that it is not a single copy-paste endpoint. You need the right product access, OAuth scopes, author URNs, media upload flow, version headers, and retry behavior before the first post goes live.
This guide shows the implementation shape for publishing LinkedIn posts from a SaaS product in 2026. SocialCast handles this flow behind one normalized publishing API, but the native workflow is useful to understand when debugging permissions or migration work.
What you need before posting
- A LinkedIn developer app with access to the appropriate LinkedIn Marketing or sharing APIs.
- OAuth 2.0 authorization for the LinkedIn member or organization admin.
- The author URN for a personal profile or organization page.
- Write scopes such as member posting for personal posts and organization posting for company pages.
- A media upload step when publishing images or video.
Personal posts versus company page posts
| Use case | Author | Typical permission | Notes |
|---|---|---|---|
| Personal profile post | urn:li:person:{id} | Member social write access | Best for user-authored content where the user is the visible author. |
| Company page post | urn:li:organization:{id} | Organization social write access | Requires the authorizing user to have the right page role. |
| Sponsored or campaign content | Ad account or campaign objects | Marketing API access | A different path from simple organic publishing. |
OAuth and permissions
Start with a standard OAuth authorization URL. Request only the scopes you need. In production, store refreshable credentials encrypted, keep the LinkedIn account connection tied to your internal workspace, and record which organization pages the user can publish to.
https://www.linkedin.com/oauth/v2/authorization
?response_type=code
&client_id=LINKEDIN_CLIENT_ID
&redirect_uri=https://yourapp.com/oauth/linkedin/callback
&scope=openid%20profile%20w_member_social%20w_organization_socialCreate a text post
For a basic post, send the author URN, lifecycle state, commentary, visibility, and distribution settings. Keep API version headers explicit so a future LinkedIn version change does not silently alter behavior.
async function createLinkedInTextPost({ accessToken, authorUrn, text }) {
const res = await fetch("https://api.linkedin.com/rest/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
"LinkedIn-Version": "202506",
"X-Restli-Protocol-Version": "2.0.0"
},
body: JSON.stringify({
author: authorUrn,
commentary: text,
visibility: "PUBLIC",
distribution: {
feedDistribution: "MAIN_FEED",
targetEntities: [],
thirdPartyDistributionChannels: []
},
lifecycleState: "PUBLISHED"
})
});
if (!res.ok) throw new Error(await res.text());
return res.headers.get("x-restli-id") || res.json();
}Images and video
- Initialize an upload for the LinkedIn owner.
- Upload the binary file to the upload URL returned by LinkedIn.
- Create the post referencing the uploaded media asset.
- Poll or listen for processing state when video is involved.
async function createLinkedInImagePost({ accessToken, authorUrn, imageAssetUrn, text }) {
const res = await fetch("https://api.linkedin.com/rest/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
"LinkedIn-Version": "202506",
"X-Restli-Protocol-Version": "2.0.0"
},
body: JSON.stringify({
author: authorUrn,
commentary: text,
visibility: "PUBLIC",
distribution: { feedDistribution: "MAIN_FEED" },
content: {
media: {
title: "Post image",
id: imageAssetUrn
}
},
lifecycleState: "PUBLISHED"
})
});
if (!res.ok) throw new Error(await res.text());
return res.headers.get("x-restli-id");
}Scheduling LinkedIn posts
LinkedIn publishing APIs are usually treated as immediate-publish endpoints. If your app offers scheduling, store a scheduled job in your own system, validate the token before publish time, and execute the API call when the post is due.
await socialcast.posts.create({
platforms: ["linkedin"],
text: "New launch notes are live.",
account_ids: ["ln_org_123"],
publish_at: "2026-08-04T15:00:00Z"
});Rate limits and retries
- Treat 429 responses as retryable and back off using the response headers when present.
- Do not retry duplicate publish requests blindly. Use idempotency keys in your own queue.
- Separate media upload retries from final publish retries.
- Log LinkedIn response bodies because permission and version errors are usually explicit.
How SocialCast simplifies this
SocialCast stores connected LinkedIn accounts, normalizes profile and organization posting, schedules jobs, retries transient failures, and returns a single post status object. Your app sends one request; SocialCast handles LinkedIn-specific author URNs, media upload, and publish state tracking.