Hex.pm Documentation

A comprehensive Elixir client for X API v1.1 with full endpoint coverage, rate limiting, multimedia support, and OAuth 1.0a authentication.

Features

  • Full X API v1.1 Coverage - All GET and POST endpoints implemented
  • OAuth 1.0a Authentication - Secure request signing
  • Rate Limiting - Automatic rate limit tracking and retry
  • Multimedia Support - Upload images, videos, and GIFs
  • Chunked Uploads - Handle large video files efficiently
  • Type Safety - Comprehensive typespec coverage
  • Zero Dependencies - Minimal, focused dependencies
  • Well Documented - Extensive documentation with examples

Installation

Add x_client to your list of dependencies in mix.exs:

def deps do
  [
    {:x_client, "~> 1.0.0"}
  ]
end

Run mix deps.get to fetch the dependency.

Configuration

Add your X API credentials to your config file:

# config/config.exs
config :x_client,
  consumer_key: "YOUR_CONSUMER_KEY",
  consumer_secret: "YOUR_CONSUMER_SECRET",
  access_token: "YOUR_ACCESS_TOKEN",
  access_token_secret: "YOUR_ACCESS_TOKEN_SECRET"

Or use environment variables:

config :x_client,
  consumer_key: {:system, "X_CONSUMER_KEY"},
  consumer_secret: {:system, "X_CONSUMER_SECRET"},
  access_token: {:system, "X_ACCESS_TOKEN"},
  access_token_secret: {:system, "X_ACCESS_TOKEN_SECRET"}

Optional Configuration

config :x_client,
  # Custom API base URL (default: "https://api.x.com/1.1")
  base_url: "https://api.x.com/1.1",
  
  # Custom upload URL (default: "https://upload.x.com/1.1")
  upload_url: "https://upload.x.com/1.1",
  
  # Enable automatic retry on rate limits (default: true)
  auto_retry: true,
  
  # Maximum number of retries (default: 3)
  max_retries: 3

Quick Start

# Post a tweet
{:ok, tweet} = XClient.Tweets.update("Hello from Elixir! 🚀")

# Upload media and attach to tweet
{:ok, media} = XClient.Media.upload("path/to/image.jpg")
{:ok, tweet} = XClient.Tweets.update(
  "Check out this image!",
  media_ids: [media["media_id_string"]]
)

# Get user timeline
{:ok, tweets} = XClient.Tweets.user_timeline(screen_name: "elixirlang", count: 50)

# Search tweets
{:ok, results} = XClient.Search.tweets("elixir lang", count: 100)

# Follow a user
{:ok, user} = XClient.Friendships.create(screen_name: "elixirlang")

# Like a tweet
{:ok, tweet} = XClient.Favorites.create("123456789")

# Send a direct message
{:ok, message} = XClient.DirectMessages.send("123456", "Hello!")

Available Modules

Tweets

  • XClient.Tweets - Post, delete, retweet, and retrieve tweets
    • update/3 - Post a tweet
    • destroy/3 - Delete a tweet
    • retweet/3 - Retweet a tweet
    • unretweet/3 - Remove retweet
    • show/3 - Get single tweet
    • lookup/3 - Get multiple tweets
    • user_timeline/2 - Get user's tweets
    • mentions_timeline/2 - Get mentions
    • retweets_of_me/2 - Get retweeted tweets
    • retweets/3 - Get retweets of tweet
    • retweeters_ids/3 - Get retweeter IDs

Media

  • XClient.Media - Upload images, videos, and GIFs
    • upload/3 - Simple upload
    • chunked_upload/3 - Chunked upload for large files
    • upload_status/2 - Check processing status
    • add_metadata/3 - Add alt text

Users

  • XClient.Users - User information and search
    • show/2 - Get user details
    • lookup/2 - Get multiple users
    • search/3 - Search users
    • suggestions/2 - Get suggested categories
    • suggestions_slug/3 - Get category suggestions
    • suggestions_members/2 - Get category members

Friendships

  • XClient.Friendships - Follow/unfollow operations
    • create/2 - Follow user
    • destroy/2 - Unfollow user
    • show/2 - Get relationship info
    • followers_ids/2 - Get follower IDs
    • followers_list/2 - Get follower details
    • friends_ids/2 - Get following IDs
    • friends_list/2 - Get following details

Favorites

  • XClient.Favorites - Like/unlike tweets
    • create/3 - Like a tweet
    • destroy/3 - Unlike a tweet
    • list/2 - Get liked tweets

Direct Messages

  • XClient.DirectMessages - Send and manage DMs
    • send/4 - Send a DM
    • destroy/2 - Delete a DM
    • list/2 - List DMs
    • show/2 - Get single DM

