XDK Elixir
Auto-generated Elixir client for the X (Twitter) API v2.
Note: This SDK is auto-generated by a fork of XDK, a Rust-based OpenAPI code generator maintained by X's developer platform team. The Elixir target is an addition to that fork. Do not hand-edit files under
lib/ortest/— all changes should be made in the generator templates and re-generated.
Installation
Add xdk_elixir to your list of dependencies in mix.exs:
def deps do
[
{:xdk_elixir, "~> 1.0"}
]
endPrerequisites
You need an X Developer account and API credentials. Go to the X Developer Portal to create a project and app.
Depending on the endpoints you want to use, you'll need one or more of:
| Credential | Env Variable | Used For |
|---|---|---|
| Bearer Token | BEARER_TOKEN | App-only access (read-only public data: search, user lookup, etc.) |
| Consumer Key + Secret | CONSUMER_KEY, SECRET_KEY | Generating bearer tokens, OAuth 1.0a signing |
| Access Token + Secret | ACCESS_TOKEN, ACCESS_TOKEN_SECRET | User-context access via OAuth 1.0a (post, like, follow, DMs, etc.) |
Most read endpoints work with just a Bearer Token. Write endpoints (posting, liking, following) require OAuth 1.0a user-context auth.
Usage
1. Start a Finch pool
XDK uses Finch for HTTP. Add it to your supervision tree:
children = [
{Finch, name: MyApp.Finch}
]
Supervisor.start_link(children, strategy: :one_for_one)2. Create a client
# App-only (Bearer Token)
client = Xdk.new(finch: MyApp.Finch, bearer: "YOUR_BEARER_TOKEN")
# Or pass auth explicitly
client = Xdk.new(finch: MyApp.Finch, auth: {:bearer, "YOUR_BEARER_TOKEN"})3. Make API calls
# Look up a user
{:ok, user} = Xdk.Users.get_by_username(client, "elaborapp",
user_fields: ["id", "name", "public_metrics"]
)
# Search recent posts
{:ok, results} = Xdk.Posts.search_recent(client,
query: "elixir lang",
max_results: 10,
tweet_fields: ["id", "text", "created_at", "author_id"]
)
# Get a post by ID
{:ok, post} = Xdk.Posts.get_by_id(client, "1234567890",
tweet_fields: ["id", "text", "author_id"]
)OAuth 1.0a (User Context)
For endpoints that require user-context authentication (posting, liking, following, DMs):
credentials = OAuther.credentials(
consumer_key: System.get_env("CONSUMER_KEY"),
consumer_secret: System.get_env("SECRET_KEY"),
token: System.get_env("ACCESS_TOKEN"),
token_secret: System.get_env("ACCESS_TOKEN_SECRET")
)
client = Xdk.new(finch: MyApp.Finch, auth: {:oauth1, credentials})
# Post a tweet
{:ok, result} = Xdk.Posts.create(client, %{"text" => "Hello from XDK Elixir!"})
# Like a post
{:ok, _} = Xdk.Users.like_post(client, user_id, %{"tweet_id" => "1234567890"})Pagination
Use Xdk.Paginator to lazily page through results:
fetch = fn token ->
opts = [query: "elixir", max_results: 100]
opts = if token, do: Keyword.put(opts, :pagination_token, token), else: opts
Xdk.Posts.search_recent(client, opts)
end
# Get all items across pages as a lazy stream
Xdk.Paginator.items(fetch)
|> Enum.take(500)Streaming
For streaming endpoints (filtered stream, sample stream):
Xdk.Stream.get_filtered_stream(client)
|> Stream.each(fn
{:ok, tweet} -> IO.inspect(tweet)
{:error, err} -> IO.warn("Stream error: #{inspect(err)}")
end)
|> Stream.run()Available Modules
Every X API endpoint group has a corresponding module:
| Module | Description |
|---|---|
Xdk.Users | User lookup, followers, following, muting, blocking, bookmarks |
Xdk.Posts | Tweet CRUD, search, counts, quotes, reposts, analytics |
Xdk.Lists | List management, members, followers |
Xdk.Spaces | Twitter Spaces |
Xdk.Communities | Communities |
Xdk.CommunityNotes | Community Notes |
Xdk.DirectMessages | DM conversations and messages |
Xdk.Media | Media upload |
Xdk.Compliance | Compliance streams and jobs |
Xdk.Stream | Filtered and sample streams |
Xdk.Trends | Trending topics |
Xdk.Usage | API usage metrics |
Xdk.Connections | User connections |
Xdk.Activity | Activity feed |
Xdk.AccountActivity | Account Activity API |
Xdk.Webhooks | Webhook management |
Xdk.News | News |
Xdk.Marketplace | Marketplace |
Xdk.Chat | Chat |
Error Handling
All API calls return {:ok, map()} or {:error, error}. Errors are structured using Splode:
case Xdk.Users.get_by_username(client, "nonexistent_user_12345") do
{:ok, data} ->
IO.inspect(data)
{:error, %Xdk.Errors.RateLimitError{retry_after_ms: ms}} ->
Process.sleep(ms)
# retry...
{:error, %Xdk.Errors.ApiError{status: 404}} ->
IO.puts("User not found")
{:error, %Xdk.Errors.TransportError{reason: reason}} ->
IO.puts("Network error: #{inspect(reason)}")
endConfiguration
Set defaults via application config so you don't have to pass them every time:
# config/config.exs
config :xdk, :default_config,
finch: MyApp.FinchThen just pass auth when creating a client:
client = Xdk.new(bearer: "YOUR_BEARER_TOKEN")Code Generation
This package is auto-generated from the X API's OpenAPI specification. The generator lives at mikehostetler/xdk (a fork of xdevplatform/xdk).
To regenerate:
cd xdk && cargo run -- elixir --latest true
cp -r xdk/elixir/lib xdk/elixir/test xdk/elixir/mix.exs ../xdk-elixir/
cd ../xdk-elixir && mix deps.get && mix testLicense
Apache-2.0 — see LICENSE for details.