DEV Community

Cover image for Comment utiliser l'API Hootsuite ?
Antoine Laurent
Antoine Laurent

Posted on • Originally published at apidog.com

Comment utiliser l'API Hootsuite ?

En bref

L'API Hootsuite permettait aux développeurs d'intégrer des flux de travail de gestion des médias sociaux par programmation. Elle utilisait l'authentification OAuth 2.0, des points de terminaison RESTful pour les profils, les publications, l'analyse et la gestion d'équipe, avec des limites de débit de 50 à 200 requêtes par minute selon le plan. Ce guide explique comment configurer l'authentification, planifier des publications, récupérer des analyses, gérer une équipe et intégrer ces workflows en production.

Note : Hootsuite a déprécié son API publique depuis 2024. Ce guide présente des solutions alternatives, notamment les intégrations partenaires Hootsuite, les webhooks et les API tierces qui offrent des fonctionnalités similaires.

Essayez Apidog dès aujourd'hui

Introduction

Hootsuite gère plus de 30 millions de comptes de médias sociaux pour plus de 200 000 entreprises dans plus de 175 pays. Pour les développeurs créant des outils de gestion sociale, des plateformes marketing ou des dashboards analytiques, intégrer des API de médias sociaux reste essentiel pour toucher cette audience.

Concrètement, les gestionnaires de médias sociaux gérant plus de 20 comptes perdent 25 à 35 heures par semaine en publication manuelle, suivi de l'engagement et reporting. Une intégration API robuste automatise la distribution de contenu, la surveillance, l'analyse des sentiments et la génération de rapports.

Statut de l'API Hootsuite et alternatives

Situation actuelle de l'API

Depuis 2024, l'API publique Hootsuite est dépréciée. Voici les options d'intégration à privilégier :

Approche Description Idéal pour
API de Plateformes Natives Intégration directe avec Facebook, Twitter, LinkedIn, etc. Contrôle total, solutions personnalisées
Audiense Intelligence d'audience détenue par Hootsuite Analyse d'audience
HeyOrca API de planification de médias sociaux Calendriers de contenu
API Buffer Gestion des médias sociaux Petites équipes
API Sprout Social Gestion sociale d'entreprise Grandes organisations
API Agorapulse CRM de médias sociaux Gestion de communauté

Approche recommandée : API de plateformes natives

Pour la plupart des besoins, intégrez directement les API des plateformes sociales pour bénéficier de la flexibilité maximale :

Plateforme Nom de l'API Fonctionnalités clés
Facebook/Instagram Graph API Publications, statistiques, commentaires
Twitter/X API v2 Tweets, analyses, flux
LinkedIn Marketing API Publications, pages, publicités
Pinterest API v5 Épingles, tableaux, analyses
TikTok Display API Vidéos, infos utilisateur
YouTube Data API Vidéos, playlists, analyses

Démarrage : Authentification multiplateforme

Étape 1 : Enregistrer les applications de développeur

Créez des comptes développeur pour chaque plateforme et stockez les identifiants de façon sécurisée :

// Stocker les credentials de manière sécurisée
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, // Utilise Facebook Login
    appSecret: process.env.FB_APP_SECRET
  }
};
Enter fullscreen mode Exit fullscreen mode

Étape 2 : Implémenter le flux OAuth 2.0

