Claude Code skill pack for Hootsuite (18 skills)
Installation
Open Claude Code and run this command:
/plugin install hootsuite-pack@claude-code-plugins-plus
Use --global to install for all projects, or --project for current project only.
Skills (18)
Configure Hootsuite CI/CD integration with GitHub Actions and testing.
Hootsuite CI Integration
Overview
Set up CI/CD for Hootsuite social media management integrations: run unit tests with mocked post scheduling and analytics responses on every PR, validate live API connectivity for social profile queries on merge to main. Hootsuite's API handles scheduled posts, social analytics, and multi-network publishing, so CI pipelines verify scheduling logic, content validation rules, and analytics data aggregation.
GitHub Actions Workflow
# .github/workflows/hootsuite-ci.yml
name: Hootsuite CI
on:
pull_request:
paths: ['src/hootsuite/**', 'tests/**']
push:
branches: [main]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm test -- --reporter=verbose
integration-tests:
if: github.ref == 'refs/heads/main'
needs: unit-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run test:integration
env:
HOOTSUITE_CLIENT_ID: ${{ secrets.HOOTSUITE_CLIENT_ID }}
HOOTSUITE_CLIENT_SECRET: ${{ secrets.HOOTSUITE_CLIENT_SECRET }}
HOOTSUITE_REFRESH_TOKEN: ${{ secrets.HOOTSUITE_REFRESH_TOKEN }}
Mock-Based Unit Tests
// tests/hootsuite-service.test.ts
import { describe, it, expect, vi } from 'vitest';
import { schedulePost, getPostAnalytics } from '../src/hootsuite-service';
vi.mock('../src/hootsuite-client', () => ({
HootsuiteClient: vi.fn().mockImplementation(() => ({
createMessage: vi.fn().mockResolvedValue({
id: 'msg_abc123',
state: 'SCHEDULED',
scheduledSendTime: '2026-04-07T14:00:00Z',
socialProfileIds: ['sp_twitter', 'sp_linkedin'],
}),
getAnalytics: vi.fn().mockResolvedValue({
postId: 'msg_abc123',
metrics: { impressions: 1200, clicks: 85, engagement_rate: 0.071 },
}),
listSocialProfiles: vi.fn().mockResolvedValue({
profiles: [
{ id: 'sp_twitter', type: 'TWITTER', name: '@company' },
{ id: 'sp_linkedin', type: 'LINKEDIN', name: 'Company Page' },
],
}),
})),
}));
describe('Hootsuite Service', () => {
it('schedules a multi-network post', async () => {
const result = await schedulePost('Launch day!', {
profiles: ['sp_twitter', 'sp_linkedin'],
scheduledTime: '2026-04-07T14:00:00Z',
});
expect(result.state).toBe('SCHEDULED');
expect(result.socialProfileIds).toHaveLength(2);
});
it('retrieves post analytics', async () => {Diagnose and fix Hootsuite common errors and exceptions.
Hootsuite Common Errors
Error Reference
401 Unauthorized
Cause: Access token expired (tokens last ~1 hour).
Fix: Refresh token via OAuth:
curl -X POST https://platform.hootsuite.com/oauth2/token \
-u "$HOOTSUITE_CLIENT_ID:$HOOTSUITE_CLIENT_SECRET" \
-d "grant_type=refresh_token&refresh_token=$HOOTSUITE_REFRESH_TOKEN"
403 Forbidden
Cause: App lacks required permissions or user doesn't own the resource.
Fix: Check app scopes in developer portal. Ensure user has access to the social profile.
422 Unprocessable Entity — scheduledSendTime
Cause: Scheduled time is in the past or invalid ISO 8601 format.
Fix: Always use future dates in ISO 8601: new Date(Date.now() + 3600000).toISOString()
422 — socialProfileIds
Cause: Profile ID invalid or disconnected.
Fix: List profiles first: GET /v1/socialProfiles and verify IDs.
429 Too Many Requests
Cause: Rate limit exceeded.
Fix: Implement exponential backoff. See hootsuite-rate-limits.
Media Upload — State REJECTED
Cause: File too large, wrong format, or exceeds platform limits.
Fix: Check per-platform limits: Twitter images 5MB, Facebook 10MB, video varies.
invalid_grant — Token Exchange
Cause: Authorization code expired (30 second lifetime) or already used.
Fix: Re-initiate OAuth flow — codes are single-use and expire in 30s.
redirecturimismatch
Cause: Redirect URI doesn't exactly match app registration.
Fix: Must match character-for-character, including trailing slash.
Quick Diagnostics
# Test token validity
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $HOOTSUITE_ACCESS_TOKEN" \
https://platform.hootsuite.com/v1/me
# List profiles (verifies full API access)
curl -s -H "Authorization: Bearer $HOOTSUITE_ACCESS_TOKEN" \
https://platform.hootsuite.com/v1/socialProfiles | python3 -m json.tool
Resources
Next Steps
For debugging tools, see hootsuite-debug-bundle.
Execute Hootsuite primary workflow: Core Workflow A.
Hootsuite Publishing — Schedule Posts with Media
Overview
Schedule social media posts with images and videos using the Hootsuite REST API. The publishing workflow involves: uploading media to get a media ID, then scheduling a message referencing that media.
Prerequisites
- Completed
hootsuite-install-authsetup - Social profiles connected in Hootsuite
- Media files (images/videos) for upload
Instructions
Step 1: Upload Media
// publishing.ts
import 'dotenv/config';
import fs from 'fs';
const TOKEN = process.env.HOOTSUITE_ACCESS_TOKEN!;
const BASE = 'https://platform.hootsuite.com/v1';
// Step 1a: Create upload URL
async function createMediaUpload(sizeBytes: number, mimeType: string) {
const response = await fetch(`${BASE}/media`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ sizeBytes, mimeType }),
});
const { data } = await response.json();
console.log('Upload URL:', data.uploadUrl);
console.log('Media ID:', data.id);
return data; // { id, uploadUrl, uploadUrlDurationSeconds }
}
// Step 1b: Upload file to the S3 URL
async function uploadFile(uploadUrl: string, filePath: string, mimeType: string) {
const fileBuffer = fs.readFileSync(filePath);
const response = await fetch(uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': mimeType },
body: fileBuffer,
});
if (response.status !== 200) throw new Error(`Upload failed: ${response.status}`);
console.log('File uploaded successfully');
}
// Step 1c: Check media status
async function getMediaStatus(mediaId: string) {
const response = await fetch(`${BASE}/media/${mediaId}`, {
headers: { 'Authorization': `Bearer ${TOKEN}` },
});
const { data } = await response.json();
console.log('Media state:', data.state); // PENDING, READY, REJECTED
return data;
}
Step 2: Schedule Post with Media
async function scheduleWithMedia(config: {
profileIds: string[];
text: string;
mediaIds: string[];
scheduledAt: Date;
}) {
const response = await fetch(`${BASE}/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: config.text,
socialProfileIds: config.profileIds,
scheduledSendTime: config.scheduledAt.toISOString(),
mediaUrls: config.mediaIds.map(id => ({ id })),
emailNotification: false,
}),
});
const result = await response.json();
for (const msg of result.data) {
console.log(`Message ${msg.id}: ${msg.state} → ${msg.scheduledSendTime}`);
}
return result;
}
Execute Hootsuite secondary workflow: Core Workflow B.
Hootsuite Analytics & URL Shortening
Overview
Retrieve social media analytics and use Ow.ly URL shortening via the Hootsuite API. Track post performance, engagement metrics, and click-through rates.
Prerequisites
- Completed
hootsuite-install-authsetup - Published posts with engagement data
Instructions
Step 1: Get Organization Analytics
import 'dotenv/config';
const TOKEN = process.env.HOOTSUITE_ACCESS_TOKEN!;
const BASE = 'https://platform.hootsuite.com/v1';
async function getOrganization() {
const response = await fetch(`${BASE}/me/organizations`, {
headers: { 'Authorization': `Bearer ${TOKEN}` },
});
const { data } = await response.json();
return data[0]; // Primary organization
}
Step 2: Shorten URLs with Ow.ly
async function shortenUrl(fullUrl: string) {
const response = await fetch(`${BASE}/shorteners/owly`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url: fullUrl }),
});
const { data } = await response.json();
console.log(`${fullUrl} → ${data.shortUrl}`);
return data;
}
// Shorten multiple URLs
async function shortenBatch(urls: string[]) {
return Promise.all(urls.map(url => shortenUrl(url)));
}
Step 3: Retrieve Message Analytics
async function getMessageAnalytics(messageId: string) {
const response = await fetch(`${BASE}/messages/${messageId}`, {
headers: { 'Authorization': `Bearer ${TOKEN}` },
});
const { data } = await response.json();
console.log(`Message: ${data.text?.substring(0, 50)}...`);
console.log(`State: ${data.state}`);
console.log(`Sent: ${data.sentAt}`);
return data;
}
// List sent messages and their performance
async function getSentMessages(profileId: string) {
const response = await fetch(
`${BASE}/messages?socialProfileIds=${profileId}&state=SENT&limit=20`,
{ headers: { 'Authorization': `Bearer ${TOKEN}` } },
);
const { data } = await response.json();
for (const msg of data) {
console.log(`[${msg.sentAt}] ${msg.text?.substring(0, 60)}`);
}
return data;
}
Step 4: Social Profile Metrics
async function getProfileDetails(profileId: string) {
const response = await fetch(`${BASE}/socialProfiles/${profileId}`, {
headers: { 'Authorization': `Bearer ${TOKEN}` },
});
const { data } = await response.json();
console.log(`Profile: @${data.socialNetworkUsername}`);
console.log(`Network: ${data.type}`);
console.log(`ID: ${data.id}`);
return data;
}
Output
- Organization analytics retrieved
- URLs shortened via Ow.ly
Optimize Hootsuite costs through tier selection, sampling, and usage monitoring.
Hootsuite Cost Tuning
Hootsuite Plans
| Plan | Price | Profiles | Users | API Access |
|---|---|---|---|---|
| Professional | $99/mo | 10 | 1 | REST API |
| Team | $249/mo | 20 | 3 | REST API |
| Business | $739/mo | 35 | 5+ | Full API + webhooks |
| Enterprise | Custom | 50+ | Unlimited | Full API + SCIM |
Cost Optimization
Step 1: Minimize API Calls
// Cache profile lists (don't refetch every request)
// Batch schedule posts (one session, many messages)
// Use bulk endpoints where available
Step 2: Right-Size Your Plan
// Audit actual profile usage
async function auditUsage() {
const profiles = await getCachedProfiles();
console.log(`Active profiles: ${profiles.length}`);
console.log(`Networks: ${[...new Set(profiles.map(p => p.type))].join(', ')}`);
// If using < 10 profiles, Professional plan may suffice
}
Step 3: Track API Usage
let apiCallCount = 0;
const originalFetch = fetch;
globalThis.fetch = async (...args) => {
if (String(args[0]).includes('hootsuite.com')) apiCallCount++;
return originalFetch(...args);
};
// Log periodically
setInterval(() => { console.log(`Hootsuite API calls: ${apiCallCount}`); apiCallCount = 0; }, 3600000);
Resources
Next Steps
For architecture, see hootsuite-reference-architecture.
Collect Hootsuite debug evidence for support tickets and troubleshooting.
Hootsuite Debug Bundle
Overview
Collect Hootsuite API connectivity status, social profile health, scheduled post state, and OAuth token validity into a single diagnostic archive. This bundle helps troubleshoot failed post scheduling, disconnected social accounts, media upload errors, and API authentication problems.
Debug Collection Script
#!/bin/bash
set -euo pipefail
BUNDLE="debug-hootsuite-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BUNDLE"
# Environment check
echo "=== Hootsuite Debug Bundle ===" | tee "$BUNDLE/summary.txt"
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$BUNDLE/summary.txt"
echo "HOOTSUITE_API_KEY: ${HOOTSUITE_API_KEY:+[SET]}" >> "$BUNDLE/summary.txt"
echo "HOOTSUITE_ACCESS_TOKEN: ${HOOTSUITE_ACCESS_TOKEN:+[SET]}" >> "$BUNDLE/summary.txt"
# API connectivity — user profile endpoint
HTTP=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${HOOTSUITE_ACCESS_TOKEN}" \
https://platform.hootsuite.com/v1/me 2>/dev/null || echo "000")
echo "API Status: HTTP $HTTP" >> "$BUNDLE/summary.txt"
# User profile and social profiles
curl -s -H "Authorization: Bearer ${HOOTSUITE_ACCESS_TOKEN}" \
https://platform.hootsuite.com/v1/me > "$BUNDLE/me.json" 2>&1 || true
curl -s -H "Authorization: Bearer ${HOOTSUITE_ACCESS_TOKEN}" \
https://platform.hootsuite.com/v1/socialProfiles > "$BUNDLE/profiles.json" 2>&1 || true
# Scheduled posts and rate limit headers
curl -s -D "$BUNDLE/rate-headers.txt" -H "Authorization: Bearer ${HOOTSUITE_ACCESS_TOKEN}" \
"https://platform.hootsuite.com/v1/messages?limit=10&state=SCHEDULED" > "$BUNDLE/scheduled-posts.json" 2>&1 || true
tar -czf "$BUNDLE.tar.gz" "$BUNDLE" && rm -rf "$BUNDLE"
echo "Bundle: $BUNDLE.tar.gz"
Analyzing the Bundle
tar -xzf debug-hootsuite-*.tar.gz
cat debug-hootsuite-*/summary.txt # Auth + connectivity
jq '.data[] | {id, type, socialNetworkId}' debug-hootsuite-*/profiles.json # Connected accounts
jq '.data[] | {id, state, scheduledSendTime}' debug-hootsuite-*/scheduled-posts.json
grep -i "ratelimit\|retry" debug-hootsuite-*/rate-headers.txt
Common Issues
| Symptom | Check in Bundle | Fix | |||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| API returns 401 | summary.txt shows HTTP 401 |
OAuth token expired; re-authorize via Hootsuite app OAuth flow | |||||||||||||||||||||||||||||||||||||||||||||
| Social profile disconnected | profiles.json shows missing or error-state profile |
Re-connect the social account in Hoots
Deploy Hootsuite integrations to Vercel, Fly.
ReadWriteEditBash(vercel:*)Bash(fly:*)Bash(gcloud:*)
Hootsuite Deploy IntegrationOverviewDeploy Hootsuite social media management backends. Key consideration: OAuth refresh tokens must persist across deployments — use a database or key-value store, not environment variables. InstructionsStep 1: Vercel Deployment
Step 2: Token Persistence
ResourcesNext StepsFor webhooks, see Create a minimal working Hootsuite example.
ReadWriteEditBash(npm:*)Bash(curl:*)
Hootsuite Hello WorldOverviewList your social media profiles and schedule a post using the Hootsuite REST API. The API base URL is Prerequisites
InstructionsStep 1: List Social Profiles
Step 2: Schedule a Post
Step 3: List Scheduled Messages
Step 4: curl Quick Test
Output
Install and configure Hootsuite SDK/CLI authentication.
ReadWriteEditBash(npm:*)Bash(curl:*)Grep
Hootsuite Install & AuthOverviewConfigure Hootsuite REST API OAuth 2.0 authentication. Hootsuite uses OAuth 2.0 with Bearer tokens. You register an app in the Hootsuite Developer Portal, get client credentials, and exchange authorization codes for access tokens. Prerequisites
InstructionsStep 1: Register Your App
Step 2: Configure Environment
Step 3: OAuth 2.0 Authorization FlowConfigure Hootsuite local development with hot reload and testing.
ReadWriteEditBash(npm:*)Bash(pnpm:*)Grep
Hootsuite Local Dev LoopOverviewSet up a development workflow for Hootsuite API integrations with mocked API responses, token management, and testing. InstructionsStep 1: Project Structure
Step 2: API Client with Auto Token Refresh
Step 3: Mocked TestsOptimize Hootsuite API performance with caching, batching, and connection pooling.
ReadWriteEdit
Hootsuite Performance TuningInstructionsStep 1: Cache Social Profiles
Step 2: Batch Message Scheduling
Step 3: Connection Reuse
ResourcesNext StepsFor cost optimization, see Execute Hootsuite production deployment checklist and rollback procedures.
ReadBash(curl:*)Grep
Hootsuite Production ChecklistOverviewHootsuite manages social media publishing, scheduling, and analytics across multiple platforms (Twitter/X, LinkedIn, Facebook, Instagram). A production integration automates post scheduling, monitors engagement, and syncs analytics. Failures mean posts go out at wrong times, media uploads get rejected, or social profile disconnections go undetected, creating gaps in your publishing calendar. Authentication & Secrets
API Integration
Error Handling & Resilience
Monitoring & Alerting
Validation ScriptImplement Hootsuite rate limiting, backoff, and idempotency patterns.
ReadWriteEdit
Hootsuite Rate LimitsOverviewHandle Hootsuite API rate limits. The API returns Rate Limits
InstructionsStep 1: Respect Retry-After Header
Step 2: Queue-Based Scheduling
ResourcesNext StepsFor security, see Implement Hootsuite reference architecture with best-practice project layout.
ReadGrep
Hootsuite Reference ArchitectureArchitecture
Project Structure
Key Decisions
ResourcesNext StepsStart with Apply production-ready Hootsuite SDK patterns for TypeScript and Python.
ReadWriteEdit
Hootsuite SDK PatternsOverviewProduction patterns for Hootsuite REST API: typed client, token management, scheduling helpers, and Python integration. InstructionsStep 1: Typed API Client
Step 2: Scheduling Helper with Timezone
Step 3: Python Client
Step 4: Cross-Platform Post FormatterApply Hootsuite security best practices for secrets and access control.
ReadWriteGrep
Hootsuite Security BasicsCredential Inventory
InstructionsStep 1: Secure Token Storage
Step 2: Token Refresh Security
Step 3: Security Checklist
ResourcesNext StepsFor production, see Analyze, plan, and execute Hootsuite SDK upgrades with breaking change detection.
ReadWriteEditBash(npm:*)Bash(git:*)
Hootsuite Upgrade & MigrationOverviewHootsuite REST API is versioned at InstructionsStep 1: Check Current API Usage
Step 2: Migration Patterns
Step 3: Social Network ChangesWhen Hootsuite adds/removes social network support:
ResourcesNext StepsFor CI, see Implement Hootsuite webhook signature validation and event handling.
ReadWriteEditBash(curl:*)
Hootsuite Webhooks & EventsOverviewHootsuite provides webhook notifications for social stream events when building Hootsuite App Directory integrations. For API-only integrations, you poll for message state changes or implement your own scheduling system with callbacks. InstructionsStep 1: Poll for Message Status Changes
Step 2: Build Custom Scheduling Webhook
Step 3: Hootsuite App Directory WebhooksFor apps listed in the Hootsuite App Directory, you receive stream events:
Resources
|