# LinkedIn

Publish text, image, video, document and poll posts to LinkedIn personal profiles and organization pages with the Zernio API, with reposts, geo-restriction, multi-organization posting and text edits.

import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

Publish text, images, videos, documents and polls to LinkedIn with `POST /v1/posts` and `platform: "linkedin"`.

One connected account posts as a personal profile or as any organization page the member administers. The same account serves analytics and comments.

## 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 minutes (personal), 30 minutes (organization page) |
| Post types | Text, Image, Multi-image, Video, Document, Poll, Repost |
| Scheduling | Yes |
| Editing published posts | Yes (text only, 3,000 characters) |
| Inbox (comments) | Yes (organization pages only) |
| Comment automations | Public reply only, read by the comment poll ([comment automations](/comment-automations/create-comment-automation)) |
| Inbox (DMs) | No (LinkedIn blocks third-party DM access) |
| Analytics | Yes |

## Before you start

LinkedIn connects personal profiles and organization pages through the same account.

- **Organization pages** get full analytics, 30-minute videos and the comments API.
- **Personal profiles** get limited analytics and 10-minute videos.

A post carries one media type: images, one video or one document, never mixed.

<Callout type="warn">
LinkedIn rejects duplicate content with a `422`, even when the earlier post is weeks old.
</Callout>

## Connect

Call `GET /v1/connect/linkedin` with `profileId` on [Get OAuth connect URL](/connect/get-connect-url).

After OAuth, the user picks a personal profile or one of the organizations they administer, in standard or headless mode. See [platforms requiring secondary selection](/guides/connecting-accounts#platforms-requiring-secondary-selection).

The [connecting accounts guide](/guides/connecting-accounts) covers the flow and [scopes](/guides/connecting-accounts#scopes) in general. [Account health](/accounts/get-all-accounts-health) reports what a connected account can do with the scopes the user granted.

To switch an existing account between personal and organization posting without a second OAuth, call [Switch LinkedIn account type](/connect/update-linkedin-organization).

### OAuth scopes

LinkedIn connections request the widest scope set of any platform because one token covers personal posting, organization pages and ads.

## Publish a post

This request publishes a text post to LinkedIn right away.

<Tabs items={['Node.js', 'Python', 'curl']}>
<Tab value="Node.js">
```typescript
import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data: published } = await zernio.posts.createPost({
  body: {
    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: '66b2e19d8c3f5a7e9d0b1c2d' }
    ],
    publishNow: true
  }
});

console.log(published.post.platforms[0].platformPostUrl);
```
</Tab>
<Tab value="Python">
```python
from zernio import Zernio

client = Zernio()

published = client.posts.create_post(
    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": "66b2e19d8c3f5a7e9d0b1c2d"}
    ],
    publish_now=True
)

print(published["post"]["platforms"][0]["platformPostUrl"])
```
</Tab>
<Tab value="curl">
```bash
curl -X POST https://zernio.com/api/v1/posts \
  -H "Authorization: Bearer $ZERNIO_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": "66b2e19d8c3f5a7e9d0b1c2d"}
    ],
    "publishNow": true
  }'
```
</Tab>
</Tabs>

Every option is on [Posts](/platforms/linkedin/posts).

## Mentions

Put the profile or company URL inside `@[...]` in the post `content` (or in a LinkedIn entry's `customContent`): `@[https://www.linkedin.com/in/jane-doe]` or `@[https://www.linkedin.com/company/acme]`. The post resolves it and publishes LinkedIn's own name as the link text.

- Custom text is optional: `@[Jane](https://www.linkedin.com/in/jane-doe)`. It must be the person's first name, last name or full name, or the company's exact name, and it is case-sensitive. Anything else is replaced with LinkedIn's name and the response carries a `warnings` entry.
- `@[Name](urn:li:person:ID)` markup from [Get LinkedIn mentions](/linkedin-mentions/get-linkedin-mentions) (`GET /v1/accounts/{accountId}/linkedin-mentions`) is published exactly as written. It is never looked up or changed, so its text must already be LinkedIn's name.
- Looking up a person by profile URL needs one of your LinkedIn accounts to administer a LinkedIn Page. Company lookups do not. Publishing a person mention works from any account.
- A scheduled or published post whose profile or company URL cannot be resolved is rejected: `linkedin_mentions_invalid` with one entry per mention under `details.mentions`, `rate_limited`, `reconnect_required`, or a retryable `503` when LinkedIn does not answer in time. Drafts save and return the problems as warnings.
- A post resolves at most 10 profile or company URL mentions across its content and LinkedIn entries (`linkedin_mentions_limit_exceeded`). A draft is checked again when it is scheduled.
- Mentions in `firstComment` are posted as plain names.
- Other platforms receive only the text: `@[linkedin.com/in/jane]` becomes `jane` (the vanity) and `@[Jane](linkedin.com/in/jane)` becomes `Jane`.

## In this section

<PlatformPages platform="linkedin" />

## Related

- [Connecting accounts](/guides/connecting-accounts): the OAuth flow and the organization selection step.
- [Create post](/posts/create-post) and [Edit post](/posts/edit-post): every field of the request.
- [LinkedIn mentions](/linkedin-mentions/get-linkedin-mentions): resolve profile and company URLs to mention URNs for post content.
- [Media uploads](/guides/media-uploads): upload images, videos and documents instead of hosting them.
- [Comments](/comments/list-inbox-comments): the inbox API.
- [Pricing](/pricing): what analytics, the inbox and outbound messages cost, and which replies count.