ملخص سريع
تُمكن واجهة برمجة تطبيقات 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)، واستراتيجيات النشر للإنتاج. بحلول النهاية، سيكون لديك تكامل LinkedIn جاهز للإنتاج.
ما هي واجهة برمجة تطبيقات 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: طلب الأذونات المطلوبة
يتطلب LinkedIn الموافقة على الأذونات:
| الإذن | الوصف | الموافقة المطلوبة |
|---|---|---|
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 يومًا:
const refreshAccessToken = async (refreshToken) => {
// ملاحظة: لا يوفر 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;
};
تحديد المعدل
فهم حدود المعدل
يفرض LinkedIn حدوداً للمعدل لكل تطبيق:
| واجهة برمجة التطبيقات | الحد | النافذة الزمنية |
|---|---|---|
| واجهة برمجة تطبيقات الملف الشخصي | 100 طلب | يومياً |
| منشورات المحتوى الذي ينشئه المستخدم (UGC) | 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)
منصة تسويق تقوم بجدولة محتوى LinkedIn:
- التحدي: جدول نشر غير متسق
- الحل: النشر الآلي عبر UGC API
- النتيجة: 5 أضعاف التفاعل، حضور متسق للعلامة التجارية
الخلاصة
توفر واجهة برمجة تطبيقات LinkedIn وصولاً شاملاً إلى ميزات الشبكة المهنية. النقاط الرئيسية المستفادة:
- مصادقة OAuth 2.0 برموز صالحة لمدة 60 يوماً
- تتوفر واجهات برمجة تطبيقات للملف الشخصي والنشر وصفحة الشركة
- تتطلب حدود المعدل إدارة دقيقة (100-500/يوم)
- يلزم التحقق من الشريك لمعظم واجهات برمجة التطبيقات
- يعمل Apidog على تبسيط اختبار واجهة برمجة التطبيقات والتعاون بين الفرق
قسم الأسئلة الشائعة
كيف أحصل على وصول إلى واجهة برمجة تطبيقات LinkedIn؟
أنشئ حساب مطور على LinkedIn، ثم أنشئ تطبيقاً، وأكمل التحقق من الشريك للوصول إلى واجهة برمجة التطبيقات المتقدمة.
هل يمكنني النشر على LinkedIn تلقائياً؟
نعم، استخدم واجهة برمجة تطبيقات UGC (المحتوى الذي ينشئه المستخدم) مع إذن w_member_social للمنشورات الشخصية أو w_organization_social للمنشورات الخاصة بالشركة.
ما هي حدود معدل LinkedIn؟
تتراوح حدود المعدل من 100-500 طلب في اليوم حسب واجهة برمجة التطبيقات. تتيح واجهة برمجة تطبيقات الإعلانات 100 طلب في الدقيقة.
كم تدوم رموز LinkedIn؟
تنتهي صلاحية رموز الوصول بعد 60 يوماً. يجب على المستخدمين إعادة المصادقة لمتابعة الوصول إلى واجهة برمجة التطبيقات.
هل يمكنني الوصول إلى اتصالات المستخدم؟
لا، أزال LinkedIn الوصول إلى واجهة برمجة تطبيقات الاتصالات لمعظم التطبيقات بسبب تغييرات الخصوصية.
