DEV Community

Cover image for How to Use Hootsuite API ?
Wanda
Wanda

Posted on • Originally published at apidog.com

How to Use Hootsuite API ?

TL;DR

The Hootsuite API allowed developers to automate social media management using OAuth 2.0, RESTful endpoints, and rate limits. However, Hootsuite’s public API is now deprecated (2024). This guide provides actionable alternatives—leveraging native social media platform APIs, webhooks, and third-party APIs for scheduling posts, fetching analytics, managing teams, and handling production integration.

Note: Since Hootsuite deprecated their public API, use native platform integrations, official partner integrations, or third-party APIs for equivalent automation.

Try Apidog today

Introduction

Hootsuite managed over 30 million social media accounts for 200,000+ businesses globally. For developers building marketing tools or analytics dashboards, direct social media API integration is now essential. Automating content distribution, engagement monitoring, sentiment analysis, and reporting saves social media teams 25-35 hours per week otherwise lost to manual effort.

Hootsuite API Status and Alternatives

Current API Situation

Hootsuite's public API is deprecated (2024). Consider these integration approaches:

Approach Description Best For
Native Platform APIs Direct Facebook, Twitter, LinkedIn, etc. Full control, custom
Audiense Hootsuite-owned audience analytics Audience analysis
HeyOrca Social media scheduling API Content calendars
Buffer API Social media management Small teams
Sprout Social API Enterprise social management Large organizations
Agorapulse API Social CRM Community management

Recommended Approach: Native Platform APIs

Direct integration with each social network’s API offers the most flexibility and reliability:

Platform API Name Key Features
Facebook/Instagram Graph API Posts, insights, comments
Twitter/X API v2 Tweets, analytics, streams
LinkedIn Marketing API Posts, company pages, ads
Pinterest API v5 Pins, boards, analytics
TikTok Display API Videos, user info
YouTube Data API Videos, playlists, analytics

Getting Started: Multi-Platform Authentication

Step 1: Register Developer Apps

Create developer accounts and register your application with each platform. Store credentials using environment variables or a secret manager:

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

Step 2: Implement OAuth 2.0 Flow

Create a unified OAuth handler for multi-platform authentication:

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

Step 3: Store Tokens Securely

Persist tokens using encrypted storage:

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

Post Scheduling and Publishing

Creating a Multi-Platform Post

Push content to all selected platforms in parallel:

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

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

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

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

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

Scheduling Posts

Queue posts for scheduled publishing using a database and job queue (e.g., Bull, Agenda):

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

Analytics and Reporting

Fetching Cross-Platform Analytics

Aggregate analytics from all supported platforms:

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

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

Helper Function

function sum(analytics, metric) {
  return Object.values(analytics).reduce((total, platform) => {
    return total + (platform.data?.[metric] || 0);
  }, 0);
}
Enter fullscreen mode Exit fullscreen mode

Team Management

Role-Based Access Control

Implement RBAC for managing team permissions:

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

Rate Limiting

Platform Rate Limits

Platform Limit Window
Facebook Graph 200 calls Per hour per user
Twitter API v2 300 tweets Per 15 min
LinkedIn 100-500 calls Per day
Instagram 200 calls Per hour

Implementing Rate Limit Handling

Use a rate limiter to avoid hitting platform caps:

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

Production Deployment Checklist

Before shipping your integration, ensure:

  • [ ] OAuth 2.0 implemented for all platforms
  • [ ] Tokens stored securely and encrypted
  • [ ] Automatic token refresh logic
  • [ ] Rate limiting for each platform
  • [ ] Error handling for all API calls
  • [ ] Logging enabled for API activity
  • [ ] Post approval workflows in place
  • [ ] Content moderation implemented
  • [ ] Analytics aggregation logic
  • [ ] Backup posting mechanisms

Real-World Use Cases

Social Media Dashboard

  • Challenge: Managing 50+ client accounts across multiple platforms
  • Solution: Unified dashboard with cross-platform posting and analytics
  • Result: 60% time savings and consistent branding

Automated Content Distribution

  • Challenge: Manual sharing of new articles/content
  • Solution: Automated posting to all platforms upon publishing
  • Result: Instant distribution, tripled social traffic

Conclusion

With Hootsuite’s public API now deprecated, direct integration with native platform APIs is the most robust approach for social media automation. Key steps:

  • Implement OAuth 2.0 for each platform
  • Respect platform-specific rate limits
  • Use platform-specific endpoints for posting and analytics
  • Aggregate analytics for cross-platform reporting
  • Tools like Apidog streamline API testing and team collaboration

FAQ Section

Does Hootsuite still have an API?

No, Hootsuite deprecated their public API in 2024. Use native APIs or alternatives like Buffer, Sprout Social, or Agorapulse.

How do I post to multiple platforms at once?

Implement OAuth for each platform and build a unified function that posts to each API in parallel.

What are the rate limits for social media APIs?

Varies by platform: Facebook (200/hour), Twitter (300/15min), LinkedIn (100-500/day), Instagram (200/hour).

How do I schedule posts?

Save posts in a database with a scheduled time and use a job queue (e.g., Bull, Agenda) to trigger publishing.

Can I get analytics from all platforms?

Yes, all major platforms expose analytics APIs. Aggregate results for unified reporting.

Top comments (0)