Utilisez un gestionnaire OAuth centralisé pour toutes les plateformes :

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()}`;
};

// Callback OAuth
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();
};
Enter fullscreen mode Exit fullscreen mode

Étape 3 : Stocker les jetons en toute sécurité

Utilisez un schéma adapté pour stocker les tokens :

// Schéma base de données pour les jetons sociaux
const SocialToken = {
  userId: 'user_123',
  platform: 'facebook',
  accessToken: 'encrypted_token_here',
  refreshToken: 'encrypted_refresh_token',
  tokenExpiry: Date.now() + 5183999, // 60 jours
  scopes: ['pages_manage_posts', 'pages_read_engagement'],
  pageId: 'page_456', // Pour Facebook/Instagram
  pageName: 'My Business Page'
};
Enter fullscreen mode Exit fullscreen mode

Planification et publication de posts

Créer un post multiplateforme

Publiez sur plusieurs plateformes en parallèle :

const createSocialPost = async (postData) => {
  const results = {};

  // Facebook
  if (postData.platforms.includes('facebook')) {
    results.facebook = await postToFacebook({
      pageId: postData.facebookPageId,
      message: postData.message,
      link: postData.link,
      photo: postData.photo
    });
  }

  // Twitter
  if (postData.platforms.includes('twitter')) {
    results.twitter = await postToTwitter({
      text: postData.message,
      media: postData.photo
    });
  }

  // LinkedIn
  if (postData.platforms.includes('linkedin')) {
    results.linkedin = await postToLinkedIn({
      authorUrn: postData.linkedinAuthorUrn,
      text: postData.message,
      contentUrl: postData.link
    });
  }

  // Instagram
  if (postData.platforms.includes('instagram')) {
    results.instagram = await postToInstagram({
      igAccountId: postData.igAccountId,
      imageUrl: postData.photo,
      caption: postData.message
    });
  }

  return results;
};

// Publication Facebook
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();
};

// Publication Twitter
const postToTwitter = async (postData) => {
  const token = await getTwitterToken();

  let mediaIds = [];
  if (postData.media) {
    // Upload média d'abord
    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();
};

// Publication LinkedIn
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();
};

// Publication Instagram
const postToInstagram = async (postData) => {
  const token = await getInstagramToken();

  // Étape 1 : Création du container media
  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();

  // Étape 2 : Publication
  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();
};
Enter fullscreen mode Exit fullscreen mode

Planification des posts

Planifiez vos posts via une base de données et une file de tâches :

const schedulePost = async (postData, scheduledTime) => {
  // Enregistrer dans la BDD pour exécution différée
  const scheduledPost = await db.scheduledPosts.create({
    message: postData.message,
    platforms: postData.platforms,
    scheduledTime: scheduledTime,
    status: 'pending',
    media: postData.media,
    link: postData.link
  });

  // Ajout à la file de jobs
  await jobQueue.add('publish-social-post', {
    postId: scheduledPost.id
  }, {
    delay: scheduledTime - Date.now()
  });

  return scheduledPost;
};

// Traitement du job
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;
  }
});
Enter fullscreen mode Exit fullscreen mode

Analyse et rapports

Récupération d'analyses multiplateformes

Récupérez et agrégerez les métriques de toutes les plateformes :

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)
  };

  // Agrégation
  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);
}
Enter fullscreen mode Exit fullscreen mode

Gestion d'équipe

Contrôle d'accès basé sur les rôles

Implémentez une gestion des permissions par rôle :

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);
};
Enter fullscreen mode Exit fullscreen mode

Limitation de débit

Limites de débit des plateformes

Plateforme Limite Fenêtre
Facebook Graph 200 appels Par heure et par utilisateur
Twitter API v2 300 tweets Par 15 min
LinkedIn 100-500 appels Par jour
Instagram 200 appels Par heure

Implémentation de la gestion des limites de débit

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++;
  }
}
Enter fullscreen mode Exit fullscreen mode

Liste de contrôle de déploiement en production

Avant de passer en production, vérifiez les points suivants :

  • [ ] Implémenter OAuth 2.0 pour toutes les plateformes
  • [ ] Stocker les jetons de façon sécurisée (chiffrement)
  • [ ] Configurer l'actualisation automatique des jetons
  • [ ] Implémenter la limitation de débit par plateforme
  • [ ] Ajouter une gestion des erreurs robuste
  • [ ] Configurer la journalisation de tous les appels API
  • [ ] Créer des workflows d'approbation de publication
  • [ ] Implémenter la modération de contenu
  • [ ] Configurer l'agrégation d'analyses
  • [ ] Mettre en place des mécanismes de publication de secours

Cas d'utilisation réels

Tableau de bord des médias sociaux

  • Défi : Gérer plus de 50 comptes clients sur plusieurs plateformes
  • Solution : Dashboard centralisé avec publication multiplateforme
  • Résultat : 60 % de gain de temps, branding cohérent

Distribution de contenu automatisée

  • Défi : Partage manuel du nouveau contenu
  • Solution : Publication automatique de chaque nouvel article sur toutes les plateformes
  • Résultat : Distribution instantanée, trafic social multiplié par 3

Conclusion

Même si l'API publique Hootsuite est dépréciée, les API natives offrent de puissantes capacités de gestion sociale. Retenez :

  • Implémentez OAuth 2.0 séparément pour chaque plateforme
  • Les limites de débit varient fortement selon la plateforme
  • La publication unifiée exige des implémentations spécifiques à chaque API
  • L'agrégation d'analyses fournit une vue consolidée
  • Apidog simplifie les tests d'API et la collaboration en équipe

Section FAQ

Hootsuite a-t-il toujours une API ?

Hootsuite a déprécié son API publique en 2024. Utilisez les API natives des plateformes ou des solutions alternatives comme Buffer, Sprout Social ou Agorapulse.

Comment publier sur plusieurs plateformes à la fois ?

Implémentez OAuth pour chaque plateforme et créez une fonction de publication unifiée qui appelle les API de chaque plateforme en parallèle.

Quelles sont les limites de débit pour les API de médias sociaux ?

Les limites varient : Facebook (200/heure), Twitter (300/15 min), LinkedIn (100-500/jour), Instagram (200/heure).

Comment planifier des posts ?

Stockez les posts dans une base de données avec un scheduled_time, puis utilisez une file de tâches (Bull, Agenda) pour publier à l'heure prévue.

Puis-je obtenir des analyses de toutes les plateformes ?

Oui, chaque plateforme fournit des API d'analyse. Agrégez les données pour générer des rapports multiplateformes.

Top comments (0)