How to Post to a LinkedIn Company Page via API

Posting to a LinkedIn company page requires different OAuth scopes and a different author URN than personal posts. Here's the full pattern with Postproxy.

Personal vs company: what’s actually different

The publish endpoint path is the same — POST /rest/posts. What changes:

Personal postCompany page post
OAuth scope requiredw_member_socialw_organization_social
Author URNurn:li:person:{member-id}urn:li:organization:{org-id}
Permission checkThe signed-in memberMember must have ADMINISTRATOR or CONTENT_ADMIN on the page

The wrong-scope failure mode is the most common: you have a working personal token, hit the publish endpoint with an organization URN, and LinkedIn returns 403 Forbidden — Insufficient permissions. Re-running OAuth with the right scope is the only fix.

With Postproxy: post to your personal profile

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": { "body": "Ten lessons from a year shipping infra." },
"profiles": ["linkedin"]
}'

Post to a company page (organization)

You connect the LinkedIn profile once. Then on each post, pass organization_id in the linkedin platform params to route to the company page instead of your personal profile:

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": { "body": "We are hiring a senior backend engineer. Apply at acme.com/careers." },
"profiles": ["linkedin"],
"platforms": {
"linkedin": {
"organization_id": "12345678"
}
}
}'

To list which organizations your connected LinkedIn account can post to, call:

Terminal window
curl -X GET "https://api.postproxy.dev/api/profiles/PROFILE_ID/placements" \
-H "Authorization: Bearer YOUR_API_KEY"

Response (LinkedIn example):

{
"placements": [
{ "id": null, "name": "Personal Profile" },
{ "id": "108520199", "name": "Acme Marketing" },
{ "id": "203488011", "name": "Acme Labs" }
]
}

id: null means your personal profile. Any other id is an organization you can post on behalf of — pass that as organization_id.

Posting media to a company page

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": { "body": "Q1 retrospective: what shipped, what slipped, what we learned." },
"profiles": ["linkedin"],
"media": ["https://yourcdn.com/q1-retro.png"],
"platforms": {
"linkedin": { "organization_id": "108520199" }
}
}'

LinkedIn supports image, video, and document attachments on company page posts.

Posting a PDF (document post)

PDFs render as inline carousels in the LinkedIn feed — useful for whitepapers and reports:

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": { "body": "Our Q1 report — 18 pages on what we built." },
"profiles": ["linkedin"],
"media": ["https://yourcdn.com/q1-report.pdf"],
"platforms": {
"linkedin": { "organization_id": "108520199" }
}
}'

Documents must be alone — don’t mix with images or videos. PDFs cap at 100 MB / 300 pages.

Multiple company pages from one account

If your account administers several pages (agency, holding company, multi-brand), make one request per page — each carries its own organization_id. Using the Python SDK:

import asyncio
from postproxy import PostProxy, PlatformParams, LinkedInParams
async def fan_out(org_ids):
async with PostProxy("your-api-key", profile_group_id="pg-abc") as client:
for org_id in org_ids:
await client.posts.create(
"New whitepaper out: acme.com/whitepaper",
profiles=["linkedin"],
platforms=PlatformParams(
linkedin=LinkedInParams(organization_id=org_id),
),
)
asyncio.run(fan_out(["108520199", "203488011", "311945522"]))

Scheduling company page posts

LinkedIn’s API has no scheduled_publish_time. Use Postproxy’s scheduled_at:

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"body": "Live at 9 AM ET: our CEO on the state of the industry.",
"scheduled_at": "2026-05-15T13:00:00Z"
},
"profiles": ["linkedin"],
"platforms": {
"linkedin": { "organization_id": "108520199" }
}
}'

Personal voice + company headline

A common pattern: post the headline from the company page and the founder’s reflection from their personal profile. Two requests, one media set:

async with PostProxy("your-api-key", profile_group_id="pg-abc") as client:
media = ["https://yourcdn.com/v3-launch.png"]
await client.posts.create(
"v3 is live. Engineering deep-dive on the blog: acme.com/blog/v3",
profiles=["linkedin"],
media=media,
platforms=PlatformParams(
linkedin=LinkedInParams(organization_id="108520199"),
),
)
await client.posts.create(
"Two years of engineering went into this. Here is what I am proud of:",
profiles=["linkedin"],
media=media,
)

Common 403 / 422 errors

ErrorWhat it actually means
403 Insufficient permissionsOAuth scope is missing w_organization_social. Re-auth.
403 Not enough permissions to accessThe member is not an admin/content-admin of the page. Add them in LinkedIn page settings.
422 Invalid author URNPersonal token used with an organization URN, or vice versa. Check organization_id.
429 ThrottledDaily post limit hit.

For a longer walkthrough of the company page automation pattern, see LinkedIn API: automate company page publishing.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.