LinkedIn API
Schedule and automate LinkedIn posts with RelayAPI — text, images, videos, document carousels, first comments, and company pages.
Quick Reference
| Property | Value |
|---|---|
| Platform key | linkedin |
| Auth method | OAuth 2.0 |
| Character limit | 3,000 |
| Images per post | 20 |
| Videos per post | 1 |
| Documents per post | 1 (PDF, PPT, PPTX, DOC, DOCX) |
| Image formats | JPEG, PNG, GIF |
| Image max size | 10 MB |
| Video formats | MP4 |
| Video max size | 500 MB |
| Video max duration | 10 min (personal), 30 min (company page) |
| Post types | Text, Image, Multi-image, Video, Document/Carousel |
| Scheduling | Yes |
| Analytics | Yes (impressions, reach, likes, comments, shares, clicks, views) |
Client options — TypeScript · Python REST/OpenAPI · Go · Java · REST API
Before You Start
LinkedIn actively suppresses posts with external links — expect a 40-50% reach drop. Always put links in a first_comment instead of the main content. LinkedIn has very strict duplicate detection — even minor rephrasing may not be enough to avoid a 422 error. You cannot mix media types (images + videos, or images + documents) in the same post. GIFs are converted to video and count against the 1-video-per-post limit.
Quick Start
Post to LinkedIn:
import Relay from '@relayapi/sdk';
const client = new Relay();
const post = await client.posts.create({
content: 'I spent 3 years building the wrong product.\n\nHere is what I learned about validating ideas before writing code...',
targets: ['linkedin'],
scheduled_at: 'now',
});
console.log(post.id); // post_abc123Content Types
Text-Only Post
Text posts have the highest organic reach on LinkedIn. First ~210 characters are visible before the "see more" fold, so front-load your hook.
const post = await client.posts.create({
content: 'I spent 3 years building the wrong product.\n\nHere is what I learned about validating ideas before writing code...',
targets: ['linkedin'],
scheduled_at: 'now',
});Single Image Post
const post = await client.posts.create({
content: 'Our new office setup!',
targets: ['linkedin'],
media: [
{ url: 'https://cdn.example.com/office.jpg', type: 'image' },
],
scheduled_at: 'now',
});Multi-Image Post (Up to 20)
LinkedIn supports up to 20 images per post. Cannot include videos or documents alongside images.
const post = await client.posts.create({
content: 'Highlights from our team retreat!',
targets: ['linkedin'],
media: [
{ url: 'https://cdn.example.com/photo1.jpg', type: 'image' },
{ url: 'https://cdn.example.com/photo2.jpg', type: 'image' },
{ url: 'https://cdn.example.com/photo3.jpg', type: 'image' },
],
scheduled_at: 'now',
});Video Post
const post = await client.posts.create({
content: 'Watch our latest product demo',
targets: ['linkedin'],
media: [
{ url: 'https://cdn.example.com/demo.mp4', type: 'video' },
],
scheduled_at: 'now',
});Document/Carousel Post (PDF)
LinkedIn uniquely supports document uploads that display as swipeable carousels. Upload a PDF, PPT, PPTX, DOC, or DOCX file. Max 100 MB, up to 300 pages.
const post = await client.posts.create({
content: 'Download our 2024 Industry Report',
targets: ['linkedin'],
media: [
{ url: 'https://cdn.example.com/report.pdf', type: 'document' },
],
scheduled_at: 'now',
target_options: {
linkedin: {
document_title: '2024 Industry Report',
},
},
});Document carousels are one of the highest-engagement post formats on LinkedIn. Each page of the PDF becomes a swipeable slide.
Post with First Comment (Put Links Here!)
LinkedIn actively suppresses posts containing external URLs — expect a 40-50% reach drop. Put links in the first comment instead.
const post = await client.posts.create({
content: 'We just published our guide to API design patterns.\n\nLink in the first comment.',
targets: ['linkedin'],
scheduled_at: 'now',
target_options: {
linkedin: {
first_comment: 'Read the full guide here: https://example.com/api-guide',
},
},
});Putting links in the main content field causes a significant reach penalty on LinkedIn. Always use first_comment for external URLs.
Company Page Post
Post to a company page instead of a personal profile by targeting the RelayAPI account created when that organization was selected during the LinkedIn connection flow. The connected member or organization URN is authoritative for every post; a post cannot use an option to redirect that OAuth token to another company.
const post = await client.posts.create({
content: 'Update from our organization!',
targets: ['acc_linkedin_company'],
scheduled_at: 'now',
});Media Requirements
Images
| Property | Requirement |
|---|---|
| Max per post | 20 |
| Formats | JPEG, PNG, GIF |
| Max file size | 8 MB per image |
| Recommended | 1200 x 627 px (1.91:1) |
| Min dimensions | 552 x 276 px |
Videos
| Property | Requirement |
|---|---|
| Max per post | 1 |
| Formats | MP4 |
| Max file size | 500 MB |
| Max duration | 10 min (personal profile), 30 min (company page) |
| Recommended | 1920 x 1080, H.264, AAC 192kbps, 30fps |
Documents
| Property | Requirement |
|---|---|
| Max per post | 1 |
| Formats | PDF, PPT, PPTX, DOC, DOCX |
| Max file size | 100 MB |
| Max pages | 300 |
target_options Fields
All fields go inside target_options.linkedin on your post request.
| Field | Type | Description |
|---|---|---|
content | string | Override content for LinkedIn specifically |
media | object[] | Override media for LinkedIn specifically |
first_comment | string | Auto-posted first comment. Put links here to avoid reach suppression. |
document_title | string | Title displayed on PDF/document carousel posts |
disable_link_preview | boolean | Suppress URL preview card in the post (default: false) |
organization_urn | string | Deprecated identity assertion only. If supplied, it must exactly match the connected member/organization URN; it never retargets the post. |
Common Errors
| Error | Cause | Fix |
|---|---|---|
| Content is a duplicate (422) | Identical or very similar content posted recently | Modify text meaningfully. LinkedIn's duplicate detection is very strict. |
| Preflight checks failed | Rate limiting or validation issue | Space posts further apart. |
| Publishing failed max retries | All retry attempts failed | Temporary issue — retry manually after a few minutes. |
| Token expired | OAuth token expired | Reconnect the account via the dashboard or Connect API. |
| Cannot mix media types | Images + videos or images + documents in same post | Use only one media type per post. GIFs count as video. |
ORGANIZATION_URN_MISMATCH | Deprecated organization_urn does not equal the connector-selected identity | Target the correct connected account and remove the compatibility field; RelayAPI rejects the mismatch before provider I/O. |
Known Quirks
- Link suppression — posts with external URLs get 40-50% less reach. Always put links in
first_comment. - Very strict duplicate detection — even minor rephrasing may not bypass the 422 duplicate error.
- Cannot mix media types — images + videos or images + documents in the same post will fail.
- GIFs are converted to video and count against the 1-video-per-post limit.
- First ~210 characters visible before the "see more" fold. Front-load your hook.
- Company pages get 30-minute video limit, personal profiles get 10 minutes.
- Document carousels are the highest-engagement format but require a PDF, PPT, or DOC file.
Automations
LinkedIn automation uses the Versioned REST API (YYYYMM format) — version pinned in api-versions.ts.
The r_member_social scope is currently closed to new apps per Microsoft docs. Only approved Community Management API apps can use the triggers and send nodes below.
Triggers
| Type | Fires on |
|---|---|
linkedin_comment | Comment on your share |
linkedin_mention | @-mention |
linkedin_reaction | Reaction added to your share |
Send nodes
Base: https://api.linkedin.com/rest with LinkedIn-Version + X-Restli-Protocol-Version: 2.0.0 headers.
| Node | Endpoint | Required fields |
|---|---|---|
linkedin_reply_to_comment | POST /socialActions/{urn}/comments | text, share_urn |
linkedin_react_to_post | POST /reactions?actor={memberUrn} | reaction (default LIKE), share_urn |
Found something wrong? Help us improve this page.