LinkedIn es la plataforma profesional más grande del mundo, utilizada para hacer networking, reclutar talento, compartir contenido y desarrollar la carrera profesional. Ofrece una API con muchas funcionalidades que permite crear integraciones para la autenticación y verificación de usuarios de LinkedIn, publicación de contenido, anuncios, eventos y gestión de comunidades.
Sin embargo, para los nuevos usuarios la API de LinkedIn puede resultar difícil de utilizar, ya que abarca varios productos y el acceso suele requerir aprobaciones y permisos específicos (permission scopes).
Por ello, en esta guía aprenderás cómo usar e integrar la API de LinkedIn en tus aplicaciones de software y flujos de automatización, desde la autenticación de usuarios hasta la publicación de contenido. El objetivo es convertir horas de prueba y error en un proceso claro y repetible que puedas aplicar en tus propias aplicaciones.
El LinkedIn Developer Portal es el lugar donde puedes crear y gestionar aplicaciones que acceden de forma segura a las APIs de LinkedIn. Desde allí puedes configurar la autenticación, solicitar permisos y administrar el acceso a los recursos de LinkedIn.
Para comenzar, debes crear una página de LinkedIn que estará vinculada con la aplicación.
.png)
Luego, accede al LinkedIn Developer Portal para crear la aplicación.
%20(1).png)
Introduce el nombre de tu aplicación, sube el logo y selecciona la página que acabas de crear en el menú desplegable para crear la app.
.png)
A continuación, verifica la página de LinkedIn para confirmar que autorizas su vinculación con la aplicación.
.png)
Se mostrará un cuadro de diálogo que te pedirá generar una URL de verificación. Genérala y abre el enlace en tu navegador para verificar la página.
.png)
Después de crear la aplicación correctamente, se generarán un a client ID y un primary client secret que se utilizarán para la autenticación y autorización de tu aplicación. Cópialos y guárdalos para utilizarlos más adelante.
.png)
Por último, haz clic en la pestaña Products y solicita acceso a autenticación de usuarios y publicación de contenido en LinkedIn.
.png)
¡Felicidades! Ahora puedes empezar a autenticar usuarios y crear publicaciones mediante la API de LinkedIn.
La API de LinkedIn utiliza OAuth 2.0 para autorizar aplicaciones y conceder acceso seguro a los recursos de LinkedIn. Antes de que tu aplicación pueda solicitar datos o actuar en nombre de un usuario, debe completar un flujo de autorización OAuth.
LinkedIn admite dos métodos de autorización:
En esta sección, implementarás el flujo OAuth de 3 pasos, que consiste en solicitar un código de autorización a LinkedIn, intercambiarlo por un token de acceso (access token) y utilizar ese token para acceder a los datos del usuario.
Antes de continuar, añade la siguiente URL de redirección a la lista de Redirect URLs en el panel de desarrollador de LinkedIn. LinkedIn enviará el código de autorización a esta URL durante la fase de desarrollo.
http://localhost:3000/auth/linkedin/callback
.png)
Los ejemplos de esta guía están escritos en JavaScript. Por lo tanto, debes instalar las siguientes herramientas para poder ejecutar el código en tu ordenador:
node -v en tu terminal.
Crea una nueva carpeta para el proyecto e instala un archivo package.json utilizando el siguiente fragmento de código:
mkdir linkedin-api-guide
cd linkedin-api-guide
npm init -y
Ejecuta el siguiente fragmento de código en la terminal para instalar las dependencias del proyecto.
npm install axios dotenv express
Añade los archivos index.js y.env al directorio del proyecto.
cd linkedin-api-guide
touch index.js .env
Declara las siguientes variables dentro del archivo .env y complétalas con tus credenciales.
ACCESS_TOKEN=
CLIENT_ID=<your_LinkedIn_client_ID>
CLIENT_SECRET=<your_LinkedIn_client_secret>
URI=http://localhost:3000/auth/linkedin/callback
Ahora vamos a implementar el flujo de autorización de miembro (OAuth de 3 pasos).
Copia el siguiente fragmento de código en el archivo index.js para importar los paquetes y las variables de entorno.
//👇🏻 Package imports
require("dotenv").config();
const express = require("express");
const axios = require("axios");
const app = express();
//👇🏻 Environment variables
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const REDIRECT_URI = process.env.URI;
El paquete dotenv carga las variables de entorno desde un archivo .env en tu aplicación, manteniendo las credenciales sensibles fuera del código fuente. Express proporciona un servidor web ligero para gestionar las redirecciones de OAuth y las rutas de la API, mientras que Axios se utiliza para enviar solicitudes HTTP a los endpoints de la API de LinkedIn.
Añade el siguiente fragmento de código en el archivo index.js
app.get("/auth/linkedin", (req, res) => {
const scope = "openid profile email w_member_social"; // Modern OIDC scopes
const state = "foobar"; // Use for CSRF protection
const callbackUrl = `https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${state}&scope=${encodeURIComponent(scope)}`;
res.redirect(callbackUrl);
});
El código anterior define la URL de autorización OAuth de LinkedIn, los permisos necesarios (scopes) y un parámetro state para la protección contra ataques CSRF. Después, redirige al usuario a la página de autorización de LinkedIn. Si el usuario aprueba el acceso, LinkedIn lo redirige de nuevo a tu URL de callback con un código de autorización.
A continuación, declara otra ruta de la API que obtenga el token de acceso del usuario utilizando ese código de autorización.
app.get("/auth/linkedin/callback", async (req, res) => {
// 1. Get the code from the URL query parameters
const code = req.query.code;
if (!code) {
return res.status(400).send("Authorization failed: No code provided.");
}
try {
// 2. Make the POST request to exchange the code for an Access Token
// LinkedIn requires 'application/x-www-form-urlencoded'
const response = await axios.post(
"https://www.linkedin.com/oauth/v2/accessToken",
null,
{
params: {
grant_type: "authorization_code",
code: code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
const accessToken = response.data.access_token;
//👇🏻 log access token to the console
console.log("Access Token:", accessToken);
/*
3-legged authorisation method placeholder
👇🏻 3. (Optional) Immediately use the token to get the user's name/email
*/
} catch (error) {
console.error(
"Error exchanging code:",
error.response?.data || error.message,
);
res.status(500).json(error.response?.data || "Internal Server Error");
}
});
El código anterior gestiona la callback de LinkedIn después de que el usuario autorice tu aplicación. Recupera el código de autorización de los parámetros de la URL y lo intercambia por un token de acceso utilizando tu Client ID, Client Secret y la Redirect URI. Este token de acceso puede luego usarse para realizar solicitudes API autorizadas en nombre del usuario.
Para obtener el perfil del usuario usando el token de acceso, actualiza el fragmento de código como se muestra a continuación:
app.get("/auth/linkedin/callback", async (req, res) => {
// 1. Get the code from the URL query parameters
const code = req.query.code;
if (!code) {
return res.status(400).send("Authorization failed: No code provided.");
}
try {
// 2. Make the POST request to exchange the code for an Access Token
// LinkedIn requires 'application/x-www-form-urlencoded'
const response = await axios.post(
"https://www.linkedin.com/oauth/v2/accessToken",
null,
{
params: {
grant_type: "authorization_code",
code: code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
const accessToken = response.data.access_token;
console.log("Access Token:", accessToken);
// 3. (Optional) Immediately use the token to get the user's name/email
const userProfile = await axios.get(
"https://api.linkedin.com/v2/userinfo",
{
headers: { Authorization: `Bearer ${accessToken}` },
},
);
res.json({
message: "Success!",
token: accessToken,
profile: userProfile.data,
});
} catch (error) {
console.error(
"Error exchanging code:",
error.response?.data || error.message,
);
res.status(500).json(error.response?.data || "Internal Server Error");
}
});
El código de autorización recibido de LinkedIn se intercambia por un token de acceso, que tu aplicación utiliza para acceder a los datos del usuario.
Finalmente, añade el siguiente fragmento de código al archivo para iniciar el servidor y ejecútalo usando node index.js
// Start the server
app.listen(3000, () =>
console.log("Server: http://localhost:3000/auth/linkedin"),
);
Aquí tienes un ejemplo de los datos devueltos por la API de autorización
{
"message": "Success!",
"token": "AQXs_b_gXF9pXBdwdvmOWEL4TQXKiHWAjnRvP-WNe4nxaIq",
"profile": {
"sub": "xzorpyHada",
"email_verified": true,
"name": "Jane Doe",
"locale": {
"country": "US",
"language": "en"
},
"given_name": "Jane",
"family_name": "Doe",
"email": "janedoe@gmail.com",
"picture": "https://media.licdn.com/dms/image/v2/<image_id>"
}
}
💡 Nota: El ejemplo de código muestra el token de acceso en la consola. En una aplicación real, debes almacenar el token de forma segura (por ejemplo, en una base de datos o en una variable de entorno segura) en lugar de guardarlo directamente en tu archivo .env
En esta sección aprenderás a publicar contenido en LinkedIn mediante su API, incluyendo publicaciones solo de texto, artículos, imágenes y videos. Partiremos del archivo index.js de la sección anterior para agregar endpoints que permitan crear estas publicaciones.
💡 Asegúrate de haber agregado tu token de acceso en la variable de entorno correspondiente dentro del archivo.env
Añade el siguiente fragmento de código en el archivo index.js
app.get("/auth/linkedin/post/share", async (req, res) => {
const accessToken = process.env.ACCESS_TOKEN;
message = "Hello LinkedIn!";
if (!accessToken) {
return res.status(401).send("Access token required");
}
try {
// STEP 1: Get the Member's ID (Person URN)
// We need this because the 'author' field requires the URN format
const userResponse = await axios.get(
"https://api.linkedin.com/v2/userinfo",
{
headers: { Authorization: `Bearer ${accessToken}` },
},
);
const personURN = `urn:li:person:${userResponse.data.sub}`;
// STEP 2: Make the POST request to share
const shareResponse = await axios.post(
"https://api.linkedin.com/v2/ugcPosts",
{
author: personURN,
lifecycleState: "PUBLISHED",
specificContent: {
"com.linkedin.ugc.ShareContent": {
shareCommentary: {
text: message || "Default share text from Node.js!",
},
shareMediaCategory: "NONE",
},
},
visibility: {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC", // or "CONNECTIONS"
},
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
"X-Restli-Protocol-Version": "2.0.0",
"Content-Type": "application/json",
},
},
);
res.status(201).json({
message: "Post shared successfully!",
data: shareResponse.data,
});
} catch (error) {
console.error(
"Error sharing content:",
error.response?.data || error.message,
);
// Return the specific LinkedIn error to help debugging
res
.status(error.response?.status || 500)
.json(error.response?.data || "Internal Server Error");
}
});
En el fragmento de código anterior, la ruta primero obtiene el ID del miembro de LinkedIn (URN) usando el token de acceso, que es necesario como el campo author al crear una publicación.
Luego, envía una solicitud POST al endpoint ugcPosts LinkedIn con el contenido de la publicación, el estado del ciclo de vida, la categoría de medios y la configuración de visibilidad. Si la solicitud es exitosa, la API devuelve los datos de la publicación creada; de lo contrario, cualquier error se registra y se devuelve en la respuesta.
Prueba el endpoint apuntando tu servidor Express a la ruta: /auth/linkedin/post/share route.
app.listen(3000, () =>
console.log("Server: http://localhost:3000/auth/linkedin/post/share"),
);
Si la solicitud es exitosa, devolverá el siguiente objeto JSON en tu navegador:
{
"message": "Post shared successfully!",
"data": {
"id": "urn:li:share:<id>"
}
}
Para compartir artículos o enlaces usando la API de LinkedIn, actualiza el objeto specificContent agregando un array media y configurando shareMediaCategory como "ARTICLE". Esto indica a LinkedIn que la publicación contiene un enlace o artículo, y no solo texto.
A continuación, crea un nuevo endpoint de la API para generar publicaciones de artículos o URLs.
app.get("/auth/linkedin/article/share", async (req, res) => {
const accessToken = process.env.ACCESS_TOKEN;
message = "Hello LinkedIn!";
if (!accessToken) {
return res.status(401).send("Access token required");
}
try {
const userResponse = await axios.get(
"https://api.linkedin.com/v2/userinfo",
{
headers: { Authorization: `Bearer ${accessToken}` },
},
);
const personURN = `urn:li:person:${userResponse.data.sub}`;
// STEP 2: Make the POST request to share
const shareResponse = await axios.post(
"https://api.linkedin.com/v2/ugcPosts",
{
author: personURN,
lifecycleState: "PUBLISHED",
specificContent: {
"com.linkedin.ugc.ShareContent": {
shareCommentary: {
text: message || "Default share text from Node.js!",
},
shareMediaCategory: "ARTICLE",
media: [
{
status: "READY",
description: {
text: "Official LinkedIn Blog - Your source for insights and information about LinkedIn.",
},
originalUrl: "https://blog.linkedin.com/",
title: {
text: "Official LinkedIn Blog",
},
},
],
},
},
visibility: {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC", // or "CONNECTIONS"
},
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
"X-Restli-Protocol-Version": "2.0.0",
"Content-Type": "application/json",
},
},
);
res.status(201).json({
message: "Post shared successfully!",
data: shareResponse.data,
});
} catch (error) {
console.error(
"Error sharing content:",
error.response?.data || error.message,
);
// Return the specific LinkedIn error to help debugging
res
.status(error.response?.status || 500)
.json(error.response?.data || "Internal Server Error");
}
});
En el fragmento de código anterior,
author al crear la publicación.shareMediaCategory como "ARTICLE" e incluye un array media con la URL, el título y la descripción del artículo.shareCommentary.text proporciona el mensaje de la publicación que aparece encima de la vista previa del artículo.ugcPosts de LinkedIn, creando una publicación de artículo publicada en el feed del usuario.
Prueba el endpoint apuntando tu servidor Express a la ruta: /auth/linkedin/article/share route.
app.listen(3000, () =>
console.log("Server: http://localhost:3000/auth/linkedin/post/share"),
);
Para subir imágenes o videos usando la API de LinkedIn, necesitas registrar la imagen o el video, subirlo a LinkedIn y crear una publicación que incluya esa imagen o video.
Primero, crea la función register como se muestra a continuación:
async function registerMedia(accessToken, personURN, mediaType = "image") {
const registerUrl =
"https://api.linkedin.com/v2/assets?action=registerUpload";
// Use 'feedshare-image' for images and 'feedshare-video' for videos
const recipe =
mediaType === "video"
? "urn:li:digitalmediaRecipe:feedshare-video"
: "urn:li:digitalmediaRecipe:feedshare-image";
const body = {
registerUploadRequest: {
recipes: [recipe],
owner: personURN,
serviceRelationships: [
{
relationshipType: "OWNER",
identifier: "urn:li:userGeneratedContent",
},
],
},
};
const response = await axios.post(registerUrl, body, {
headers: {
Authorization: `Bearer ${accessToken}`,
"X-Restli-Protocol-Version": "2.0.0",
"Content-Type": "application/json",
},
});
return {
uploadUrl:
response.data.value.uploadMechanism[
"com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest"
].uploadUrl,
asset: response.data.value.asset,
};
}
Según el fragmento de código anterior,
feedshare-image) o un video (feedshare-video).assets?action=registerUpload con la información requerida de receta (recipe) y propiedad (ownership), lo que devuelve la uploadUrl y el asset identifier.A continuación, agrega la función de subida (upload) al archivo index.js
async function uploadBinary(uploadUrl, accessToken, filePath) {
const fileBuffer = fs.readFileSync(filePath);
await axios.put(uploadUrl, fileBuffer, {
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/octet-stream", // or the specific mime-type (image/png, video/mp4)
"X-Restli-Protocol-Version": "2.0.0",
},
});
console.log("Upload successful.");
}
La uploadBinary function sube el archivo multimedia (imagen o video) a LinkedIn utilizando la uploadUrl que devuelve la función registerMedia
Finalmente, crea la función share, que utiliza tanto registerMedia como uploadBinary antes de compartir la imagen o el video en LinkedIn.
app.get("/auth/linkedin/share-media", async (req, res) => {
const accessToken = process.env.ACCESS_TOKEN;
const filePath = "./cover.png"; // Path to your local file
try {
// Step 0: Get User URN (if you don't have it)
const userRes = await axios.get("https://api.linkedin.com/v2/userinfo", {
headers: { Authorization: `Bearer ${accessToken}` },
});
const personURN = `urn:li:person:${userRes.data.sub}`;
// Step 1: Register
const { uploadUrl, asset } = await registerMedia(
accessToken,
personURN,
"image",
);
// Step 2: Upload Binary
await uploadBinary(uploadUrl, accessToken, filePath);
// Step 3: Create the UGC Post using the asset
const shareResponse = await axios.post(
"https://api.linkedin.com/v2/ugcPosts",
{
author: personURN,
lifecycleState: "PUBLISHED",
specificContent: {
"com.linkedin.ugc.ShareContent": {
shareCommentary: { text: "Posting with an image!" },
shareMediaCategory: "IMAGE", // Change to VIDEO if uploading video
media: [
{
status: "READY",
media: asset, // The URN from Step 1
title: { text: "My Image Title" },
},
],
},
},
visibility: { "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC" },
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
"X-Restli-Protocol-Version": "2.0.0",
},
},
);
res.json({ success: true, post: shareResponse.data });
} catch (error) {
console.error(error.response?.data || error.message);
res.status(500).json(error.response?.data || "Upload failed");
}
});
El fragmento de código anterior muestra el flujo completo para publicar una imagen en LinkedIn:
registerMedia que devuelve una uploadUrl y un asset identifier.uploadBinary sube el archivo de imagen a LinkedIn utilizando la uploadUrl. shareMediaCategory como "IMAGE" e incluyendo un mensaje de publicación y un título opcional.
💡 Nota:Los ejemplos de esta guía utilizan solicitudes HTTP GET para permitir probar los endpoints de la API directamente desde un navegador web. En una aplicación real, deberías reemplazar estas solicitudes GET por solicitudes POST (u otros métodos HTTP apropiados) cuando así lo requiera la API de LinkedIn.
Late s una plataforma integral de programación de redes sociales que te permite conectar múltiples cuentas de redes sociales y publicar contenido en ellas. Con su API, puedes programar y publicar contenido en redes sociales, incluidas imágenes o videos, en 13 plataformas, entre ellas LinkedIn.
Hasta ahora, has aprendido cómo crear y compartir contenido en LinkedIn utilizando su API.
Sin embargo, la API tiene limitaciones: no admite mensajes directos ni permite enviar solicitudes de conexión. El uso de herramientas de automatización del navegador como Selenium o Puppeteer puede poner en riesgo tu cuenta.
Aquíes done entra WaLead. WaLead es una plataforma de automatización de LinkedIn basada en la nube para gestionar solicitudes de conexión, mensajes personalizados y campañas a gran escala. No requiere un navegador, admite múltiples cuentas y reduce el riesgo para tu cuenta.
Con WaLead, los equipos de ventas y marketing pueden:
Todo esto se puede hacer de forma fácil y segura, sin poner en peligro tu cuenta de LinkedIn.
En esta guía, has aprendido cómo crear y compartir contenido utilizando la API de LinkedIn.
Para una autenticación más sencilla y funciones más avanzadas, la API de Late ofrece una solución potente que también te permite programar y publicar contenido, incluidos archivos multimedia, en 13 plataformas de redes sociales, entre ellas LinkedIn.
Aunque estas APIs son excelentes para la publicación de contenido, no cubren mensajes directos, solicitudes de conexión o prospección a gran escala, áreas en las que WaLead destaca.
En conjunto, estas herramientas proporcionan a desarrolladores, profesionales de marketing y equipos de ventas un conjunto completo de herramientas para la creación de contenido, programación y prospección en LinkedIn.
¡Gracias por leer! 🙌
.png)
.png)
Sí. Para utilizar muchas funciones de la API de LinkedIn debes crear una aplicación en el LinkedIn Developer Portal y solicitar acceso a determinados productos, como autenticación de usuarios o publicación de contenido. Algunas funciones requieren aprobación previa de LinkedIn.
No. La API de LinkedIn no permite enviar mensajes directos ni solicitudes de conexión. Principalmente está diseñada para autenticación, acceso a perfiles y publicación de contenido.
La API de LinkedIn utiliza OAuth 2.0 para autenticación y autorización. La mayoría de integraciones usan el flujo OAuth de 3 pasos (3-legged OAuth), donde el usuario concede permisos a la aplicación antes de acceder a sus datos.
Sí. Sin embargo, publicar contenido multimedia requiere varios pasos: registrar el archivo, subirlo a LinkedIn y luego crear una publicación que haga referencia al recurso subido.

Aprende a crear secuencias de outreach en LinkedIn que aumentan respuestas y generan leads.

Importa leads desde CSV o Sheets en WaLead y acelera tu alcance con automatización en LinkedIn.
Obtén consejos para usar cronologías de actividad y actualizaciones de estado en LinkedIn
.png)