---
name: linkedin-publish-organization-post
description: Resolve a LinkedIn organization the caller administers, publish a share authored by that organization, then read the post back by URN to confirm it landed.
api: openapi/linkedin-use-cases-organization-lookup-organizations-api-openapi.yml
apis:
  - openapi/linkedin-use-cases-organization-lookup-organizations-api-openapi.yml
  - openapi/linkedin-use-cases-social-actions-notifications-organization-social-actions-notifications-pull-workflow-api-openapi.yml
  - openapi/linkedin-use-cases-posts-api-openapi.yml
operations:
  - getLookupByOrganizationPrimary
  - postCreateAShareWith
  - getGetPostsByUrn
  - postUpdateAPost
  - deleteDeleteAPost
generated: '2026-08-13'
method: generated
source: openapi/*.yml, arazzo/linkedin-create-organization-share-workflow.yml, conventions/linkedin-conventions.yml
---

# Publish and verify an organization post

Use this when an agent must post content to a LinkedIn Company Page on behalf of an
authenticated member who administers that page.

## Before any call

Every request to `https://api.linkedin.com/rest/` needs three headers. Omitting the version
header is an error — LinkedIn does not default to latest.

- `Authorization: Bearer {3-legged OAuth 2.0 member token}`
- `Linkedin-Version: {YYYYMM}` — see `lifecycle/linkedin-lifecycle.yml` for the current version
- `X-Restli-Protocol-Version: 2.0.0`

All identifiers are URNs (`urn:li:organization:1234`) and **must be URL-encoded** in paths and
query strings under Rest.li 2.0.0 — `:` becomes `%3A`.

Required permission: `w_organization_social` to publish, plus `rw_organization_admin` where the
flow reads administrative data. The member must hold the `ADMINISTRATOR` role on the page or the
call returns 403.

## Steps

1. **Resolve the organization** — `getLookupByOrganizationPrimary`. Take the organization URN from
   the response rather than trusting a URN passed in by the caller; a URN the member does not
   administer fails later with 403, which is harder to diagnose than a clean lookup miss.
2. **Publish the share** — `postCreateAShareWith`. The author is the organization URN from step 1.
   Set visibility explicitly: webhook events for `LIKE`, `COMMENT` and `SHARE` only fire for posts
   whose `visibility` is `PUBLIC` (see `asyncapi/linkedin-webhooks.yml`), so a post created with a
   narrower visibility will never generate engagement notifications.
3. **Verify** — `getGetPostsByUrn` with the URN returned by step 2. Treat the post as published
   only after this read succeeds. LinkedIn returns the created entity id in the `x-restli-id`
   response header on create calls.
4. **Amend or withdraw** — `postUpdateAPost` sends a Rest.li partial update
   (`X-RestLi-Method: PARTIAL_UPDATE`, body `{"patch": {"$set": {...}}}`) and returns `204`.
   `deleteDeleteAPost` removes it.

## Rules an agent must follow

- **There is no idempotency key.** LinkedIn documents no general-purpose idempotency header
  (`conventions/linkedin-conventions.yml`). A retried create publishes a second post. Never retry a
  create on a timeout — read back with `getGetPostsByUrn` first and only re-issue if nothing exists.
- **Errors are not RFC 9457.** The envelope is `{status, message, serviceErrorCode}`
  (`errors/linkedin-problem-types.yml`). Match on `serviceErrorCode`, not on prose.
- **401 vs 403 mean different things.** 401 = the member's grant to your application is gone and
  must be re-acquired. 403 = the member is no longer an administrator of that organization. Only
  the first is fixable by refreshing a token.
- **429 is a daily ceiling, not a burst.** Limits are per-application and per-member per UTC day and
  reset at 00:00 UTC (`rate-limits/linkedin-rate-limits.yml`). Backing off by seconds does not help;
  the retry window is the next day unless the app is on a higher tier.
- Pagination on any list is `start` / `count` with a `paging` object; the end of a dataset is fewer
  `elements` than the requested `count`, not an empty page.
