ملخص سريع
تُمكن واجهة برمجة تطبيقات LinkedIn (API) المطورين من التكامل مع شبكة LinkedIn المهنية برمجياً. تستخدم مصادقة OAuth 2.0، ونقاط نهاية RESTful وGraphQL للملفات الشخصية والمنشورات والتعليقات وصفحات الشركات والإعلانات، مع حدود معدل تبلغ 100-500 طلب يومياً لكل تطبيق. يغطي هذا الدليل إعداد المصادقة، والوصول إلى الملفات الشخصية، ونشر المحتوى، وإدارة صفحات الشركات، وواجهة برمجة إعلانات API، واستراتيجيات التكامل للإنتاج.
مقدمة
يضم LinkedIn أكثر من 900 مليون مستخدم محترف في أكثر من 200 دولة. بالنسبة للمطورين الذين يقومون ببناء أدوات توظيف أو منصات تسويق أو تطبيقات B2B، يعد تكامل واجهة برمجة تطبيقات LinkedIn ضرورياً للوصول إلى هذا الجمهور المحترف.
الواقع هو أن مسوقي B2B الذين يديرون حضور LinkedIn يدوياً يخسرون 15-20 ساعة أسبوعياً في النشر وتتبع التفاعل وتوليد العملاء المحتملين. يوفر تكامل قوي لواجهة برمجة تطبيقات LinkedIn أتمتة توزيع المحتوى، والتقاط العملاء المحتملين، وتحليلات التفاعل، وسير عمل التوظيف.
يرشدك هذا الدليل إلى كيفية تنفيذ تكامل LinkedIn خطوة بخطوة: مصادقة OAuth 2.0، الوصول للملفات الشخصية، النشر، إدارة صفحات الشركات، تكامل الإعلانات، webhooks، واستراتيجيات النشر للإنتاج.
💡 يعمل Apidog على تبسيط اختبار تكامل واجهة برمجة التطبيقات. اختبر نقاط نهاية LinkedIn الخاصة بك، وتحقق من تدفقات OAuth، وافحص استجابات واجهة برمجة التطبيقات، وقم بتصحيح مشكلات الأذونات في مساحة عمل واحدة. قم باستيراد مواصفات واجهة برمجة التطبيقات، والاستجابات الوهمية (mock responses)، وشارك سيناريوهات الاختبار مع فريقك.
ما هي واجهة برمجة تطبيقات LinkedIn (API)؟
يوفر LinkedIn واجهات برمجة تطبيقات RESTful وGraphQL للوصول إلى بيانات الشبكة المهنية. تتعامل واجهة برمجة التطبيقات مع:
- معلومات الملف الشخصي للمستخدم (بموافقته)
- صفحات الشركة والتحديثات
- المنشورات والتعليقات والتفاعلات
- الاتصالات (محدودة)
- إعلانات الوظائف والطلبات
- إدارة إعلانات LinkedIn
- نماذج توليد العملاء المحتملين
- الرسائل (للشركاء المحددين فقط)
الميزات الرئيسية
| الميزة | الوصف |
|---|---|
| RESTful + GraphQL | أنماط متعددة لواجهة برمجة التطبيقات |
| OAuth 2.0 | يتطلب تفويض المستخدم |
| تحديد المعدل (Rate Limiting) | 100-500 طلب/يوم لكل تطبيق |
| صفحات الشركات | عمليات CRUD كاملة |
| واجهة برمجة تطبيقات الإعلانات (Ads API) | إدارة الحملات |
| الخطافات الويب (Webhooks) | إشعارات في الوقت الفعلي |
| تحميل الوسائط | الصور ومقاطع الفيديو |
منتجات واجهة برمجة التطبيقات
| واجهة برمجة التطبيقات (API) | مستوى الوصول | حالة الاستخدام |
|---|---|---|
| تسجيل الدخول باستخدام LinkedIn | مفتوح | مصادقة المستخدم |
| واجهة برمجة تطبيقات الملف الشخصي | شريك | قراءة ملف تعريف المستخدم |
| واجهة برمجة تطبيقات مسؤول الشركة | شريك | إدارة صفحات الشركة |
| واجهة برمجة تطبيقات الإعلانات | شريك | إدارة حملات الإعلانات |
| واجهة برمجة تطبيقات نشر الوظائف | شريك | نشر الوظائف وإدارتها |
| منصة المطورين للتسويق | شريك | وصول كامل لواجهة برمجة التطبيقات |
إصدارات واجهة برمجة التطبيقات
| الإصدار | الحالة | تاريخ الانتهاء |
|---|---|---|
| v2 | حالي | نشط |
| v1 | متقاعد | ديسمبر 2023 |
البدء: إعداد المصادقة
الخطوة 1: إنشاء حساب مطور LinkedIn
- زر بوابة مطوري LinkedIn
- سجل الدخول باستخدام حساب LinkedIn الخاص بك.
- أنشئ تطبيقاً جديداً من لوحة التحكم (My Apps).
- أدخل تفاصيل التطبيق (اسم، شعار، وصف).
الخطوة 2: تكوين إعدادات التطبيق
عين المتغيرات البيئية التالية:
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;
// احصل على هذه من لوحة تحكم تطبيقك
// https://www.linkedin.com/developers/apps/{appId}/auth
الخطوة 3: طلب الأذونات المطلوبة
حدد الأذونات اللازمة لتطبيقك:
| الإذن | الوصف | الموافقة المطلوبة |
|---|---|---|
r_liteprofile |
الملف الشخصي الأساسي | موافق عليه تلقائياً |
r_emailaddress |
عنوان البريد الإلكتروني | موافق عليه تلقائياً |
w_member_social |
النشر نيابة عن المستخدم | تحقق الشريك |
r_basicprofile |
الملف الشخصي الكامل | تحقق الشريك |
r_organization_social |
الوصول إلى صفحة الشركة | تحقق الشريك |
w_organization_social |
النشر على صفحة الشركة | تحقق الشريك |
rw_ads |
إدارة الإعلانات | تحقق الشريك |
r_ads_reporting |
تحليلات الإعلانات | تحقق الشريك |
الخطوة 4: بناء عنوان URL للتفويض
نفذ تدفق 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()}`;
};
// الاستخدام
const state = require('crypto').randomBytes(16).toString('hex');
const authUrl = getAuthUrl(state, ['r_liteprofile', 'r_emailaddress', 'w_member_social']);
console.log(`إعادة توجيه المستخدم إلى: ${authUrl}`);
الخطوة 5: تبادل الكود لرمز الوصول
عالج رد اتصال 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 يوم
};
};
// التعامل مع رد الاتصال
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// تخزين الرموز بأمان
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);
res.status(500).send('فشل المصادقة');
}
});
الخطوة 6: تحديث رمز الوصول
رموز الوصول تنتهي بعد 60 يوماً. LinkedIn لا يوفر refresh token. نفذ إشعاراً للمستخدم لإعادة المصادقة عند اقتراب انتهاء الصلاحية.
const refreshAccessToken = async (refreshToken) => {
// لا توجد رموز تحديث (refresh token) في LinkedIn
// يجب على المستخدمين إعادة المصادقة بعد 60 يومًا
// نفذ منطق إشعار انتهاء الصلاحية هنا
};
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
if (user.linkedin_token_expires < Date.now() + 86400000) { // 24 ساعة
await notifyUserToReauth(user.id);
throw new Error('انتهت صلاحية الرمز، يرجى إعادة المصادقة');
}
return user.linkedin_access_token;
};
الخطوة 7: إجراء استدعاءات واجهة برمجة التطبيقات المصادق عليها
أنشئ دالة طلب عامة:
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.message}`);
}
return response.json();
};
// الاستخدام
const profile = await linkedinRequest('/me');
console.log(`مرحباً، ${profile.localizedFirstName} ${profile.localizedLastName}`);
الوصول إلى الملف الشخصي
الحصول على ملف تعريف المستخدم
const getUserProfile = async () => {
const response = await linkedinRequest('/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))');
return response;
};
// الاستخدام
const profile = await getUserProfile();
console.log(`الاسم: ${profile.localizedFirstName} ${profile.localizedLastName}`);
console.log(`المعرف: ${profile.id}`);
console.log(`الصورة: ${profile.profilePicture?.['displayImage~']?.elements?.[0]?.identifiers?.[0]?.identifier}`);
الحصول على عنوان البريد الإلكتروني
const getUserEmail = async () => {
const response = await linkedinRequest('/emailAddress?q=members&projection=(emailAddress*)');
return response;
};
// الاستخدام
const email = await getUserEmail();
console.log(`البريد الإلكتروني: ${email.elements?.[0]?.emailAddress}`);
حقول الملف الشخصي المتاحة
| الحقل | الإذن | الوصف |
|---|---|---|
id |
r_liteprofile | معرف عضو LinkedIn |
firstName |
r_liteprofile | الاسم الأول |
lastName |
r_liteprofile | الاسم الأخير |
profilePicture |
r_liteprofile | رابط صورة الملف |
headline |
r_basicprofile | العنوان المهني |
summary |
r_basicprofile | قسم "حول" |
positions |
r_basicprofile | تاريخ العمل |
educations |
r_basicprofile | تاريخ التعليم |
emailAddress |
r_emailaddress | البريد الإلكتروني |
نشر المحتوى
إنشاء منشور نصي
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;
};
// الاستخدام
const post = await createPost('urn:li:person:ABC123', {
text: 'متحمسون للإعلان عن إطلاق منتجنا الجديد! 🚀 #ابتكار #شركة_ناشئة'
});
console.log(`تم إنشاء المنشور: ${post.id}`);
إنشاء منشور بصورة
const createPostWithImage = async (authorUrn, postData) => {
// الخطوة 1: تسجيل تحميل الوسائط
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;
// الخطوة 2: تحميل الصورة إلى عنوان URL المقدم
await fetch(uploadUrl, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + await getAccessToken(),
'Content-Type': 'application/octet-stream'
},
body: postData.imageBuffer
});
// الخطوة 3: إنشاء منشور بالصورة المحملة
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;
};
إنشاء منشور بفيديو
const createPostWithVideo = async (authorUrn, postData) => {
// تسجيل تحميل الفيديو
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;
// تحميل الفيديو (استخدم عناوين URL للتحميل الموقعة مسبقًا من الاستجابة)
// ... منطق التحميل ...
// إنشاء منشور
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;
};
مواصفات الوسائط
| نوع الوسائط | التنسيق | الحد الأقصى للحجم | المدة |
|---|---|---|---|
| صورة | JPG, PNG, GIF | 8 ميجابايت | غير متوفر |
| فيديو | MP4, MOV | 5 جيجابايت | 15 دقيقة كحد أقصى |
| مستند | PDF, PPT, DOC | 100 ميجابايت | غير متوفر |
إدارة صفحة الشركة
الحصول على معلومات الشركة
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;
};
// الاستخدام
const company = await getCompanyInfo('1234567');
console.log(`الشركة: ${company.localizedName}`);
console.log(`المتابعون: ${company.followerCount}`);
console.log(`الموقع الإلكتروني: ${company.website}`);
النشر على صفحة الشركة
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;
};
// الاستخدام
const post = await createCompanyPost('urn:li:organization:1234567', {
text: 'نحن نوظف! انضم إلى فريقنا المتنامي. #وظائف #توظيف'
});
الحصول على متابعي الشركة
const getFollowerCount = async (organizationId) => {
const response = await linkedinRequest(
`/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:${organizationId}`
);
return response;
};
تحديد المعدل
فهم حدود المعدل
| واجهة برمجة التطبيقات | الحد | النافذة الزمنية |
|---|---|---|
| واجهة برمجة تطبيقات الملف الشخصي | 100 طلب | يومياً |
| منشورات المحتوى الذي ينشئه المستخدم | 50 منشوراً | يومياً |
| إدارة الشركة | 500 طلب | يومياً |
| واجهة برمجة تطبيقات الإعلانات | 100 طلب | لكل دقيقة |
رؤوس تحديد المعدل (Rate Limit Headers)
| الرأس | الوصف |
|---|---|
X-Restli-Quota-Remaining |
الطلبات المتبقية |
X-Restli-Quota-Reset |
الثواني حتى إعادة الضبط |
استكشاف المشكلات الشائعة وإصلاحها
المشكلة: 401 غير مصرح به
- تحقق من أن رمز الوصول لم تنته صلاحيته (60 يوماً)
- تأكد من أن نطاق الرمز يتضمن المورد المطلوب
- تحقق من وجود رأس
Authorization: Bearer {token}
المشكلة: 403 ممنوع
- تحقق أن التطبيق لديه الأذونات المطلوبة
- تأكد من موافقة المستخدم على النطاقات اللازمة
- قد يكون التحقق من الشريك مطلوباً
المشكلة: 429 تم تحديد المعدل
- نفذ قائمة انتظار للطلبات
- قم بتخزين الاستجابات مؤقتاً لتقليل الاستدعاءات
- استخدم webhooks بدلاً من الاستقصاء (polling)
قائمة التحقق من النشر للإنتاج
قبل الانطلاق تأكد من:
- [ ] أكمل التحقق من شريك LinkedIn
- [ ] نفذ OAuth 2.0 مع تخزين آمن للرموز
- [ ] أضف إشعارات انتهاء صلاحية الرمز (60 يوماً)
- [ ] قم بإعداد تحديد المعدل وقائمة الانتظار
- [ ] قم بتكوين نقاط نهاية الـ webhook
- [ ] نفذ معالجة الأخطاء الشاملة
- [ ] أضف التسجيل لجميع استدعاءات واجهة برمجة التطبيقات
- [ ] أنشئ مراجعة للامتثال لإرشادات العلامة التجارية
حالات الاستخدام في العالم الحقيقي
منصة التوظيف
- التحدي: النشر اليدوي عبر قنوات متعددة
- الحل: تكامل LinkedIn Jobs API
- النتيجة: توفير 80% من الوقت، 3 أضعاف عدد الطلبات
أتمتة التسويق للشركات (B2B)
- التحدي: جدول نشر غير متسق
- الحل: النشر الآلي عبر UGC API
- النتيجة: 5 أضعاف التفاعل، حضور متسق للعلامة التجارية
الخلاصة
توفر واجهة برمجة تطبيقات LinkedIn وصولاً شاملاً لميزات الشبكة المهنية. النقاط الأساسية:
- مصادقة OAuth 2.0 برموز صالحة لمدة 60 يوماً
- توفر واجهات برمجة تطبيقات للملف الشخصي والنشر وصفحة الشركة
- تتطلب حدود المعدل إدارة دقيقة (100-500/يوم)
- يلزم التحقق من الشريك لمعظم واجهات برمجة التطبيقات
- Apidog يبسط اختبار API والتعاون بين الفرق
قسم الأسئلة الشائعة
كيف أحصل على وصول إلى واجهة برمجة تطبيقات LinkedIn؟
أنشئ حساب مطور على LinkedIn، ثم أنشئ تطبيقاً، وأكمل التحقق من الشريك للوصول إلى واجهة برمجة التطبيقات المتقدمة.
هل يمكنني النشر على LinkedIn تلقائياً؟
نعم، استخدم واجهة برمجة تطبيقات UGC (المحتوى الذي ينشئه المستخدم) مع إذن w_member_social للمنشورات الشخصية أو w_organization_social للمنشورات الخاصة بالشركة.
ما هي حدود معدل LinkedIn؟
تتراوح حدود المعدل من 100-500 طلب في اليوم حسب واجهة برمجة التطبيقات. تتيح واجهة برمجة تطبيقات الإعلانات 100 طلب في الدقيقة.
كم تدوم رموز LinkedIn؟
تنتهي صلاحية رموز الوصول بعد 60 يوماً. يجب على المستخدمين إعادة المصادقة لمتابعة الوصول إلى واجهة برمجة التطبيقات.
هل يمكنني الوصول إلى اتصالات المستخدم؟
لا، أزال LinkedIn الوصول إلى واجهة برمجة تطبيقات الاتصالات لمعظم التطبيقات بسبب تغييرات الخصوصية.
Top comments (0)