How to Post to LinkedIn via API: Direct LinkedIn API vs PostZen
Post to LinkedIn via API with the native LinkedIn Posts API or use PostZen to handle OAuth, media, scheduling, account IDs, and post status through one REST API.
Post to LinkedIn via API in 2026
Posting to LinkedIn via API means your server creates a LinkedIn post without a person opening LinkedIn and pasting the copy by hand. The post can come from a CMS, an AI content workflow, a product onboarding flow, a content calendar, or a customer-facing publishing feature.
You have two practical paths.
Use LinkedIn’s native APIs when your team needs full control over the LinkedIn integration and has time to own app review, OAuth, media uploads, version headers, token storage, retries, and platform-specific errors.
Use PostZen when LinkedIn posting is part of a broader product workflow. PostZen gives server-side integrations one public API for profiles, connected social accounts, OAuth connection flows, media uploads, and post creation. The production API host is https://api.postzen.dev, and the public posts endpoint can create a draft, schedule a post, or publish now.
If you are evaluating the hosted integration path, start with PostZen’s LinkedIn API integration page, then compare plan fit on pricing before you wire production accounts.
Direct LinkedIn API requirements
LinkedIn’s current Posts API uses POST https://api.linkedin.com/rest/posts for organic post creation. LinkedIn also documents older UGC share flows, but its Posts API documentation now states that the Posts API replaces ugcPosts and requires versioned request headers.
For a basic personal-profile post, you need a LinkedIn developer app and the w_member_social permission. LinkedIn describes that scope as the permission to post, comment, and like posts on behalf of an authenticated member.
For organization posts, LinkedIn uses w_organization_social. The authenticated member must have a valid role on the organization page, such as administrator, direct sponsored content poster, or content admin.
Versioned Posts API requests need these pieces:
Authorization: Bearer LINKEDIN_ACCESS_TOKEN
Linkedin-Version: YYYYMM
X-Restli-Protocol-Version: 2.0.0
Content-Type: application/json
LinkedIn’s post body needs an author URN, commentary, visibility, distribution, lifecycle state, and reshare setting. This is a text-only organization post:
{
"author": "urn:li:organization:5515715",
"commentary": "We shipped a new product update.",
"visibility": "PUBLIC",
"distribution": {
"feedDistribution": "MAIN_FEED",
"targetEntities": [],
"thirdPartyDistributionChannels": []
},
"lifecycleState": "PUBLISHED",
"isReshareDisabledByAuthor": false
}
The successful response is 201 Created. LinkedIn returns the post ID in the x-restli-id response header, so your code has to read headers as well as status codes.
Direct LinkedIn API posting flow
The native LinkedIn flow is manageable for a prototype. It gets expensive when you need production behavior across many customer accounts.
First, create and configure a LinkedIn app. The app needs the right product access, redirect URI, client ID, and client secret. Store the secret server-side. Do not ship it to the browser.
Second, run OAuth. Your app sends the user to LinkedIn’s authorization screen, receives an authorization code on your callback URL, and exchanges that code server-side for access tokens. You need a state value for CSRF protection and a durable place to store tokens per connected account.
Third, find the author. Personal posts use a person URN. Organization posts use an organization URN. If the user expects to post to a company page, your product also needs to confirm that the connected user has the right page role.
Fourth, publish through POST /rest/posts. You need the current LinkedIn version header, the Rest.li protocol header, and the correct content schema for text, image, video, document, article, poll, or multi-image content.
Fifth, handle operations. A production integration needs token refresh, retry rules, rate-limit behavior, clear customer-facing errors, and a support view that can explain why a post failed.

