Production-ready Go client for the Threads API with complete endpoint coverage, OAuth 2.0 authentication, rate limiting, and comprehensive error handling.
- Complete API coverage (posts, users, replies, insights, locations)
- OAuth 2.0 flow and existing token support
- Intelligent rate limiting with exponential backoff
- Type-safe error handling
- Thread-safe concurrent usage
- Comprehensive test coverage
go get github.com/tirthpatell/threads-go
client, err := threads.NewClientWithToken("your-access-token", &threads.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
RedirectURI: "your-redirect-uri",
})
// Create a post
post, err := client.CreateTextPost(context.Background(), &threads.TextPostContent{
Text: "Hello Threads!",
})
config := &threads.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
RedirectURI: "your-redirect-uri",
Scopes: []string{"threads_basic", "threads_content_publish"},
}
client, err := threads.NewClient(config)
// Get authorization URL
authURL := client.GetAuthURL(config.Scopes)
// Redirect user to authURL
// Exchange authorization code for token
err = client.ExchangeCodeForToken("auth-code-from-callback")
err = client.GetLongLivedToken() // Convert to long-lived token
export THREADS_CLIENT_ID="your-client-id"
export THREADS_CLIENT_SECRET="your-client-secret"
export THREADS_REDIRECT_URI="your-redirect-uri"
export THREADS_ACCESS_TOKEN="your-access-token" # optional
client, err := threads.NewClientFromEnv()
threads_basic
- Basic profile accessthreads_content_publish
- Create and publish poststhreads_manage_insights
- Access analytics datathreads_manage_replies
- Manage replies and conversationsthreads_read_replies
- Read replies to poststhreads_keyword_search
- Search functionalitythreads_delete
- Delete poststhreads_location_tagging
- Location services
// Create different post types
textPost, err := client.CreateTextPost(ctx, &threads.TextPostContent{
Text: "Hello Threads!",
})
imagePost, err := client.CreateImagePost(ctx, &threads.ImagePostContent{
Text: "Check this out!",
ImageURL: "https://example.com/image.jpg",
})
// Get posts
post, err := client.GetPost(ctx, threads.PostID("123"))
posts, err := client.GetUserPosts(ctx, threads.UserID("456"), &threads.PostsOptions{Limit: 25})
// Delete post
err = client.DeletePost(ctx, threads.PostID("123"))
// Get user info
me, err := client.GetMe(ctx)
user, err := client.GetUser(ctx, threads.UserID("123"))
// Public profiles
publicUser, err := client.LookupPublicProfile(ctx, "@username")
posts, err := client.GetPublicProfilePosts(ctx, "username", nil)
// Reply to posts
reply, err := client.ReplyToPost(ctx, threads.PostID("123"), &threads.PostContent{
Text: "Great post!",
})
// Get replies
replies, err := client.GetReplies(ctx, threads.PostID("123"), &threads.RepliesOptions{Limit: 50})
// Manage visibility
err = client.HideReply(ctx, threads.PostID("456"))
// Post insights
insights, err := client.GetPostInsights(ctx, threads.PostID("123"), []string{"views", "likes"})
// Account insights
insights, err := client.GetAccountInsights(ctx, threads.UserID("456"), []string{"views"}, "lifetime")
// Search posts
results, err := client.KeywordSearch(ctx, "golang", &threads.SearchOptions{Limit: 25})
// Location search
locations, err := client.SearchLocations(ctx, "New York", nil, nil)
For large datasets, use iterators to automatically handle pagination:
// Posts iterator
userID := threads.ConvertToUserID("user_id")
iterator := threads.NewPostIterator(client, userID, &threads.PostsOptions{
Limit: 25,
})
for iterator.HasNext() {
response, err := iterator.Next(ctx)
if err != nil {
log.Fatal(err)
}
for _, post := range response.Data {
fmt.Printf("Post: %s\n", post.Text)
}
}
// Replies iterator
replyIterator := threads.NewReplyIterator(client, threads.PostID("123"), &threads.RepliesOptions{
Limit: 50,
})
// Search iterator
searchIterator := threads.NewSearchIterator(client, "golang", "keyword", &threads.SearchOptions{
Limit: 25,
})
// Collect all results at once
allPosts, err := iterator.Collect(ctx)
config := &threads.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
RedirectURI: "https://yourapp.com/callback",
Scopes: []string{"threads_basic", "threads_content_publish"},
HTTPTimeout: 30 * time.Second,
Debug: false,
}
For advanced configuration including retry logic, custom logging, and token storage, see the GoDoc documentation.
The client provides typed errors for different scenarios:
switch {
case threads.IsAuthenticationError(err):
// Handle authentication issues
case threads.IsRateLimitError(err):
rateLimitErr := err.(*threads.RateLimitError)
time.Sleep(rateLimitErr.RetryAfter)
case threads.IsValidationError(err):
validationErr := err.(*threads.ValidationError)
log.Printf("Invalid %s: %s", validationErr.Field, err.Error())
}
Error types: AuthenticationError
, RateLimitError
, ValidationError
, NetworkError
, APIError
# Unit tests
go test ./...
# Integration tests (requires valid credentials)
export THREADS_ACCESS_TOKEN="your-token"
go test ./tests/integration/...
See CONTRIBUTING.md for guidelines.
MIT License - see LICENSE file for details.