En bref
L'API LinkedIn permet aux développeurs d'intégrer leur application au réseau professionnel de LinkedIn de manière programmatique. Elle utilise l'authentification OAuth 2.0, des points de terminaison RESTful et GraphQL pour les profils, les publications, les commentaires, les pages d'entreprise et les publicités, avec des limitations de débit de 100 à 500 requêtes par jour et par application. Ce guide couvre la configuration de l'authentification, l'accès au profil, la publication de contenu, la gestion des pages d'entreprise, l'API publicitaire et les stratégies d'intégration en production.
Essayez Apidog dès aujourd'hui
Introduction
LinkedIn compte plus de 900 millions d'utilisateurs professionnels dans plus de 200 pays. Pour les développeurs qui créent des outils de recrutement, des plateformes marketing ou des applications B2B, l'intégration de l'API LinkedIn est essentielle pour atteindre ce public professionnel.
Voici la réalité : les spécialistes du marketing B2B gérant manuellement leur présence sur LinkedIn perdent 15 à 20 heures par semaine à publier, suivre l'engagement et générer des prospects. Une solide intégration de l'API LinkedIn automatise la distribution de contenu, la capture de prospects, l'analyse de l'engagement et les flux de travail de recrutement.
Ce guide vous accompagne tout au long du processus complet d'intégration de l'API LinkedIn. Vous apprendrez l'authentification OAuth 2.0, l'accès au profil, la publication de contenu, la gestion des pages d'entreprise, l'intégration des publicités, les webhooks et les stratégies de déploiement en production. À la fin, vous disposerez d'une intégration LinkedIn prête pour la production.
💡 Astuce : Apidog simplifie les tests d'intégration d'API. Testez vos points de terminaison LinkedIn, validez les flux OAuth, inspectez les réponses API et déboguez les problèmes d'autorisation dans un seul espace de travail. Importez des spécifications API, simulez des réponses et partagez des scénarios de test avec votre équipe.
Qu'est-ce que l'API LinkedIn ?
LinkedIn fournit des API RESTful et GraphQL pour accéder aux données du réseau professionnel. L'API gère :
- Les informations de profil utilisateur (avec consentement)
- Les pages et mises à jour des entreprises
- Les publications, commentaires et réactions
- Les connexions (limité)
- Les offres d'emploi et candidatures
- La gestion des publicités LinkedIn
- Les formulaires de génération de prospects
- La messagerie (partenaires limités uniquement)
Fonctionnalités clés
| Fonctionnalité | Description |
|---|---|
| RESTful + GraphQL | Plusieurs styles d'API |
| OAuth 2.0 | Autorisation utilisateur requise |
| Rate Limiting | 100-500 requêtes/jour par application |
| Company Pages | Opérations CRUD complètes |
| Ads API | Gestion des campagnes |
| Webhooks | Notifications en temps réel |
| Media Upload | Images et vidéos |
Produits API
| API | Niveau d'accès | Cas d'utilisation |
|---|---|---|
| Sign In with LinkedIn | Ouvert | Authentification utilisateur |
| Profile API | Partenaire | Lire le profil utilisateur |
| Company Admin API | Partenaire | Gérer les pages d'entreprise |
| Ads API | Partenaire | Gestion des campagnes publicitaires |
| Job Posting API | Partenaire | Publier et gérer des offres d'emploi |
| Marketing Developer Platform | Partenaire | Accès API complet |
Versions de l'API
| Version | Statut | Date de fin |
|---|---|---|
| v2 | Actuelle | Active |
| v1 | Retirée | Décembre 2023 |
Démarrage : Configuration de l'authentification
Étape 1 : Créer un compte développeur LinkedIn
- Visitez le Portail développeur LinkedIn
- Connectez-vous avec votre compte LinkedIn
- Cliquez sur Créer une application dans le tableau de bord Mes applications
- Remplissez les détails de l'application (nom, logo, description)
Étape 2 : Configurer les paramètres de l'application
Configurez l'authentification de l'application :
const LINKEDIN_CLIENT_ID = process.env.LINKEDIN_CLIENT_ID;
const LINKEDIN_CLIENT_SECRET = process.env.LINKEDIN_CLIENT_SECRET;
const LINKEDIN_REDIRECT_URI = process.env.LINKEDIN_REDIRECT_URI;
// Get these from your app dashboard
// https://www.linkedin.com/developers/apps/{appId}/auth
Étape 3 : Demander les autorisations requises
LinkedIn exige l'approbation des autorisations :
| Permission | Description | Approbation requise |
|---|---|---|
r_liteprofile |
Profil de base (nom, photo) | Approuvé automatiquement |
r_emailaddress |
Adresse e-mail | Approuvé automatiquement |
w_member_social |
Publier au nom de l'utilisateur | Vérification partenaire |
r_basicprofile |
Profil complet | Vérification partenaire |
r_organization_social |
Accès aux pages d'entreprise | Vérification partenaire |
w_organization_social |
Publier sur une page d'entreprise | Vérification partenaire |
rw_ads |
Gestion des publicités | Vérification partenaire |
r_ads_reporting |
Analyse des publicités | Vérification partenaire |
Étape 4 : Construire l'URL d'autorisation
Implémentez le flux OAuth 2.0 :
const getAuthUrl = (state, scopes = ['r_liteprofile', 'r_emailaddress']) => {
const params = new URLSearchParams({
response_type: 'code',
client_id: LINKEDIN_CLIENT_ID,
redirect_uri: LINKEDIN_REDIRECT_URI,
scope: scopes.join(' '),
state: state
});
return `https://www.linkedin.com/oauth/v2/authorization?${params.toString()}`;
};
// Usage
const state = require('crypto').randomBytes(16).toString('hex');
const authUrl = getAuthUrl(state, ['r_liteprofile', 'r_emailaddress', 'w_member_social']);
console.log(`Redirect user to: ${authUrl}`);
Étape 5 : Échanger le code contre un jeton d'accès
Gérez le rappel OAuth :
const exchangeCodeForToken = async (code) => {
const response = 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: code,
client_id: LINKEDIN_CLIENT_ID,
client_secret: LINKEDIN_CLIENT_SECRET,
redirect_uri: LINKEDIN_REDIRECT_URI
})
});
const data = await response.json();
return {
accessToken: data.access_token,
expiresIn: data.expires_in // 60 days
};
};
// Handle callback
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// Store tokens securely
await db.users.update(req.session.userId, {
linkedin_access_token: tokens.accessToken,
linkedin_token_expires: Date.now() + (tokens.expiresIn * 1000)
});
res.redirect('/success');
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
});
Étape 6 : Actualiser le jeton d'accès
Les jetons d'accès expirent après 60 jours :
const refreshAccessToken = async (refreshToken) => {
// Note: LinkedIn doesn't provide refresh tokens
// Users must re-authenticate after 60 days
// Implement expiry notification
};
// Check token expiry before API calls
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
if (user.linkedin_token_expires < Date.now() + 86400000) { // 24 hours
// Notify user to re-authenticate
await notifyUserToReauth(user.id);
throw new Error('Token expired, please re-authenticate');
}
return user.linkedin_access_token;
};
Étape 7 : Effectuer des appels API authentifiés
Créez un client API réutilisable :
const LINKEDIN_BASE_URL = 'https://api.linkedin.com/v2';
const linkedinRequest = async (endpoint, options = {}) => {
const accessToken = await ensureValidToken(options.userId);
const response = await fetch(`${LINKEDIN_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'X-Restli-Protocol-Version': '2.0.0',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`LinkedIn API Error: ${error.message}`);
}
return response.json();
};
// Usage
const profile = await linkedinRequest('/me');
console.log(`Hello, ${profile.localizedFirstName} ${profile.localizedLastName}`);
Accès au profil
Obtenir le profil utilisateur
Récupérez le profil de l'utilisateur authentifié :
const getUserProfile = async () => {
const response = await linkedinRequest('/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))');
return response;
};
// Usage
const profile = await getUserProfile();
console.log(`Name: ${profile.localizedFirstName} ${profile.localizedLastName}`);
console.log(`ID: ${profile.id}`);
console.log(`Photo: ${profile.profilePicture?.['displayImage~']?.elements?.[0]?.identifiers?.[0]?.identifier}`);
Obtenir l'adresse e-mail
Récupérez l'e-mail de l'utilisateur :
const getUserEmail = async () => {
const response = await linkedinRequest('/emailAddress?q=members&projection=(emailAddress*)');
return response;
};
// Usage
const email = await getUserEmail();
console.log(`Email: ${email.elements?.[0]?.emailAddress}`);
Champs de profil disponibles
| Champ | Permission | Description |
|---|---|---|
id |
r_liteprofile | ID du membre LinkedIn |
firstName |
r_liteprofile | Prénom |
lastName |
r_liteprofile | Nom de famille |
profilePicture |
r_liteprofile | URL de la photo de profil |
headline |
r_basicprofile | Titre professionnel |
summary |
r_basicprofile | Section À propos |
positions |
r_basicprofile | Historique professionnel |
educations |
r_basicprofile | Historique des études |
emailAddress |
r_emailaddress | E-mail principal |
Publication de contenu
Créer une publication
Publiez un contenu texte sur le fil d'actualité de l'utilisateur :
const createPost = async (authorUrn, postContent) => {
const response = await linkedinRequest('/ugcPosts', {
method: 'POST',
body: JSON.stringify({
author: authorUrn,
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postContent.text
},
shareMediaCategory: 'NONE'
}
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
}
})
});
return response;
};
// Usage
const post = await createPost('urn:li:person:ABC123', {
text: 'Excited to announce our new product launch! 🚀 #innovation #startup'
});
console.log(`Post created: ${post.id}`);
Créer une publication avec une image
Publiez un contenu avec une image :
const createPostWithImage = async (authorUrn, postData) => {
// Step 1: Register media upload
const uploadRegistration = await linkedinRequest('/assets?action=registerUpload', {
method: 'POST',
body: JSON.stringify({
registerUploadRequest: {
recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],
owner: authorUrn,
serviceRelationships: [
{
relationshipType: 'OWNER',
identifier: 'urn:li:userGeneratedContent'
}
]
}
})
});
const uploadUrl = uploadRegistration.value.uploadMechanism['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest'].uploadUrl;
const assetUrn = uploadRegistration.value.asset;
// Step 2: Upload image to provided URL
await fetch(uploadUrl, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + await getAccessToken(),
'Content-Type': 'application/octet-stream'
},
body: postData.imageBuffer
});
// Step 3: Create post with uploaded image
const post = await linkedinRequest('/ugcPosts', {
method: 'POST',
body: JSON.stringify({
author: authorUrn,
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postData.text
},
shareMediaCategory: 'IMAGE',
media: [
{
status: 'READY',
description: {
text: postData.imageDescription || ''
},
media: assetUrn,
title: {
text: postData.title || ''
}
}
]
}
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
}
})
});
return post;
};
Créer une publication avec une vidéo
Publiez un contenu vidéo :
const createPostWithVideo = async (authorUrn, postData) => {
// Register video upload
const uploadRegistration = await linkedinRequest('/assets?action=registerUpload', {
method: 'POST',
body: JSON.stringify({
registerUploadRequest: {
recipes: ['urn:li:digitalmediaRecipe:feedshare-video'],
owner: authorUrn,
serviceRelationships: [
{
relationshipType: 'OWNER',
identifier: 'urn:li:userGeneratedContent'
}
]
}
})
});
const assetUrn = uploadRegistration.value.asset;
// Upload video (use presigned upload URLs from response)
// ... upload logic ...
// Create post
const post = await linkedinRequest('/ugcPosts', {
method: 'POST',
body: JSON.stringify({
author: authorUrn,
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: { text: postData.text },
shareMediaCategory: 'VIDEO',
media: [{ status: 'READY', media: assetUrn }]
}
},
visibility: { 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC' }
})
});
return post;
};
Spécifications des médias
| Type de média | Format | Taille maximale | Durée |
|---|---|---|---|
| Image | JPG, PNG, GIF | 8 Mo | N/A |
| Vidéo | MP4, MOV | 5 Go | 15 min max |
| Document | PDF, PPT, DOC | 100 Mo | N/A |
Gestion des pages d'entreprise
Obtenir des informations sur l'entreprise
Récupérez les détails de la page d'entreprise :
const getCompanyInfo = async (companyId) => {
const response = await linkedinRequest(
`/organizations/${companyId}?projection=(id,localizedName,vanityName,tagline,description,universalName,logoV2(original~:playableStreams),companyType,companyPageUrl,confirmedLocations,industries,followerCount,staffCountRange,website, specialties)`
);
return response;
};
// Usage
const company = await getCompanyInfo('1234567');
console.log(`Company: ${company.localizedName}`);
console.log(`Followers: ${company.followerCount}`);
console.log(`Website: ${company.website}`);
Publier sur une page d'entreprise
Partagez une mise à jour sur une page d'entreprise :
const createCompanyPost = async (organizationUrn, postContent) => {
const response = await linkedinRequest('/ugcPosts', {
method: 'POST',
body: JSON.stringify({
author: organizationUrn,
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postContent.text
},
shareMediaCategory: postContent.media ? 'IMAGE' : 'NONE',
media: postContent.media ? [
{
status: 'READY',
media: postContent.media.assetUrn
}
] : []
}
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
}
})
});
return response;
};
// Usage
const post = await createCompanyPost('urn:li:organization:1234567', {
text: "We're hiring! Join our growing team. #careers #hiring"
});
Obtenir les abonnés de l'entreprise
Récupérez le nombre d'abonnés :
const getFollowerCount = async (organizationId) => {
const response = await linkedinRequest(
`/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:${organizationId}`
);
return response;
};
Limitation de débit
Comprendre les limitations de débit
LinkedIn applique des limitations de débit par application :
| API | Limite | Fenêtre |
|---|---|---|
| Profile API | 100 requêtes | Par jour |
| UGC Posts | 50 publications | Par jour |
| Company Admin | 500 requêtes | Par jour |
| Ads API | 100 requêtes | Par minute |
En-têtes de limitation de débit
| En-tête | Description |
|---|---|
X-Restli-Quota-Remaining |
Requêtes restantes |
X-Restli-Quota-Reset |
Secondes avant réinitialisation |
Dépannage des problèmes courants
Problème : 401 Non autorisé
Solutions :
- Vérifiez que le jeton d'accès n'a pas expiré (60 jours)
- Vérifiez que la portée du jeton inclut la ressource demandée
- Assurez-vous que l'en-tête
Authorization: Bearer {token}est présent
Problème : 403 Interdit
Solutions :
- Vérifiez que l'application dispose des autorisations requises
- Vérifiez que l'utilisateur a approuvé les portées demandées
- Une vérification partenaire peut être requise
Problème : 429 Limitation de débit
Solutions :
- Mettre en œuvre une file d'attente de requêtes
- Mettre en cache les réponses pour réduire les appels
- Utiliser des webhooks au lieu de l'interrogation
Liste de contrôle du déploiement en production
Avant la mise en ligne :
- [ ] Effectuer la vérification partenaire LinkedIn
- [ ] Implémenter OAuth 2.0 avec un stockage sécurisé des jetons
- [ ] Ajouter des notifications d'expiration de jeton (60 jours)
- [ ] Configurer la limitation de débit et la mise en file d'attente
- [ ] Configurer les points de terminaison des webhooks
- [ ] Implémenter une gestion complète des erreurs
- [ ] Ajouter la journalisation pour tous les appels API
- [ ] Créer un examen de conformité aux directives de marque
Cas d'utilisation concrets
Plateforme de recrutement
Un outil de recrutement automatise la publication d'offres d'emploi :
- Défi : Publication manuelle sur plusieurs canaux
- Solution : Intégration de l'API LinkedIn Jobs
- Résultat : 80% de gain de temps, 3x plus de candidatures
Automatisation du marketing B2B
Une plateforme marketing planifie du contenu LinkedIn :
- Défi : Calendrier de publication incohérent
- Solution : Publication automatisée via l'API UGC
- Résultat : 5x plus d'engagement, présence de marque cohérente
Conclusion
L'API LinkedIn offre un accès complet aux fonctionnalités du réseau professionnel. Principaux points à retenir :
- Authentification OAuth 2.0 avec des jetons valides 60 jours
- API de profil, de publication et de page d'entreprise disponibles
- Les limitations de débit nécessitent une gestion attentive (100-500/jour)
- La vérification partenaire est requise pour la plupart des API
- Apidog simplifie les tests d'API et la collaboration d'équipe
Section FAQ
Comment puis-je accéder à l'API LinkedIn ?
Créez un compte développeur LinkedIn, créez une application et effectuez la vérification partenaire pour un accès avancé à l'API.
Puis-je publier automatiquement sur LinkedIn ?
Oui, utilisez l'API UGC (User Generated Content) avec la permission w_member_social pour les publications personnelles ou w_organization_social pour les publications d'entreprise.
Quelles sont les limitations de débit de LinkedIn ?
Les limitations de débit varient de 100 à 500 requêtes par jour selon l'API. L'API Ads autorise 100 requêtes par minute.
Combien de temps les jetons LinkedIn sont-ils valides ?
Les jetons d'accès expirent après 60 jours. Les utilisateurs doivent se réauthentifier pour continuer à accéder à l'API.
Puis-je accéder aux connexions utilisateur ?
Non, LinkedIn a supprimé l'accès à l'API des connexions pour la plupart des applications en raison de modifications liées à la confidentialité.
Top comments (0)