EDA - Elixir Discord API
A modern Discord library for Elixir, inspired by JDA (Java Discord API).
Quick Start
Add your bot token to config:
config :eda, token: System.get_env("DISCORD_TOKEN"), intents: [:guilds, :guild_messages, :message_content]
Create a consumer module:
defmodule MyBot.Consumer do @behaviour EDA.Consumer
def handle_event({:MESSAGE_CREATE, msg}) do
if msg.content == "!ping" do EDA.API.Message.create(msg.channel_id, "Pong!") endend
def handleevent(), do: :ok end
Register your consumer:
config :eda, consumer: MyBot.Consumer
Start your application and the bot will connect automatically!
Features
- WebSocket Gateway connection with automatic reconnection
- REST API client with rate limiting
- ETS-based caching for guilds, users, and channels
- Simple consumer behaviour for handling events
- Telemetry integration for observability
Summary
Functions
Awaits an INTERACTION_CREATE event matching the given filter.
Requests all members and waits for completion.
Awaits a MESSAGE_CREATE event matching the given filter.
Awaits a MESSAGE_REACTION_ADD event matching the given filter.
Blocks until all shards have finished loading their guilds.
Returns the configured consumer module.
Fetches specific members by user IDs (max 100).
Returns the configured gateway encoding.
Returns the configured gateway intents as a bitfield.
Returns the gateway heartbeat latency in milliseconds for the given shard.
Retrieves message history with automatic pagination.
Returns a lazy Stream of messages from a channel.
Purges messages from a channel with auto-chunking.
Returns true if all shards have finished loading their guilds.
Requests all members for a guild (fire-and-forget, caches automatically).
Searches members by username prefix (max 100 results).
Sets the bot's activity on all shards.
Updates the bot's presence on all shards.
Sets the bot's status on all shards without changing the activity.
Returns the configured shard mode.
Returns the configured bot token.
Functions
@spec await_component( (term() -> boolean()), keyword() ) :: {:ok, term()} | {:ok, [term()]} | {:error, :timeout}
Awaits an INTERACTION_CREATE event matching the given filter.
Useful for collecting button clicks, select menu selections, and modal submissions.
Examples
{:ok, interaction} = EDA.await_component(fn i ->
EDA.Interaction.custom_id(i) == "confirm_btn"
end, timeout: 30_000)
Requests all members and waits for completion.
@spec await_message( (term() -> boolean()), keyword() ) :: {:ok, term()} | {:ok, [term()]} | {:error, :timeout}
Awaits a MESSAGE_CREATE event matching the given filter.
Examples
{:ok, msg} = EDA.await_message(fn msg ->
msg.channel_id == channel_id and msg.author["id"] == user_id
end, timeout: 30_000)
@spec await_reaction( (term() -> boolean()), keyword() ) :: {:ok, term()} | {:ok, [term()]} | {:error, :timeout}
Awaits a MESSAGE_REACTION_ADD event matching the given filter.
Examples
{:ok, reaction} = EDA.await_reaction(fn r ->
r.message_id == msg_id and r.user_id != bot_id
end, timeout: 60_000)
@spec await_ready(timeout()) :: :ok | {:error, :timeout}
Blocks until all shards have finished loading their guilds.
Returns :ok when the bot is fully ready, or {:error, :timeout} if the
timeout expires. Uses OTP's native GenServer.call suspension — no scheduler
is blocked.
If the bot is already ready, returns :ok immediately.
Options
timeout— maximum wait in milliseconds (default60_000)
Examples
EDA.await_ready()
EDA.await_ready(30_000)
@spec consumer() :: module() | nil
Returns the configured consumer module.
@spec fetch_members(String.t() | integer(), [String.t() | integer()], keyword()) :: {:ok, [map()]} | {:error, :timeout}
Fetches specific members by user IDs (max 100).
@spec gateway_encoding() :: :etf | :json
Returns the configured gateway encoding.
:etf(default) — Erlang External Term Format (binary, efficient):json— JSON via Jason (text, useful for debugging)
Configuration
config :eda, gateway_encoding: :etf # default
config :eda, gateway_encoding: :json
@spec intents() :: integer()
Returns the configured gateway intents as a bitfield.
@spec latency(non_neg_integer()) :: non_neg_integer() | nil
Returns the gateway heartbeat latency in milliseconds for the given shard.
Defaults to shard 0 (single-shard bots). Returns nil if the shard
hasn't received a heartbeat ACK yet or isn't connected.
Examples
EDA.latency() # => 42
EDA.latency(1) # => 55 (shard 1)
Retrieves message history with automatic pagination.
Returns a lazy Stream of messages from a channel.
Purges messages from a channel with auto-chunking.
@spec ready?() :: boolean()
Returns true if all shards have finished loading their guilds.
Non-blocking — reads from :persistent_term (O(1)).
Requests all members for a guild (fire-and-forget, caches automatically).
@spec search_members(String.t() | integer(), String.t(), keyword()) :: {:ok, [map()]} | {:error, :timeout}
Searches members by username prefix (max 100 results).
Sets the bot's activity on all shards.
Options
:type— activity type (default:playing):url— stream URL (only for:streaming):status— status to set alongside the activity (default:online)
Examples
EDA.set_activity("Elixir", type: :playing)
EDA.set_activity("on Twitch", type: :streaming, url: "https://twitch.tv/example")
@spec set_presence(EDA.Presence.t() | keyword()) :: :ok
Updates the bot's presence on all shards.
Accepts an %EDA.Presence{} struct or a keyword list of options.
Examples
EDA.set_presence(EDA.Presence.new(status: :dnd, activities: [EDA.Presence.playing("Elixir")]))
EDA.set_presence(status: :idle, activities: [EDA.Presence.watching("you")])
@spec set_status(EDA.Presence.status()) :: :ok
Sets the bot's status on all shards without changing the activity.
Examples
EDA.set_status(:dnd)
EDA.set_status(:invisible)
@spec shard_config() :: :auto | pos_integer() | {Range.t(), pos_integer()}
Returns the configured shard mode.
:auto(default) — use Discord's recommended shard countinteger— fixed number of shards (e.g.4→ shards 0..3){Range.t(), integer}— specific shards on this node (e.g.{0..1, 4})
@spec token() :: String.t() | nil
Returns the configured bot token.