The LinkedIn API is not one API. It is six product families, five of which sit behind a partner application, and one of which is free and returns four fields.
That sentence is the whole platform. Everything else — the OAuth flows, the token lifetimes, the version headers — is detail that only matters once you know which tier you actually qualify for. Most developers spend a week on OAuth before discovering the endpoint they needed does not exist at their tier.
This is the reference we wish existed when we started. What each tier returns, what it costs, how authentication actually works, which errors you will hit, and — at the end, honestly — where the official platform stops and what people use instead.
Everything about the official platform here is sourced to LinkedIn's own documentation on Microsoft Learn, linked throughout.
What the LinkedIn API is
LinkedIn's platform is a set of RESTful APIs grouped into product categories: Consumer, Marketing, Sales, Talent, Learning, and Regulatory Developer Products. Each category has its own permissions, its own approval path, and its own data scope.
There is no general-purpose endpoint. There is no public search. There is no way to fetch an arbitrary profile by URL. Access is organised around one of two ideas: your application acts on behalf of a member who has personally consented, or your application is an approved commercial partner in a specific vertical.
Per LinkedIn's permissions reference, most permissions and partner programs require explicit approval, and Open Permissions are the only ones available to all developers without special approval.
That is the sentence that decides your architecture.
The free tier, precisely
Three permissions are self-serve. You can add them from the Products tab of your app in the Developer Portal with no application and no wait.
| Product | Scope | What it returns |
|---|---|---|
| Sign in with LinkedIn using OpenID Connect | profile | The authenticated member's name, headline, and photo |
| Sign in with LinkedIn using OpenID Connect | email | The authenticated member's primary email address |
| Share on LinkedIn | w_member_social | Post, comment, and like on behalf of an authenticated member |
That is the complete free tier. Name, headline, photo, email — for people who have clicked "Allow" on a consent screen in your own application — plus the ability to publish on their behalf.
No work history. No education. No skills. No connections. No follower counts. No company data. No job listings. No people search. No profile lookup. No engagement metrics. No data about anyone who is not your own authenticated user.
If you are building social login or a scheduling tool, this is genuinely everything you need and it is free. Use it and stop reading. If you need data about people who have no relationship with your product, no configuration of this tier will produce it.
The five gated programs
| Program | What it covers | How to apply | Current state |
|---|---|---|---|
| Marketing — Advertising API | Campaign management, audiences, ad analytics, conversion tracking | Developer Portal → your app → Products tab → add Advertising API | Approval required. Audience permissions can only be requested after you are already an approved Advertising API partner |
| Sales — SNAP | Sales Navigator analytics, display services, CRM validation, matched public member profiles | LinkedIn Sales Solutions partner application | Reported closed to new applicants through 2026 |
| Talent | Recruiter System Connect, Apply Connect, Apply with LinkedIn, Premium Job Posting | LinkedIn Talent Solutions ATS partner application |
The Compliance row matters more than its size suggests. r_compliance and w_compliance still appear in documentation, which means they still appear in blog posts, Stack Overflow answers, and AI-generated integration plans. They are documented history. There is no application form.
On Sales: reporting through 2026 indicates SNAP is not accepting new partner applications, with existing partners retaining access. Verify current status before you design anything around it.
Getting your credentials
Nothing in this section requires approval, and it takes about ten minutes.
1. Create a LinkedIn Page for your company. Registration requires an associated Page and verified admin rights on it. This blocks more first-time developers than any other step. A minimal Page is enough.
2. Register the app at the Developer Portal. You supply a name, the associated Page, a privacy policy URL, and a logo. The privacy policy URL is checked — point it at a real page.
3. Verify the Page association using the link LinkedIn generates. Instant with admin rights, impossible without.
4. Read your credentials from the Auth tab. LinkedIn assigns each application a unique Client ID — which its documentation also calls the Consumer key/API key — and a Client Secret. LinkedIn's guidance is explicit: never share the Client Secret, never pass it in a URL, never post it in support forums or chat.
This is the source of the most common misconception in the category. People search for a "LinkedIn API key," find the Client ID, put it in a header, and get a 401. The Client ID is not a credential you send to an endpoint. It identifies your app during authorization. What authorizes API calls is an access token you obtain through OAuth.
| Credential | What it is | What it's for |
|---|---|---|
| Client ID | Public app identifier, labelled "API key" in places | Identifying your app in the authorization URL |
| Client Secret | Private app password | Exchanging an authorization code for a token |
| Access token | The actual API credential | Authorization: Bearer <token> on every request |
5. Add a redirect URL on the same Auth tab. The rules are strict:
- Absolute and HTTPS —
https://dev.example.com/auth/linkedin/callback, not a relative path - Query parameters are ignored — everything after
?is stripped before comparison - No
#fragments
For Postman testing, LinkedIn suggests https://oauth.pstmn.io/v1/callback with browser authorization enabled.
6. Enable products under the Products tab. This is where scopes come from — a scope your app has not been granted will fail authorization.
7. Generate a test token. The Developer Portal includes a token generator that walks the OAuth flow manually, so you can make a real call before writing integration code.
Member authorization: 3-legged OAuth
Use this when you need data belonging to a specific member, or to act on their behalf. It is the flow behind every "Sign in with LinkedIn" button.
Step 1 — Send the member to the authorization page
1GET https://www.linkedin.com/oauth/v2/authorization
2 ?response_type=code
3 &client_id=YOUR_CLIENT_ID
4 &redirect_uri=https://dev.example.com/auth/linkedin/callback
5 &state=a_random_unguessable_string
6 &scope=openid%20profile%20emailLinkedIn's guidance on state is to verify the returned value matches what you sent and return a 401 if it does not, since a mismatch indicates a possible CSRF attack. Treat it as required.
If multiple scopes are requested, the member must consent to all of them and cannot select individually. Requesting more scopes than you need directly increases abandonment at the consent screen.
Step 2 — Exchange the code for a token
The member returns with code and state on the query string. The authorization code has a 30-minute lifespan and must be used promptly — after that you restart the flow.
1import os
2import requests
3
4resp = requests.post(
5 "https://www.linkedin.com/oauth/v2/accessToken",
6 data={
7 "grant_type": "authorization_code",
8 "code": auth_code,
9 "client_id": os.environ["LINKEDIN_CLIENT_ID"],
10 "client_secret": os.environ["LINKEDIN_CLIENT_SECRET"],
11 "redirect_uri": "https://dev.example.com/auth/linkedin/callback",
12 },
13 headers={"Content-Type": "application/x-www-form-urlencoded"},
14)
15
16token = resp.json()["access_token"]1const params = new URLSearchParams({
2 grant_type: 'authorization_code',
3 code: authCode,
4 client_id: process.env.LINKEDIN_CLIENT_ID,
5 client_secret: process.env.LINKEDIN_CLIENT_SECRET,
6 redirect_uri: 'https://dev.example.com/auth/linkedin/callback',
7});
8
9const res = await fetch('https://www.linkedin.com/oauth/v2/accessToken', {
10 method: 'POST',
11 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
12 body: params,
13});
14
15const { access_token: token } = await res.json();All five body parameters are mandatory. Omitting any one returns a 400 naming the missing field.
Step 3 — Call the API
1curl -X GET 'https://api.linkedin.com/v2/userinfo' \
2 -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'Note the Authorization: Bearer header. Your Client ID does not appear.
Application authorization: 2-legged OAuth
Use this for APIs that are not member-specific. It is simpler — no consent screen, no redirect — but it is not available by default and not available at all for Marketing APIs.
1curl --location --request POST 'https://www.linkedin.com/oauth/v2/accessToken' \
2 --header 'Content-Type: application/x-www-form-urlencoded' \
3 --data-urlencode 'grant_type=client_credentials' \
4 --data-urlencode 'client_id={your_client_id}' \
5 --data-urlencode 'client_secret={your_client_secret}'Two things about this flow catch people out.
The token lasts 30 minutes. The response returns expires_in: 1800. It must be used immediately, and there is no refresh token — you request a new one when the current one expires. Any long-running job needs token acquisition inside the retry loop, not at startup.
Your app probably cannot use it. LinkedIn's documentation states applications cannot access these APIs by default. The characteristic failure is:
1{
2 "error": "access_denied",
3 "error_description": "This application is not allowed to create application tokens"
4}That is not a bug in your code. It means your app has not been granted application-token permission, which requires contacting LinkedIn support or holding the relevant enterprise product.
Token lifetimes and the refresh trap
This is where teams get hurt in production, sixty days after launch.
| Flow | Token lifetime | Refresh |
|---|---|---|
| 3-legged (member) | 60 days | Re-run the authorization flow; programmatic refresh tokens limited to certain partners |
| 2-legged (application) | 30 minutes | None — request a new token |
Three-legged access tokens are issued with a 60-day lifespan. LinkedIn's documented refresh path is to send the member through the authorization flow again. The consent screen is bypassed and the redirect is silent — but only if the member is still logged in to linkedin.com and their current token has not yet expired. If either condition fails, they go through the full authorization process again.
Read that twice. The standard refresh is browser-dependent. A backend cron job that wakes on day 61 to renew tokens cannot do it — there is no session to piggyback on. Programmatic refresh tokens exist but are available only to a limited set of partners.
Start building with 100 free credits
Access profiles, companies, jobs, and more through our reliable, high-performance API. No credit card required.
Two practical consequences:
- Refresh at day 45, not day 59. You need runway for members who have not visited recently.
- Build re-consent as a normal product flow, not an error page. Some percentage of your users will always need it.
And one silent landmine: if you request a different scope than previously granted, all existing access tokens are invalidated. Shipping a feature that adds a scope logs out your entire user base at once, with no error in your logs — just a wave of 401s.
Versioning
Versioned LinkedIn APIs — Marketing in particular — require a version header in YYYYMM format, for example Linkedin-Version: 202602, with versions supported for a minimum of one year. Some older Consumer endpoints still respond on the legacy unversioned /v2/ path shown in LinkedIn's OAuth documentation.
Confirm the base path and version requirements against the reference page for the specific product you are integrating rather than assuming one convention across the platform. This is the single most common source of "the docs say this endpoint exists but I get a 404."
Separately: LinkedIn does not support TLS 1.0.
![LinkedIn API vs Unofficial APIs: Access, Cost & Limits [2026]](https://blog.linkdapi.com/uploads/linkedin_vs_linkdapi_9f12bd33e8.png)


