JavaScript Examples
These examples demonstrate how to use the Tailwind API with JavaScript and TypeScript.
Replace the example account, board, post, media, and destination values with your own. Scheduling examples use a date in 2099 so they remain valid; choose the future date and time you actually want.
// No additional dependencies needed - fetch is built into Node.js 18+const API_URL = 'https://api-v1.tailwind.ai';const API_KEY = process.env.TAILWIND_API_KEY;
const headers = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json'};npm install axiosimport axios from 'axios';
const api = axios.create({ baseURL: 'https://api-v1.tailwind.ai', headers: { 'Authorization': `Bearer ${process.env.TAILWIND_API_KEY}`, 'Content-Type': 'application/json' }});List Accounts
Section titled “List Accounts”async function listAccounts() { const response = await fetch(`${API_URL}/v1/accounts`, { headers });
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }
const { data } = await response.json(); return data.accounts;}
// Usageconst accounts = await listAccounts();console.log('Accounts:', accounts);List Boards
Section titled “List Boards”async function listBoards(accountId) { const response = await fetch( `${API_URL}/v1/accounts/${accountId}/boards`, { headers } );
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }
const { data } = await response.json(); return data.boards;}
// Usageconst boards = await listBoards('123456');console.log('Boards:', boards);Create and Schedule a Post
Section titled “Create and Schedule a Post”async function createPost(accountId, postData) { const response = await fetch( `${API_URL}/v1/accounts/${accountId}/posts`, { method: 'POST', headers, body: JSON.stringify(postData) } );
if (!response.ok) { const error = await response.json(); throw new Error(error.error?.message || 'Failed to create post'); }
const { data } = await response.json(); return data.post;}
// Usage - Create a scheduled postconst post = await createPost('123456', { mediaUrl: 'https://example.com/my-image.jpg', title: 'Amazing Recipe', description: 'Try this delicious recipe! #recipes #cooking', url: 'https://myblog.com/recipe', boardId: '1106196864631757445', altText: 'A colorful plate of food', sendAt: '2099-01-20T14:00:00Z'});
console.log('Created post:', post.id);console.log('Status:', post.status);Create and Schedule a Video Post
Section titled “Create and Schedule a Video Post”// Set mediaType to 'video' for video pinsconst videoPost = await createPost('123456', { mediaUrl: 'https://example.com/my-video.mp4', mediaType: 'video', title: 'Watch This Tutorial', description: 'Step-by-step guide #tutorial #video', url: 'https://myblog.com/tutorial', boardId: '1106196864631757445', sendAt: '2099-01-20T14:00:00Z'});
console.log('Video post created:', videoPost.id);Create a Draft Post
Section titled “Create a Draft Post”// Omit sendAt to create a draftconst draft = await createPost('123456', { mediaUrl: 'https://example.com/my-image.jpg', title: 'Draft for Review', description: 'I will schedule this later', boardId: '1106196864631757445'});
console.log('Draft created:', draft.id);// draft.status will be 'draft'Schedule a Draft
Section titled “Schedule a Draft”If the draft doesn’t already have a boardId, provide one when scheduling:
async function schedulePost(accountId, postId, sendAt, boardId) { const body = { sendAt }; if (boardId) body.boardId = boardId;
const response = await fetch( `${API_URL}/v1/accounts/${accountId}/posts/${postId}/schedule`, { method: 'POST', headers, body: JSON.stringify(body) } );
if (!response.ok) { const error = await response.json(); throw new Error(error.error?.message || 'Failed to schedule post'); }
const { data } = await response.json(); return data.post;}
// Usageconst scheduled = await schedulePost( '123456', 'post_abc123', '2099-01-25T09:00:00Z', '1106196864631757445' // Required if draft has no board assigned);
console.log('Scheduled for:', new Date(scheduled.sendAt * 1000));List Posts with Filtering
Section titled “List Posts with Filtering”async function listPosts(accountId, options = {}) { const params = new URLSearchParams();
if (options.status) params.set('status', options.status); if (options.limit) params.set('limit', options.limit.toString()); if (options.cursor) params.set('cursor', options.cursor); if (options.startDate) params.set('startDate', options.startDate); if (options.endDate) params.set('endDate', options.endDate);
const url = `${API_URL}/v1/accounts/${accountId}/posts?${params}`; const response = await fetch(url, { headers });
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }
const { data } = await response.json(); return { posts: data.posts, cursor: data.cursor };}
// List queued posts (default)const queued = await listPosts('123456');console.log('Queued posts:', queued.posts.length);
// List draftsconst drafts = await listPosts('123456', { status: 'draft' });console.log('Drafts:', drafts.posts.length);
// List sent posts in a date rangeconst sent = await listPosts('123456', { status: 'sent', startDate: '2024-01-01T00:00:00Z', endDate: '2024-01-31T23:59:59Z', limit: 100});console.log('Sent in January:', sent.posts.length);Delete a Post
Section titled “Delete a Post”async function deletePost(accountId, postId) { const response = await fetch( `${API_URL}/v1/accounts/${accountId}/posts/${postId}`, { method: 'DELETE', headers } );
if (!response.ok) { const error = await response.json(); throw new Error(error.error?.message || 'Failed to delete post'); }
return true;}
// Usageawait deletePost('123456', 'post_abc123');console.log('Post deleted');Complete Example: Bulk Scheduler
Section titled “Complete Example: Bulk Scheduler”/** * Schedule multiple posts with a delay between each */async function bulkSchedule(accountId, posts) { const results = [];
for (const postData of posts) { try { const post = await createPost(accountId, postData); results.push({ success: true, post }); console.log(`Scheduled: ${post.id}`); } catch (error) { results.push({ success: false, error: error.message, data: postData }); console.error(`Failed:`, error.message); } }
return results;}
// Usageconst postsToSchedule = [ { mediaUrl: 'https://example.com/image1.jpg', title: 'Post 1', description: 'First post', url: 'https://example.com/post-1', boardId: '1106196864631757445', sendAt: '2099-01-20T09:00:00Z' }, { mediaUrl: 'https://example.com/image2.jpg', title: 'Post 2', description: 'Second post', url: 'https://example.com/post-2', boardId: '1106196864631757445', sendAt: '2099-01-20T14:00:00Z' }, { mediaUrl: 'https://example.com/image3.jpg', title: 'Post 3', description: 'Third post', url: 'https://example.com/post-3', boardId: '1106196864631757445', sendAt: '2099-01-20T19:00:00Z' }];
const results = await bulkSchedule('123456', postsToSchedule);console.log(`Scheduled ${results.filter(r => r.success).length} posts`);TypeScript Types
Section titled “TypeScript Types”interface Account { id: string; userId?: string; displayName: string | null; username: string | null; avatarUrl: string | null; tokenAuthorized: boolean; isDomainVerified: boolean; createdAt: number | null;}
interface Board { id: string; name: string; isCollaborator: boolean; isSecret: boolean;}
interface Post { id: string; status: 'draft' | 'queued' | 'sent' | 'uploading'; mediaUrl: string; mediaType: 'image' | 'video'; title: string | null; description: string | null; url: string | null; boardId: string | null; altText: string | null; sendAt: number | null; sentAt: number | null; createdAt: number; pinId: string | null; isSimplifiedPin: boolean;}
interface CreatePostInput { mediaUrl: string; mediaType?: 'image' | 'video'; title?: string; description?: string; url?: string; /** Required when sendAt is provided; use a numeric Pinterest board ID */ boardId?: string; altText?: string; isSimplifiedPin?: boolean; /** Requires title, description, url, and boardId when set */ sendAt?: string;}Error Handling
Section titled “Error Handling”async function safeApiCall(fn) { try { return await fn(); } catch (error) { if (error.message.includes('401')) { console.error('Authentication failed. Check your API key.'); } else if (error.message.includes('429')) { console.error('Daily rate limit exceeded. Retry after midnight UTC.'); } else if (error.message.includes('404')) { console.error('Resource not found. Check your IDs.'); } else { console.error('API error:', error.message); } throw error; }}
// Usageconst accounts = await safeApiCall(() => listAccounts());