TL;DR
Die LinkedIn API ermöglicht Entwicklern die programmatische Integration in das professionelle Netzwerk von LinkedIn. Sie verwendet OAuth 2.0-Authentifizierung, RESTful- und GraphQL-Endpunkte für Profile, Beiträge, Kommentare, Unternehmensseiten und Anzeigen, mit Ratenbegrenzungen von 100-500 Anfragen pro Tag pro App. Dieser Leitfaden behandelt die Einrichtung der Authentifizierung, den Profilzugriff, das Veröffentlichen von Inhalten, die Verwaltung von Unternehmensseiten, die Ads API und Strategien für die Produktionsintegration.
Einleitung
LinkedIn hat über 900 Millionen professionelle Nutzer in mehr als 200 Ländern. Für Entwickler, die Recruiting-Tools, Marketingplattformen oder B2B-Anwendungen erstellen, ist die Integration der LinkedIn API unerlässlich, um dieses professionelle Publikum zu erreichen.
Die Realität sieht so aus: B2B-Marketer, die ihre LinkedIn-Präsenz manuell verwalten, verlieren wöchentlich 15-20 Stunden für das Posten, die Verfolgung des Engagements und die Lead-Generierung. Eine solide LinkedIn API-Integration automatisiert die Inhaltsverteilung, Lead-Erfassung, Engagement-Analysen und Rekrutierungs-Workflows.
Dieser Leitfaden führt Sie durch den gesamten Prozess der LinkedIn API-Integration. Sie lernen die OAuth 2.0-Authentifizierung, den Profilzugriff, das Veröffentlichen von Inhalten, die Verwaltung von Unternehmensseiten, die Anzeigenintegration, Webhooks und Strategien für die Produktionsbereitstellung kennen. Am Ende werden Sie eine produktionsreife LinkedIn-Integration haben.
Was ist die LinkedIn API?
LinkedIn bietet RESTful- und GraphQL-APIs für den Zugriff auf Daten des professionellen Netzwerks. Die API verarbeitet:
- Benutzerprofilinformationen (mit Zustimmung)
- Unternehmensseiten und Updates
- Beiträge, Kommentare und Reaktionen
- Verbindungen (begrenzt)
- Stellenanzeigen und Bewerbungen
- LinkedIn Ads-Verwaltung
- Lead-Generierungsformulare
- Nachrichten (nur für ausgewählte Partner)
Hauptfunktionen
| Funktion | Beschreibung |
|---|---|
| RESTful + GraphQL | Mehrere API-Stile |
| OAuth 2.0 | Benutzerautorisierung erforderlich |
| Ratenbegrenzung | 100-500 Anfragen/Tag pro App |
| Unternehmensseiten | Vollständige CRUD-Operationen |
| Ads API | Kampagnenverwaltung |
| Webhooks | Echtzeit-Benachrichtigungen |
| Medien-Upload | Bilder und Videos |
API-Produkte
| API | Zugriffsebene | Anwendungsfall |
|---|---|---|
| Anmelden mit LinkedIn | Offen | Benutzerauthentifizierung |
| Profil-API | Partner | Benutzerprofil lesen |
| Unternehmensadmin-API | Partner | Unternehmensseiten verwalten |
| Ads API | Partner | Anzeigenkampagnenverwaltung |
| Job Posting API | Partner | Stellenanzeigen veröffentlichen und verwalten |
| Marketing Developer Platform | Partner | Voller API-Zugriff |
API-Versionen
| Version | Status | Enddatum |
|---|---|---|
| v2 | Aktuell | Aktiv |
| v1 | Veraltet | Dezember 2023 |
Erste Schritte: Authentifizierungs-Setup
Schritt 1: LinkedIn-Entwicklerkonto erstellen
Bevor Sie auf die API zugreifen:
- Besuchen Sie das LinkedIn Developer Portal
- Melden Sie sich mit Ihrem LinkedIn-Konto an
- Klicken Sie im My Apps-Dashboard auf App erstellen
- Füllen Sie die App-Details (Name, Logo, Beschreibung) aus
Schritt 2: App-Einstellungen konfigurieren
Richten Sie die App-Authentifizierung ein:
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;
// Holen Sie diese von Ihrem App-Dashboard
// https://www.linkedin.com/developers/apps/{appId}/auth
Schritt 3: Erforderliche Berechtigungen anfordern
LinkedIn erfordert die Genehmigung von Berechtigungen:
| Berechtigung | Beschreibung | Genehmigung erforderlich |
|---|---|---|
r_liteprofile |
Basisches Profil (Name, Foto) | Automatisch genehmigt |
r_emailaddress |
E-Mail-Adresse | Automatisch genehmigt |
w_member_social |
Im Namen des Benutzers posten | Partnerverifizierung |
r_basicprofile |
Vollständiges Profil | Partnerverifizierung |
r_organization_social |
Zugriff auf Unternehmensseiten | Partnerverifizierung |
w_organization_social |
Auf Unternehmensseite posten | Partnerverifizierung |
rw_ads |
Anzeigenverwaltung | Partnerverifizierung |
r_ads_reporting |
Anzeigenanalysen | Partnerverifizierung |
Schritt 4: Autorisierungs-URL erstellen
Implementieren Sie den OAuth 2.0-Flow:
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()}`;
};
// Verwendung
const state = require('crypto').randomBytes(16).toString('hex');
const authUrl = getAuthUrl(state, ['r_liteprofile', 'r_emailaddress', 'w_member_social']);
console.log(`Benutzer weiterleiten zu: ${authUrl}`);
Schritt 5: Code gegen Zugriffstoken tauschen
OAuth-Rückruf behandeln:
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 Tage
};
};
// Rückruf behandeln
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// Token sicher speichern
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-Fehler:', error);
res.status(500).send('Authentifizierung fehlgeschlagen');
}
});
Schritt 6: Zugriffstoken aktualisieren
Zugriffstoken laufen nach 60 Tagen ab:
const refreshAccessToken = async (refreshToken) => {
// Hinweis: LinkedIn stellt keine Refresh-Token bereit
// Benutzer müssen sich nach 60 Tagen neu authentifizieren
// Implementieren Sie eine Ablaufbenachrichtigung
};
// Token-Ablauf vor API-Aufrufen prüfen
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
if (user.linkedin_token_expires < Date.now() + 86400000) { // 24 Stunden
// Benutzer zur erneuten Authentifizierung benachrichtigen
await notifyUserToReauth(user.id);
throw new Error('Token abgelaufen, bitte neu authentifizieren');
}
return user.linkedin_access_token;
};
Schritt 7: Authentifizierte API-Aufrufe tätigen
Wiederverwendbaren API-Client erstellen:
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-Fehler: ${error.message}`);
}
return response.json();
};
// Verwendung
const profile = await linkedinRequest('/me');
console.log(`Hallo, ${profile.localizedFirstName} ${profile.localizedLastName}`);
Profilzugriff
Benutzerprofil abrufen
Profil des authentifizierten Benutzers abrufen:
const getUserProfile = async () => {
const response = await linkedinRequest('/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))');
return response;
};
// Verwendung
const profile = await getUserProfile();
console.log(`Name: ${profile.localizedFirstName} ${profile.localizedLastName}`);
console.log(`ID: ${profile.id}`);
console.log(`Foto: ${profile.profilePicture?.['displayImage~']?.elements?.[0]?.identifiers?.[0]?.identifier}`);
E-Mail-Adresse abrufen
E-Mail des Benutzers abrufen:
const getUserEmail = async () => {
const response = await linkedinRequest('/emailAddress?q=members&projection=(emailAddress*)');
return response;
};
// Verwendung
const email = await getUserEmail();
console.log(`E-Mail: ${email.elements?.[0]?.emailAddress}`);
Verfügbare Profilfelder
| Feld | Berechtigung | Beschreibung |
|---|---|---|
id |
r_liteprofile | LinkedIn-Mitglieds-ID |
firstName |
r_liteprofile | Vorname |
lastName |
r_liteprofile | Nachname |
profilePicture |
r_liteprofile | Profilfoto-URL |
headline |
r_basicprofile | Berufliche Überschrift |
summary |
r_basicprofile | Über-Mich-Bereich |
positions |
r_basicprofile | Berufserfahrung |
educations |
r_basicprofile | Ausbildungsgeschichte |
emailAddress |
r_emailaddress | Primäre E-Mail |
Inhalte posten
Einen Beitrag erstellen
Textbeitrag im Feed des Benutzers teilen:
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;
};
// Verwendung
const post = await createPost('urn:li:person:ABC123', {
text: 'Excited to announce our new product launch! 🚀 #innovation #startup'
});
console.log(`Beitrag erstellt: ${post.id}`);
Einen Beitrag mit Bild erstellen
Beitrag mit Medien teilen:
const createPostWithImage = async (authorUrn, postData) => {
// Schritt 1: Medien-Upload registrieren
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;
// Schritt 2: Bild an die bereitgestellte URL hochladen
await fetch(uploadUrl, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + await getAccessToken(),
'Content-Type': 'application/octet-stream'
},
body: postData.imageBuffer
});
// Schritt 3: Beitrag mit hochgeladenem Bild erstellen
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;
};
Einen Beitrag mit Video erstellen
Videoinhalte teilen:
const createPostWithVideo = async (authorUrn, postData) => {
// Video-Upload registrieren
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;
// Video hochladen (verwenden Sie vorgenerierte Upload-URLs aus der Antwort)
// ... Upload-Logik ...
// Beitrag erstellen
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;
};
Medienspezifikationen
| Medientyp | Format | Max. Größe | Dauer |
|---|---|---|---|
| Bild | JPG, PNG, GIF | 8 MB | N/A |
| Video | MP4, MOV | 5 GB | max. 15 Min. |
| Dokument | PDF, PPT, DOC | 100 MB | N/A |
Unternehmensseitenverwaltung
Unternehmensinformationen abrufen
Details zur Unternehmensseite abrufen:
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;
};
// Verwendung
const company = await getCompanyInfo('1234567');
console.log(`Unternehmen: ${company.localizedName}`);
console.log(`Follower: ${company.followerCount}`);
console.log(`Webseite: ${company.website}`);
Auf Unternehmensseite posten
Update auf Unternehmensseite teilen:
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;
};
// Verwendung
const post = await createCompanyPost('urn:li:organization:1234567', {
text: 'Wir stellen ein! Werden Sie Teil unseres wachsenden Teams. #karriere #einstellung'
});
Follower des Unternehmens abrufen
Follower-Anzahl abrufen:
const getFollowerCount = async (organizationId) => {
const response = await linkedinRequest(
`/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:${organizationId}`
);
return response;
};
Ratenbegrenzung
Ratenbegrenzungen verstehen
LinkedIn erzwingt Ratenbegrenzungen pro App:
| API | Limit | Fenster |
|---|---|---|
| Profil-API | 100 Anfragen | Pro Tag |
| UGC-Beiträge | 50 Beiträge | Pro Tag |
| Unternehmensadmin | 500 Anfragen | Pro Tag |
| Ads API | 100 Anfragen | Pro Minute |
Ratenbegrenzungs-Header
| Header | Beschreibung |
|---|---|
X-Restli-Quota-Remaining |
Verbleibende Anfragen |
X-Restli-Quota-Reset |
Sekunden bis zum Zurücksetzen |
Fehlerbehebung bei häufigen Problemen
Problem: 401 Nicht autorisiert
Lösungen:
- Überprüfen Sie, ob das Zugriffstoken nicht abgelaufen ist (60 Tage)
- Prüfen Sie, ob der Token-Scope die angeforderte Ressource enthält
- Stellen Sie sicher, dass der Header
Authorization: Bearer {token}vorhanden ist
Problem: 403 Verboten
Lösungen:
- Überprüfen Sie, ob die App die erforderlichen Berechtigungen besitzt
- Prüfen Sie, ob der Benutzer die angeforderten Scopes genehmigt hat
- Partnerverifizierung kann erforderlich sein
Problem: 429 Ratenbegrenzung erreicht
Lösungen:
- Implementieren Sie eine Anfragewarteschlange
- Cachen Sie Antworten, um Aufrufe zu reduzieren
- Verwenden Sie Webhooks anstelle von Polling
Checkliste für die Produktionsbereitstellung
Vor der Live-Schaltung:
- [ ] Vollständige LinkedIn-Partnerverifizierung
- [ ] Implementierung von OAuth 2.0 mit sicherer Token-Speicherung
- [ ] Hinzufügen von Token-Ablaufbenachrichtigungen (60 Tage)
- [ ] Einrichtung von Ratenbegrenzung und Warteschlange
- [ ] Konfiguration von Webhook-Endpunkten
- [ ] Implementierung einer umfassenden Fehlerbehandlung
- [ ] Hinzufügen von Protokollierung für alle API-Aufrufe
- [ ] Erstellung einer Überprüfung der Markenrichtlinienkonformität
Anwendungsfälle in der Praxis
Rekrutierungsplattform
Ein Rekrutierungstool automatisiert Stellenanzeigen:
- Herausforderung: Manuelles Posten über mehrere Kanäle
- Lösung: LinkedIn Jobs API-Integration
- Ergebnis: 80 % Zeitersparnis, 3x Bewerbungen
B2B Marketing-Automatisierung
Eine Marketingplattform plant LinkedIn-Inhalte:
- Herausforderung: Inkonstanter Veröffentlichungsplan
- Lösung: Automatisiertes Posten über die UGC API
- Ergebnis: 5x Engagement, konsistente Markenpräsenz
Fazit
Die LinkedIn API bietet umfassenden Zugriff auf professionelle Netzwerkfunktionen. Wichtigste Erkenntnisse:
- OAuth 2.0-Authentifizierung mit 60-Tage-Tokens
- Profil-, Posting- und Unternehmensseiten-APIs verfügbar
- Ratenbegrenzungen erfordern sorgfältige Verwaltung (100-500/Tag)
- Partnerverifizierung für die meisten APIs erforderlich
- Apidog optimiert API-Tests und Teamzusammenarbeit
FAQ-Bereich
Wie erhalte ich Zugang zur LinkedIn API?
Erstellen Sie ein LinkedIn-Entwicklerkonto, erstellen Sie eine App und schließen Sie die Partnerverifizierung für erweiterten API-Zugriff ab.
Kann ich automatisch auf LinkedIn posten?
Ja, verwenden Sie die UGC (User Generated Content) API mit der Berechtigung w_member_social für persönliche Beiträge oder w_organization_social für Unternehmensbeiträge.
Was sind LinkedIn-Ratenbegrenzungen?
Die Ratenbegrenzungen liegen je nach API zwischen 100 und 500 Anfragen pro Tag. Die Ads API erlaubt 100 Anfragen pro Minute.
Wie lange sind LinkedIn-Tokens gültig?
Zugriffstoken laufen nach 60 Tagen ab. Benutzer müssen sich erneut authentifizieren, um den API-Zugriff fortzusetzen.
Kann ich auf Benutzerverbindungen zugreifen?
Nein, LinkedIn hat den API-Zugriff auf Verbindungen für die meisten Apps aufgrund von Datenschutzänderungen entfernt.
