Skip to main content

Creating Posts

Learn how to create and schedule social media posts using the Flow API.

Basic Post Creation

Immediate Post

Post immediately to all connected platforms:

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Hello from Flow! 🚀',
// Omit scheduledFor to post immediately
});

Scheduled Post

Schedule a post for a specific time:

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'This posts tomorrow at 9 AM',
scheduledFor: new Date('2024-12-26T09:00:00Z'),
});

Post with Media

Attach images or videos:

// First, upload media
const media = await flow.media.upload({
file: fs.readFileSync('image.jpg'),
filename: 'image.jpg',
});

// Then create post with media
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Check out this image!',
mediaKeys: [media.key],
});

Post Content

Text Content

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Your post content here',
});

Limits:

  • Minimum: 1 character
  • Maximum: 10,000 characters
  • Platform-specific limits apply (Twitter: 280 chars, etc.)

Media Content

// Upload multiple images
const media1 = await flow.media.upload({ file: image1, filename: 'img1.jpg' });
const media2 = await flow.media.upload({ file: image2, filename: 'img2.jpg' });

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Multiple images!',
mediaKeys: [media1.key, media2.key],
});

Limits:

  • Maximum 10 media files per post
  • Supported formats: JPG, PNG, GIF, WebP, MP4, MOV
  • Maximum file size: 10MB

Post Without Content

Some platforms allow posts with only media:

const post = await flow.posts.create({
channelId: 'channel_123',
mediaKeys: [media.key],
// content is optional if media is provided
});

Scheduling

Schedule for Specific Time

// Schedule for specific date/time
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Scheduled post',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});

Schedule Relative to Now

// Post in 1 hour
const oneHourLater = new Date(Date.now() + 60 * 60 * 1000);

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Posts in 1 hour',
scheduledFor: oneHourLater,
});

Schedule for Tomorrow

const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(9, 0, 0, 0); // 9 AM

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Tomorrow at 9 AM',
scheduledFor: tomorrow,
});

Post Status

Posts have the following statuses:

  • queued - Scheduled for future publication
  • flowing - Currently being published to platforms
  • done - Successfully published to all platforms
  • blocked - Failed to publish (e.g., rate limit, content policy)

Check Status

const post = await flow.posts.get(postId);
console.log('Status:', post.status);

// Filter by status
const queuedPosts = await flow.posts.list({
filter: { status: 'queued' },
});

AI Optimization

Enable AI optimization to automatically adapt content for each platform:

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Original content that will be optimized',
enableOptimization: true, // Enable AI optimization
});

The AI will:

  • Adapt content length for each platform
  • Optimize hashtags and mentions
  • Adjust tone and style
  • Format for platform-specific requirements

AI optimization adapts your content for each platform automatically. Enable it when creating posts or configure it at the channel level.

Capacity Limits

Channels can have capacity limits configured:

// This will fail if capacity limit is exceeded
try {
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'New post',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});
} catch (error) {
if (error.code === 'CAPACITY_LIMIT_EXCEEDED') {
console.error('Channel capacity limit exceeded for this time');
}
}

Capacity limits help prevent over-posting and maintain engagement. Check channel capacity before scheduling posts.

Idempotency

Use idempotency keys to safely retry requests:

const idempotencyKey = `post-${channelId}-${Date.now()}`;

const post = await flow.posts.create(
{
channelId: 'channel_123',
content: 'Hello!',
},
{
idempotencyKey,
}
);

See Idempotency for details.

Error Handling

try {
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Hello!',
});
} catch (error) {
if (error instanceof FlowError) {
switch (error.status) {
case 400:
console.error('Validation error:', error.details);
break;
case 404:
console.error('Channel not found');
break;
case 429:
console.error('Rate limited. Retry after:', error.retryAfter);
break;
default:
console.error('Error:', error.message);
}
}
}

Examples

Daily Post Scheduler

async function scheduleDailyPost(channelId: string, content: string) {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(9, 0, 0, 0); // 9 AM

return await flow.posts.create({
channelId,
content,
scheduledFor: tomorrow,
});
}

Content with Hashtags

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Exciting product launch! #product #launch #tech',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});

Multi-Platform Post

// Post to all platforms connected to the channel
const post = await flow.posts.create({
channelId: 'channel_123', // Channel with Twitter, LinkedIn, Instagram
content: 'Announcing our new feature!',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});

Post with Mentions

const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Thanks @partner for the collaboration! 🎉',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});

Best Practices

  1. Always validate content before creating posts
  2. Use idempotency keys for critical operations
  3. Check channel capacity before scheduling
  4. Handle errors gracefully with proper retry logic
  5. Monitor post status to ensure delivery
  6. Use webhooks for real-time notifications

Next Steps