Back to Blog

How to Post to LinkedIn via API A Developer's Guide

Learn how to post to LinkedIn via API with this practical developer's guide. Master OAuth 2.0, craft posts, handle rate limits, and automate your content.

By

Add social media scheduling and analytics to your app in minutes with Late's API.

Try Late free

So, what does it actually mean to post to LinkedIn through an API?

Simply put, you're using your own code to create and publish content directly to a personal profile or company page, bypassing LinkedIn's user interface entirely. You hook into LinkedIn's official APIs, handle authentication with OAuth 2.0, and send structured data to their endpoints. This opens the door for some seriously powerful automation and integration with your own systems.

Why Bother Automating LinkedIn Posts with the API?

Two professionals collaborate on a laptop, using a scheduling app to automate posts.

Stepping away from manual posting is about more than just clawing back a few minutes in your day. While third-party scheduling tools are convenient, direct API integration offers a level of control and customization that off-the-shelf software just can't touch. It turns content distribution from a repetitive chore into a dynamic, event-driven part of your development and marketing workflows.

Think about a B2B tech company that automatically shares a new case study the second it’s published on their website, complete with the right hashtags and a tracked link. That's not just scheduling—it's intelligent automation that guarantees your content is timely and relevant, without anyone needing to lift a finger.

Get Granular Control and True Scalability

Direct API access gives you the keys to build completely bespoke content pipelines. A marketing agency could build post-scheduling right into their client's project management tool, so that a simple "approved" status triggers the post to go live. This kind of tight integration cuts down on friction and nearly eliminates the risk of manual errors.

By tapping into the API, developers can:

  • Build Custom Scheduling Logic: Forget rigid posting schedules. You can create complex cadences that third-party tools can't handle, like publishing content only when specific market signals or internal data triggers are met.
  • Lock in Brand Consistency: Programmatically enforce brand guidelines. Think specific URL shorteners, tracking parameters, or standardized calls-to-action applied to every single post, every time.
  • Integrate with CI/CD Pipelines: Automatically announce new software releases, feature updates, or bug fixes on your company page as a seamless part of your deployment process.

The real magic of the API isn't just posting to LinkedIn, but posting from your core business systems. It connects your content strategy directly to your operational reality, making your professional presence a true reflection of your company's pulse.

Run Sophisticated Content Experiments

Trying to manually A/B test content on social media is a nightmare—it's tedious and the results are often fuzzy. The API lets you run data-backed experiments at scale. You could systematically test different headline variations, image styles, or posting times for a series of articles and then use the analytics API to measure precisely which combination drove the most engagement.

This approach transforms your content strategy from a static plan into a living system that constantly learns and optimizes itself. For developers building cross-platform tools, understanding the nuances of a social media API is foundational. You can see how different platforms stack up by exploring the broader landscape of an API for social media and how they enable these kinds of powerful integrations.

Ultimately, using the LinkedIn API isn't just a technical exercise; it's a strategic move to build a smarter, more scalable, and more responsive content engine.

Setting Up Your LinkedIn Developer App

Before you can write a single line of code, you need to introduce your application to LinkedIn. This is all done in the LinkedIn Developer Portal, where you'll create an "app" that serves as your project's digital passport for everything that follows—authentication, API calls, the works.

First things first, head over to the portal and hit "Create app." You'll fill out some basic info like an app name and logo. The one thing that trips people up is the requirement to associate your app with a LinkedIn Company Page. This is non-negotiable, even if your grand plan is only to post to a personal profile.

Don't have one? No problem. Just create a placeholder page for this purpose. It takes five minutes and is a necessary hoop to jump through.

Once your app is created, you'll land on its dashboard. The very next thing you need to do is get it verified. Look for a prompt on the "Settings" tab. This step is just LinkedIn's way of confirming you actually have admin control over the Company Page you linked. It’s a quick but critical gatekeeper for unlocking the rest of the settings.

Enabling Products and Scopes

With your app verified, it's time to tell LinkedIn what you actually want to do. This is handled by enabling "Products." For posting content, there are two you absolutely need to add:

  • Share on LinkedIn: This is the big one. It gives your app the fundamental ability to publish shares, images, and videos.
  • Sign In with LinkedIn: This product enables the OAuth 2.0 flow, which is how you'll get permission from a user to post on their behalf.

