LinkedIn Posting API: Post to Profiles and Pages

By Nick ReyesPublished 8 min read

The short answer

The LinkedIn posting API is the Posts API: one POST to /rest/posts with an author URN, the post text, and a Linkedin-Version header. Personal profiles need the w_member_social scope, which the self-serve Share on LinkedIn product grants. Company Pages need w_organization_social from a vetted product, usually the Community Management API. Adeli publishes LinkedIn text and image posts through one social media API.

The LinkedIn posting API is LinkedIn's Posts API: a single POST /rest/posts call with an author URN, the post's commentary, and a Linkedin-Version header. The request itself is short. What trips people up is the LinkedIn product behind the app, because that decides whether you can post as a person, as a company Page, or not at all.

Most failed first attempts come from a scope the app was never granted. This guide walks through which product gives which scope, then the requests for each kind of post. For OAuth, token lifetimes, and the full app setup, see our LinkedIn API integration guide.

Which LinkedIn API do you use to post?

Every LinkedIn post created through the API goes through the Posts API; what changes is the scope your token carries. LinkedIn grants posting scopes through three developer products, and only one of them is self-serve:

LinkedIn product Posting scope it grants Post as How you get it
Share on LinkedIn w_member_social The member who authorized your app Self-serve, from the app's Products tab
Community Management API w_member_social, w_organization_social A member or a company Page Vetted, with Development and Standard tiers
Advertising API w_member_social, w_organization_social A member or a company Page Vetted, for advertising use cases

The scope lists come from LinkedIn's permissions table and its open permissions list. Pick the product by use case. LinkedIn reviews each request against what the product is for, and a scheduling or publishing tool belongs on the Community Management API. Our Community Management API explainer covers that application and its tiers.

Common mistakes when posting through the LinkedIn API

The same few errors show up again and again in developer forums. Most of them trace back to the scope table above.

"The personal account connection works fine. But when I try to connect the organization page using OAuth2, I get the following error …" Djagryn, n8n community forum (June 2025)

"I consistently get an unauthorized_scope_error related to w_organization_social, even though I am trying to post as a Person." celso_cunha, n8n community forum (June 2025)

"Basically, permission w_organization_social is required, but not available in LinkedIn application settings." Miquel_Colomer, n8n community forum (February 2021)

"The API call is consistently failing with a permission error, even though I have an authorised connection with what I understand to be the required permissions for the attempted operation." Kedama, Stack Overflow (March 2024)

"ERROR :: /author :: "urn:li:person:aba2390d-7792-4cb2-ad6b-e116d9783606" does not match urn:li:company:\d+|urn:li:member:\d+" usrmetamask, Stack Overflow (July 2024)

"Recently our app was able to create LinkedIn posts via UGC Posts API and the URL preview functionality worked perfectly … But after we migrated to the new API it seems that it is not possible anymore" AndrewK, Stack Overflow (January 2023)

The pattern:

  • Asking for a scope the app doesn't have. If your OAuth URL requests w_organization_social and the app only holds Share on LinkedIn, LinkedIn rejects the whole consent with unauthorized_scope_error, even for a personal post. Request only the scopes your products grant.
  • The wrong ID in the author URN. The author has to be urn:li:person:{id} built from the member's LinkedIn ID, or urn:li:organization:{id}. Your own user ID, or any other identifier, fails validation.
  • Old endpoints. /v2/shares and /v2/ugcPosts predate the versioned Posts API, so tutorials built on them behave differently. Step 3 covers the link-preview change.

Step 1: Get a token with the right scope

A LinkedIn post needs a three-legged OAuth token from the member who will be the author, or from an admin of the Page that will be the author. There are no app-only tokens for posting.

  • Personal profile: request w_member_social.
  • Company Page: request w_organization_social, plus rw_organization_admin if you need to look up which Pages the member manages.

The LinkedIn API integration guide has the authorization URL and the code exchange.

Step 2: Build the author URN

The author field takes a person URN (urn:li:person:{id}) or an organization URN (urn:li:organization:{id}), and the token's scopes must match it. LinkedIn's Post schema says to get the person ID from the Retrieve Current Member's Profile API, and the organization ID from the member's organization access list.

