LinkedIn Post API Example Builder
Get a working LinkedIn post API example for your exact post: text, image, multi-image, article or poll, in curl, Python or Node, with the headers LinkedIn requires and every reserved character escaped so the post is not cut off.
How to create a LinkedIn post with the API
A LinkedIn post is POST https://api.linkedin.com/rest/posts with Authorization Bearer, Linkedin-Version YYYYMM and X-Restli-Protocol-Version 2.0.0 headers, and a JSON body with author, commentary, visibility, distribution and lifecycleState PUBLISHED.
1 request: one POST /rest/posts.
- No person ID yet, so the author is a placeholder. The ID is the sub claim from the OpenID Connect userinfo endpoint.
# Create the post. The new post URN comes back in the x-restli-id response header.
curl -i -X POST 'https://api.linkedin.com/rest/posts' \
-H "Authorization: Bearer $LINKEDIN_TOKEN" \
-H 'Linkedin-Version: 202609' \
-H 'X-Restli-Protocol-Version: 2.0.0' \
-H 'Content-Type: application/json' \
--data '{
"author": "urn:li:person:{PERSON_ID}",
"commentary": "Q3 results \\(up 40%\\) are in. Thanks to \\@\\[Jane\\]\\(urn:li:person:abc123\\) and the team \\#growth\n\n\\* Revenue: \\[redacted\\] \\<for now\\>\n\\* Churn: down\\_2 \\~ flat",
"visibility": "PUBLIC",
"distribution": {
"feedDistribution": "MAIN_FEED",
"targetEntities": [],
"thirdPartyDistributionChannels": []
},
"lifecycleState": "PUBLISHED",
"isReshareDisabledByAuthor": false
}'Built in your browser. Nothing is sent to LinkedIn or to OpenTweet. Set LINKEDIN_TOKEN to an access token with the w_member_social scope before you run it.
What each content type needs
Every type goes through the same /rest/posts call. What changes is the content field and how many uploads come first. Limits are from LinkedIn's Posts, Images, MultiImage and Poll API pages on Microsoft Learn.
| Post type | Body field | Requests | Limits |
|---|---|---|---|
| Text only | no content field | 1 | commentary only |
| Single image | content.media.id | 3 | JPG, GIF or PNG, under 36,152,320 pixels, altText up to 4,086 characters |
| Multi-image | content.multiImage.images[] | 2 per image + 1 | 2 to 20 images, organic posts only |
| Article | content.article | 1, or 3 with a thumbnail | source, title, description and thumbnail set by you, no scraping |
| Poll | content.poll | 1 | question 140, options 30 each, 2 to 4 options, 1 to 14 days |
What the API will not do
Organic carousels are not supported (carousels are sponsored only). Polls are single-vote only and cannot be edited after creation. After publishing, only commentary, the call to action, the landing page, lifecycleState and ad context can be changed with a PARTIAL_UPDATE.The fields in the body
author is urn:li:person:{id}, where the id is the sub from Sign In with LinkedIn using OpenID Connect, or urn:li:organization:{id} for a Company Page.
commentary is the post text in little text format. It is required, and its reserved characters need escaping.
visibility is PUBLIC, CONNECTIONS (first-degree network) or LOGGED_IN. A fourth value, CONTAINER, hands visibility to a container such as a group.
distribution is { feedDistribution: MAIN_FEED, targetEntities: [], thirdPartyDistributionChannels: [] } for a normal feed post.
lifecycleState must be PUBLISHED. It is the only value LinkedIn accepts on create.
Linkedin-Version is a month in YYYYMM form. LinkedIn has no unversioned calls, and a missing or retired version is rejected. If you get a 426, see LinkedIn API 426 NONEXISTENT_VERSION.
Escaping: why API posts get cut off
LinkedIn's little text format reserves fifteen characters, and its docs say each one needs a backslash even when it is not part of a mention or hashtag. The builder escapes them by default. Switch to the escaper tab to see which characters in your text were the problem.
\|{}@[]()<>#*_~The tradeoff: an escaped #tag or @ publishes as plain text. To keep a real mention, leave @[Name](urn:li:person:id) unescaped with the keep option, and see how to mention someone with the LinkedIn API. The full write-up is in why a LinkedIn API post is cut off at a parenthesis.
Or skip the LinkedIn app setup
Connect your LinkedIn profile to OpenTweet once and post with one call. No developer app, no image upload dance, and OpenTweet escapes the reserved characters for you. The same call can post to X and Bluesky too.
curl -X POST https://opentweet.io/api/v1/posts \
-H "Authorization: Bearer ot_your_key" \
-H "Content-Type: application/json" \
-d '{
"text": "Q3 results (up 40%) are in. Thanks to the team.",
"platforms": ["linkedin"],
"publish_now": true
}'OpenTweet posts to personal LinkedIn profiles with text and images. Polls, article cards and Company Pages still need LinkedIn's API directly.
7-day free trial, then from $11.99/mo. API, X, Bluesky and LinkedIn on every plan.
LinkedIn Posts API FAQ
What does a LinkedIn post API example request look like?
POST https://api.linkedin.com/rest/posts with three headers: Authorization: Bearer and your token, Linkedin-Version with a month such as 202609, and X-Restli-Protocol-Version: 2.0.0. The JSON body needs author (a person or organization URN), commentary, visibility, distribution with feedDistribution MAIN_FEED, and lifecycleState PUBLISHED. A 201 response carries the new post URN in the x-restli-id header.
Why is my LinkedIn API post truncated?
LinkedIn reads commentary as little text format, where | { } @ [ ] ( ) < > # \ * _ ~ are markup. LinkedIn says every one of them must be escaped with a backslash, even outside a mention or hashtag. An unescaped parenthesis or bracket can cut the post off. The escaper tab marks each one and gives you the escaped text.
How many requests does an image post take?
Three for one image: POST /rest/images?action=initializeUpload with the author as owner, a PUT of the bytes to the uploadUrl it returns, then POST /rest/posts with content.media.id set to the image URN. A multi-image post repeats the first two calls for each image, so four images take nine requests.
What are the LinkedIn poll limits in the API?
The question can be up to 140 characters, each option up to 30, and a poll takes 2 to 4 options. Duration is ONE_DAY, THREE_DAYS, SEVEN_DAYS or FOURTEEN_DAYS. Only single-vote polls exist, setting isVoterVisibleToAuthor to false returns 400, and a poll cannot be edited after it is created.
Does the API fetch the title and image for an article link?
No. LinkedIn says the Posts API does not scrape the URL. You set content.article.source, title and description yourself, and the thumbnail is an image URN you upload through the Images API first.
Is there a LinkedIn API Postman collection?
LinkedIn publishes curl samples on Microsoft Learn, and this builder turns them into requests you can run as they are: copy the curl tab and paste it into Postman with Import (replace $LINKEDIN_TOKEN with your token first), or run it in a terminal after setting LINKEDIN_TOKEN.
Can I post as a Company Page?
Yes, with author set to urn:li:organization and an access token that has w_organization_social. The signed-in member also needs the ADMINISTRATOR, CONTENT_ADMIN or DIRECT_SPONSORED_CONTENT_POSTER role on that Page. Posting as yourself needs only w_member_social.
Can OpenTweet post to LinkedIn for me?
Yes, to your personal LinkedIn profile, with text and images, from the dashboard or one call to the OpenTweet API with platforms set to linkedin. OpenTweet escapes every reserved character for you. It does not post polls, article cards or to Company Pages. Plans start at $11.99/month with a 7-day trial.
Related tools and guides
LinkedIn Little Text Escaper
Find the characters that cut an API post off and get the escaped text.
Post to LinkedIn with Python
OAuth, the person URN, text and image posts, step by step.
LinkedIn API Error Decoder
Paste a LinkedIn API error and get the cause and the fix.
Mention someone with the LinkedIn API
The @[Name](urn) syntax and why names must match exactly.
LinkedIn API post cut off
The reserved characters and an escape function in Python and JavaScript.
LinkedIn Scheduler
Schedule posts to your LinkedIn profile from a draft or an API call.