TL;DR
La API de LinkedIn permite a los desarrolladores integrarse programáticamente con la red profesional de LinkedIn. Utiliza autenticación OAuth 2.0, puntos finales RESTful y GraphQL para perfiles, publicaciones, comentarios, páginas de empresa y anuncios, con límites de tasa de 100-500 solicitudes por día por aplicación. Esta guía cubre la configuración de la autenticación, el acceso al perfil, la publicación de contenido, la gestión de páginas de empresa, la API de anuncios y las estrategias de integración en producción.
Introducción
LinkedIn tiene más de 900 millones de usuarios profesionales en más de 200 países. Para los desarrolladores que crean herramientas de reclutamiento, plataformas de marketing o aplicaciones B2B, la integración de la API de LinkedIn es esencial para llegar a esta audiencia profesional.
Esta es la realidad: los especialistas en marketing B2B que gestionan manualmente la presencia en LinkedIn pierden de 15 a 20 horas semanales en la publicación, el seguimiento del engagement y la generación de leads. Una sólida integración de la API de LinkedIn automatiza la distribución de contenido, la captura de leads, el análisis del engagement y los flujos de trabajo de reclutamiento.
Esta guía le guiará a través del proceso completo de integración de la API de LinkedIn. Aprenderá sobre la autenticación OAuth 2.0, el acceso al perfil, la publicación de contenido, la gestión de páginas de empresa, la integración de anuncios, los webhooks y las estrategias de implementación en producción. Al final, tendrá una integración de LinkedIn lista para producción.
💡 Apidog simplifica las pruebas de integración de API. Pruebe sus puntos finales de LinkedIn, valide los flujos de OAuth, inspeccione las respuestas de la API y depure los problemas de permisos en un solo espacio de trabajo. Importe especificaciones de API, simule respuestas y comparta escenarios de prueba con su equipo.
¿Qué es la API de LinkedIn?
LinkedIn proporciona APIs RESTful y GraphQL para acceder a los datos de la red profesional. La API maneja:
- Información del perfil de usuario (con consentimiento)
- Páginas y actualizaciones de empresa
- Publicaciones, comentarios y reacciones
- Conexiones (limitado)
- Publicaciones y solicitudes de empleo
- Gestión de LinkedIn Ads
- Formularios de generación de leads
- Mensajería (solo socios limitados)
Características Clave
| Característica | Descripción |
|---|---|
| RESTful + GraphQL | Múltiples estilos de API |
| OAuth 2.0 | Requiere autorización de usuario |
| Límite de Tasa | 100-500 solicitudes/día |
| Páginas de Empresa | Operaciones CRUD completas |
| API de Anuncios | Gestión de campañas |
| Webhooks | Notificaciones en tiempo real |
| Carga de Medios | Imágenes y vídeos |
Productos de la API
| API | Nivel de Acceso | Caso de Uso |
|---|---|---|
| Iniciar Sesión con LinkedIn | Abierto | Autenticación de usuario |
| API de Perfil | Socio | Leer perfil de usuario |
| API de Administración de Empresa | Socio | Gestionar páginas de empresa |
| API de Anuncios | Socio | Gestión de campañas publicitarias |
| API de Publicación de Empleos | Socio | Publicar y gestionar empleos |
| Plataforma de Desarrolladores de Marketing | Socio | Acceso completo a la API |
Versiones de la API
| Versión | Estado | Fecha de Finalización |
|---|---|---|
| v2 | Actual | Activa |
| v1 | Retirada | Diciembre de 2023 |
Primeros Pasos: Configuración de la Autenticación
Paso 1: Crear una Cuenta de Desarrollador de LinkedIn
- Visite el Portal de Desarrolladores de LinkedIn
- Inicie sesión con su cuenta de LinkedIn
- Haga clic en Crear Aplicación en el panel de Mis Aplicaciones
- Complete los detalles de la aplicación (nombre, logotipo, descripción)
Paso 2: Configurar los Ajustes de la Aplicación
Configure la autenticación:
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;
// Obtenga estos datos del panel de su aplicación
// https://www.linkedin.com/developers/apps/{appId}/auth
Paso 3: Solicitar los Permisos Necesarios
Solicite y configure los permisos requeridos para su funcionalidad:
| Permiso | Descripción | Aprobación Requerida |
|---|---|---|
r_liteprofile |
Perfil básico (nombre, foto) | Automática |
r_emailaddress |
Dirección de correo electrónico | Automática |
w_member_social |
Publicar en nombre del usuario | Verificación de socio |
r_basicprofile |
Perfil completo | Verificación de socio |
r_organization_social |
Acceso a página de empresa | Verificación de socio |
w_organization_social |
Publicar en página de empresa | Verificación de socio |
rw_ads |
Gestión de anuncios | Verificación de socio |
r_ads_reporting |
Análisis de anuncios | Verificación de socio |
Paso 4: Construir la URL de Autorización
Implemente el flujo OAuth 2.0 para obtener el consentimiento del usuario:
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()}`;
};
// Uso
const state = require('crypto').randomBytes(16).toString('hex');
const authUrl = getAuthUrl(state, ['r_liteprofile', 'r_emailaddress', 'w_member_social']);
console.log(`Redirigir usuario a: ${authUrl}`);
Paso 5: Intercambiar el Código por un Token de Acceso
Implemente el endpoint de callback para intercambiar el código de autorización por un token de acceso:
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 días
};
};
// Manejar la devolución de llamada
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// Almacenar tokens de forma segura
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('Error de OAuth:', error);
res.status(500).send('Autenticación fallida');
}
});
Paso 6: Refrescar el Token de Acceso
LinkedIn no ofrece tokens de refresco. Debe implementar notificaciones de caducidad y pedir que el usuario vuelva a autenticarse cada 60 días.
const refreshAccessToken = async (refreshToken) => {
// Nota: LinkedIn no proporciona tokens de refresco
// Los usuarios deben volver a autenticarse después de 60 días
// Implementar notificación de caducidad
};
// Verificar la caducidad del token antes de las llamadas a la API
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
if (user.linkedin_token_expires < Date.now() + 86400000) { // 24 horas
// Notificar al usuario para que vuelva a autenticarse
await notifyUserToReauth(user.id);
throw new Error('Token expirado, por favor, vuelva a autenticarse');
}
return user.linkedin_access_token;
};
Paso 7: Realizar Llamadas Autenticadas a la API
Cree un cliente de API reutilizable para gestionar las solicitudes autenticadas:
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(`Error de la API de LinkedIn: ${error.message}`);
}
return response.json();
};
// Uso
const profile = await linkedinRequest('/me');
console.log(`Hola, ${profile.localizedFirstName} ${profile.localizedLastName}`);
Acceso al Perfil
Obtener el Perfil del Usuario
Obtenga el perfil autenticado:
const getUserProfile = async () => {
const response = await linkedinRequest('/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))');
return response;
};
// Uso
const profile = await getUserProfile();
console.log(`Nombre: ${profile.localizedFirstName} ${profile.localizedLastName}`);
console.log(`ID: ${profile.id}`);
console.log(`Foto: ${profile.profilePicture?.['displayImage~']?.elements?.[0]?.identifiers?.[0]?.identifier}`);
Obtener la Dirección de Correo Electrónico
Acceda al correo electrónico del usuario autenticado:
const getUserEmail = async () => {
const response = await linkedinRequest('/emailAddress?q=members&projection=(emailAddress*)');
return response;
};
// Uso
const email = await getUserEmail();
console.log(`Correo electrónico: ${email.elements?.[0]?.emailAddress}`);
Campos de Perfil Disponibles
| Campo | Permiso | Descripción |
|---|---|---|
id |
r_liteprofile | ID de miembro de LinkedIn |
firstName |
r_liteprofile | Nombre |
lastName |
r_liteprofile | Apellido |
profilePicture |
r_liteprofile | URL de la foto de perfil |
headline |
r_basicprofile | Titular profesional |
summary |
r_basicprofile | Sección "Acerca de" |
positions |
r_basicprofile | Historial laboral |
educations |
r_basicprofile | Historial educativo |
emailAddress |
r_emailaddress | Correo electrónico principal |
Publicación de Contenido
Crear una Publicación
Comparta una publicación de texto en el feed del usuario:
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;
};
// Uso
const post = await createPost('urn:li:person:ABC123', {
text: '¡Emocionados de anunciar el lanzamiento de nuestro nuevo producto! 🚀 #innovación #startup'
});
console.log(`Publicación creada: ${post.id}`);
Crear una Publicación con Imagen
Use el flujo de carga de medios para agregar imágenes a las publicaciones:
const createPostWithImage = async (authorUrn, postData) => {
// Paso 1: Registrar la carga de medios
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;
// Paso 2: Subir imagen a la URL proporcionada
await fetch(uploadUrl, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + await getAccessToken(),
'Content-Type': 'application/octet-stream'
},
body: postData.imageBuffer
});
// Paso 3: Crear publicación con la imagen subida
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;
};
Crear una Publicación con Vídeo
Para compartir vídeos, registre primero la carga y luego publique:
const createPostWithVideo = async (authorUrn, postData) => {
// Registrar la carga de vídeo
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;
// Subir vídeo (usar URLs de carga pre-firmadas de la respuesta)
// ... lógica de carga ...
// Crear publicación
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;
};
Especificaciones de Medios
| Tipo de Medio | Formato | Tamaño Máx. | Duración |
|---|---|---|---|
| Imagen | JPG, PNG, GIF | 8MB | N/A |
| Vídeo | MP4, MOV | 5GB | 15 min máx. |
| Documento | PDF, PPT, DOC | 100MB | N/A |
Gestión de Páginas de Empresa
Obtener Información de la Empresa
Consulte datos de la página de empresa por ID:
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;
};
// Uso
const company = await getCompanyInfo('1234567');
console.log(`Empresa: ${company.localizedName}`);
console.log(`Seguidores: ${company.followerCount}`);
console.log(`Sitio web: ${company.website}`);
Publicar en la Página de Empresa
Cree publicaciones como organización:
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;
};
// Uso
const post = await createCompanyPost('urn:li:organization:1234567', {
text: '¡Estamos contratando! Únase a nuestro creciente equipo. #carreras #contratación'
});
Obtener Seguidores de la Empresa
Obtenga el conteo de seguidores de la página de empresa:
const getFollowerCount = async (organizationId) => {
const response = await linkedinRequest(
`/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:${organizationId}`
);
return response;
};
Límites de Tasa
Comprendiendo los Límites de Tasa
| API | Límite | Ventana |
|---|---|---|
| API de Perfil | 100 solicitudes | Por día |
| Publicaciones UGC | 50 publicaciones | Por día |
| Administración Empresa | 500 solicitudes | Por día |
| API de Anuncios | 100 solicitudes | Por minuto |
Cabeceras de Límite de Tasa
| Cabecera | Descripción |
|---|---|
X-Restli-Quota-Remaining |
Solicitudes restantes |
X-Restli-Quota-Reset |
Segundos hasta reinicio |
Resolución de Problemas Comunes
Problema: 401 No Autorizado
Soluciones:
- Verifique que el token de acceso no haya expirado (60 días)
- Compruebe que el alcance del token incluye el recurso solicitado
- Asegúrese de que la cabecera
Authorization: Bearer {token}esté presente
Problema: 403 Prohibido
Soluciones:
- Verifique que la aplicación tenga los permisos necesarios
- Compruebe que el usuario aprobó los ámbitos solicitados
- Puede ser necesaria la verificación de socio
Problema: 429 Límite de Tasa Alcanzado
Soluciones:
- Implemente cola de solicitudes
- Almacene en caché las respuestas para reducir llamadas
- Use webhooks en lugar de sondeo
Lista de Verificación de Implementación en Producción
Antes de salir en vivo, asegúrese de:
- [ ] Completar la verificación de socio de LinkedIn
- [ ] Implementar OAuth 2.0 con almacenamiento seguro de tokens
- [ ] Añadir notificaciones de caducidad de tokens (60 días)
- [ ] Configurar límites de tasa y cola
- [ ] Configurar puntos finales de webhook
- [ ] Implementar un manejo de errores exhaustivo
- [ ] Añadir registro para todas las llamadas a la API
- [ ] Crear revisión de cumplimiento de directrices de marca
Casos de Uso en el Mundo Real
Plataforma de Reclutamiento
Automatice publicaciones de empleo:
- Desafío: Publicación manual en múltiples canales
- Solución: Integración con la API de Empleos de LinkedIn
- Resultado: 80% de ahorro de tiempo, 3x más solicitudes
Automatización de Marketing B2B
Automatice la programación de contenido:
- Desafío: Horario de publicación inconsistente
- Solución: Publicación automatizada vía API UGC
- Resultado: 5x más engagement, presencia de marca consistente
Conclusión
La API de LinkedIn proporciona acceso completo a las características de la red profesional. Puntos clave:
- Autenticación OAuth 2.0 con tokens de 60 días
- APIs de perfil, publicación y página de empresa disponibles
- Los límites de tasa requieren una gestión cuidadosa (100-500/día)
- Verificación de socio requerida para la mayoría de las APIs
- Apidog agiliza las pruebas de API y la colaboración en equipo
Sección de Preguntas Frecuentes
¿Cómo obtengo acceso a la API de LinkedIn?
Cree una cuenta de desarrollador de LinkedIn, cree una aplicación y complete la verificación de socio para obtener acceso avanzado a la API.
¿Puedo publicar en LinkedIn automáticamente?
Sí, utilice la API UGC (Contenido Generado por el Usuario) con el permiso w_member_social para publicaciones personales o w_organization_social para publicaciones de empresa.
¿Cuáles son los límites de tasa de LinkedIn?
Los límites de tasa varían de 100 a 500 solicitudes por día, dependiendo de la API. La API de Anuncios permite 100 solicitudes por minuto.
¿Cuánto tiempo duran los tokens de LinkedIn?
Los tokens de acceso expiran después de 60 días. Los usuarios deben volver a autenticarse para continuar con el acceso a la API.
¿Puedo acceder a las conexiones de los usuarios?
No, LinkedIn eliminó el acceso a la API de conexiones para la mayoría de las aplicaciones debido a cambios de privacidad.
Top comments (0)