Skip to main content

TypeScript/JavaScript SDK

Official TypeScript/JavaScript SDK for the Flow API.

Installation

npm install @flowdev/sdk
# or
yarn add @flowdev/sdk
# or
pnpm add @flowdev/sdk

Quick Start

import { Flow } from '@flowdev/sdk';

const flow = new Flow('flow_sk_live_abc12345_xyz789...');

// Create a post
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Hello from Flow!',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
});

console.log('Post created:', post.id);

Configuration

const flow = new Flow(apiKey, {
baseURL: 'https://api.flow.dev', // default
timeout: 30000, // 30 seconds, default
maxRetries: 3, // default
retryDelay: 1000, // Initial delay in ms, default
});

Posts

List Posts

// List all posts
const posts = await flow.posts.list();

// With filters
const posts = await flow.posts.list({
filter: {
status: 'queued',
channelId: 'channel_123',
},
sort: '-scheduledFor',
page: 1,
perPage: 50,
});

Create Post

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

// Scheduled post
const post = await flow.posts.create({
channelId: 'channel_123',
content: 'Scheduled post',
scheduledFor: new Date('2024-12-25T10:00:00Z'),
mediaKeys: ['media_key_123'], // optional
enableOptimization: true, // optional
}, {
idempotencyKey: 'unique-key-123', // optional
});

Get Post

const post = await flow.posts.get('post_123');

Update Post

// Only works if post is still 'queued'
await flow.posts.update('post_123', {
content: 'Updated content',
scheduledFor: new Date('2024-12-26T10:00:00Z'),
});

Delete Post

await flow.posts.delete('post_123');

Batch Operations

// Batch create
const result = await flow.posts.createBatch({
posts: [
{ channelId: 'channel_123', content: 'Post 1' },
{ channelId: 'channel_123', content: 'Post 2' },
],
});

// Batch update
await flow.posts.updateBatch({
posts: [
{ id: 'post_1', content: 'Updated 1' },
{ id: 'post_2', content: 'Updated 2' },
],
});

// Batch delete
await flow.posts.deleteBatch({
postIds: ['post_1', 'post_2', 'post_3'],
});

Channels

List Channels

const channels = await flow.channels.list();

Create Channel

const channel = await flow.channels.create({
name: 'My Channel',
color: '#3B82F6', // optional
});

Get Channel

const channel = await flow.channels.get('channel_123');

Update Channel

await flow.channels.update('channel_123', {
name: 'Updated Name',
color: '#FF0000',
});

Delete Channel

await flow.channels.delete('channel_123');

Webhooks

List Webhooks

const webhooks = await flow.webhooks.list();

Create Webhook

const { secret } = await flow.webhooks.create({
url: 'https://example.com/webhooks/flow',
events: ['post.delivered', 'post.failed'],
});

console.log('Webhook secret:', secret); // Save this!

Get Webhook

const webhook = await flow.webhooks.get('webhook_123');

Update Webhook

await flow.webhooks.update('webhook_123', {
url: 'https://new-url.com/webhooks/flow',
events: ['post.delivered'],
active: false,
});

Delete Webhook

await flow.webhooks.delete('webhook_123');

Get Deliveries

const deliveries = await flow.webhooks.getDeliveries('webhook_123', {
status: 'failed',
page: 1,
perPage: 50,
});

Test Webhook

await flow.webhooks.test('webhook_123');

API Keys

List API Keys

const keys = await flow.apiKeys.list();

Create API Key

const { apiKey } = await flow.apiKeys.create({
name: 'Production Key',
permissions: ['posts:write', 'channels:read'], // optional
});

console.log('API Key:', apiKey); // Save this!

Get API Key

const key = await flow.apiKeys.get('key_123');

Update API Key

await flow.apiKeys.update('key_123', {
name: 'Updated Name',
});

Delete API Key

await flow.apiKeys.delete('key_123');

Media

Upload Media

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

console.log('Media key:', media.key);

Get Media

const url = await flow.media.getUrl('media_key_123');

Delete Media

await flow.media.delete('media_key_123');

Error Handling

import { Flow, FlowError } from '@flowdev/sdk';

try {
const post = await flow.posts.create({
channelId: 'invalid',
content: 'Test',
});
} catch (error) {
if (error instanceof FlowError) {
switch (error.status) {
case 401:
console.error('Authentication failed');
break;
case 403:
console.error('Permission denied');
break;
case 404:
console.error('Resource not found');
break;
case 429:
console.error(`Rate limited. Retry after ${error.retryAfter}s`);
break;
default:
console.error('API error:', error.message);
}

// Access error details
if (error.details) {
error.details.forEach(detail => {
console.error(`${detail.field}: ${detail.message}`);
});
}
}
}

TypeScript Types

All types are exported:

import { 
Flow,
Post,
Channel,
Webhook,
ApiKey,
Media,
CreatePostRequest,
UpdatePostRequest,
} from '@flowdev/sdk';

const flow = new Flow(apiKey);
const posts: Post[] = await flow.posts.list();

Advanced Usage

Custom Headers

const post = await flow.posts.create(
{ channelId: 'channel_123', content: 'Hello' },
{
headers: {
'X-Custom-Header': 'value',
},
}
);

Request Interceptors

// Add custom request logic
flow.client.interceptors.request.use(config => {
config.headers['X-Custom-Header'] = 'value';
return config;
});

Response Interceptors

// Handle responses
flow.client.interceptors.response.use(
response => response,
error => {
// Custom error handling
console.error('Request failed:', error);
return Promise.reject(error);
}
);

Examples

Schedule Weekly Posts

async function scheduleWeeklyPosts(channelId: string, contents: string[]) {
const posts = contents.map((content, index) => {
const date = new Date();
date.setDate(date.getDate() + index + 1);
date.setHours(9, 0, 0, 0);

return {
channelId,
content,
scheduledFor: date,
};
});

return await flow.posts.createBatch({ posts });
}

Monitor Post Status

async function waitForPostDelivery(postId: string) {
while (true) {
const post = await flow.posts.get(postId);

if (post.status === 'done') {
console.log('Post delivered!');
break;
} else if (post.status === 'blocked') {
console.error('Post blocked');
break;
}

await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
}
}

Next Steps