LinkedIn API: posting reference
LinkedIn appears as two independent channels: one for a personal profile and one for a company page. A single workspace can connect both at the same time and post to each separately.
For an overview and use cases, see LinkedIn Profile API and LinkedIn Page API.
| Channel ID | Target |
|---|---|
linkedin | Personal profile (the individual who connected the account) |
linkedin_page | Company page (the organization whose page was selected during OAuth) |
A workspace posts to one company page. When the connecting member administers several Pages, they pick one right after signing in to LinkedIn.
Both channels share a single LinkedIn OAuth token under the hood. Reconnecting either refreshes credentials for both. LinkedIn access tokens last 60 days. When LinkedIn issued a refresh token with the connection, OmniSocials renews the token automatically before it expires, until LinkedIn's one-year refresh limit; otherwise the workspace gets an email 7 days before the expiry and the channel has to be reconnected.
Supported content types
| Type | linkedin (Profile) | linkedin_page (Page) |
|---|---|---|
| Feed post | ✅ | ✅ |
| Story | - | - |
| Reel | - | - |
LinkedIn does not support stories or reels through its API. Only feed posts work.
Minimal example
Posting to a personal profile:
Terminal
Posting to a company page:
Terminal
Posting the same content to both simultaneously: include both account IDs in the accounts array. OmniSocials publishes to each independently.
Terminal
Platform-specific options
Set a first comment under the channel's own key: linkedin for the profile, linkedin_page for the company page:
| Field | Type | Description |
|---|---|---|
linkedin.first_comment | string | Text auto-posted as the first comment on the profile post right after it publishes (max 1250 characters). Common for "link in first comment" to avoid the in-caption link reach penalty. |
linkedin_page.first_comment | string | Same, for the company page post (max 1250 characters). |
linkedin.carousel_as_images | boolean | true publishes 2 or more images as a plain multi-image gallery instead of the default document carousel. See Media requirements. |
linkedin.document_source | string | original_pdf (default) or slides. When the images are the unchanged pages of one uploaded PDF, the default sends that original file as the document; slides rebuilds it from the slide images. See Original PDF. |
linkedin_page.carousel_as_images, linkedin_page.document_source | Same, for the company page post. Independent per channel. | |
linkedin_poll | object | Non-sponsored poll; see Polls below. |
video_cover | object | Top-level. Video thumbnail for a video post, applied to both channels; use video_cover.overrides.linkedin or .linkedin_page to give one channel its own frame or image. See Video covers. |
Aside from the optional first comment and poll, LinkedIn has no required option fields; the default create-post body works for both channels.
Video thumbnails go through LinkedIn's Videos API (initializeUpload with uploadThumbnail, then the image is uploaded before the video is finalized). A thumbnail that cannot be uploaded never fails the post; LinkedIn then picks its own frame.
Polls
LinkedIn's Poll API lets you post a non-sponsored poll: a question with 2-4 answer options and a duration. Pass a top-level linkedin_poll object keyed by channel: linkedin (personal profile) and linkedin_page (company page) each carry their own independent poll, or none. content is still the post's caption, shown above the poll.
Terminal
| Field | Type | Description |
|---|---|---|
linkedin_poll.linkedin | object | null | Poll for the personal profile post. Omit or null = not a poll. |
linkedin_poll.linkedin_page | object | null | Poll for the company page post. Omit or null = not a poll. |
Each poll object:
| Field | Type | Description |
|---|---|---|
question | string | The poll question (max 140 characters). |
options | string[] | 2-4 answer options (max 30 characters each). |
duration | string | ONE_DAY | THREE_DAYS | SEVEN_DAYS | FOURTEEN_DAYS. |
A poll is mutually exclusive with media and a link share on that channel's post; if the request also carries media_urls/media_ids or a link share, the poll silently takes priority at publish time (same precedence LinkedIn's own media-vs-article rule uses), so don't send both.
Post a different poll to the profile and the page in one call by setting both keys:
JSON
linkedin_poll is also accepted on PATCH /posts/{id}; it replaces the whole object wholesale (both channels), so send the full desired state, not just the channel you're changing. GET /posts/{id} echoes it back. Set a channel's key to null (or send linkedin_poll: null) to clear that channel's poll (or every poll) and revert to a normal post.
Media requirements
| Media | Requirement |
|---|---|
| Image | JPEG, PNG, GIF, or WebP (WebP is converted to JPEG at post time), max 10 MB |
| Video | MP4 or MOV, up to 30 minutes, max 5 GB |
LinkedIn supports text-only posts, a single image, a multi-image carousel, or video. Mixing image and video in the same post is not supported.
Posting 2 or more images publishes LinkedIn's native document carousel: OmniSocials renders the images into a single PDF and uploads it as a document, the same swipeable format LinkedIn's own composer produces, instead of a plain multi-image gallery. The API sets no LinkedIn image count of its own; the OmniSocials composer takes up to 9 images per post. When the images are the pages of a PDF you uploaded, LinkedIn receives that original file instead; see Original PDF.
Prefer the plain multi-image gallery for a specific post? Set carousel_as_images: true on the linkedin and/or linkedin_page option object (the same objects that carry first_comment). The flag is independent per channel and is ignored for text-only posts, single images, videos, and polls:
JSON
On PATCH /posts/{id} the flag merges per channel: true sets it, false (or null) reverts that channel to the default document carousel, and omitting it keeps the current value. GET /posts/{id} echoes it back inside each channel's option object.
Original PDF
Uploading a PDF renders its pages to images and keeps the original file, either as one item per page or as one document item (pdf_mode: "document", the web library's default). When a LinkedIn post's images are exactly the rendered pages of one PDF, in order and unchanged, LinkedIn receives that original file as the document instead of one rebuilt from the page images. Text stays sharp, in-document links keep working, viewers download the real file, and every page is included, even past the 20-slide cap. Nothing to set: attach the slide media_ids the upload returned, in order.
The check is per channel and per post. Reordering, removing or editing a slide, or adding another image, means the images are no longer that PDF's pages, and the document is rebuilt from the slides as before. The same applies to a PDF over 100 MB or 300 pages (LinkedIn's document limits).
To send the rebuilt document on purpose, for example to publish a flattened copy, set document_source: "slides" on the channel's option object:
JSON
On PATCH /posts/{id} it merges per channel: "slides" sets it, "original_pdf" (or null) reverts to the default, and omitting it keeps the current value. GET /posts/{id} echoes document_source inside the channel's option object when it is set to "slides". The option is ignored when the images are not a PDF's pages, when carousel_as_images is true, and for text-only posts, single images, videos and polls.
Alt text
Pass an accessibility description per media item by using an object entry instead of a bare string (works in media_urls and media_ids). It is sent as LinkedIn's altText on images: both single-image posts and multi-image galleries, where each image carries its own description. Video and documents don't support alt text (a LinkedIn limitation):
JSON
The same alt also delivers to Mastodon, Bluesky, X, Pinterest, and Instagram (images), so one description covers a cross-platform post.
Mentions
Mentions are available in the OmniSocials web composer only: type @ to mention a company by its exact LinkedIn name, or a person who follows a Page you administer. The API, the MCP server and the CLI have no mentions field, so an @name in content is published as plain text, not as a mention.
Limitations
- Stories and reels are not available through LinkedIn's public API
- LinkedIn enforces a 3,000 character limit per post. Posts exceeding this are rejected.
- Posting to company pages requires the connecting user to be an administrator of the page (media uploads need a Super admin or Content admin role). One page per workspace.
- The personal profile channel (
linkedin) requires the Community Management API product on LinkedIn Developer, which is automatically configured for OmniSocials customers