Platforms

LinkedIn

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

PropertyValue
Character limit3,000
Images per postUp to 4 (matches Synposter cross-platform cap)
Videos per post1
Image formatsJPEG, PNG, GIF
Image max size10 MB
Video formatMP4 only
Video max size200 MB
Account typesPersonal members + organization pages
VisibilityPUBLIC (default) or CONNECTIONS
ThreadsNot supported (LinkedIn has no thread concept)
Replies / quotesNot supported via Synposter
PollsNot supported via Synposter
SchedulingYes — same /v1/posts/scheduled endpoint
Analytics — orgsYes (impressions, likes, comments, shares, clicks)
Analytics — membersNot 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:

PropertyValue
account_kind=personurn:li:person:<memberId>
account_kind=organizationurn: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:

PropertyValue
PUBLICVisible to everyone on LinkedIn (default)
CONNECTIONSVisible 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:

PropertyValue
impressionsYes
likesYes
commentsYes
sharesYes
clicksYes
savesNot exposed by LinkedIn
viewsNot exposed by LinkedIn
engagementRateYes (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:

text
r_basicprofile w_member_social rw_organization_admin w_organization_social r_organization_social

Whichever 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.