Resumen
La API de Hootsuite permitía integraciones programáticas para la gestión de redes sociales. Usaba OAuth 2.0, endpoints RESTful para perfiles, publicaciones, analítica y gestión de equipos, con límites de tasa de 50-200 solicitudes/minuto según el plan. Esta guía cubre autenticación, programación de publicaciones, obtención de análisis, gestión de equipos y estrategias de integración en producción.
Nota: Hootsuite desaprobó su API pública en 2024. Aquí verás alternativas: integraciones con socios, webhooks y APIs de terceros con funcionalidades equivalentes.
Introducción
Hootsuite gestiona más de 30 millones de cuentas en más de 200.000 empresas de 175+ países. Si desarrollas herramientas para social media, marketing o dashboards de análisis, la integración con APIs de redes sociales es clave para acceder a esta audiencia empresarial.
El reto: gestores de redes sociales con más de 20 cuentas pierden entre 25 y 35 horas semanales en tareas manuales. Una buena integración de APIs puede automatizar publicación, monitoreo, análisis de sentimiento y reporting.
Estado de la API de Hootsuite y alternativas
Situación actual de la API
Desde 2024, la API pública de Hootsuite está desaprobada. 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
La integración directa con las APIs oficiales de cada red social ofrece máxima flexibilidad y control. Ejemplo de principales opciones:
| 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
Crea cuentas de desarrollador en cada plataforma y almacena las credenciales de forma segura:
// 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
Centraliza el manejo de OAuth para varias 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
Ejemplo de esquema para guardar tokens:
// 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
Envía publicaciones a varias plataformas en paralelo:
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
Utiliza una base de datos y una cola de trabajos para programar 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
Agrega métricas de cada red social y centraliza los resultados:
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
Define permisos y roles en tu sistema:
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
Implementa tu propio rate limiter para cada plataforma:
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 lanzar, asegúrate de lo siguiente:
- [ ] Implementar OAuth 2.0 para todas las plataformas
- [ ] Almacenar tokens de forma segura y cifrada
- [ ] Configurar la actualización automática de tokens
- [ ] Implementar limitación de tasa por plataforma
- [ ] Añadir manejo robusto de errores
- [ ] Configurar logs para todas las llamadas a la API
- [ ] Crear flujos de aprobación de publicaciones
- [ ] Implementar moderación de contenido
- [ ] Configurar agregación de analítica
- [ ] Crear mecanismos de publicación de respaldo
Casos de uso en el mundo real
Panel de control de redes sociales
Escenario: Agencia gestiona 50+ cuentas de clientes
Solución: Dashboard central con publicación multiplataforma
Resultado: 60% menos tiempo, marca coherente
Distribución automatizada de contenido
Escenario: Editor quiere compartir artículos nuevos automáticamente
Solución: Automatización para publicar en todas las plataformas
Resultado: Distribución instantánea, triplica tráfico social
Conclusión
Aunque la API pública de Hootsuite ya no está disponible, las APIs nativas ofrecen capacidades completas para gestión y analítica social. Claves de implementación:
- Implementa OAuth 2.0 por plataforma
- Los límites de tasa varían considerablemente
- La publicación unificada exige lógica específica por canal
- La agregación de analítica multiplica el valor del reporting
- Apidog optimiza pruebas y colaboración en APIs
Sección de Preguntas Frecuentes
¿Hootsuite todavía tiene una API?
No, Hootsuite desaprobó su API pública en 2024. Usa APIs nativas o plataformas externas como Buffer, Sprout Social o Agorapulse.
¿Cómo publico en múltiples plataformas a la vez?
Implementa OAuth para cada red y crea una función que publique en paralelo usando la API de cada una.
¿Cuáles son los límites de tasa para las APIs de redes sociales?
Varían: Facebook (200/hora), Twitter (300/15min), LinkedIn (100-500/día), Instagram (200/hora).
¿Cómo programo publicaciones?
Guarda los posts en una base de datos con scheduled_time y usa una cola de trabajos (Bull, Agenda) para publicarlos cuando corresponda.
¿Puedo obtener análisis de todas las plataformas?
Sí, cada red social tiene su propia API de analítica. Agrega los datos para un reporte multiplataforma.
Top comments (0)