LinkedIn API
Postproxy publishes feed posts and polls to a LinkedIn personal profile or a company page (organization), including image, video, and document (PDF/slide) posts.
Every request below uses the base URL https://api.postproxy.dev and an Authorization: Bearer YOUR_API_KEY header. Replace YOUR_API_KEY and the example IDs with your own.
Profiles and profile groups
Section titled “Profiles and profile groups”Every post targets one or more profiles. A profile is one connected account — for LinkedIn, a personal profile or a company page (organization). Reference one in a request by its id (the prof_abc123 in the examples below) or by the platform name "linkedin", which selects the group’s LinkedIn profile (a group holds at most one profile per platform). List what’s connected with GET /api/profiles.
Profiles live in profile groups — containers that organize the accounts for one brand, client, or project. List groups with GET /api/profile_groups, and connect a new LinkedIn profile with the Initialize Connection endpoint.
Example: get profiles and profile groups
List the profiles you can post to — GET /api/profiles:
curl -X GET "https://api.postproxy.dev/api/profiles" \ -H "Authorization: Bearer YOUR_API_KEY"{ "data": [ { "id": "prof_abc123", "name": "My Company", "platform": "linkedin", "status": "active", "profile_group_id": "grp_xyz789", "expires_at": null, "post_count": 53, "avatar_url": "https://cdn.postproxy.dev/uploads/avatar_prof_abc123.jpg" } ]}List your profile groups — GET /api/profile_groups:
curl -X GET "https://api.postproxy.dev/api/profile_groups" \ -H "Authorization: Bearer YOUR_API_KEY"{ "data": [ { "id": "grp_xyz789", "name": "Main Brand", "profiles_count": 5 }, { "id": "grp_def456", "name": "Client Project", "profiles_count": 3 } ]}At a glance
Section titled “At a glance”| Platform ID | linkedin |
| Formats | post (default), poll |
| Character limit | 3,000 |
| Media | Optional |
| Placements | Personal profile + organizations — selected with organization_id |
| Reshares | Yes — pass reshare_urn |
| Polls | Yes — see Polls |
| Country targeting | Organization posts — see Country targeting |
| Mentions | Company pages — see Mentions; person lookup coming soon |
| Comments | Coming soon |
| Direct messages | No |
| Post chains | No |
Publishing
Section titled “Publishing”Formats
Section titled “Formats”| Format | Description |
|---|---|
post | Feed post (default) |
poll | Native LinkedIn poll — see Polls |
Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | No | Post as a company page. Omit to post on the personal profile |
reshare_urn | string | No | Reshare an existing LinkedIn post — see Resharing |
alt_text | string or array | No | Alt text for images (single and multi-image posts) — see Alt text |
countries | array or string | No | Show the post only to members in these countries (organization posts) — see Country targeting |
| Media | Max size | Formats | Count | Duration |
|---|---|---|---|---|
| Image | 8 MB | jpg, png, gif | 20 | — |
| Video | 5 GB | mp4, mov, avi | 1 | up to 15 min |
| Document | 100 MB | pdf, doc, docx, ppt, pptx | 1 | — |
- Text-only posts are allowed; media is optional.
- Images and video cannot be mixed.
- A document must be posted on its own — it cannot be combined with images or video. Max 300 pages.
- Minimum image dimensions: 552×276 px.
# Post to the personal profilecurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "We are excited to share our latest product update!" }, "profiles": ["prof_abc123"], "media": ["https://example.com/image.jpg"], "platforms": { "linkedin": {} } }'# Post to a company pagecurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Hiring! We are growing the engineering team." }, "profiles": ["prof_abc123"], "platforms": { "linkedin": { "organization_id": "12345678" } } }'# Document (PDF carousel) — must be the only attachmentcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Our 2026 industry report — free download." }, "profiles": ["prof_abc123"], "media": ["https://example.com/report.pdf"], "platforms": { "linkedin": { "organization_id": "12345678" } } }'Set format to poll to publish a native LinkedIn poll. The post body becomes the commentary shown above the poll, poll_question is what members vote on, and poll_options lists the choices. Voting is single-select and closes after poll_duration_days.
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | No | Publish the poll as a company page. Omit to post on the personal profile |
poll_question | string | Yes | 1–140 characters |
poll_options | array of strings | Yes | 2–4 choices, max 30 characters each |
poll_duration_days | integer | No | How long the poll accepts votes: 1, 3, 7, or 14. Defaults to 7 |
countries | array or string | No | Organization polls only — see Country targeting |
- Polls can’t carry media —
mediatogether with thepollformat returns a422. - Polls can’t be combined with
reshare_urn, and can’t be edited after publishing. - LinkedIn forbids polls that ask for political opinions, health status, or other sensitive data.
- Available in the composer as a content-type toggle, and via the API.
# Publish a pollcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "We are picking next quarter'"'"'s stack." }, "profiles": ["prof_abc123"], "platforms": { "linkedin": { "format": "poll", "poll_question": "Which framework do you prefer?", "poll_options": ["Rails", "Django", "Laravel", "Other"], "poll_duration_days": 7 } } }'Country targeting
Section titled “Country targeting”Restrict an organization-page post (feed post or poll) so only members in the given countries see it in the feed. Pass countries as ISO 3166-1 alpha-2 codes — an array or a comma-separated string, up to 25 countries, case-insensitive.
# Feed post visible only to members in the US, Canada, and the UKcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "North America and UK: our regional pricing just launched." }, "profiles": ["prof_abc123"], "platforms": { "linkedin": { "organization_id": "12345678", "countries": ["US", "CA", "GB"] } } }'- LinkedIn only allows targeting on organization pages —
countrieswithoutorganization_idreturns a422. - LinkedIn requires the targeted audience to exceed 300 of the page’s followers; a smaller audience fails at publish time with LinkedIn’s error.
- Targeting is set at publish time and can’t be changed afterwards.
Supported country codes
AE, AR, AT, AU, BD, BE, BG, BH, BR, BY, CA, CH, CL, CN, CO, CR, CY, CZ, DE, DK, EE, EG, ES, FI, FR, GB, GE, GH, GR, HK, HR, HU, ID, IE, IL, IN, IS, IT, JO, JP, KE, KR, KW, KZ, LB, LK, LT, LU, LV, MA, MT, MX, MY, NG, NL, NO, NP, NZ, OM, PA, PE, PH, PK, PL, PT, QA, RO, RS, RU, SA, SE, SG, SI, SK, TH, TN, TR, TW, UA, US, UY, VE, VG, VI, VN, ZA. Any other code returns a 422.
Resharing
Section titled “Resharing”Reshare an existing LinkedIn post by passing reshare_urn in the LinkedIn platform parameters — on POST /api/posts, or PATCH it onto a post that hasn’t published yet. The post body becomes the commentary shown above the reshared post; send an empty body for a plain repost.
reshare_urn accepts either form:
| Value | Example |
|---|---|
| Post URN | urn:li:share:7123456789012345678, urn:li:ugcPost:…, urn:li:activity:… |
| LinkedIn post URL | https://www.linkedin.com/feed/update/urn:li:activity:7123456789012345678/ |
- A pasted URL is normalized to its URN, and that normalized value is what
platforms[].paramsreturns. - A value that can’t be parsed into a URN returns a
422. - A reshare can’t carry its own media — LinkedIn shows the reshared post’s media instead — so
mediatogether withreshare_urnreturns a422. - Combine
reshare_urnwithorganization_idto reshare as a company page. - API only for now — the composer has no field for it yet.
# Reshare with commentary, on the personal profilecurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "This matches what we are seeing too." }, "profiles": ["prof_abc123"], "platforms": { "linkedin": { "reshare_urn": "urn:li:share:7123456789012345678" } } }'# Plain repost as a company page — empty body, pasted post URLcurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "" }, "profiles": ["prof_abc123"], "platforms": { "linkedin": { "organization_id": "12345678", "reshare_urn": "https://www.linkedin.com/feed/update/urn:li:activity:7123456789012345678/" } } }'Mentions
Section titled “Mentions”@-mention a company page by writing @[Display Name](urn) into the post body — for example @[Postproxy](urn:li:organization:110810308). Without the URN the mention publishes as plain text: no link, no notification.
Get the URN from GET /api/profiles/:id/resolve_mention, which turns a company page URL (or just its slug) into the URN plus the page’s display name. Company, showcase, and school pages all resolve — the page doesn’t have to be one you administer.
# 1. Resolve the pagecurl -X GET "https://api.postproxy.dev/api/profiles/prof_abc123/resolve_mention?url=https://www.linkedin.com/company/postproxy" \ -H "Authorization: Bearer YOUR_API_KEY"# → { "urn": "urn:li:organization:110810308", "name": "Postproxy", ... }
# 2. Mention it in the post bodycurl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Publishing this via @[Postproxy](urn:li:organization:110810308) — one API for every network." }, "profiles": ["prof_abc123"] }'Person mentions can’t be resolved yet — person lookup is coming soon.
Placements
Section titled “Placements”A LinkedIn profile can publish to the personal profile and to any organizations the account administers. List them with the placements endpoint:
- The personal profile is returned with
id: null. - Each organization’s
idis the value you pass asorganization_id.
# List placements (personal profile + organizations)curl "https://api.postproxy.dev/api/profiles/prof_abc123/placements" \ -H "Authorization: Bearer YOUR_API_KEY"Omit organization_id to publish on the personal profile.
Comments
Section titled “Comments”Coming soon. Comment list, reply, hide, and delete support for LinkedIn is in progress. When live, comments will be managed through the Comments API.
Direct messages
Section titled “Direct messages”Not supported.
Postproxy records periodic stat snapshots you can pull as a timeseries; field names pass through from LinkedIn unchanged.
Profile stats
Section titled “Profile stats”Follower and page-view metrics for company pages, refreshed roughly every 23 hours and scoped per organization — pass the placement_id. See the Profile stats endpoint (GET /api/profiles/:id/stats).
Fields: followerCount, shareCount, likeCount, commentCount, clickCount, engagement, allPageViews, overviewPageViews, aboutPageViews, careersPageViews, peoplePageViews, insightsPageViews
# Fetch the stats timeseries for one organization (placement_id is the organization_id)curl "https://api.postproxy.dev/api/profiles/prof_abc123/stats?placement_id=12345678" \ -H "Authorization: Bearer YOUR_API_KEY"Post stats
Section titled “Post stats”Per-post engagement, captured after publish via the Post stats endpoint (GET /api/posts/stats). Organization posts only — LinkedIn returns no stats for personal (member) profiles. LinkedIn currently reports impressions only.
Fields: impressions
# Fetch post statscurl "https://api.postproxy.dev/api/posts/stats?post_ids=post_abc123&profiles=linkedin" \ -H "Authorization: Bearer YOUR_API_KEY"Webhooks
Section titled “Webhooks”Subscribe with the Webhooks API:
curl -X POST "https://api.postproxy.dev/api/webhooks" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/webhooks/postproxy", "events": ["platform_post.published", "platform_post.insights", "profile.stats"] }'Events relevant to LinkedIn:
| Event | When |
|---|---|
post.processed | A post is ready to publish |
platform_post.published | A post was published to the platform |
platform_post.failed | A post failed to publish (retries exhausted) |
platform_post.failed_waiting_for_retry | A publish attempt failed; will retry |
platform_post.insights | New analytics snapshot |
profile.connected / .disconnected | Connection state changed |
profile.stats | New profile stats snapshot — fires once per organization (not for the personal profile) |
media.failed | A media attachment failed to process |
What you can’t do
Section titled “What you can’t do”LinkedIn’s API doesn’t expose the following, so they aren’t available through Postproxy:
- Publishing long-form articles (the
linkedin.com/article/neweditor). - Sending direct messages or InMail.
- Scheduling or posting events.
- Starting or sending newsletters.
- Reacting to other people’s posts.
- Following hashtags.
- Mentioning individual people — company-page mentions work today; person lookup is coming soon.
- Combining different media types in one post — images can’t run alongside video, and a document can’t share a post with images or video.
- Retrieving past posts, profile stats, or post insights for a personal profile — LinkedIn’s API only exposes history and analytics for organizations.
- Choose the audience with
organization_id: present → company page, absent → personal profile. - Document posts (PDF, DOCX, PPTX) render as LinkedIn’s native multi-page carousel and must be the only attachment.
- A reshare is a normal post with
reshare_urnset — thebodyis the commentary, and it can’t add media of its own.