Adding these Products makes certain permissions available, but you still have to explicitly ask for them. Jump over to the "Auth" tab to configure your OAuth 2.0 scopes. This is where you define exactly what permissions your app will request from a user.

I can't stress this enough: only ask for what you absolutely need. Requesting a bunch of unnecessary scopes is the fastest way to erode user trust and get your app rejected during review. Think of it like a valet—you give them the key to the car, not your whole house.

For most posting applications, you'll need a handful of core scopes to get the job done.

Essential LinkedIn API Permission Scopes for Posting

Here’s a quick rundown of the minimum required OAuth 2.0 scopes you’ll need to create and manage posts through the API. Getting these right is key to a smooth authentication flow.

Scope NameDescriptionWhen to Use
w_member_socialGrants permission to post, comment, and like on behalf of the authenticated member.This is the core permission for creating posts on a user's personal profile.
r_liteprofileAllows access to a member's basic profile info, like their name and profile picture.You need this to get the user's URN (urn:li:person:{id}), which is required to specify the author of a post.
w_organization_socialGrants permission to post, comment, and like on behalf of an organization where the user is an admin.Use this if your app needs to publish content to a Company Page instead of a personal profile.

Getting these scopes configured correctly ensures your app asks for exactly the right permissions, making the user experience smoother and increasing the chances of your app passing LinkedIn's review process.