For a Page, the member also needs a role there. The Posts API reference restricts w_organization_social to members who are ADMINISTRATOR, DIRECT_SPONSORED_CONTENT_POSTER, or CONTENT_ADMIN on the Page. A valid token from a member with no role still gets a 403.

Step 3: Create the post

Send POST https://api.linkedin.com/rest/posts with Linkedin-Version and X-Restli-Protocol-Version: 2.0.0 headers. This one posts as a member, mentions an organization, and adds a hashtag:

curl -X POST https://api.linkedin.com/rest/posts \
  -H "Authorization: Bearer <MEMBER_TOKEN>" \
  -H "Linkedin-Version: 202610" \
  -H "X-Restli-Protocol-Version: 2.0.0" \
  -H "Content-Type: application/json" \
  -d '{
    "author": "urn:li:person:<PERSON_ID>",
    "commentary": "Shipped our new release with @[Devtestco](urn:li:organization:2414183) #buildinpublic",
    "visibility": "PUBLIC",
    "distribution": {
      "feedDistribution": "MAIN_FEED",
      "targetEntities": [],
      "thirdPartyDistributionChannels": []
    },
    "lifecycleState": "PUBLISHED",
    "isReshareDisabledByAuthor": false
  }'

Details from the Posts API reference:

  • Mentions use @[Name](urn) inside commentary. The name has to match the entity's name, case-sensitive, or it renders as plain text. A member mention can match the first name, last name, or full name. An organization mention must match the full name.
  • Visibility accepts PUBLIC, CONNECTIONS, LOGGED_IN, or CONTAINER.
  • Link previews are not scraped. For an article post, you set content.article with the source URL, a title, and a thumbnail image you uploaded yourself. A bare URL in the text stays a bare URL. That is the change AndrewK hit above.

Jan Vlnas, a developer who migrated an integration from ugcPosts to the versioned API, summed up the payload change:

"the new Posts API is definitely an overall improvement. Deeply nested structures with confusing properties and arbitrary nesting of arrays – it's all gone." Jan Vlnas, LinkedIn's New Posts API: The Good, The Bad, and The Ugly (April 2023)

So moving off ugcPosts means rewriting the payload as well as the URL. specificContent, shareCommentary, and shareMediaCategory collapse into a flat commentary and content.

Step 4: Add an image, video, or document

Media goes up first through its own API, which returns a URN; the post then references that URN in content.media.id. Each upload names the same owner as the post's author.

Content Upload API What LinkedIn accepts
Image POST /rest/images?action=initializeUpload JPG, GIF, or PNG under 36,152,320 pixels; GIFs up to 250 frames
Video POST /rest/videos?action=initializeUpload, then finalizeUpload MP4, 3 seconds to 30 minutes, 75 KB to 500 MB
Document POST /rest/documents?action=initializeUpload PDF, PPT, PPTX, DOC, or DOCX, up to 100 MB and 300 pages
Several images Images API, then a multiImage post Organic posts only

The limits are from LinkedIn's Images API, Videos API, and Documents API pages. Video is the one with extra steps:

  1. Call initializeUpload with owner and fileSizeBytes. The response holds a video URN and an uploadInstructions array with one URL per 4 MB part.
  2. PUT each byte range to its uploadUrl and keep the ETag from every response.
  3. Call finalizeUpload with the video URN, the uploadToken, and the ETags in part order as uploadedPartIds.
  4. Create the post with "content": { "media": { "id": "urn:li:video:…", "title": "…" } }.

A document post needs content.media.title, because the Documents API makes it required.

How do you know the post worked?

LinkedIn returns HTTP 201 Created and puts the new post's ID in the x-restli-id response header, as urn:li:share:… or urn:li:ugcPost:…. There's no response body to parse. Save the ID: you need it to edit, delete, or read analytics later, and it builds the public link https://www.linkedin.com/feed/update/<post-id>/. To read how those posts perform, see the LinkedIn post analytics API.

The errors you'll see most, from the Posts API's error table:

