Resumen
La API de Hootsuite permite a los desarrolladores integrarse programáticamente con los flujos de trabajo de gestión de redes sociales. Utiliza autenticación OAuth 2.0, puntos finales RESTful para perfiles, publicaciones, análisis y gestión de equipos, con límites de tasa de 50-200 solicitudes por minuto según el plan. Esta guía cubre la configuración de autenticación, la programación de publicaciones, la recuperación de análisis, la gestión de equipos y las estrategias de integración en producción.
Nota: Hootsuite ha desaprobado su API pública a partir de 2024. Esta guía cubre enfoques alternativos, incluidas las integraciones de socios de Hootsuite, webhooks y APIs de gestión de redes sociales de terceros que proporcionan una funcionalidad similar.
Introducción
Hootsuite gestiona más de 30 millones de cuentas de redes sociales para más de 200.000 empresas en más de 175 países. Para los desarrolladores que crean herramientas de redes sociales, plataformas de marketing o paneles de análisis, la integración de la API de redes sociales es esencial para llegar a esta masiva audiencia empresarial.
Esta es la realidad: los gestores de redes sociales que manejan más de 20 cuentas pierden entre 25 y 35 horas semanales en la publicación manual, el seguimiento del engagement y la generación de informes. Una sólida integración de la API de redes sociales automatiza la distribución de contenido, el monitoreo del engagement, el análisis de sentimientos y la generación de informes de rendimiento.
Estado de la API de Hootsuite y alternativas
Situación actual de la API
A partir de 2024, Hootsuite ha desaprobado su API pública. Opciones de integración:
| Enfoque | Descripción | Ideal para |
|---|---|---|
| APIs de Plataformas Nativas | Integración directa con Facebook, Twitter, LinkedIn, etc. | Control total, soluciones personalizadas |
| Audiense | Inteligencia de audiencia propiedad de Hootsuite | Análisis de audiencia |
| HeyOrca | API de programación de redes sociales | Calendarios de contenido |
| API de Buffer | Gestión de redes sociales | Equipos pequeños |
| API de Sprout Social | Gestión social empresarial | Grandes organizaciones |
| API de Agorapulse | CRM de redes sociales | Gestión de la comunidad |
Enfoque recomendado: APIs de plataformas nativas
Para la mayoría de los casos de uso, la integración directa con las plataformas sociales ofrece la mayor flexibilidad:
| Plataforma | Nombre de la API | Características clave |
|---|---|---|
| Facebook/Instagram | Graph API | Publicaciones, insights, comentarios |
| Twitter/X | API v2 | Tweets, análisis, streams |
| Marketing API | Publicaciones, páginas de empresa, anuncios | |
| API v5 | Pines, tableros, análisis | |
| TikTok | Display API | Videos, información del usuario |
| YouTube | Data API | Videos, listas de reproducción, análisis |
Primeros pasos: Autenticación multiplataforma
Paso 1: Registrar aplicaciones de desarrollador
Cree cuentas de desarrollador para cada plataforma:
// Store credentials securely
const SOCIAL_CREDENTIALS = {
facebook: {
appId: process.env.FB_APP_ID,
appSecret: process.env.FB_APP_SECRET,
redirectUri: process.env.FB_REDIRECT_URI
},
twitter: {
apiKey: process.env.TWITTER_API_KEY,
apiSecret: process.env.TWITTER_API_SECRET,
redirectUri: process.env.TWITTER_REDIRECT_URI
},
linkedin: {
clientId: process.env.LINKEDIN_CLIENT_ID,
clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
redirectUri: process.env.LINKEDIN_REDIRECT_URI
},
instagram: {
appId: process.env.FB_APP_ID, // Uses Facebook Login
appSecret: process.env.FB_APP_SECRET
}
};
Paso 2: Implementar el flujo OAuth 2.0
Manejador OAuth unificado para múltiples plataformas:
const getAuthUrl = (platform, state) => {
const configs = {
facebook: {
url: 'https://www.facebook.com/v18.0/dialog/oauth',
params: {
client_id: SOCIAL_CREDENTIALS.facebook.appId,
redirect_uri: SOCIAL_CREDENTIALS.facebook.redirectUri,
scope: 'pages_manage_posts,pages_read_engagement,instagram_basic,instagram_content_publish',
state
}
},
twitter: {
url: 'https://twitter.com/i/oauth2/authorize',
params: {
client_id: SOCIAL_CREDENTIALS.twitter.apiKey,
redirect_uri: SOCIAL_CREDENTIALS.twitter.redirectUri,
scope: 'tweet.read tweet.write users.read offline.access',
state,
response_type: 'code'
}
},
linkedin: {
url: 'https://www.linkedin.com/oauth/v2/authorization',
params: {
client_id: SOCIAL_CREDENTIALS.linkedin.clientId,
redirect_uri: SOCIAL_CREDENTIALS.linkedin.redirectUri,
scope: 'w_member_social r_basicprofile',
state,
response_type: 'code'
}
}
};
const config = configs[platform];
const params = new URLSearchParams(config.params);
return `${config.url}?${params.toString()}`;
};
// Handle OAuth callback
const handleOAuthCallback = async (platform, code) => {
const tokenEndpoints = {
facebook: 'https://graph.facebook.com/v18.0/oauth/access_token',
twitter: 'https://api.twitter.com/2/oauth2/token',
linkedin: 'https://www.linkedin.com/oauth/v2/accessToken'
};
const response = await fetch(tokenEndpoints[platform], {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
client_id: SOCIAL_CREDENTIALS[platform].apiKey || SOCIAL_CREDENTIALS[platform].appId || SOCIAL_CREDENTIALS[platform].clientId,
client_secret: SOCIAL_CREDENTIALS[platform].appSecret || SOCIAL_CREDENTIALS[platform].apiSecret,
redirect_uri: SOCIAL_CREDENTIALS[platform].redirectUri,
code,
grant_type: 'authorization_code'
})
});
return response.json();
};
Paso 3: Almacenar tokens de forma segura
// Database schema for social tokens
const SocialToken = {
userId: 'user_123',
platform: 'facebook',
accessToken: 'encrypted_token_here',
refreshToken: 'encrypted_refresh_token',
tokenExpiry: Date.now() + 5183999, // 60 days
scopes: ['pages_manage_posts', 'pages_read_engagement'],
pageId: 'page_456', // For Facebook/Instagram
pageName: 'My Business Page'
};
Programación y publicación de publicaciones
Creando una publicación multiplataforma
Publique en múltiples plataformas simultáneamente:
const createSocialPost = async (postData) => {
const results = {};
// Facebook Page Post
if (postData.platforms.includes('facebook')) {
results.facebook = await postToFacebook({
pageId: postData.facebookPageId,
message: postData.message,
link: postData.link,
photo: postData.photo
});
}
// Twitter Post
if (postData.platforms.includes('twitter')) {
results.twitter = await postToTwitter({
text: postData.message,
media: postData.photo
});
}
// LinkedIn Post
if (postData.platforms.includes('linkedin')) {
results.linkedin = await postToLinkedIn({
authorUrn: postData.linkedinAuthorUrn,
text: postData.message,
contentUrl: postData.link
});
}
// Instagram Post
if (postData.platforms.includes('instagram')) {
results.instagram = await postToInstagram({
igAccountId: postData.igAccountId,
imageUrl: postData.photo,
caption: postData.message
});
}
return results;
};
// Facebook posting
const postToFacebook = async (postData) => {
const token = await getFacebookPageToken(postData.pageId);
const params = new URLSearchParams({
message: postData.message,
access_token: token
});
if (postData.link) {
params.append('link', postData.link);
}
if (postData.photo) {
params.append('photo', postData.photo);
}
const response = await fetch(
`https://graph.facebook.com/v18.0/${postData.pageId}/feed?${params.toString()}`,
{ method: 'POST' }
);
return response.json();
};
// Twitter posting
const postToTwitter = async (postData) => {
const token = await getTwitterToken();
let mediaIds = [];
if (postData.media) {
// Upload media first
const mediaUpload = await uploadTwitterMedia(postData.media, token);
mediaIds = [mediaUpload.media_id_string];
}
const response = await fetch('https://api.twitter.com/2/tweets', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: postData.text,
media: mediaIds.length > 0 ? { media_ids: mediaIds } : undefined
})
});
return response.json();
};
// LinkedIn posting
const postToLinkedIn = async (postData) => {
const token = await getLinkedInToken();
const post = {
author: postData.authorUrn,
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: postData.text
},
shareMediaCategory: postData.contentUrl ? 'ARTICLE' : 'NONE',
media: postData.contentUrl ? [{
status: 'READY',
media: postData.contentUrn,
description: { text: postData.text }
}] : []
}
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
}
};
const response = await fetch('https://api.linkedin.com/v2/ugcPosts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'X-Restli-Protocol-Version': '2.0.0'
},
body: JSON.stringify(post)
});
return response.json();
};
// Instagram posting
const postToInstagram = async (postData) => {
const token = await getInstagramToken();
// Step 1: Create media container
const containerResponse = await fetch(
`https://graph.facebook.com/v18.0/${postData.igAccountId}/media`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({
image_url: postData.imageUrl,
caption: postData.caption
})
}
);
const container = await containerResponse.json();
// Step 2: Publish
const publishResponse = await fetch(
`https://graph.facebook.com/v18.0/${postData.igAccountId}/media_publish`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ creation_id: container.id })
}
);
return publishResponse.json();
};
Programación de publicaciones
Implemente la programación de publicaciones:
const schedulePost = async (postData, scheduledTime) => {
// Store in database for later execution
const scheduledPost = await db.scheduledPosts.create({
message: postData.message,
platforms: postData.platforms,
scheduledTime: scheduledTime,
status: 'pending',
media: postData.media,
link: postData.link
});
// Set up job queue
await jobQueue.add('publish-social-post', {
postId: scheduledPost.id
}, {
delay: scheduledTime - Date.now()
});
return scheduledPost;
};
// Job processor
jobQueue.process('publish-social-post', async (job) => {
const post = await db.scheduledPosts.findById(job.data.postId);
try {
const result = await createSocialPost(post);
await db.scheduledPosts.update(post.id, {
status: 'published',
publishedAt: new Date(),
results: result
});
return result;
} catch (error) {
await db.scheduledPosts.update(post.id, {
status: 'failed',
error: error.message
});
throw error;
}
});
Análisis e informes
Obtención de análisis multiplataforma
Agregue métricas de todas las plataformas:
const getSocialAnalytics = async (accountId, dateRange) => {
const analytics = {
facebook: await getFacebookAnalytics(accountId.facebook, dateRange),
twitter: await getTwitterAnalytics(accountId.twitter, dateRange),
linkedin: await getLinkedInAnalytics(accountId.linkedin, dateRange),
instagram: await getInstagramAnalytics(accountId.instagram, dateRange)
};
// Aggregate metrics
const totals = {
impressions: sum(analytics, 'impressions'),
engagement: sum(analytics, 'engagement'),
clicks: sum(analytics, 'clicks'),
shares: sum(analytics, 'shares'),
comments: sum(analytics, 'comments'),
newFollowers: sum(analytics, 'newFollowers')
};
return { analytics, totals };
};
// Facebook Insights
const getFacebookAnalytics = async (pageId, dateRange) => {
const token = await getFacebookPageToken(pageId);
const metrics = [
'page_impressions_unique',
'page_engaged_users',
'page_post_engagements',
'page_clicks',
'page_fan_adds'
];
const params = new URLSearchParams({
metric: metrics.join(','),
since: dateRange.from,
until: dateRange.until,
access_token: token
});
const response = await fetch(
`https://graph.facebook.com/v18.0/${pageId}/insights?${params.toString()}`
);
return response.json();
};
// Twitter Analytics
const getTwitterAnalytics = async (userId, dateRange) => {
const token = await getTwitterToken();
const response = await fetch(
`https://api.twitter.com/2/users/${userId}/metrics/private`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return response.json();
};
// LinkedIn Analytics
const getLinkedInAnalytics = async (organizationId, dateRange) => {
const token = await getLinkedInToken();
const response = await fetch(
`https://api.linkedin.com/v2/organizationalEntityFollowerStatistics?q=organizationalEntity&organizationalEntity=${organizationId}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return response.json();
};
// Instagram Insights
const getInstagramAnalytics = async (igAccountId, dateRange) => {
const token = await getInstagramToken();
const metrics = [
'impressions',
'reach',
'engagement',
'profile_views',
'follower_count'
];
const params = new URLSearchParams({
metric: metrics.join(','),
period: 'day',
since: dateRange.from,
until: dateRange.until
});
const response = await fetch(
`https://graph.facebook.com/v18.0/${igAccountId}/insights?${params.toString()}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return response.json();
};
function sum(analytics, metric) {
return Object.values(analytics).reduce((total, platform) => {
return total + (platform.data?.[metric] || 0);
}, 0);
}
Gestión de equipos
Control de acceso basado en roles
const TEAM_ROLES = {
ADMIN: 'admin',
MANAGER: 'manager',
CONTRIBUTOR: 'contributor',
VIEWER: 'viewer'
};
const ROLE_PERMISSIONS = {
[TEAM_ROLES.ADMIN]: ['create', 'read', 'update', 'delete', 'manage_team', 'billing'],
[TEAM_ROLES.MANAGER]: ['create', 'read', 'update', 'approve_posts'],
[TEAM_ROLES.CONTRIBUTOR]: ['create', 'read'],
[TEAM_ROLES.VIEWER]: ['read']
};
const checkPermission = (userRole, requiredPermission) => {
const permissions = ROLE_PERMISSIONS[userRole] || [];
return permissions.includes(requiredPermission);
};
Limitación de tasa
Límites de tasa de la plataforma
| Plataforma | Límite | Ventana |
|---|---|---|
| Facebook Graph | 200 llamadas | Por hora por usuario |
| Twitter API v2 | 300 tweets | Cada 15 min |
| 100-500 llamadas | Por día | |
| 200 llamadas | Por hora |
Implementación del manejo de límites de tasa
class SocialMediaRateLimiter {
constructor() {
this.limits = {
facebook: { limit: 200, window: 3600000 },
twitter: { limit: 300, window: 900000 },
linkedin: { limit: 500, window: 86400000 },
instagram: { limit: 200, window: 3600000 }
};
this.counters = {};
}
async request(platform, endpoint, options) {
await this.waitForCapacity(platform);
const response = await fetch(endpoint, options);
this.incrementCounter(platform);
return response;
}
async waitForCapacity(platform) {
const limit = this.limits[platform];
const counter = this.counters[platform] || { count: 0, resetTime: Date.now() };
if (Date.now() > counter.resetTime + limit.window) {
counter.count = 0;
counter.resetTime = Date.now();
}
if (counter.count >= limit.limit) {
const waitTime = counter.resetTime + limit.window - Date.now();
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.counters[platform] = counter;
}
incrementCounter(platform) {
if (!this.counters[platform]) {
this.counters[platform] = { count: 0, resetTime: Date.now() };
}
this.counters[platform].count++;
}
}
Lista de verificación de implementación en producción
Antes de salir en vivo:
- [ ] Implementar OAuth 2.0 para todas las plataformas
- [ ] Almacenar tokens de forma segura con cifrado
- [ ] Configurar la actualización automática de tokens
- [ ] Implementar limitación de tasa por plataforma
- [ ] Añadir manejo integral de errores
- [ ] Configurar el registro para todas las llamadas a la API
- [ ] Crear flujos de trabajo de aprobación de publicaciones
- [ ] Implementar moderación de contenido
- [ ] Configurar la agregación de análisis
- [ ] Crear mecanismos de publicación de respaldo
Casos de uso en el mundo real
Panel de control de redes sociales
Una agencia de marketing construye un panel de control unificado:
- Desafío: Gestión de más de 50 cuentas de clientes en todas las plataformas
- Solución: Panel de control central con publicación multiplataforma
- Resultado: Ahorro del 60% de tiempo, presencia de marca consistente
Distribución automatizada de contenido
Un editor automatiza el intercambio de artículos:
- Desafío: Compartir manualmente nuevo contenido
- Solución: Publicar automáticamente nuevos artículos en todas las plataformas
- Resultado: Distribución instantánea, 3x tráfico social
Conclusión
Aunque la API pública de Hootsuite está desaprobada, las APIs de plataformas nativas proporcionan capacidades completas de gestión de redes sociales. Puntos clave:
- Implementar OAuth 2.0 para cada plataforma por separado
- Los límites de tasa varían significativamente según la plataforma
- La publicación unificada requiere implementaciones específicas de cada plataforma
- La agregación de análisis proporciona insights multiplataforma
- Apidog optimiza las pruebas de API y la colaboración en equipo
Sección de Preguntas Frecuentes
¿Hootsuite todavía tiene una API?
Hootsuite desaprobó su API pública en 2024. Utilice las APIs de plataformas nativas o plataformas de gestión alternativas como Buffer, Sprout Social o Agorapulse.
¿Cómo publico en múltiples plataformas a la vez?
Implemente OAuth para cada plataforma y cree una función de publicación unificada que llame a la API de cada plataforma en paralelo.
¿Cuáles son los límites de tasa para las APIs de redes sociales?
Los límites varían: Facebook (200/hora), Twitter (300/15min), LinkedIn (100-500/día), Instagram (200/hora).
¿Cómo programo publicaciones?
Almacene las publicaciones en una base de datos con scheduled_time, luego use una cola de trabajos (Bull, Agenda) para publicarlas a la hora programada.
¿Puedo obtener análisis de todas las plataformas?
Sí, cada plataforma proporciona APIs de análisis. Agregue datos para informes multiplataforma.
