LinkedIn API
Schedule and automate LinkedIn posts with Zernio API - Personal profiles, company pages, images, videos, documents, and multi-organization posting
Quick Reference
| Property | Value |
|---|---|
| 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 | 8 MB |
| Video formats | MP4, MOV, AVI |
| Video max size | 5 GB |
| Video max duration | 10 min (personal), 30 min (company page) |
| Post types | Text, Image, Multi-image, Video, Document |
| Scheduling | Yes |
| Inbox (Comments) | Yes (add-on, company pages only) |
| Inbox (DMs) | No (LinkedIn blocks third-party DM access) |
| Analytics | Yes |
Before You Start
LinkedIn actively suppresses posts containing external links. Your post's organic reach can drop 40-50% if you include a URL in the caption. Best practice: put your link in the first comment using the firstComment field. Also: LinkedIn rejects duplicate content with a 422 error. You cannot post the same text twice, even across different time periods.
Additional details:
- Works with personal profiles AND company pages
- Company pages: full analytics, 30-min video, comments API
- Personal profiles: limited analytics, 10-min video
- Cannot mix media types (images + videos or images + documents in the same post)
- First ~210 characters of your post are visible before the "see more" fold
Quick Start
Post to LinkedIn in under 60 seconds:
const { post } = await zernio.posts.createPost({
content: 'Excited to share our latest update!\n\nWe have been working hard on this feature...',
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Excited to share our latest update!\n\nWe have been working hard on this feature...",
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Excited to share our latest update!\n\nWe have been working hard on this feature...",
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Content Types
Text-Only Post
Text posts get the highest organic reach on LinkedIn. The first ~210 characters appear before the "see more" fold, so lead with your hook. Up to 3,000 characters total.
const { post } = await zernio.posts.createPost({
content: 'I spent 3 years building the wrong product.\n\nHere is what I learned about validating ideas before writing code...',
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="I spent 3 years building the wrong product.\n\nHere is what I learned about validating ideas before writing code...",
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "I spent 3 years building the wrong product.\n\nHere is what I learned about validating ideas before writing code...",
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Single Image Post
Attach one image to a post. Recommended size is 1200 x 627 px (landscape).
const { post } = await zernio.posts.createPost({
content: 'Our new office setup is looking great!',
mediaItems: [
{ type: 'image', url: 'https://cdn.example.com/office.jpg' }
],
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Our new office setup is looking great!",
media_items=[
{"type": "image", "url": "https://cdn.example.com/office.jpg"}
],
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Our new office setup is looking great!",
"mediaItems": [
{"type": "image", "url": "https://cdn.example.com/office.jpg"}
],
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Multi-Image Post
LinkedIn supports up to 20 images in a single post. Cannot include videos or documents alongside images.
const { post } = await zernio.posts.createPost({
content: 'Highlights from our team retreat!',
mediaItems: [
{ type: 'image', 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' }
],
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Highlights from our team retreat!",
media_items=[
{"type": "image", "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"}
],
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Highlights from our team retreat!",
"mediaItems": [
{"type": "image", "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"}
],
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Video Post
One video per post. Personal profiles support up to 10 minutes, company pages up to 30 minutes. MP4, MOV, and AVI formats.
const { post } = await zernio.posts.createPost({
content: 'Watch our latest product demo',
mediaItems: [
{ type: 'video', url: 'https://cdn.example.com/demo.mp4' }
],
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Watch our latest product demo",
media_items=[
{"type": "video", "url": "https://cdn.example.com/demo.mp4"}
],
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Watch our latest product demo",
"mediaItems": [
{"type": "video", "url": "https://cdn.example.com/demo.mp4"}
],
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Document/Carousel Post
LinkedIn uniquely supports document uploads (PDF, PPT, PPTX, DOC, DOCX) that display as swipeable carousels. Max 100 MB, up to 300 pages. Cannot include images or videos alongside a document.
const { post } = await zernio.posts.createPost({
content: 'Download our 2024 Industry Report',
mediaItems: [
{ type: 'document', url: 'https://cdn.example.com/report.pdf' }
],
platforms: [
{ platform: 'linkedin', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Download our 2024 Industry Report",
media_items=[
{"type": "document", "url": "https://cdn.example.com/report.pdf"}
],
platforms=[
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Download our 2024 Industry Report",
"mediaItems": [
{"type": "document", "url": "https://cdn.example.com/report.pdf"}
],
"platforms": [
{"platform": "linkedin", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Document tips:
- First page is the cover/preview -- design it to grab attention
- Design for mobile viewing (large fonts, minimal text per slide)
- Ideal length for engagement: 10-15 pages
- Password-protected PDFs will not work
Media Requirements
Images
| Property | Requirement |
|---|---|
| Max images | 20 per post |
| Formats | JPEG, PNG, GIF |
| Max file size | 8 MB per image |
| Recommended | 1200 x 627 px |
| Min dimensions | 552 x 276 px |
| Max dimensions | 8192 x 8192 px |
Aspect Ratios
| Type | Ratio | Dimensions | Use Case |
|---|---|---|---|
| Landscape | 1.91:1 | 1200 x 627 px | Link shares, standard |
| Square | 1:1 | 1080 x 1080 px | Engagement |
| Portrait | 1:1.25 | 1080 x 1350 px | Mobile feed |
Videos
| Property | Requirement |
|---|---|
| Max videos | 1 per post |
| Formats | MP4, MOV, AVI |
| Max file size | 5 GB |
| Max duration | 10 min (personal), 30 min (company page) |
| Min duration | 3 seconds |
| Resolution | 256 x 144 px to 4096 x 2304 px |
| Aspect ratio | 1:2.4 to 2.4:1 |
| Frame rate | 10-60 fps |
Recommended Video Specs
| Property | Recommended |
|---|---|
| Resolution | 1920 x 1080 px (1080p) |
| Aspect ratio | 16:9 (landscape) or 1:1 (square) |
| Frame rate | 30 fps |
| Codec | H.264 |
| Audio | AAC, 192 kbps |
| Bitrate | 10-30 Mbps |
Documents
| Property | Requirement |
|---|---|
| Max documents | 1 per post |
| Formats | PDF, PPT, PPTX, DOC, DOCX |
| Max file size | 100 MB |
| Max pages | 300 pages |
Platform-Specific Fields
All fields go inside platformSpecificData on the LinkedIn platform entry.
| Field | Type | Description |
|---|---|---|
documentTitle | string | Title displayed on LinkedIn document (PDF/carousel) posts. Required by LinkedIn for document posts. If omitted, falls back to the media item title, then the filename. |
organizationUrn | string | Post to a specific LinkedIn company page. Format: urn:li:organization:123456. Get available orgs via GET /v1/accounts/{accountId}/linkedin-organizations. If omitted, posts to default org or personal profile. |
firstComment | string | Auto-posted as first comment after publish. Best practice: put external links here since LinkedIn suppresses link posts by 40-50%. |
disableLinkPreview | boolean | Set to true to suppress the automatic URL preview card. Default: false. |
geoRestriction | object | Restrict post visibility to specific countries. Organization pages only, requires 300+ targeted followers. See Geo-Restriction below. |
Geo-Restriction
Restrict who can see your LinkedIn post by country. This is a hard visibility restriction: only followers in the specified countries see the post. Organization pages only (not personal profiles). LinkedIn requires the targeted audience to exceed 300 followers or the post will be rejected.
{
"platforms": [{
"platform": "linkedin",
"accountId": "YOUR_ORG_ACCOUNT_ID",
"platformSpecificData": {
"geoRestriction": {
"countries": ["US", "ES"]
}
}
}]
}geoRestriction.countries accepts up to 25 uppercase ISO 3166-1 alpha-2 country codes. Zernio automatically resolves country codes to LinkedIn geo URNs. Currently supports 44 countries; unsupported country codes are silently skipped.
LinkedIn Document Titles
LinkedIn requires a title for document (PDF/carousel) posts. Set platformSpecificData.documentTitle to control the title shown on LinkedIn.
Note: If
documentTitleis omitted, Zernio falls back to the media itemtitle, then thefilename.
curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Download our 2024 Industry Report",
"mediaItems": [
{"type": "document", "url": "https://cdn.example.com/report.pdf"}
],
"platforms": [{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"documentTitle": "2024 Industry Report"
}
}],
"publishNow": true
}'const { post } = await zernio.posts.createPost({
content: 'Download our 2024 Industry Report',
mediaItems: [
{ type: 'document', url: 'https://cdn.example.com/report.pdf' }
],
platforms: [{
platform: 'linkedin',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
documentTitle: '2024 Industry Report'
}
}],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Download our 2024 Industry Report",
media_items=[
{"type": "document", "url": "https://cdn.example.com/report.pdf"}
],
platforms=[{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"documentTitle": "2024 Industry Report"
}
}],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")Multi-Organization Posting
If your connected LinkedIn account manages multiple organizations (company pages), you can post to different organizations from the same account connection.
List available organizations:
const organizations = await zernio.accounts.getLinkedInOrganizations('YOUR_ACCOUNT_ID');
console.log('Available organizations:', organizations);organizations = client.accounts.get_linkedin_organizations("YOUR_ACCOUNT_ID")
print("Available organizations:", organizations)curl -X GET https://zernio.com/api/v1/accounts/YOUR_ACCOUNT_ID/linkedin-organizations \
-H "Authorization: Bearer YOUR_API_KEY"Post to multiple organizations using the same accountId with different organizationUrn values:
const { post } = await zernio.posts.createPost({
content: 'Exciting updates from our organization!',
platforms: [
{
platform: 'linkedin',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: { organizationUrn: 'urn:li:organization:111111111' }
},
{
platform: 'linkedin',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: { organizationUrn: 'urn:li:organization:222222222' }
}
],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Exciting updates from our organization!",
platforms=[
{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {"organizationUrn": "urn:li:organization:111111111"}
},
{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {"organizationUrn": "urn:li:organization:222222222"}
}
],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Exciting updates from our organization!",
"platforms": [
{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"organizationUrn": "urn:li:organization:111111111"
}
},
{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"organizationUrn": "urn:li:organization:222222222"
}
}
],
"publishNow": true
}'The organizationUrn format is urn:li:organization: followed by the organization ID.
First Comment
Put external links in the first comment to avoid LinkedIn's link suppression algorithm:
const { post } = await zernio.posts.createPost({
content: 'We just published our guide to API design patterns.\n\nLink in the first comment.',
platforms: [{
platform: 'linkedin',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
firstComment: 'Read the full guide here: https://example.com/api-guide'
}
}],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="We just published our guide to API design patterns.\n\nLink in the first comment.",
platforms=[{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"firstComment": "Read the full guide here: https://example.com/api-guide"
}
}],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "We just published our guide to API design patterns.\n\nLink in the first comment.",
"platforms": [{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"firstComment": "Read the full guide here: https://example.com/api-guide"
}
}],
"publishNow": true
}'Disable Link Preview
When posting text with URLs and no media, LinkedIn auto-generates a link preview card. To suppress it:
const { post } = await zernio.posts.createPost({
content: 'Check out our latest blog post! https://example.com/blog/new-post',
platforms: [{
platform: 'linkedin',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
disableLinkPreview: true
}
}],
publishNow: true
});
console.log('Posted to LinkedIn!', post._id);result = client.posts.create(
content="Check out our latest blog post! https://example.com/blog/new-post",
platforms=[{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"disableLinkPreview": True
}
}],
publish_now=True
)
post = result.post
print(f"Posted to LinkedIn! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Check out our latest blog post! https://example.com/blog/new-post",
"platforms": [{
"platform": "linkedin",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"disableLinkPreview": true
}
}],
"publishNow": true
}'Media URL Requirements
These do not work as media URLs:
- Google Drive -- returns an HTML download page, not the file
- Dropbox -- returns an HTML preview page
- OneDrive / SharePoint -- returns HTML
- iCloud -- returns HTML
Test your URL in an incognito browser window. If you see a webpage instead of the raw image or video, it will not work.
Media URLs must be:
- Publicly accessible (no authentication required)
- Returning actual media bytes with the correct
Content-Typeheader - Not behind redirects that resolve to HTML pages
- Hosted on a fast, reliable CDN
Supabase URLs: Zernio auto-proxies Supabase storage URLs, so they work without additional configuration.
Analytics
Requires Analytics add-on
Available metrics via the Analytics API:
| Metric | Available |
|---|---|
| Impressions | ✅ |
| Reach | ✅ |
| Likes | ✅ |
| Comments | ✅ |
| Shares | ✅ |
| Saves | ✅ (personal accounts only) |
| Sends | ✅ (personal accounts only, LinkedIn messaging) |
| Clicks | ✅ (organization accounts only) |
| Views | ✅ (video posts only) |
LinkedIn also provides dedicated analytics endpoints for deeper insights:
- Personal Aggregate Analytics -- Totals or daily time series across a personal account's posts. Covers impressions, reach, reactions, comments, shares, saves, sends.
- Organization Aggregate Analytics -- Impressions, clicks, reactions, engagement rate, follower gains (organic vs paid), and page-view metrics for organization pages. Requires the authenticated member to be an ADMINISTRATOR on the org and all three org scopes (r_organization_social + r_organization_followers + r_organization_admin).
- Post Analytics -- Per-post metrics by URN. Works for both personal and organization accounts (saves and sends are personal-only, org returns 0).
- Post Reactions -- Individual reactions with reactor profiles (organization accounts only).
const analytics = await zernio.analytics.getAnalytics({
platform: 'linkedin',
fromDate: '2024-01-01',
toDate: '2024-01-31'
});
console.log(analytics.posts);analytics = client.analytics.get(
platform="linkedin",
from_date="2024-01-01",
to_date="2024-01-31"
)
print(analytics["posts"])curl "https://zernio.com/api/v1/analytics?platform=linkedin&fromDate=2024-01-01&toDate=2024-01-31" \
-H "Authorization: Bearer YOUR_API_KEY"What You Can't Do
These features are not available through LinkedIn's API:
- Publish long-form articles (linkedin.com/article/new/)
- Create polls
- Create events
- Send InMail or DMs
- Create newsletters
- Add reactions to other posts
- Create hashtag-following or tag connections
- Mix media types (images + videos or images + documents in the same post)
Common Errors
LinkedIn has a 9.5% failure rate across Zernio's platform (8,082 failures out of 85,512 attempts). Here are the most frequent errors and how to fix them:
| Error | What it means | How to fix |
|---|---|---|
| "Content is a duplicate of urn:li:share:XXXX" (422) | Identical or very similar content was already posted | Modify the text meaningfully. LinkedIn's duplicate detection is strict -- even minor rephrasing may not be enough. |
| "Publishing failed during preflight checks" | Rate limiting or validation caught an issue before publishing | Space posts further apart. Check account health in the dashboard. |
| "Publishing failed due to max retries reached" | All 3 retry attempts failed | Temporary issue. Retry manually or check LinkedIn's status page. |
| Token expired | OAuth access token has expired or been revoked | Reconnect the LinkedIn account. Subscribe to the account.disconnected webhook to catch this proactively. |
| "Cannot mix media types" | Post contains images + videos or images + documents | Use only one media type per post. |
| Video processing failed | Codec, duration, or aspect ratio is out of spec | Ensure codec is H.264, duration is within limits (10 min personal / 30 min company), and aspect ratio is between 1:2.4 and 2.4:1. |
| Link preview showing wrong image | Open Graph meta tags on the URL are incorrect or missing | Update the og:image tag on your website. LinkedIn caches previews -- use the LinkedIn Post Inspector to refresh. |
Inbox
Requires Inbox add-on, Build: +$10/mo · Accelerate: +$50/unit · Unlimited: +$1,000/mo
LinkedIn supports comments only (no DMs via API).
Comments
| Feature | Supported |
|---|---|
| List comments on posts | ✅ |
| Reply to comments | ✅ |
| Delete comments | ✅ |
| Like comments | ❌ (API restricted) |
Limitations
- No DMs - LinkedIn's messaging API is not available for third-party apps
- Organization accounts only - Comments require an organization (company page) account type
- No comment likes - Liking/reacting to comments via API is restricted. However, you can read post reactions via
GET /v1/accounts/{accountId}/linkedin-post-reactions(organization accounts only).
See Comments API Reference for endpoint details.
Related Endpoints
- Connect LinkedIn Account - OAuth flow
- Create Post - Post creation and scheduling
- Upload Media - Image and video uploads
- LinkedIn Organizations - List company pages
- LinkedIn Mentions - Track brand mentions
- LinkedIn Aggregate Analytics - Organization-level analytics
- LinkedIn Post Analytics - Post-level performance metrics
- LinkedIn Post Reactions - Who reacted to a post (organization accounts)
- Comments - Inbox API