Platforms
Publish to LinkedIn personal profiles and company pages through the same POST /v1/posts endpoint as X. Synposter handles OAuth, token refresh, image and video upload, and the URN switching between member and organization authors.
Overview
One LinkedIn OAuth grant gets you a personal account plus one connected account per organization page the authenticating member admins. Each shows up as a separate connected_accounts row with account_kind set to person or organization. To post, you pass the relevant account's id in the accounts[] array — the rest is unchanged from posting to X.
Quick reference
| Property | Value |
|---|---|
| Character limit | 3,000 |
| Images per post | Up to 4 (matches Synposter cross-platform cap) |
| Videos per post | 1 |
| Image formats | JPEG, PNG, GIF |
| Image max size | 10 MB |
| Video format | MP4 only |
| Video max size | 200 MB |
| Account types | Personal members + organization pages |
| Visibility | PUBLIC (default) or CONNECTIONS |
| Threads | Not supported (LinkedIn has no thread concept) |
| Replies / quotes | Not supported via Synposter |
| Polls | Not supported via Synposter |
| Scheduling | Yes — same /v1/posts/scheduled endpoint |
| Analytics — orgs | Yes (impressions, likes, comments, shares, clicks) |
| Analytics — members | Not available (requires r_member_social) |
Before you start
Member analytics are not available. LinkedIn gates the r_member_socialscope behind a restricted-access program that most apps don't qualify for. Posts published to a personal LinkedIn account come back from GET /v1/analytics with metricsError: "metrics_unavailable_for_kind". Organization-page posts have full analytics.
Company pages need the Community Management API. The w_organization_socialscope used for org posting is part of LinkedIn's Community Management API product, which requires manual approval (apply at developer.linkedin.com). Personal posting works with the auto-approved Share on LinkedIn product.
Multi-image posts are images-only.LinkedIn doesn't allow mixing image and video in a single post, and multi-image posts must all be images (no GIF/video mixed in).
Quick start
1. Connect a LinkedIn account
Send the user through the OAuth flow. Synposter creates one connected account for the personal profile plus one per organization page they admin.
curl -X POST https://api.synposter.com/v1/connect/linkedin \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"redirectUri": "https://yourapp.com/connect/done"
}'The response contains an authUrl; redirect the user to it. After authorization, the user lands at your redirectUri with ?profileId=...&accountId=...&platform=linkedin&orgCount=N. If orgCountis > 0, additional organization accounts have been created — list them with GET /v1/accounts?profileId=....
2. Publish a post
curl -X POST https://api.synposter.com/v1/posts \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accounts": [
{
"id": "fc062a80-...",
"platform": "linkedin",
"platformOptions": {
"visibility": "PUBLIC"
}
}
],
"text": "Excited to share our latest update!"
}'3. Publish with media
Upload media via POST /v1/mediafirst to get a public URL, then reference it in the post body. Synposter forwards the bytes through LinkedIn's 3-step Images API (or chunked Videos API for video) automatically.
curl -X POST https://api.synposter.com/v1/posts \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accounts": [
{
"id": "fc062a80-...",
"platform": "linkedin"
}
],
"text": "Launch day!",
"media": [
{
"type": "image",
"url": "https://media.synposter.com/.../launch.png"
}
]
}'Personal vs. organization accounts
Each connected_accountsrow is either a person or an organization. The dispatcher constructs the right author URN based on the row's account_kind:
| Property | Value |
|---|---|
| account_kind=person | urn:li:person:<memberId> |
| account_kind=organization | urn:li:organization:<orgId> |
Both share the same OAuth token (LinkedIn issues one token per grant covering all kinds the member admins). The kind is already encoded in the connected_accounts row, so your post body is identical regardless of which you target — pass theaccountId and Synposter does the right thing.
Visibility
Pass platformOptions.visibility on the per-account entry to control who sees the post:
| Property | Value |
|---|---|
PUBLIC | Visible to everyone on LinkedIn (default) |
CONNECTIONS | Visible only to the account's network |
Media
Images
JPG, PNG, or GIF. Up to 10 MB each. Up to 4 per post (matches our cross-platform cap; LinkedIn supports up to 9 internally — we'll bump if customers need it). Single-image posts use LinkedIn's content.media shape; 2+ images use content.multiImage.
Video
MP4 only. Up to 200 MB. One video per post; can't mix with images. Synposter chunks the upload according to LinkedIn's Videos API instructions and finalizes once all parts have landed.
Videos go into a PROCESSING state on LinkedIn's side after upload. The POST /v1/posts response is still 201 — LinkedIn finishes processing async and the post becomes visible after.
Analytics
For organization-page posts, GET /v1/analytics returns full metrics:
| Property | Value |
|---|---|
| impressions | Yes |
| likes | Yes |
| comments | Yes |
| shares | Yes |
| clicks | Yes |
| saves | Not exposed by LinkedIn |
| views | Not exposed by LinkedIn |
| engagementRate | Yes (LinkedIn-computed) |
For personal posts, calls return metrics_unavailable_for_kind — see the warning at the top of the page.
OAuth scopes
Synposter requests the following on every LinkedIn OAuth flow:
r_basicprofile w_member_social rw_organization_admin w_organization_social r_organization_socialWhichever your dev app is approved for are granted; the rest are silently ignored. r_basicprofile + w_member_social are auto-granted with the Share on LinkedIn product. The three organization scopes require Community Management API approval.