TwilioElixir
The complete Twilio SDK for Elixir — auto-generated from Twilio's official OpenAPI specs with full-fidelity mapping across all 54 spec files, 37 products, 494 services, and 467 typed resources.
Twilio has a fragmented feature set across its official SDKs. This library aims to combine the best features from each the official Twilio SDKs (Python, Ruby, Node, and Java) and ships them all in one idiomatic Elixir package.
Features
- From Node — 429 rate-limit retry with exponential backoff and full jitter
- From Java — 5xx server-error retry, connection pooling (Finch/NimblePool, auto-sized)
- From Python — Connection-error retry, auto-sized pool scaling
- From Ruby — TwiML generation (functional pipeline builder), webhook validation, API surface parity
- New in this library — Retry-After header parsing, idempotency tokens for safe POST retries, structured
:telemetryevents, typedTwilio.Errorstructs withretryable?/1 - Full API coverage — 494 services and 467 typed resources across 37 products, auto-generated from 54 OpenAPI spec files with full-fidelity mapping
- Dual pagination — Auto-detects v2010 flat and v1/v2/v3 meta wrapper formats
- Async test stubs — Per-process HTTP stubs via NimbleOwnership
Installation
Add twilio_elixir to your dependencies in mix.exs:
def deps do
[
{:twilio_elixir, "~> 0.1.1"}
]
endRequires Elixir 1.19+ and OTP 27+.
Quick Start
Configuration
# config/runtime.exs
config :twilio_elixir,
account_sid: System.fetch_env!("TWILIO_ACCOUNT_SID"),
auth_token: System.fetch_env!("TWILIO_AUTH_TOKEN")Send a Message
client = Twilio.client()
{:ok, message} = Twilio.Api.V2010.MessageService.create(client, %{
"To" => "+15551234567",
"From" => "+15559876543",
"Body" => "Hello from Elixir!"
})
message.sid #=> "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
message.status #=> "queued"Make a Call
{:ok, call} = Twilio.Api.V2010.CallService.create(client, %{
"To" => "+15551234567",
"From" => "+15559876543",
"Url" => "http://demo.twilio.com/docs/voice.xml"
})Error Handling
case Twilio.Api.V2010.MessageService.create(client, params) do
{:ok, message} ->
IO.puts("Sent: #{message.sid}")
{:error, %Twilio.Error{code: 21211} = err} ->
IO.puts("Invalid phone number: #{err.message}")
{:error, %Twilio.Error{} = err} ->
IO.puts("Error #{err.code}: #{err.message}")
endPagination
# Single page
{:ok, page} = Twilio.Api.V2010.MessageService.list(client)
# Lazy auto-paging stream
client
|> Twilio.Api.V2010.MessageService.stream()
|> Stream.take(100)
|> Enum.to_list()TwiML
Generate TwiML XML for voice and messaging webhooks:
alias Twilio.TwiML.VoiceResponse
xml = VoiceResponse.new()
|> VoiceResponse.say("Hello! Press 1 for sales.", voice: "alice")
|> VoiceResponse.gather(num_digits: 1, action: "/handle-key", children: [
{"Say", %{}, ["Press 1 for sales, 2 for support."]}
])
|> VoiceResponse.to_xml()alias Twilio.TwiML.MessagingResponse
xml = MessagingResponse.new()
|> MessagingResponse.message("Thanks for your message!")
|> MessagingResponse.to_xml()See the TwiML guide for all verbs and a complete IVR example.
Webhook Validation
Verify that incoming requests are from Twilio:
# Form-encoded webhooks
Twilio.Webhook.valid?(url, params, signature, auth_token)
# JSON body webhooks
Twilio.Webhook.valid_body?(url, body, signature, auth_token)See the Webhooks guide for Phoenix integration and status callback handling.
Testing
Use Twilio.Test to stub HTTP requests in your tests with async: true:
defmodule MyApp.NotifierTest do
use ExUnit.Case, async: true
test "sends SMS" do
Twilio.Test.stub(fn _method, _url, _headers, _body ->
{201, [], ~s({"sid": "SMxxx", "status": "queued"})}
end)
client = Twilio.client("ACtest", "token")
assert {:ok, msg} = Twilio.Api.V2010.MessageService.create(client, %{
"To" => "+15551234567",
"From" => "+15559876543",
"Body" => "Test"
})
assert msg.sid == "SMxxx"
end
endSee the Testing guide for error simulation, pagination stubs, and process isolation patterns.
Guides
- Getting Started - Installation, configuration, making API calls, pagination, retries
- Webhooks - Signature verification, Phoenix integration, status callbacks
- TwiML - Voice and messaging XML builders, IVR example
- Testing - HTTP stubs, error simulation, async test patterns
- Telemetry - Observability, logging, metrics integration
Telemetry Events
| Event | Measurements | Metadata |
|---|---|---|
[:twilio, :request, :start] | system_time | method, path, product |
[:twilio, :request, :stop] | duration | method, path, product, status, retries, request_id, error |
[:twilio, :request, :exception] | duration | method, path, product, kind, reason |
[:twilio, :request, :retry] | attempt, wait_ms | method, path, product, status, reason |
See the Telemetry guide for logging setup and StatsD/Prometheus integration.
Code Generation
The SDK is auto-generated from Twilio's OpenAPI specs. To regenerate:
# Download latest specs
bash scripts/sync_openapi.sh
# Generate code
mix twilio.generate --clean --statsWeekly CI automatically pulls the latest specs, regenerates, and opens a PR.
License
MIT License. See LICENSE for details.