UNPKG

threads-api-ai

Version:

A Node.js client library for the Facebook Threads API with TypeScript support

613 lines (439 loc) 14.7 kB
# threads-api-ai A Node.js client library for the Facebook Threads API with full TypeScript support. ## Features - ✅ **OAuth 2.0 Authentication** - Complete authentication flow with short-lived and long-lived tokens - ✅ **User Profile API** - Get user profile information and threads - ✅ **Publishing API** - Create and publish text, image, video, and carousel posts - ✅ **TypeScript Support** - Full type definitions for all API methods - ✅ **Promise-based** - Modern async/await API - ✅ **Error Handling** - Comprehensive error handling with detailed messages - 🚧 **More features coming soon** - Insights, replies, webhooks, and more ## Installation ```bash npm install threads-api-ai ``` ## Prerequisites Before using this library, you need to: 1. Create a Threads app in the [Meta Developer Portal](https://developers.facebook.com/) 2. Get your App ID and App Secret 3. Configure OAuth redirect URI in your app settings 4. Request necessary permissions/scopes ## Quick Start ```typescript import ThreadsAPI from 'threads-api-ai'; // Initialize the client const client = new ThreadsAPI({ appId: 'YOUR_APP_ID', appSecret: 'YOUR_APP_SECRET', redirectUri: 'https://yourapp.com/callback' }); // Step 1: Generate authorization URL const authUrl = client.auth.getAuthorizationUrl([ 'threads_basic', 'threads_content_publish' ], 'optional-state-for-csrf'); console.log('Visit this URL to authorize:', authUrl); // Step 2: After user authorizes, exchange code for tokens const code = 'CODE_FROM_CALLBACK'; const tokens = await client.auth.completeAuthFlow(code); console.log('Access Token:', tokens.access_token); console.log('Expires in:', tokens.expires_in, 'seconds'); ``` ## Authentication Guide The Threads API uses OAuth 2.0 for authentication. This library provides methods for the complete authentication flow. ### Available Scopes - `threads_basic` - Read basic profile information - `threads_content_publish` - Publish content on behalf of the user - `threads_manage_insights` - Read insights and analytics - `threads_manage_replies` - Manage replies to posts - `threads_read_replies` - Read replies to posts ### Complete Authentication Flow ```typescript import ThreadsAPI from 'threads-api-ai'; const client = new ThreadsAPI({ appId: process.env.THREADS_APP_ID!, appSecret: process.env.THREADS_APP_SECRET!, redirectUri: 'https://yourapp.com/auth/callback' }); // 1. Generate authorization URL const authUrl = client.auth.getAuthorizationUrl([ 'threads_basic', 'threads_content_publish' ], 'your-random-state-string'); // Redirect user to authUrl... // User authorizes and is redirected back to your callback URL with a code // 2. Exchange code for tokens (this method handles both short and long-lived tokens) const tokens = await client.auth.completeAuthFlow(code); // Save tokens.access_token securely - it's valid for ~60 days ``` ### Manual Token Exchange If you prefer to handle the token exchange manually: ```typescript // Get short-lived token (valid for ~1 hour) const shortToken = await client.auth.getAccessToken(code); // Exchange for long-lived token (valid for ~60 days) const longToken = await client.auth.getLongLivedToken(shortToken.access_token); ``` ### Refreshing Long-Lived Tokens Long-lived tokens expire after ~60 days. Refresh them before they expire: ```typescript const refreshedToken = await client.auth.refreshLongLivedToken( currentLongLivedToken ); // Save the new token - it's valid for another ~60 days ``` ## Express.js Example Here's a complete example using Express.js: ```typescript import express from 'express'; import ThreadsAPI from 'threads-api-ai'; const app = express(); const client = new ThreadsAPI({ appId: process.env.THREADS_APP_ID!, appSecret: process.env.THREADS_APP_SECRET!, redirectUri: 'http://localhost:3000/auth/callback' }); // Route to initiate OAuth app.get('/auth/threads', (req, res) => { const authUrl = client.auth.getAuthorizationUrl([ 'threads_basic', 'threads_content_publish' ], req.session.state); // Use session-based state for security res.redirect(authUrl); }); // OAuth callback route app.get('/auth/callback', async (req, res) => { try { const { code, state } = req.query; // Verify state matches (CSRF protection) if (state !== req.session.state) { throw new Error('State mismatch'); } // Complete auth flow and get long-lived token const tokens = await client.auth.completeAuthFlow(code as string); // Save tokens securely (e.g., in database) req.session.accessToken = tokens.access_token; res.send('Authentication successful!'); } catch (error) { console.error('Auth error:', error); res.status(500).send('Authentication failed'); } }); app.listen(3000); ``` ## User Profile API Once you have an access token, you can retrieve user profile information and threads. ### Get User Profile ```typescript // Get the authenticated user's profile const profile = await client.profile.getProfile(accessToken); console.log('User ID:', profile.id); console.log('Username:', profile.username); console.log('Profile Picture:', profile.threads_profile_picture_url); console.log('Bio:', profile.threads_biography); // Get specific fields only const customProfile = await client.profile.getProfile( accessToken, ['id', 'username'] // Only fetch these fields ); ``` ### Get User's Threads ```typescript // Get the authenticated user's threads const threads = await client.profile.getUserThreads(accessToken); console.log('User threads:', threads.data); // Get threads with custom fields and limit const customThreads = await client.profile.getUserThreads( accessToken, 'me', // or specific user ID ['id', 'text', 'permalink', 'timestamp'], // fields to retrieve 10 // limit ); ``` ### Get Single Thread ```typescript // Get a specific thread by ID const thread = await client.profile.getThread(accessToken, 'THREAD_ID'); console.log('Thread text:', thread.text); console.log('Permalink:', thread.permalink); console.log('Media URL:', thread.media_url); ``` ## Publishing API Create and publish text posts, images, videos, and carousels. ### Publish a Text Post ```typescript // Simple text post (all in one step) const result = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'TEXT', text: 'Hello from Threads API! 👋' } ); console.log('Published thread ID:', result.id); ``` ### Publish an Image Post ```typescript // Post with image const imagePost = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'IMAGE', image_url: 'https://example.com/image.jpg', text: 'Check out this image!' } ); ``` ### Publish a Video Post ```typescript // Post with video const videoPost = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'VIDEO', video_url: 'https://example.com/video.mp4', text: 'Watch this video!' } ); ``` ### Publish a Carousel Post ```typescript // Create carousel items first const item1 = await client.publishing.createCarouselItem( accessToken, 'me', { image_url: 'https://example.com/image1.jpg' } ); const item2 = await client.publishing.createCarouselItem( accessToken, 'me', { image_url: 'https://example.com/image2.jpg' } ); // Create and publish carousel const carousel = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'CAROUSEL', carousel_item_ids: [item1.id, item2.id], text: 'Swipe to see more!' } ); ``` ### Reply to a Thread ```typescript // Reply to another thread const reply = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'TEXT', text: 'This is a reply!', reply_to_id: 'PARENT_THREAD_ID' } ); ``` ### Control Who Can Reply ```typescript // Control reply permissions const post = await client.publishing.createAndPublishThread( accessToken, 'me', { media_type: 'TEXT', text: 'Only people I follow can reply', reply_control: 'accounts_you_follow' // or 'everyone' or 'mentioned_only' } ); ``` ### Manual Two-Step Publishing If you need more control, you can manually create and publish in two steps: ```typescript // Step 1: Create thread container const container = await client.publishing.createThread( accessToken, 'me', { media_type: 'TEXT', text: 'My post' } ); // Step 2: Publish the container const published = await client.publishing.publishThread( accessToken, 'me', { creation_id: container.id } ); console.log('Published thread ID:', published.id); ``` ### Check Publishing Limits ```typescript // Get publishing rate limit info const limits = await client.publishing.getPublishingLimit(accessToken); console.log('Quota usage:', limits.data); ``` ## Error Handling The library throws detailed errors with API error codes and messages: ```typescript try { const tokens = await client.auth.getAccessToken(code); } catch (error) { console.error(error.message); // Example: "Threads API Error (190): Invalid OAuth access token" } ``` ## API Reference ### `ThreadsAPI` Main client class. #### Constructor ```typescript new ThreadsAPI(config: ThreadsAPIConfig) ``` **Parameters:** - `config.appId` (string) - Your Threads App ID - `config.appSecret` (string) - Your Threads App Secret - `config.redirectUri` (string) - OAuth redirect URI - `config.apiVersion` (string, optional) - API version (default: 'v1.0') #### Properties - `auth` - Authentication handler - `profile` - User profile handler - `publishing` - Publishing handler ### `ThreadsAuth` Authentication handler (accessible via `client.auth`). #### Methods ##### `getAuthorizationUrl(scopes, state?)` Generate OAuth authorization URL. **Parameters:** - `scopes` (ThreadsScope[]) - Array of permission scopes - `state` (string, optional) - State parameter for CSRF protection **Returns:** Authorization URL (string) ##### `getAccessToken(code)` Exchange authorization code for short-lived access token. **Parameters:** - `code` (string) - Authorization code from callback **Returns:** Promise<AccessTokenResponse> ##### `getLongLivedToken(shortLivedToken)` Exchange short-lived token for long-lived token. **Parameters:** - `shortLivedToken` (string) - Short-lived access token **Returns:** Promise<LongLivedTokenResponse> ##### `refreshLongLivedToken(longLivedToken)` Refresh a long-lived token. **Parameters:** - `longLivedToken` (string) - Current long-lived token **Returns:** Promise<RefreshTokenResponse> ##### `completeAuthFlow(code)` Complete full OAuth flow (recommended method). **Parameters:** - `code` (string) - Authorization code from callback **Returns:** Promise<LongLivedTokenResponse> ### `ThreadsProfile` User profile handler (accessible via `client.profile`). #### Methods ##### `getProfile(accessToken, fields?)` Get the authenticated user's profile. **Parameters:** - `accessToken` (string) - User's access token - `fields` (string[], optional) - Fields to retrieve (default: id, username, threads_profile_picture_url, threads_biography) **Returns:** Promise<ThreadsUserProfile> ##### `getUserThreads(accessToken, userId?, fields?, limit?)` Get a user's threads. **Parameters:** - `accessToken` (string) - User's access token - `userId` (string, optional) - User ID (default: 'me') - `fields` (string[], optional) - Fields to retrieve - `limit` (number, optional) - Number of threads (default: 25, max: 100) **Returns:** Promise<any> ##### `getThread(accessToken, threadId, fields?)` Get a specific thread by ID. **Parameters:** - `accessToken` (string) - User's access token - `threadId` (string) - Thread ID - `fields` (string[], optional) - Fields to retrieve **Returns:** Promise<any> ### `ThreadsPublishing` Publishing handler (accessible via `client.publishing`). #### Methods ##### `createThread(accessToken, userId, params)` Create a thread container (step 1 of publishing). **Parameters:** - `accessToken` (string) - User's access token - `userId` (string) - User ID (default: 'me') - `params` (CreateThreadParams) - Thread creation parameters **Returns:** Promise<CreateThreadResponse> ##### `publishThread(accessToken, userId, params)` Publish a thread container (step 2 of publishing). **Parameters:** - `accessToken` (string) - User's access token - `userId` (string) - User ID (default: 'me') - `params` (PublishThreadParams) - Publishing parameters **Returns:** Promise<PublishThreadResponse> ##### `createAndPublishThread(accessToken, userId, params)` Create and publish a thread in one step (convenience method). **Parameters:** - `accessToken` (string) - User's access token - `userId` (string) - User ID (default: 'me') - `params` (CreateThreadParams) - Thread creation parameters **Returns:** Promise<PublishThreadResponse> ##### `createCarouselItem(accessToken, userId, params)` Create a carousel item for carousel posts. **Parameters:** - `accessToken` (string) - User's access token - `userId` (string) - User ID (default: 'me') - `params` (CreateCarouselItemParams) - Carousel item parameters **Returns:** Promise<CreateThreadResponse> ##### `getPublishingLimit(accessToken, userId?)` Get the publishing limit for the user. **Parameters:** - `accessToken` (string) - User's access token - `userId` (string, optional) - User ID (default: 'me') **Returns:** Promise<any> ## TypeScript Types All types are exported and available for use: ```typescript import { ThreadsAPIConfig, ThreadsScope, AccessTokenResponse, LongLivedTokenResponse, RefreshTokenResponse, ThreadsUserProfile, MediaType, CreateThreadParams, CreateThreadResponse, PublishThreadParams, PublishThreadResponse, CreateCarouselItemParams, Thread } from 'threads-api-ai'; ``` ## Roadmap - [x] OAuth 2.0 Authentication - [x] User Profile API - [x] Publishing API (create posts) - [x] Text posts - [x] Image posts - [x] Video posts - [x] Carousel posts - [x] Reply control - [x] Publishing limits - [ ] Media API (upload images/videos) - [ ] Insights API (analytics) - [ ] Replies API (manage comments) - [ ] Webhooks support ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## License MIT ## Support For issues and questions, please use the [GitHub Issues](https://github.com/yourusername/threads-api-ai/issues) page. ## Disclaimer This is an unofficial library and is not affiliated with Meta Platforms, Inc. ## Resources - [Official Threads API Documentation](https://developers.facebook.com/docs/threads) - [Meta Developer Portal](https://developers.facebook.com/)