Publishing LinkedIn Posts via the UGC API v2: Steps, Example, and Pitfalls
Publish LinkedIn posts programmatically using the UGC API v2. Learn to handle OAuth tokens, two-step media uploads, and pagination while avoiding rate limits.
18 Jan 2026, 23:22 UTC

Publishing Programmatically to LinkedIn
To publish a post from a server, send a JSON payload to POST https://api.linkedin.com/v2/ugcPosts using an OAuth 2.0 access token with the w_member_social (or w_social) scope. The request requires a specific structure: the author's URN, a lifecycle state of PUBLISHED, a specificContent object defining the post type, and a visibility setting. For media-rich posts, you must first register the asset and upload the binary before referencing the resulting asset URN in the final post payload.
Authentication and Token Management
All requests must include an Authorization: Bearer {access_token} header. To identify the author URN (e.g., urn:li:person:123456789), call GET https://api.linkedin.com/v2/me. Note that LinkedIn access tokens typically expire after 60 days; your application must implement a refresh logic to prevent 401 Unauthorized errors during automated publishing.
Minimal Text-Only Post Configuration
Ensure the Content-Type is set to application/json. Sending data as form-data will result in a 400 Bad Request.
POST /v2/ugcPosts HTTP/1.1
Host: api.linkedin.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"author": "urn:li:person:YOUR_MEMBER_ID",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": {
"text": "Automated technical update from my server."
},
"shareMediaCategory": "NONE"
}
},
"visibility": {
"comMemberNetwork": "PUBLIC"
}
}
A successful request returns an HTTP 201 Created status and a post URN (e.g., urn:li:ugcPost:12345).
Two-Step Media Upload Workflow
Media cannot be sent directly in the ugcPosts payload. It requires a separate asset registration process.
1. Register the Upload
Request an upload URL by calling POST https://api.linkedin.com/v2/assets?action=registerUpload with the following metadata:
{
"registerRequest": {
"serviceName": "ImageUpload",
"mediaMetadata": {
"digitalType": "image/jpeg",
"width": 1000,
"height": 600
}
}
}
The API returns an uploadUrl and an asset URN.
2. Upload Binary Data
Perform a PUT request to the provided uploadUrl. The body must be the raw binary file, and the Content-Type header must match the digitalType specified during registration (e.g., image/jpeg).
3. Reference the Asset in the Post
Include the asset URN in the specificMedia array and change shareMediaCategory to IMAGE or VIDEO:
{
"author": "urn:li:person:YOUR_MEMBER_ID",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": {
"text": "Check out this image!"
},
"shareMediaCategory": "IMAGE",
"specificMedia": [
{
"status": "urn:li:asset:ASSET_URN"
}
]
}
},
"visibility": {
"comMemberNetwork": "PUBLIC"
}
}
Handling Response Pagination
When retrieving posts via GET https://api.linkedin.com/v2/ugcPosts, LinkedIn uses start and count query parameters. The response includes a paging object containing total, start, and count. To fetch all records, iterate by incrementing the start value by the count value until start equals or exceeds total.
Limits and Common Pitfalls
- Rate Limits: Standard tiers are often limited to 1,000 calls per 10 minutes. Exceeding this returns a 429 Too Many Requests response.
- File Size Constraints: Images are limited to 5 MB and videos to 20 MB. Exceeding these limits triggers a 400 Bad Request.
- Visibility Enums: Only
PUBLIC,CONNECTIONS, andPRIVATEare supported. Invalid strings cause 400 errors. - MIME Types: Ensure the
digitalTypematches the actual file binary; discrepancies will result in upload failures.
Verification Steps
- Connectivity Check: Use curl to POST a text-only share; verify the 201 response and the presence of a post URN.
- Pagination Check: Call
/v2/ugcPosts?start=0&count=10and confirmpaging.totalmatches the expected count of posts. - Constraint Test: Attempt to upload a file exceeding 5 MB to confirm the API returns a 400 error.
- Auth Check: Verify the
Authorizationheader uses theBearerprefix. A 401 response indicates an expired token.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.