LinkedIn API Integration: Post for Your Users
A LinkedIn API integration that posts for your users runs on LinkedIn's Community Management API. You get the product approved, connect each user with OAuth, find the Pages they administer, then publish through the Posts API with a LinkedIn-Version header. Tokens last 60 days. Adeli already holds Community Management API access, so your users connect LinkedIn through one social media API instead.
A LinkedIn API integration that publishes for your users runs on LinkedIn's Community Management API: get the product approved for your app, connect each user through OAuth, find the Pages they administer, and create posts through the Posts API with a versioned header. The request itself is short. Most integrations stall on access, token lifetimes, and monthly API versions.
This guide is for teams building a product where each customer connects their own LinkedIn account. For paid campaigns, see the LinkedIn Ads API guide.
Does LinkedIn have an API?
Yes. LinkedIn has several APIs, and the one for posting is the Community Management API. It covers the Posts API, the Images API, Page lookups, and Page and member analytics. Other LinkedIn programs (Advertising, Lead Sync, Sign In with LinkedIn) are separate products with separate access.
| What your product does | LinkedIn product | Key scopes |
|---|---|---|
| Posts as a company Page | Community Management API | w_organization_social, rw_organization_admin |
| Posts as a member's personal profile | Community Management API | w_member_social |
| Reads Page analytics | Community Management API | rw_organization_admin, r_organization_social |
| Runs ad campaigns | Advertising API | rw_ads, r_ads_reporting |
LinkedIn requires the Community Management API to be the only product on its developer app, so a product that also needs ads or sign-in runs more than one LinkedIn app.
How do you get LinkedIn API access?
You get LinkedIn API access by requesting the Community Management API on a developer app tied to a verified LinkedIn Page. LinkedIn vets the request for a registered legal organization, a commercial use case, a verified business email, and a website on the organization's domain.
Approval starts you on Development tier, which LinkedIn's access tiers page limits for testing:
| Development tier | Standard tier | |
|---|---|---|
| Daily calls | 500 per app, 100 per member | No such caps |
BATCH_GET |
Blocked | Available |
| Social action webhooks | Off | Available |
| How to get it | Default after vetting | A separate application with a screen recording |
The Standard tier application needs an approved use case, a privacy policy, and a recording of your product: the full OAuth flow, posting, and how you display engagement. LinkedIn doesn't let you re-apply with the same app if Standard tier is rejected. You'd start over with a new app on Development tier, so get the recording right the first time.
What do you need before you start?
- A LinkedIn developer app with the Community Management API approved.
- A LinkedIn Page verified for the app, belonging to your company.
- An HTTPS redirect URI registered on the app's Auth tab.
- The current API version in
YYYYMMform, from LinkedIn's versioning page. - A test member who administers a test Page, so you can try both posting targets.
Step 1: Connect each user with OAuth
Each of your users signs in to LinkedIn and grants your app the posting scopes; your server exchanges the code for their token. Send them to LinkedIn's authorization page:
https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>&scope=w_organization_social%20rw_organization_admin%20w_member_socialCheck state on the callback, then exchange the code from your server, as LinkedIn's authorization code flow describes:
curl -X POST https://www.linkedin.com/oauth/v2/accessToken \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=authorization_code \
-d code=<CODE> \
-d client_id=<CLIENT_ID> \
-d client_secret=<CLIENT_SECRET> \
-d redirect_uri=<REDIRECT_URI>Store the token encrypted, against your user, with its expiry.
Step 2: Pick the posting target: a Page or a personal profile
A LinkedIn post has one author: either a member (urn:li:person:…) or an organization (urn:li:organization:…). To find the Pages a member can post for, list their role assignments:
curl "https://api.linkedin.com/rest/organizationAcls?q=roleAssignee&state=APPROVED" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Linkedin-Version: 202610" \
-H "X-Restli-Protocol-Version: 2.0.0"Keep the Pages where the member's role is ADMINISTRATOR, CONTENT_ADMIN, or DIRECT_SPONSORED_CONTENT_POSTER. Then let your user choose. A member with no eligible Page can still post as themselves with w_member_social.
Save the chosen author URN with the connection. On Development tier, each Page is a separate lookup because BATCH_GET is blocked, so cache the result instead of calling on every page load.
Step 3: Publish through the Posts API
Create a post with POST /rest/posts, the author URN, and the Linkedin-Version header. This text post follows LinkedIn's Posts API reference:
curl -X POST https://api.linkedin.com/rest/posts \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Linkedin-Version: 202610" \
-H "X-Restli-Protocol-Version: 2.0.0" \
-H "Content-Type: application/json" \
-d '{
"author": "urn:li:organization:<ORG_ID>",
"commentary": "We just shipped a faster publishing workflow.",
"visibility": "PUBLIC",
"distribution": {
"feedDistribution": "MAIN_FEED",
"targetEntities": [],
"thirdPartyDistributionChannels": []
},
"lifecycleState": "PUBLISHED",
"isReshareDisabledByAuthor": false
}'A success is HTTP 201 with the new post's URN in the x-restli-id response header. For an image, first call POST /rest/images?action=initializeUpload with the author as owner, upload the bytes to the returned uploadUrl, then add the image URN to the post under content.media.id.
Two rules for post creation:
- Don't use
/v2/ugcPosts. The Posts API replaced it. - Don't blindly retry post creation. If the response is ambiguous, a retry can publish the same post twice.
Step 4: Handle tokens and versions over time
LinkedIn access tokens last 60 days, and API versions are supported for about a year, so a LinkedIn API integration needs ongoing upkeep.
- Tokens. LinkedIn's refresh token docs say programmatic refresh tokens go to approved partners only. They last a year, and refreshing doesn't extend that year. Without one, prompt the member to reconnect before day 60.
- Versions. Each
Linkedin-Versionis supported for roughly 12 months. A sunset version returns HTTP426, so pin a version, track LinkedIn's recent changes, and move forward before the sunset date. - Rate limits. A
429means you've hit a daily limit. On Development tier that can come from any of your customers, because the 500-call budget is shared across the app.
Is the LinkedIn API free?
LinkedIn doesn't charge for the Community Management API, but the integration costs approval time and maintenance.
| Cost | Who carries it when you go direct |
|---|---|
| Vetting and the Standard tier application | Your team, with a screen recording and no second try on the same app |
| Token expiry every 60 days | Your team and your users, unless you're an approved partner |
| Monthly API versions | Your team, migrating before each sunset |
| Separate apps for ads and sign-in | Your team, one approval each |
| Debugging failed posts | Your team, from LinkedIn's error responses |
Is there a faster way to build a LinkedIn API integration?
Adeli is a unified social media API that already holds LinkedIn Community Management API access, so your product doesn't need its own LinkedIn application. Your users connect a personal profile or a Page they administer, and you publish with the same API key you use for every other network.
Start a connection for one of your users. Members who administer a Page pick the profile or Page on an Adeli-hosted chooser:
curl -X POST https://app.tryadeli.com/api/v1/profiles/<PROFILE_ID>/connect \
-H "Authorization: Bearer $ADELI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "platform": "linkedin", "redirectUrl": "https://yourapp.example/callback" }'Then publish:
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": "We just shipped a faster publishing workflow."
}'What Adeli handles for you:
- API access. Adeli holds the Community Management API approval and pins a verified LinkedIn API version, so LinkedIn's version changes are Adeli's work.
- Targets. Adeli finds the Pages a member can post for and lets them choose a Page or their personal profile.
- Text and image posts. Adeli checks the image's real format and size, runs LinkedIn's upload flow, and never retries a post in a way that could duplicate it.
- Tokens. Adeli stores each grant encrypted, rotates refresh tokens when LinkedIn issues them, and flags the account for reconnect when it can't.
- Analytics. Followers, impressions, reactions, comments, and shares for Pages and personal profiles, through the analytics API.
- Clear errors. Every publish returns a per-platform status, and Adeli logs every call it makes to LinkedIn, with the status, latency, and LinkedIn's error code. When a post fails, a person at hello@tryadeli.com can tell you why.
The same key publishes to Instagram, Facebook, TikTok, YouTube, X, and Bluesky through Adeli's posting API. The LinkedIn publish docs list every field.