TL;DR
A API do LinkedIn permite que desenvolvedores se integrem à rede profissional do LinkedIn de forma programática. Ela usa autenticação OAuth 2.0, endpoints RESTful e GraphQL para perfis, publicações, comentários, páginas de empresas e anúncios, com limites de taxa de 100-500 requisições por dia por aplicativo. Este guia aborda a configuração de autenticação, acesso a perfis, publicação de conteúdo, gerenciamento de páginas de empresas, API de anúncios e estratégias de integração de produção.
Introdução
O LinkedIn tem mais de 900 milhões de usuários profissionais em mais de 200 países. Para desenvolvedores que criam ferramentas de recrutamento, plataformas de marketing ou aplicativos B2B, a integração da API do LinkedIn é essencial para alcançar esse público profissional.
Esta é a realidade: profissionais de marketing B2B que gerenciam a presença no LinkedIn manualmente perdem 15-20 horas semanais em postagem, acompanhamento de engajamento e geração de leads. Uma integração sólida com a API do LinkedIn automatiza a distribuição de conteúdo, a captura de leads, a análise de engajamento e os fluxos de trabalho de recrutamento.
Este guia detalha todo o processo de integração da API do LinkedIn. Você aprenderá autenticação OAuth 2.0, acesso a perfis, publicação de conteúdo, gerenciamento de páginas de empresas, integração de anúncios, webhooks e estratégias de implantação em produção. Ao final, você terá uma integração com o LinkedIn pronta para produção.
O Que É a API do LinkedIn?
O LinkedIn fornece APIs RESTful e GraphQL para acessar dados da rede profissional. A API gerencia:
- Informações de perfil de usuário (com consentimento)
- Páginas de empresas e atualizações
- Publicações, comentários e reações
- Conexões (limitado)
- Publicações de vagas e candidaturas
- Gerenciamento de Anúncios do LinkedIn
- Formulários de geração de leads
- Mensagens (apenas parceiros limitados)
Principais Recursos
| Recurso | Descrição |
|---|---|
| RESTful + GraphQL | Múltiplos estilos de API |
| OAuth 2.0 | Autorização do usuário necessária |
| Limite de Taxa | 100-500 requisições/dia por aplicativo |
| Páginas de Empresas | Operações CRUD completas |
| API de Anúncios | Gerenciamento de campanhas |
| Webhooks | Notificações em tempo real |
| Upload de Mídia | Imagens e vídeos |
Produtos da API
| API | Nível de Acesso | Caso de Uso |
|---|---|---|
| Entrar com LinkedIn | Aberto | Autenticação de usuário |
| API de Perfil | Parceiro | Ler perfil de usuário |
| API de Administração de Empresas | Parceiro | Gerenciar páginas de empresas |
| API de Anúncios | Parceiro | Gerenciamento de campanhas de anúncios |
| API de Publicação de Vagas | Parceiro | Publicar e gerenciar vagas |
| Plataforma de Desenvolvedores de Marketing | Parceiro | Acesso completo à API |
Versões da API
| Versão | Status | Data de Término |
|---|---|---|
| v2 | Atual | Ativa |
| v1 | Aposentada | Dezembro de 2023 |
Primeiros Passos: Configuração de Autenticação
Passo 1: Criar Conta de Desenvolvedor LinkedIn
Antes de acessar a API:
- Visite o Portal de Desenvolvedores do LinkedIn
- Faça login com sua conta LinkedIn
- Clique em Criar Aplicativo no painel Meus Aplicativos
- Preencha os detalhes do aplicativo (nome, logo, descrição)
Passo 2: Configurar Definições do Aplicativo
Configure a autenticação do aplicativo:
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;
// Get these from your app dashboard
// https://www.linkedin.com/developers/apps/{appId}/auth
Passo 3: Solicitar Permissões Necessárias
O LinkedIn requer aprovação de permissões:
| Permissão | Descrição | Aprovação Necessária |
|---|---|---|
r_liteprofile |
Perfil básico (nome, foto) | Aprovado automaticamente |
r_emailaddress |
Endereço de e-mail | Aprovado automaticamente |
w_member_social |
Publicar em nome do usuário | Verificação de parceiro |
r_basicprofile |
Perfil completo | Verificação de parceiro |
r_organization_social |
Acesso à página da empresa | Verificação de parceiro |
w_organization_social |
Publicar na página da empresa | Verificação de parceiro |
rw_ads |
Gerenciamento de anúncios | Verificação de parceiro |
r_ads_reporting |
Análises de anúncios | Verificação de parceiro |
Passo 4: Construir URL de Autorização
Implementar fluxo 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()}`;
};
// Usage
const state = require('crypto').randomBytes(16).toString('hex');
const authUrl = getAuthUrl(state, ['r_liteprofile', 'r_emailaddress', 'w_member_social']);
console.log(`Redirecionar usuário para: ${authUrl}`);
Passo 5: Trocar Código por Token de Acesso
Lidar com o callback 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 dias
};
};
// Handle callback
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// Armazenar tokens com segurança
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:', error);
res.status(500).send('Autenticação falhou');
}
});
Passo 6: Atualizar Token de Acesso
Tokens de acesso expiram após 60 dias:
const refreshAccessToken = async (refreshToken) => {
// Nota: O LinkedIn não fornece tokens de atualização
// Usuários devem se reautenticar após 60 dias
// Implementar notificação de expiração
};
// Verificar expiração do token antes das chamadas de API
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
if (user.linkedin_token_expires < Date.now() + 86400000) { // 24 horas
// Notificar usuário para reautenticar
await notifyUserToReauth(user.id);
throw new Error('Token expirado, por favor, reautentique');
}
return user.linkedin_access_token;
};
Passo 7: Fazer Chamadas de API Autenticadas
Criar cliente de API reutilizável:
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(`Erro da API do LinkedIn: ${error.message}`);
}
return response.json();
};
// Usage
const profile = await linkedinRequest('/me');
console.log(`Olá, ${profile.localizedFirstName} ${profile.localizedLastName}`);
Acesso ao Perfil
Obtendo Perfil do Usuário
Buscar o perfil do usuário autenticado:
const getUserProfile = async () => {
const response = await linkedinRequest('/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))');
return response;
};
// Usage
const profile = await getUserProfile();
console.log(`Nome: ${profile.localizedFirstName} ${profile.localizedLastName}`);
console.log(`ID: ${profile.id}`);
console.log(`Foto: ${profile.profilePicture?.['displayImage~']?.elements?.[0]?.identifiers?.[0]?.identifier}`);
Obtendo Endereço de E-mail
Buscar e-mail do usuário:
const getUserEmail = async () => {
const response = await linkedinRequest('/emailAddress?q=members&projection=(emailAddress*)');
return response;
};
// Usage
const email = await getUserEmail();
console.log(`E-mail: ${email.elements?.[0]?.emailAddress}`);
Campos de Perfil Disponíveis
| Campo | Permissão | Descrição |
|---|---|---|
id |
r_liteprofile | ID de membro do LinkedIn |
firstName |
r_liteprofile | Primeiro nome |
lastName |
r_liteprofile | Sobrenome |
profilePicture |
r_liteprofile | URL da foto de perfil |
headline |
r_basicprofile | Título profissional |
summary |
r_basicprofile | Seção "Sobre" |
positions |
r_basicprofile | Histórico de trabalho |
educations |
r_basicprofile | Histórico educacional |
emailAddress |
r_emailaddress | E-mail principal |
Publicação de Conteúdo
Criando uma Publicação
Compartilhar publicação de texto no feed do usuário:
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;
};
// Usage
const post = await createPost('urn:li:person:ABC123', {
text: 'Animados para anunciar o lançamento do nosso novo produto! 🚀 #inovação #startup'
});
console.log(`Publicação criada: ${post.id}`);
Criando uma Publicação com Imagem
Compartilhar publicação com mídia:
const createPostWithImage = async (authorUrn, postData) => {
// Passo 1: Registrar upload de mídia
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;
// Passo 2: Fazer upload da imagem para a URL fornecida
await fetch(uploadUrl, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + await getAccessToken(),
'Content-Type': 'application/octet-stream'
},
body: postData.imageBuffer
});
// Passo 3: Criar publicação com a imagem carregada
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;
};
Criando uma Publicação com Vídeo
Compartilhar conteúdo de vídeo:
const createPostWithVideo = async (authorUrn, postData) => {
// Registrar upload 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;
// Fazer upload do vídeo (usar URLs de upload pré-assinadas da resposta)
// ... lógica de upload ...
// Criar publicação
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;
};
Especificações de Mídia
| Tipo de Mídia | Formato | Tamanho Máximo | Duração |
|---|---|---|---|
| Imagem | JPG, PNG, GIF | 8MB | N/A |
| Vídeo | MP4, MOV | 5GB | 15 min no máximo |
| Documento | PDF, PPT, DOC | 100MB | N/A |
Gerenciamento de Páginas de Empresas
Obtendo Informações da Empresa
Buscar detalhes da página da empresa:
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;
};
// Usage
const company = await getCompanyInfo('1234567');
console.log(`Empresa: ${company.localizedName}`);
console.log(`Seguidores: ${company.followerCount}`);
console.log(`Site: ${company.website}`);
Publicando em Páginas de Empresas
Compartilhar atualização na página da empresa:
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;
};
// Usage
const post = await createCompanyPost('urn:li:organization:1234567', {
text: 'Estamos contratando! Junte-se à nossa equipe em crescimento. #carreiras #contratação'
});
Obtendo Seguidores da Empresa
Buscar contagem de seguidores:
const getFollowerCount = async (organizationId) => {
const response = await linkedinRequest(
`/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=urn:li:organization:${organizationId}`
);
return response;
};
Limite de Taxa
Entendendo os Limites de Taxa
O LinkedIn impõe limites de taxa por aplicativo:
| API | Limite | Janela |
|---|---|---|
| API de Perfil | 100 requisições | Por dia |
| Publicações UGC | 50 publicações | Por dia |
| Administração de Empresas | 500 requisições | Por dia |
| API de Anúncios | 100 requisições | Por minuto |
Cabeçalhos de Limite de Taxa
| Cabeçalho | Descrição |
|---|---|
X-Restli-Quota-Remaining |
Requisições restantes |
X-Restli-Quota-Reset |
Segundos até a redefinição |
Resolução de Problemas Comuns
Problema: 401 Não Autorizado
Soluções:
- Verifique se o token de acesso não expirou (60 dias)
- Verifique se o escopo do token inclui o recurso solicitado
- Garanta que o cabeçalho
Authorization: Bearer {token}esteja presente
Problema: 403 Proibido
Soluções:
- Verifique se o aplicativo tem as permissões necessárias
- Verifique se o usuário aprovou os escopos solicitados
- A verificação de parceiro pode ser necessária
Problema: 429 Limite de Taxa Atingido
Soluções:
- Implemente filas de requisições
- Armazene respostas em cache para reduzir chamadas
- Use webhooks em vez de polling
Checklist de Implantação em Produção
Antes de entrar em produção:
- [ ] Conclua a verificação de Parceiro do LinkedIn
- [ ] Implemente OAuth 2.0 com armazenamento seguro de tokens
- [ ] Adicione notificações de expiração de token (60 dias)
- [ ] Configure limite de taxa e filas
- [ ] Configure endpoints de webhook
- [ ] Implemente tratamento abrangente de erros
- [ ] Adicione log para todas as chamadas de API
- [ ] Crie revisão de conformidade com diretrizes de marca
Casos de Uso Reais
Plataforma de Recrutamento
Uma ferramenta de recrutamento automatiza a publicação de vagas:
- Desafio: Publicação manual em múltiplos canais
- Solução: Integração com a API de Vagas do LinkedIn
- Resultado: 80% de economia de tempo, 3x mais candidaturas
Automação de Marketing B2B
Uma plataforma de marketing agenda conteúdo do LinkedIn:
- Desafio: Agendamento de publicações inconsistente
- Solução: Publicação automatizada via API UGC
- Resultado: 5x mais engajamento, presença de marca consistente
Conclusão
A API do LinkedIn fornece acesso abrangente a recursos da rede profissional. Principais pontos:
- Autenticação OAuth 2.0 com tokens de 60 dias
- APIs de perfil, publicação e páginas de empresas disponíveis
- Limites de taxa exigem gerenciamento cuidadoso (100-500/dia)
- Verificação de parceiro necessária para a maioria das APIs
- Apidog simplifica o teste de API e a colaboração em equipe
Seção de Perguntas Frequentes (FAQ)
Como faço para obter acesso à API do LinkedIn?
Crie uma conta de Desenvolvedor LinkedIn, crie um aplicativo e complete a verificação de Parceiro para acesso avançado à API.
Posso publicar no LinkedIn automaticamente?
Sim, use a API UGC (Conteúdo Gerado pelo Usuário) com a permissão w_member_social para publicações pessoais ou w_organization_social para publicações de empresas.
Quais são os limites de taxa do LinkedIn?
Os limites de taxa variam de 100 a 500 requisições por dia, dependendo da API. A API de Anúncios permite 100 requisições por minuto.
Quanto tempo duram os tokens do LinkedIn?
Tokens de acesso expiram após 60 dias. Usuários devem se reautenticar para continuar o acesso à API.
Posso acessar as conexões do usuário?
Não, o LinkedIn removeu o acesso à API de conexões para a maioria dos aplicativos devido a mudanças de privacidade.