Media posts need extra handling
Text posts are the shortest path through LinkedIn. Media posts add more moving parts.
LinkedIn’s Images API asks you to initialize an upload, upload the binary to the returned upload URL, and reference the returned urn:li:image:{id} in the post body. LinkedIn documents JPG, GIF, and PNG support for images, plus a pixel-count ceiling. The image owner also has to match the member or organization context.
The same pattern applies to other media types. You do not send a finished image post in one request. You upload or register the media first, then publish the post with the media URN.
That separation is reasonable for LinkedIn. Your product still has to turn it into a reliable user workflow:
- Validate file type, size, and ownership before the publish attempt.
- Keep the upload state separate from the final post state.
- Save enough IDs to debug a failed post later.
- Tell the user whether they can fix the issue or need to reconnect the account.
Post to LinkedIn with PostZen
PostZen is built for teams that want LinkedIn posting as part of a product workflow rather than a one-off script.
The public API covers five pieces that matter for LinkedIn automation:
- Profiles for grouping social accounts.
- Connected account listing and disconnects.
- OAuth connection flows for social providers.
- Presigned media upload URLs for PostZen-hosted media.
- Post creation for drafts, scheduled posts, and immediate publishing.
LinkedIn is one of the supported public platform inputs in the PostZen OpenAPI spec, alongside Instagram, TikTok, Facebook, YouTube, Threads, X, and the twitter alias. PostZen also accepts platform-specific settings for LinkedIn visibility with PUBLIC and CONNECTIONS.
PostZen still respects the platform boundary. LinkedIn decides what it will accept. PostZen gives your application a smaller surface area: connect an account, list the account ID, upload media when needed, then create the post through one public endpoint.
Teams comparing vendors can also use the social media API comparison pages to check how PostZen positions against broader scheduling and publishing tools.
PostZen API example: publish a LinkedIn post
Start by sending your user through PostZen’s LinkedIn connect flow. The connect endpoint returns an authorization URL tied to a PostZen profile:
curl "https://api.postzen.dev/v1/connect/linkedin?profileId=profile-id" \
-H "Authorization: Bearer $POSTZEN_API_KEY"
After the user connects LinkedIn, list connected LinkedIn accounts and save the account _id you want to post through:
curl "https://api.postzen.dev/v1/accounts?platform=linkedin&status=connected" \
-H "Authorization: Bearer $POSTZEN_API_KEY"
Publish the post with POST /v1/posts. PostZen requires one creation mode per request: publishNow, scheduledFor, or isDraft.
curl -X POST "https://api.postzen.dev/v1/posts" \
-H "Authorization: Bearer $POSTZEN_API_KEY" \
-H "Content-Type: application/json" \
-H "x-request-id: linkedin-launch-2026-07-01" \
-d '{
"title": "Launch announcement",
"content": "We shipped the new release. Here is what changed and who it helps.",
"publishNow": true,
"platforms": [
{
"platform": "linkedin",
"accountId": "account-id",
"settings": {
"visibility": "PUBLIC"
}
}
]
}'
PostZen returns the created post object and per-platform results. Post platform statuses include scheduled, pending, publishing, published, and failed, so your UI can show the state without inventing its own status vocabulary.
The x-request-id header is optional, but useful. Repeating the same value returns the original post instead of creating a duplicate.
Schedule LinkedIn posts and upload media
Scheduling uses the same endpoint. Replace publishNow with scheduledFor and include a timezone:
{
"title": "Next week launch post",
"content": "Our LinkedIn launch post is ready for review.",
"scheduledFor": "2026-07-08T16:00:00Z",
"timezone": "America/New_York",
"platforms": [
{
"platform": "linkedin",
"accountId": "account-id",
"settings": {
"visibility": "PUBLIC"
}
}
]
}
For media, create a presigned upload URL first:
curl -X POST "https://api.postzen.dev/v1/media/presign" \
-H "Authorization: Bearer $POSTZEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "launch-image.png",
"contentType": "image/png",
"size": 1048576
}'
Upload the file to the returned uploadUrl, then pass the returned publicUrl in mediaItems:
{
"title": "Launch image post",
"content": "A visual walkthrough of the release.",
"publishNow": true,
"mediaItems": [
{
"url": "https://media.example.com/users/user-id/media/upload-id/launch-image.png",
"title": "Release walkthrough image"
}
],
"platforms": [
{
"platform": "linkedin",
"accountId": "account-id"
}
]
}
The PostZen API also accepts external image or video URLs in mediaItems, but PostZen-hosted media gives your integration a predictable upload path.
Direct LinkedIn API vs PostZen
| Decision point | Direct LinkedIn API | PostZen API |
|---|---|---|
| Best fit | Teams that need full LinkedIn-specific control. | Products that need LinkedIn posting as part of a broader social publishing workflow. |
| OAuth | Your app owns the LinkedIn OAuth flow, token storage, and reauthorization path. | PostZen returns connect URLs and stores connected account state behind the API. |
| Post creation | Your code calls LinkedIn’s versioned Posts API. | Your code calls POST https://api.postzen.dev/v1/posts. |
| Scheduling | You build the queue, worker, retries, and failed-state handling. | scheduledFor creates a scheduled post through the same endpoint. |
| Media | You initialize LinkedIn media uploads, upload binaries, store URNs, and compose media post payloads. | You can presign PostZen-hosted media and attach returned URLs in mediaItems. |
| Multi-platform expansion | Each platform becomes a new integration. | The same post model supports LinkedIn plus Instagram, TikTok, Facebook, YouTube, Threads, and X. |
Choose the native LinkedIn API if LinkedIn is the whole product surface and your team wants to own the LinkedIn-specific details.
Choose PostZen if you are building scheduling, AI content publishing, customer workspaces, or multi-platform social features. Your team still designs the user experience. PostZen handles the repeated integration plumbing.
Common LinkedIn API errors
Native LinkedIn integrations fail in a few predictable places.
401 Unauthorized means the token is missing, invalid, expired, or tied to the wrong user context. Your app needs a refresh or reconnect path.
403 Forbidden points to missing permission, wrong member or organization role, or an app that lacks access to the required LinkedIn product.
400 Bad Request often comes from a malformed author URN, missing required headers, a stale LinkedIn version, or a request body that does not match the current Posts API schema.
429 Too Many Requests means you hit a rate limit. Your worker should back off, retry with discipline, and avoid hammering the same endpoint.
PostZen cannot make LinkedIn accept a post that violates LinkedIn’s rules. It can reduce the number of places your application has to manage errors, and it gives your UI one post status model to render across platforms.
FAQ
Can I post to LinkedIn via API without a LinkedIn developer app?
If you integrate with LinkedIn’s native APIs, no. You need a LinkedIn developer app, product access, OAuth credentials, and user authorization.
If you use PostZen, your application integrates with PostZen’s API. Your users still authorize their LinkedIn accounts through an OAuth flow, but your product does not have to own the direct LinkedIn app setup in its own code path.
Can PostZen publish now and schedule for later?
Yes. The PostZen public posts endpoint supports publishing with publishNow, scheduling with scheduledFor, and draft creation with isDraft. The API expects one of those modes per request.
Can I attach images to LinkedIn posts?
Yes. Native LinkedIn image posts require a separate upload flow before the final post request. With PostZen, request a presigned media upload URL, upload the file, then attach the returned public URL in mediaItems.
Can I post to multiple platforms from the same request?
PostZen’s post model accepts an array of platform targets. That lets your product use one post creation flow for LinkedIn and other supported social networks instead of separate code paths for each platform.
Does PostZen refresh LinkedIn tokens?
The current PostZen dashboard backend includes a 24-hour connected social token refresh cron and LinkedIn support in the refresh path. If a connected account still needs user action, your app should surface the account status and send the user back through the connect flow.