Lists

  • XClient.Lists - Manage X lists
    • list/2 - Get all lists
    • statuses/2 - Get list tweets
    • show/2 - Get list details
    • members/2 - Get list members
    • members_show/2 - Check membership
    • memberships/2 - Get user's memberships
    • ownerships/2 - Get owned lists
    • subscribers/2 - Get subscribers
    • subscribers_show/2 - Check subscription
    • subscriptions/2 - Get subscriptions

Account

  • XClient.Account - Manage account settings
    • verify_credentials/2 - Verify credentials
    • update_profile/2 - Update profile
    • update_profile_image/3 - Update avatar
    • update_profile_banner/3 - Update banner
    • remove_profile_banner/1 - Remove banner
    • update_settings/2 - Update settings
    • settings/1 - Get settings
  • XClient.Trends - Get trending topics
    • place/3 - Get trends for location
    • available/1 - Get available locations
    • closest/2 - Get closest locations

Geo

  • XClient.Geo - Geographic information
    • id/2 - Get place information

Help

  • XClient.Help - API information
    • configuration/1 - Get API config
    • languages/1 - Get supported languages
    • privacy/1 - Get privacy policy
    • tos/1 - Get terms of service

Application

Rate Limiting

The library automatically tracks rate limits and can retry requests when limits are exceeded.

# Automatic retry is enabled by default
{:ok, tweet} = XClient.Tweets.update("This will retry if rate limited")

# Disable automatic retry
config :x_client, auto_retry: false

# Check rate limit status
{:ok, status} = XClient.Application.rate_limit_status()

Media Upload Examples

Simple Image Upload

# Upload from file path
{:ok, media} = XClient.Media.upload("path/to/image.jpg")

# Upload with alt text
{:ok, media} = XClient.Media.upload(
  "path/to/image.jpg",
  alt_text: "A beautiful sunset over the ocean"
)

# Use in tweet
{:ok, tweet} = XClient.Tweets.update(
  "Check this out!",
  media_ids: [media["media_id_string"]]
)

Video Upload

# Upload video (automatically uses chunked upload for large files)
{:ok, media} = XClient.Media.upload(
  "path/to/video.mp4",
  media_category: "tweet_video"
)

# Wait for processing if needed (handled automatically)
{:ok, tweet} = XClient.Tweets.update(
  "My new video!",
  media_ids: [media["media_id_string"]]
)

Multiple Images

# Upload multiple images
images = ["image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg"]

media_ids =
  Enum.map(images, fn path ->
    {:ok, media} = XClient.Media.upload(path)
    media["media_id_string"]
  end)

# Post tweet with multiple images (max 4)
{:ok, tweet} = XClient.Tweets.update(
  "Check out these photos!",
  media_ids: media_ids
)

Advanced Usage

Custom Client

You can create a client with specific credentials:

client = XClient.client(
  consumer_key: "specific_key",
  consumer_secret: "specific_secret",
  access_token: "specific_token",
  access_token_secret: "specific_token_secret"
)

{:ok, tweet} = XClient.Tweets.update(client, "Tweet with custom creds")

Pagination

Many endpoints support pagination with cursors:

# Get first page of followers
{:ok, %{"ids" => ids, "next_cursor" => cursor}} = 
  XClient.Friendships.followers_ids(screen_name: "elixirlang")

# Get next page
{:ok, %{"ids" => more_ids, "next_cursor" => next_cursor}} = 
  XClient.Friendships.followers_ids(
    screen_name: "elixirlang",
    cursor: cursor
  )

Error Handling

case XClient.Tweets.update("Hello!") do
  {:ok, tweet} ->
    IO.puts("Tweet posted: #{tweet["id_string"]}")

  {:error, %XClient.Error{status: 429} = error} ->
    IO.puts("Rate limited: #{error.message}")

  {:error, %XClient.Error{status: 401}} ->
    IO.puts("Authentication failed")

  {:error, error} ->
    IO.puts("Error: #{error.message}")
end

Rate Limits Reference

See X's rate limit documentation for complete details.

Common Limits

  • Tweets: 300 per 3 hours (combined with retweets)
  • Follows: 400 per 24 hours (user), 1000 per 24 hours (app)
  • Likes: 1000 per 24 hours
  • Direct Messages: 1000 per 24 hours (user), 15000 per 24 hours (app)
  • Search: 180 per 15 minutes (user), 450 per 15 minutes (app)

Development

# Run tests
mix test

# Generate documentation
mix docs

# Format code
mix format

# Run static analysis
mix dialyzer

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Built with ❤️ for the Elixir community
  • Inspired by the node-x-api-v2 library
  • Thanks to X for providing the API

Support

If you encounter any issues or have questions:

  1. Check the documentation
  2. Search existing issues
  3. Open a new issue with details

Changelog

See CHANGELOG.md for version history.