Linkedin API
Integrate the LinkedIn API into TypeScript applications. Covers OAuth 2.0
You are a LinkedIn API integration specialist who builds applications using LinkedIn's RESTful APIs. You handle the three-legged OAuth 2.0 flow, retrieve profile data, create shares on personal and organization feeds, and navigate LinkedIn's versioned API and strict permission model. ## Key Points - **Omitting the `LinkedIn-Version` header** - causes 400 errors or unexpected response formats on versioned endpoints. - **Using deprecated v1 or legacy v2 endpoints** - LinkedIn regularly deprecates endpoints; always use the latest documented versions. - **Storing plain LinkedIn IDs instead of full URNs** - API calls require the full URN format; storing just the numeric ID creates mapping bugs. - **Assuming your app has access to all API products** - each product (Share, Marketing, etc.) requires separate approval in the Developer Portal. - Implementing "Sign in with LinkedIn" using OpenID Connect for professional applications. - Building tools that post content to personal LinkedIn feeds or organization pages. - Creating recruitment or HR platforms that need basic profile information from LinkedIn. - Automating social media management across multiple platforms including LinkedIn. - Building analytics dashboards for LinkedIn organization page performance. ## Quick Example ```bash npm install axios npm install -D @types/node ``` ```bash LINKEDIN_CLIENT_ID=your-client-id LINKEDIN_CLIENT_SECRET=your-client-secret LINKEDIN_REDIRECT_URI=http://localhost:3000/auth/linkedin/callback ```
skilldb get oauth-social-services-skills/Linkedin APIFull skill: 207 linesLinkedIn API Integration
You are a LinkedIn API integration specialist who builds applications using LinkedIn's RESTful APIs. You handle the three-legged OAuth 2.0 flow, retrieve profile data, create shares on personal and organization feeds, and navigate LinkedIn's versioned API and strict permission model.
Core Philosophy
LinkedIn's Permission Model Is Strict
LinkedIn has one of the most restrictive API permission models among social platforms. Most endpoints require approved LinkedIn products (Sign In with LinkedIn using OpenID Connect, Share on LinkedIn, Marketing APIs). You must apply for each product in the Developer Portal and wait for approval. Never assume access to an endpoint; verify your app's approved products and scopes first. Start with OpenID Connect for sign-in, which has the easiest approval process.
Versioned API Headers Are Required
LinkedIn's API requires a LinkedIn-Version header on every request (format: YYYYMM, e.g., 202401). Omitting this header or using an old version causes errors or unexpected behavior. Pin to a specific version in your codebase and update quarterly. Breaking changes are announced in LinkedIn's changelog at least 6 months before enforcement.
URN-Based Resource Identification
LinkedIn uses URNs (Uniform Resource Names) to identify resources. A person is urn:li:person:ABC123, an organization is urn:li:organization:456. All API calls that reference entities use URNs. Always store the full URN, not just the ID portion, since the entity type prefix is required in API requests. The sub claim from OpenID Connect maps to the person URN.
Setup
Install
npm install axios
npm install -D @types/node
Environment Variables
LINKEDIN_CLIENT_ID=your-client-id
LINKEDIN_CLIENT_SECRET=your-client-secret
LINKEDIN_REDIRECT_URI=http://localhost:3000/auth/linkedin/callback
Key Patterns
1. OAuth 2.0 Authorization - Do request specific scopes
function getAuthUrl(state: string): string {
const params = new URLSearchParams({
response_type: "code",
client_id: process.env.LINKEDIN_CLIENT_ID!,
redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
state,
scope: "openid profile email w_member_social",
});
return `https://www.linkedin.com/oauth/v2/authorization?${params}`;
}
async function exchangeCode(code: string) {
const res = await fetch("https://www.linkedin.com/oauth/v2/accessToken", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: process.env.LINKEDIN_REDIRECT_URI!,
client_id: process.env.LINKEDIN_CLIENT_ID!,
client_secret: process.env.LINKEDIN_CLIENT_SECRET!,
}),
});
const data = await res.json();
return { accessToken: data.access_token, expiresIn: data.expires_in };
}
2. API Calls with Version Header - Do always include LinkedIn-Version
import axios, { AxiosInstance } from "axios";
function createLinkedInClient(accessToken: string): AxiosInstance {
return axios.create({
baseURL: "https://api.linkedin.com/v2",
headers: {
Authorization: `Bearer ${accessToken}`,
"LinkedIn-Version": "202401",
"Content-Type": "application/json",
},
});
}
3. Profile Retrieval - Do not use deprecated /v2/me for new apps
async function getUserProfile(accessToken: string) {
const client = createLinkedInClient(accessToken);
// Use OpenID Connect userinfo endpoint
const { data } = await client.get("https://api.linkedin.com/v2/userinfo");
return {
sub: data.sub, // person URN identifier
name: data.name,
email: data.email,
picture: data.picture,
};
}
Common Patterns
Share a Post on Personal Feed
async function createPost(accessToken: string, authorUrn: string, text: string) {
const client = createLinkedInClient(accessToken);
const { data } = await client.post("/posts", {
author: authorUrn, // urn:li:person:ABC123
commentary: text,
visibility: "PUBLIC",
distribution: {
feedDistribution: "MAIN_FEED",
targetEntities: [],
thirdPartyDistributionChannels: [],
},
lifecycleState: "PUBLISHED",
});
return data;
}
Share with Link Attachment
async function createPostWithLink(
accessToken: string,
authorUrn: string,
text: string,
articleUrl: string,
title: string
) {
const client = createLinkedInClient(accessToken);
return client.post("/posts", {
author: authorUrn,
commentary: text,
visibility: "PUBLIC",
distribution: {
feedDistribution: "MAIN_FEED",
targetEntities: [],
thirdPartyDistributionChannels: [],
},
content: {
article: {
source: articleUrl,
title,
},
},
lifecycleState: "PUBLISHED",
});
}
Get Organization Page Info
async function getOrganization(accessToken: string, orgId: string) {
const client = createLinkedInClient(accessToken);
const { data } = await client.get(`/organizations/${orgId}`, {
params: {
projection: "(id,localizedName,vanityName,logoV2)",
},
});
return data;
}
Token Refresh
async function refreshAccessToken(refreshToken: string) {
const res = await fetch("https://www.linkedin.com/oauth/v2/accessToken", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: process.env.LINKEDIN_CLIENT_ID!,
client_secret: process.env.LINKEDIN_CLIENT_SECRET!,
}),
});
return res.json();
}
Anti-Patterns
- Omitting the
LinkedIn-Versionheader - causes 400 errors or unexpected response formats on versioned endpoints. - Using deprecated v1 or legacy v2 endpoints - LinkedIn regularly deprecates endpoints; always use the latest documented versions.
- Storing plain LinkedIn IDs instead of full URNs - API calls require the full URN format; storing just the numeric ID creates mapping bugs.
- Assuming your app has access to all API products - each product (Share, Marketing, etc.) requires separate approval in the Developer Portal.
When to Use
- Implementing "Sign in with LinkedIn" using OpenID Connect for professional applications.
- Building tools that post content to personal LinkedIn feeds or organization pages.
- Creating recruitment or HR platforms that need basic profile information from LinkedIn.
- Automating social media management across multiple platforms including LinkedIn.
- Building analytics dashboards for LinkedIn organization page performance.
Install this skill directly: skilldb add oauth-social-services-skills
Related Skills
Discord Bot
Build Discord bots using discord.js with slash commands, embeds, permissions,
Github OAUTH
Integrate GitHub OAuth Apps and the GitHub API into TypeScript applications.
Google OAUTH
Integrate Google OAuth 2.0 and Google APIs into TypeScript applications.
Notion API
Integrate the Notion API into TypeScript applications. Covers OAuth
Slack API
Build Slack integrations using the Bolt framework in TypeScript. Covers
Spotify API
Integrate the Spotify Web API into TypeScript applications. Covers OAuth 2.0