Status Code Usual cause
400 MISSING_FIELD distribution, visibility, or lifecycleState left out
400 FIELD_LENGTH_TOO_LONG commentary or another text field over its limit
401 EMPTY_ACCESS_TOKEN No bearer token on the request
403 ACCESS_DENIED Missing scope, or no Page role for an organization author
422 UNPROCESSABLE_ENTITY Values that don't fit together
429 TOO_MANY_REQUESTS A daily rate limit was hit

Don't retry a create blindly. A timeout after LinkedIn accepted the post means a retry publishes it twice. Check the author's recent posts first.

Can you schedule or edit LinkedIn posts through the API?

The LinkedIn Posts API has no scheduling field: PUBLISHED is the only lifecycleState it accepts on create. To schedule, store the post in your own system and send the create call at the planned time.

After publishing:

  • Edit with POST /rest/posts/{encoded id} and the header X-RestLi-Method: PARTIAL_UPDATE. Only commentary, the call-to-action label, the landing page, lifecycleState, and ad fields can change; the media can't. Success is 204.
  • Delete with DELETE /rest/posts/{encoded id}. It's idempotent: deleting an already deleted post still returns 204. There's no batch delete.

Is the LinkedIn posting API free?

LinkedIn charges no fee for the Posts API; you pay in daily call limits that depend on the product. The Share on LinkedIn page lists 150 requests per member and 100,000 per app each day. The Community Management API's Development tier allows 500 calls per app and 100 per member in 24 hours, and Standard tier lifts those caps. Access, tokens, and upkeep are the real costs, and the integration guide breaks them down.

How do you post to LinkedIn through Adeli?

Adeli publishes LinkedIn text posts and single-image posts to a member's personal profile or a Page they administer, with the same request shape as every other network. Adeli holds the Community Management API access, so your app doesn't need its own LinkedIn product approval. Each of your users connects their LinkedIn account once, and you publish with their accountId:

curl -X POST https://app.tryadeli.com/api/v1/posts \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "linkedin",
    "accountId": "<ACCOUNT_ID>",
    "commentary": "Our spring schedule is live.",
    "image": { "content_type": "image/png", "base64": "<BASE64>" }
  }'

What that covers, per the LinkedIn publish docs:

  • Author. The connected account is either the profile or one Page, chosen on an Adeli-hosted picker when the member administers a Page. You never build URNs.
  • Media. One kind per post: one image, 2 to 20 images, one MP4 video, or one PDF document. You upload through Adeli's media uploads endpoint and pass the upload_id, and Adeli runs LinkedIn's upload flow and waits for a video to finish processing before it creates the post.
  • Mentions. Up to 20 mentions of Pages or people, by URN and the name's position in the commentary.
  • Result. A 201 with the post's providerId and permalink.
  • Errors. 403 permission_required when the member lost their Page role, 429 rate_limited with a retry delay, and no automatic retry of a create, so a post never lands twice.

The same key publishes to Instagram, TikTok, YouTube, X, and Bluesky through the posting API, and LinkedIn post and Page stats come back through the analytics API. Pricing is free to start.

faq

Frequently asked questions

Can I post to LinkedIn without the Community Management API?

Yes, for personal profiles. The Share on LinkedIn product is self-serve in the LinkedIn Developer Portal and grants w_member_social, which lets your app post on behalf of the member who authorized it. Posting as a company Page needs w_organization_social, which only vetted products such as the Community Management API grant.

Does the LinkedIn API support carousel posts?

Not as organic posts. LinkedIn's Posts API documentation lists carousels as sponsored-only. For an organic post with several images, use the MultiImage API, which LinkedIn supports for non-sponsored posts only.

Why does LinkedIn return 403 ACCESS_DENIED when I create a post?

A 403 ACCESS_DENIED from the Posts API means the token lacks the scope for that author or the member lacks a Page role. A Page post needs w_organization_social and an ADMINISTRATOR, CONTENT_ADMIN or DIRECT_SPONSORED_CONTENT_POSTER role on that Page. A member post needs w_member_social.

Power your next project
with one ads & social media API

Give your users publishing, scheduling, and analytics through one integration your team can actually maintain.

Try with agents

Start with free credits. No credit card required.