XmtpElixirSdk
Copy Markdownxmtp_elixir_sdk is an Elixir-first XMTP SDK for apps that want to work with
clients, conversations, groups, messages, consent state, and sync flows from
Phoenix or general Elixir applications.
The production path is backed by the official Rust XMTP SDK through a supervised native bridge. The Elixir modules give Phoenix code a normal supervised runtime, plain structs, and explicit room/conversation functions while the protocol work stays in the upstream SDK.

What You Can Do With It
With this SDK you can:
- create and register XMTP clients for server-owned wallets
- connect user or agent chat identities behind a product-safe state machine
- resolve wallet addresses to inbox ids with shared normalization and caching
- reopen existing XMTP clients by address
- open direct messages and groups
- send, count, sync, and read text messages
- inspect conversations, group members, and inbox reachability
- keep Phoenix room behavior behind a typed room panel
How The SDK Is Organized
The main modules are:
XmtpElixirSdk: top-level entrypoint and convenience helpersXmtpElixirSdk.Native: native-backed client, conversation, and message operationsXmtpElixirSdk.Clients: client creation, registration, accounts, recovery, installationsXmtpElixirSdk.Conversations: create and find DMs and groupsXmtpElixirSdk.Messages: send, list, count, publish, and decode messagesXmtpElixirSdk.Groups: group metadata, membership, roles, and permissionsXmtpElixirSdk.Preferences: inbox state, consent, and preference syncXmtpElixirSdk.Sync: archive and device sync flowsXmtp.Identity: product-safe identity registration and wallet signature flowXmtp.Resolver: normalized wallet-to-inbox resolution with positive and null cachesXmtp.Installations: product-safe device status and cleanup guidanceXmtp.Rooms: shared room action facade for Phoenix appsXmtp.RoomPanel: typed room display contract for host appsXmtp.Metadata.Profile: Regent profile metadata codecXmtp.Metadata.GroupAppData: Regent group appData codecXmtp.Sync: room mirror sync, idempotency, and ordering helpers
Installation
Add the dependency to your mix.exs:
def deps do
[
{:xmtp_elixir_sdk, "~> 0.1.1"}
]
endThen fetch dependencies:
mix deps.get
The package builds its native bridge during mix compile. You can also build
the release bridge directly:
mix native.build
Quick Start
The smallest useful flow is:
- start a runtime
- create a server-owned client
- create a direct message
- send a message
- list messages
alias XmtpElixirSdk.Native
alias XmtpElixirSdk.Runtime
{:ok, _pid} = XmtpElixirSdk.start_runtime(name: :demo_xmtp)
runtime = Runtime.new(:demo_xmtp)
{:ok, client} =
Native.create_client(runtime,
private_key: System.fetch_env!("XMTP_AGENT_PRIVATE_KEY"),
env: :dev,
db_path: "priv/xmtp/demo.sqlite3",
app_version: "my_app/0.1.0"
)
{:ok, dm} = Native.create_dm(client, "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
{:ok, _message_id} = Native.send_text(dm, "hello from elixir")
{:ok, messages} = Native.list_messages(dm, limit: 25, direction: :descending)Common Flows
Create a native client
Use XmtpElixirSdk.Native.create_client/2 when the server owns the wallet key
for a room, agent, relay, or moderation worker:
{:ok, client} =
XmtpElixirSdk.Native.create_client(runtime,
private_key: private_key,
env: :dev,
db_path: db_path,
app_version: "my_app/0.1.0"
)Use build_existing_client/3 when the identity is already registered and the
server only needs to reopen it:
{:ok, client} =
XmtpElixirSdk.Native.build_existing_client(runtime, address,
env: :dev,
db_path: db_path
)Open a direct message
{:ok, dm} = XmtpElixirSdk.Native.create_dm(client, peer_address)Create a group
{:ok, group} =
XmtpElixirSdk.Native.create_group(client, [bob_address, carol_address],
name: "Product Team",
description: "Product room"
)You can pass group options if you want to set a name, description, image, or app data at creation time.
Send and read messages
{:ok, _message_id} = XmtpElixirSdk.Native.send_text(group, "hello group")
{:ok, listed} = XmtpElixirSdk.Native.list_messages(group, limit: 50)
{:ok, count} = XmtpElixirSdk.Native.count_messages(group)Inspect a group
{:ok, members} = XmtpElixirSdk.Native.members(group)
{:ok, synced} = XmtpElixirSdk.Native.sync_conversation(group)Check reachability
{:ok, result} = XmtpElixirSdk.Native.can_message(client, [peer_address])
{:ok, inbox_id} = XmtpElixirSdk.Native.inbox_id_for(client, peer_address)For Regent product rooms, prefer the shared resolver so wallet normalization, missing inboxes, and cannot-message states are handled one way:
{:ok, _pid} = Xmtp.Resolver.start_link(name: MyApp.XmtpResolver)
{:ok, target} =
Xmtp.Resolver.resolve_for_room_invite(
MyApp.XmtpResolver,
client,
%{wallet_address: "0xabc0000000000000000000000000000000000001"}
)Connect a chat identity
Product apps own the account row. Xmtp.Identity owns XMTP registration:
{:ok, state} =
Xmtp.Identity.ensure_identity(%{
runtime: MyApp.XmtpIdentity.Runtime,
principal: %{
kind: :human,
id: human.id,
wallet_address: human.wallet_address,
inbox_id: human.xmtp_inbox_id
},
stored_inbox_id: human.xmtp_inbox_id
})
case state.status do
:ready -> human
:needs_wallet_signature -> state.signature_request
endAfter the wallet signs state.signature_request.text, complete the request and
store the returned inbox_id on the product account.
List and sync conversations
{:ok, _result} = XmtpElixirSdk.Native.sync_all(client)
{:ok, conversations} = XmtpElixirSdk.Native.list_conversations(client, conversation_type: :group)Browser Wallet Signing
Browser wallet integration belongs at the app layer. For user-owned wallets,
keep the wallet approval in the browser and call your Phoenix wrapper after the
person approves the action. For server-owned wallets, use XmtpElixirSdk.Native
from supervised server code.
Browser Shim
The browser_shim/ directory is for browser-only work, such as worker-style
actions and browser-managed storage requests. It is not bundled into the Hex
package as a runtime dependency.
If your app runs fully on the server, you can usually ignore it.
Phoenix Rooms
Phoenix apps should keep room mechanics behind Xmtp.Rooms and render from the
Xmtp.RoomPanel struct the wrapper returns. See
docs/phoenix-frontend-agent-guide.md
for the frontend agent rules.
The room mirror schemas are optional host-owned storage. If a Phoenix app uses
Xmtp.RoomServer, copy the versioned migration template into that app and keep
product-specific room rules in that app. See
docs/storage-contract.md.
Environment Helpers
The SDK includes helpers for XMTP environment URLs:
Publishing
Build the package locally with:
mix hex.build
Generate docs with:
mix docs
Publish the package with:
mix hex.publish
Publish docs with:
mix hex.publish docs