After picking your scopes, the final configuration step is setting a Redirect URI (you'll also see it called a callback URL). This is just a secure URL on your server where LinkedIn will send the user back—along with a precious authorization code—after they approve your app's permission request.

This URI must be an exact match, https:// and all, to what you use in your code. For local testing, something like http://localhost:3000/callback is a common and perfectly fine choice.

With all that done, your Client ID and Client Secret will be waiting for you on the "Auth" tab. These are your app's credentials. Treat them like passwords and keep them safe. You now have everything you need to start authenticating users.

Navigating the OAuth 2.0 Authentication Flow

Before you can post anything, you have to get through authentication. This is often the part that feels the most complicated, but once you get the hang of it, it's straightforward. LinkedIn uses a standard security protocol called 3-legged OAuth 2.0.

Think of it like a digital valet service. Your app asks a user for permission, the user hands LinkedIn a temporary key (never their actual password), and LinkedIn gives that key to your app to perform actions on the user's behalf. This process ensures your application never touches or stores a user's real credentials, which is a massive win for security and building trust with your users.

The entire flow is a three-part dance between your application, the user, and LinkedIn's servers.

First, you'll need to create and configure an app in the LinkedIn Developer Portal. This is where you'll define what your app does and get the keys you need for the OAuth dance.

Diagram illustrating a three-step process: Create with a grid icon, Configure with a gear icon, and Keys with a key icon.

Phase 1: Requesting an Authorization Code

The journey kicks off when you send the user to LinkedIn's authorization URL. This isn't an API call in the traditional sense; you're actually redirecting the user's browser to a specific LinkedIn page. You’ll build this URL with several query parameters that tell LinkedIn about your app and the permissions you're requesting.

Here are the critical parameters you'll need to tack onto that URL:

  • response_type: This must always be set to code.
  • client_id: Your app's unique Client ID, which you get from the developer portal.
  • redirect_uri: The exact callback URL you configured in your app's settings. It must be an exact match.
  • scope: A space-separated list of the permissions you need, like r_liteprofile w_member_social.

When the user follows this link, they land on a familiar LinkedIn consent screen. It shows your app's name and clearly lists the permissions you’re asking for. If they click "Allow," LinkedIn sends them back to your redirect_uri with a temporary authorization code attached to the URL.

This code is your ticket to the next phase.

Phase 2: Exchanging the Code for an Access Token

That authorization code is short-lived and can only be used once. Its sole purpose is to prove the user just granted you permission. Now, your server needs to make a direct, back-end API call to LinkedIn to swap this temporary code for something much more valuable: an access token.

This is a POST request to LinkedIn's access token endpoint. It's a secure, server-to-server call, so you'll include your app's Client ID and Client Secret to prove your app's identity.

Here’s a quick curl example of what that token exchange looks like in practice: curl -X POST 'https://www.linkedin.com/oauth/v2/accessToken'
-H 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'grant_type=authorization_code'
--data-urlencode 'code={YOUR_AUTHORIZATION_CODE}'
--data-urlencode 'redirect_uri={YOUR_REDIRECT_URI}'
--data-urlencode 'client_id={YOUR_CLIENT_ID}'
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' If everything checks out, LinkedIn's server will respond with a JSON object containing the access_token. This is the key you'll use for all future API requests on behalf of that user.

The access token is the prize of the entire OAuth flow. It's a bearer token that represents the user's delegated authority. Guard it carefully—anyone who has this token can act as that user within the scopes you were granted.

Phase 3: Making Authenticated API Calls

With a valid access token in hand, you can finally post to LinkedIn via API. Every request you make to a protected endpoint must include this token in an Authorization header.

For example, to get the authenticated user's profile info (which you'll need to specify the post's author), you just make a simple GET request: curl -X GET 'https://api.linkedin.com/v2/userinfo'
-H 'Authorization: Bearer {YOUR_ACCESS_TOKEN}' The response will contain the user's unique URN (e.g., urn:li:person:{id}), which is a critical piece of information for creating posts.

One last thing to keep in mind: LinkedIn access tokens don't last forever. They typically have a lifespan of 60 days. After that, the token expires, and any API calls made with it will fail with a 401 Unauthorized error. To maintain access without bothering the user again, you'll need to implement a token refresh flow. This is crucial for any application that needs long-term, uninterrupted access.

Crafting and Publishing Your First API Post

A person typing code on a laptop, with a notebook and pen, for publishing via API.

Alright, you’ve got a valid access token. Now the fun part begins: actually building the data payload that becomes your first live post. The structure of this JSON object is the blueprint for your content, defining everything from the text down to the visibility settings.

This isn’t just a technical exercise; you're building a powerful content engine. Think about it: LinkedIn has over 1 billion members, yet a tiny fraction—just 1% of users—posts content weekly. That small group generates a staggering 9 billion impressions per week. By learning to post to LinkedIn via API, you're tapping directly into a system built for massive reach.

Of course, once you have the technical side sorted, you still need to craft a message that connects. If you need some inspiration, check out these compelling social media content ideas to fuel your strategy.

Constructing a Basic Text Post

Let's start with the most straightforward case: a simple text-only update. This is the foundation for every other type of post. At its core, you'll be making a POST call to the https://api.linkedin.com/rest/posts endpoint, and the JSON body needs a few key fields to work.

Your JSON payload has to define:

  • author: The URN of the person or company publishing the post. This is critical—it tells LinkedIn who the content is from.
  • commentary: This is just the main text of your post. Simple enough.
  • visibility: Sets who can see your post. PUBLIC is what you'll use most of the time.
  • distribution: This tells LinkedIn where the post should appear. For a standard feed post, you'll set feedDistribution to MAIN_FEED.
  • lifecycleState: Must be set to PUBLISHED to make the post go live immediately.

A common snag is getting the author URN right. It’s not your username. For a personal profile, the format is urn:li:person:{id}, and for a company page, it's urn:li:organization:{id}. You can find your personal ID from the /userinfo endpoint we covered back in the authentication section.

Pro Tip: Don't forget the headers. Always include X-Restli-Protocol-Version: 2.0.0 and Linkedin-Version: {YYYYMM} in your API calls. Forgetting these is a super common source of errors, and LinkedIn requires them to process your request correctly.

Here’s what that looks like in a Python example using the popular requests library.

import requests import json

access_token = 'YOUR_ACCESS_TOKEN' author_urn = 'urn:li:person:YOUR_PERSON_ID'

url = "https://api.linkedin.com/rest/posts"

headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json', 'X-Restli-Protocol-Version': '2.0.0', 'Linkedin-Version': '202405' # Use a recent version }

post_data = { "author": author_urn, "commentary": "This is my first post created using the LinkedIn API!", "visibility": "PUBLIC", "distribution": { "feedDistribution": "MAIN_FEED", "targetEntities": [], "thirdPartyDistributionChannels": [] }, "lifecycleState": "PUBLISHED", "isReshareDisabledByAuthor": False }

response = requests.post(url, headers=headers, data=json.dumps(post_data))

print(response.status_code) print(response.headers.get('x-restli-id')) If everything went smoothly, you'll get back a 201 Created status code. The response headers will also contain the URN of your brand-new post.

Adding Images and Videos

Want to post media like images or videos? Things get a bit more involved. You can't just toss a URL into the payload. LinkedIn makes you perform a three-step dance to make sure the media is properly hosted and processed on their end.

  1. Register the Upload: First, you hit an endpoint to tell LinkedIn you plan to upload a file. In return, you get a unique asset URN (like urn:li:image:{id}) and a temporary, one-time upload URL.
  2. Upload the Asset: Next, you make a PUT request directly to that special upload URL, sending the raw binary data of your image or video file.
  3. Create the Post: Finally, you build your post payload just like the text-only example, but this time you'll include a content object that references the asset URN you got back in step one.

This multi-step approach is all about performance and reliability. It separates the post's metadata from the heavy lifting of the actual media upload. It's definitely more complex, but a dedicated https://getlate.dev/blog/scheduling-tool-for-linkedin can abstract all these steps away, handling the entire upload and posting flow behind a single API call.

Here’s a conceptual example in Node.js for posting an image. This snippet focuses on the final step, assuming you've already uploaded the image and have its URN.

const axios = require('axios');

const accessToken = 'YOUR_ACCESS_TOKEN'; const authorUrn = 'urn:li:organization:YOUR_ORG_ID'; const imageUrn = 'urn:li:image:YOUR_UPLOADED_IMAGE_URN'; // From upload step

const postApiUrl = 'https://api.linkedin.com/rest/posts';

const postPayload = { author: authorUrn, commentary: 'Check out this awesome image we shared via the API!', visibility: 'PUBLIC', distribution: { feedDistribution: 'MAIN_FEED', }, content: { media: { id: imageUrn, altText: 'A descriptive alt text for accessibility.' }, }, lifecycleState: 'PUBLISHED', isReshareDisabledByAuthor: false, };

const config = { headers: { 'Authorization': Bearer ${accessToken}, 'X-Restli-Protocol-Version': '2.0.0', 'Linkedin-Version': '202405', 'Content-Type': 'application/json', }, };

axios.post(postApiUrl, postPayload, config) .then(response => { console.log('Post created successfully!'); console.log('Post ID:', response.headers['x-restli-id']); }) .catch(error => { console.error('Error creating post:', error.response.data); }); Once you get comfortable with these payloads, you'll have the power to create rich, engaging content programmatically. It completely changes how you can interact with one of the world's most important professional networks.

Handling Rate Limits and Common API Errors

A laptop displays data analytics charts and graphs with a coffee mug and 'HANDLE API ERRORS' text.

Let's be real: a production-ready integration is defined by how it handles failure, not just success. As you start to post to LinkedIn via API at any real volume, you're going to hit errors. It's not a matter of if, but when. Building a resilient app means planning for this from day one.

Like any sane API provider, LinkedIn uses rate limits to protect its infrastructure from being swamped. Think of these limits not as suggestions, but as a hard ceiling on how many requests you can make. Ignore them at your peril.

Understanding LinkedIn's Rate Limiting Policies

LinkedIn’s approach to rate limiting is layered, and you need to be mindful of both:

  • Per-User Limits: Each authenticated user gets their own bucket of API calls. This is fair—it stops one hyperactive user on your app from ruining the experience for everyone else.
  • Per-Application Limits: Your app as a whole also has a global limit. This is the total number of calls your application can make across all its users in a given period.

When you hit either of these limits, you'll get a 429 Too Many Requests response. The rookie mistake is to immediately retry. Don't do that.

The professional way to handle a 429 error is to implement an exponential backoff strategy. This is a classic algorithm where you wait a bit before retrying, then double the wait time for each subsequent failure. It’s a simple, elegant way to give the API a breather and show you're a good citizen on the network.

Decoding Common HTTP Error Codes

Beyond getting rate limited, you'll see a handful of other HTTP status codes pop up. Each one is a clue, telling you exactly what went wrong so you can fix it.

Here’s a quick field guide to the errors you'll see most often:

Status CodeError NameCommon Cause & How to Fix It
401UnauthorizedThis almost always means your Access Token is dead. It's likely expired, invalid, or the user revoked it. First, try using your refresh token to get a new one. If that fails, the user has to go through the OAuth flow again.
403ForbiddenYou've hit a permission wall. Your app tried to do something it wasn't given the scope for—like posting to a company page (w_organization_social) when you only have permission to post as a member (w_member_social). Go back and check the scopes you requested.
400Bad RequestThis is usually a problem with the data you sent. Your JSON payload is probably busted. Look for a missing required field (like author), a typo in a URN, or a simple syntax error. Validate your JSON against the official docs before sending it.

By building handlers for these scenarios right into your code, you create an application that doesn't just crash and burn. Instead, it can intelligently manage failures, retry when it makes sense, and give users clear instructions when their input is needed. This is what separates a quick script from a professional-grade tool.

Measuring Post Performance with the Analytics API

Pushing content out is only half the job. If you’re not measuring its impact, you're flying blind. When you post to LinkedIn via API, every share you create becomes a valuable data point. The real magic happens when you close the loop and programmatically pull performance metrics back into your system.

This transforms your integration from a simple publishing tool into a full-blown content optimization engine. Forget manually checking your posts—you can make authenticated GET requests to LinkedIn’s analytics endpoints to pull key engagement numbers right where you need them. It's how you can systematically track what works and what doesn't, all based on cold, hard data.

Accessing Key Engagement Metrics

LinkedIn’s API gives you programmatic access to the metrics that actually matter for gauging how your content is doing. For any given post URN, you can fetch the core data points:

  • Impressions: The total number of times your post was shown to members.
  • Clicks: How many times people clicked your content, company name, or logo.
  • Likes: The total count of "like" reactions.
  • Comments: The number of comments your post has sparked.

Once you’re successfully publishing posts, this is the logical next step. For a deeper look into what these numbers mean, check out this guide on analyzing content performance on LinkedIn, which offers a great framework for interpreting the data you pull from the API.

By piping these metrics into a custom dashboard or an internal BI tool, you can move past vanity metrics. You create a direct feedback loop connecting content creation to actual business outcomes, which is the key to making smarter decisions.

LinkedIn has been beefing up these capabilities, too. Their latest updates allow for deeper analytics that can connect a post to tangible user actions, like tracking profile views or new follows generated from a specific piece of content.

By automating both publishing and analysis, you unlock the ability to A/B test your content strategy at scale. To get into the nitty-gritty, our detailed guide on the LinkedIn analytics API breaks down the specific endpoints and data you can access. This strategic approach ensures your content efforts aren't just consistent, but are constantly improving.

Common Questions About the LinkedIn Post API

Any time you’re digging into a new API, you're bound to hit a few quirks and head-scratching moments. When you're learning to post to LinkedIn via API, a few questions pop up time and time again. Let’s get you some straight answers.

Can I Post to a LinkedIn Group Using the API?

Short answer: nope. This is a big one that trips up a lot of developers.

A while back, LinkedIn decided to shut down API access for posting to Groups to cut down on spam and improve the quality of conversations. It was a good move for users, but it means any Group-related activity has to be done the old-fashioned way—directly on the LinkedIn website or in their app.

For now, the API is exclusively for publishing to:

  • Personal member profiles
  • Official Company Pages

What Is the Difference Between a Share and a UGC Post?

This is just a classic case of API evolution. You'll see both "Shares" and "UGC Post" in the documentation, and it's easy to get them mixed up.

Think of it this way: "Shares" is the legacy API, and "UGC Post" (which stands for User Generated Content) is the modern one you should be using.

While the old Shares API might look a bit simpler for a quick text-only post, you really want to build everything with the UGC Post API. It’s the only one that supports modern features like multi-image carousels, native video, and articles. Sticking with UGC Posts makes sure your app won't break tomorrow and can handle all the cool media formats.

How Do I Format Mentions in an API Post?

You can’t just throw an "@" symbol in your text and call it a day—that won't work. To properly tag a person or a company, you have to be more explicit in your request.

Your JSON payload needs a dedicated mentions array. Inside this array, you’ll create an object for each tag.

Each mention object needs two key things:

  1. The start position and length of the text you want to hyperlink (e.g., where "Late" starts in your text and how many characters it is).
  2. The full URN of the person or company you’re tagging, like urn:li:person:{id} or urn:li:organization:{id}.

It's a bit more work, but this structured approach is how LinkedIn ensures your mentions are precise and link to the correct profiles every time.


Tired of juggling different social media APIs? Late unifies ten platforms, including LinkedIn, into a single, straightforward API. Skip the platform-specific complexities and start shipping features in minutes, not months. Check out the unified social media API.

Build social media automation into your product

Add social media scheduling and analytics to your app in minutes with Late's API.

Built for developers. Loved by agencies. Trusted by 6,325 users.