In the previous episode, we saw how to handle an inbound call to an Asterisk extension from Elixir. However, the actual module that was used to handle the call was written in Erlang. Today we're going to write an AGI module in Elixir. Let's get started.


I'm in the same project that we ended the last episode with. In the meantime, I've written an API client for a friend's API for getting contact information when all you have is a phone number, called EveryoneAPI.

First, let's have a look at the everyoneapi client library.

((( vim ~/elixir/everyoneapi/lib/everyoneapi.ex )))

defmodule Everyoneapi do
  use HTTPoison.Base
  require Logger

  # We just set up the base url
  @base_url ""

  # Here's our nicer public api for getting the info for a phone number
  def info!(number) do
    get! "/v1/phone/+12052153957"

  # We prefix the url with the base url so we don't have to type out the whole
  # url every time we talk to the API
  def process_url(url) do
    @base_url <> url

  # For every outbound request, we add our basic auth header
  def process_request_headers(headers) do
    Enum.into(headers, [{"Authorization", "Basic #{encoded_basic}"}])

  # The basic auth header consists of getting the username and password out of #
  # the application's configuration, concatenating them separated by a colon, and
  # then Base64 encoding the resulting string
  defp encoded_basic do
    account_sid = Application.get_env :everyoneapi, :account_sid
    auth_token = Application.get_env :everyoneapi, :auth_token
    combined = "#{account_sid}:#{auth_token}"

  # Finally, the body JSON is decoded
  def process_response_body(body) do
    Logger.warn body

So this wasn't the point of the episode, but I wanted to look at it because it took me a few minutes to figure out how to inject that header into the request.

Next, we're going to modify an Asterisk extension such that we can dial in, and it will make an API call for a hardcoded number, presently. It will then read out the contact name associated with that number in EveryoneAPI.

We'll open up lib/everyoneapi_demo.ex:

defmodule EveryoneapiDemo do
  require Logger

  # The erlagi interface expects a handler module that responds to `new_call/1`
  # and calls it with an agicall record
  def new_call(call) do
    # We start our API client up every call.  This is stupid and inefficient,
    # but it works for now.
    result =! "+12052153957"
    # We'll extract the name out of the response from the API
    name = result.body["data"]["name"]
    # Then we just answer the call
    # And read out the characters in the name.
    :erlagi.say_alpha(call, String.to_char_list(name), '#')

Next, we need to modify our configuration to use this module for the callback instead of the erlagi_demo module. Open up config/config.exs

    {:localhost, host: '', port: 20000, backlog: 5, callback: EveryoneapiDemo}

Restart the app by launching iex.

Finally, we'll just try it out by dialing in to our extension.

((( dial extension 2601 )))


In today's episode, we built on the previous episode by building our own Asterisk AGI handler module in Elixir, and we looked at building an http api client using basic auth. See you soon!