Claude-code-plugins-plus-skills hootsuite-core-workflow-a
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/hootsuite-pack/skills/hootsuite-core-workflow-a" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-hootsuite-core-workflow-a && rm -rf "$T"
manifest:
plugins/saas-packs/hootsuite-pack/skills/hootsuite-core-workflow-a/SKILL.mdsource content
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
setuphootsuite-install-auth - 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; }
Step 3: Complete Publishing Flow
async function publishPostWithImage( profileId: string, text: string, imagePath: string, scheduledAt: Date ) { // 1. Create upload URL const stats = fs.statSync(imagePath); const mimeType = imagePath.endsWith('.png') ? 'image/png' : 'image/jpeg'; const media = await createMediaUpload(stats.size, mimeType); // 2. Upload file to S3 await uploadFile(media.uploadUrl, imagePath, mimeType); // 3. Wait for media processing let status = await getMediaStatus(media.id); while (status.state === 'PENDING') { await new Promise(r => setTimeout(r, 2000)); status = await getMediaStatus(media.id); } if (status.state !== 'READY') { throw new Error(`Media rejected: ${status.state}`); } // 4. Schedule post with media return scheduleWithMedia({ profileIds: [profileId], text, mediaIds: [media.id], scheduledAt, }); }
Step 4: Bulk Scheduling
interface ScheduledPost { text: string; profileIds: string[]; scheduledAt: Date; imagePath?: string; } async function bulkSchedule(posts: ScheduledPost[]) { const results = []; for (const post of posts) { if (post.imagePath) { results.push(await publishPostWithImage(post.profileIds[0], post.text, post.imagePath, post.scheduledAt)); } else { results.push(await scheduleWithMedia({ profileIds: post.profileIds, text: post.text, mediaIds: [], scheduledAt: post.scheduledAt })); } await new Promise(r => setTimeout(r, 500)); // Rate limit buffer } return results; }
Output
- Media uploaded and processed
- Posts scheduled with images across social profiles
- Bulk scheduling support
Error Handling
| Error | Cause | Solution |
|---|---|---|
Media | File too large or wrong format | Check size limits per network |
| Date in the past | Must be future date |
| Image exceeds limit | Compress or resize image |
| Missing profile | Profile disconnected | Reconnect in Hootsuite dashboard |
Resources
Next Steps
For analytics, see
hootsuite-core-workflow-b.