Skip to content

whatsapp api for devs, like slack build kit

License

Notifications You must be signed in to change notification settings

zeeetech/anu-ex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

anu

Hex.pm Docs License

Composable Elixir SDK for the WhatsApp Business API.

Anu is an open core platform for building on WhatsApp. This repo contains the Elixir SDK — the first official client. TypeScript, Python, and Go SDKs are coming.

Docs · Landing page · Cloud

Quick look

Anu.Message.new("5511999999999")
|> Anu.Message.text("Your order has shipped!")
|> Anu.Message.buttons([
  {"Track", :track_order},
  {"Cancel", :cancel}
])
|> Anu.deliver()

Installation

Requires Elixir 1.19+ and OTP 27+.

Add anu to your dependencies in mix.exs:

def deps do
  [
    {:anu, "~> 0.1"}
  ]
end

Configuration

Anu talks directly to Meta's Cloud API. Bring your own token:

# config/config.exs
config :anu,
  access_token: System.get_env("WHATSAPP_ACCESS_TOKEN"),
  phone_number_id: System.get_env("WHATSAPP_PHONE_NUMBER_ID"),
  verify_token: System.get_env("WHATSAPP_VERIFY_TOKEN")

Finch pool

Anu uses Finch for HTTP. You can configure the connection pool to tune concurrency for your workload:

# config/config.exs
config :anu, :finch_pool,
  size: 50,
  count: 4

Or start a named Finch instance and pass it in:

# In your application supervisor
children = [
  {Finch, name: MyApp.Finch, pools: %{
    "https://graph.facebook.com" => [size: 100, count: 8]
  }}
]

# config/config.exs
config :anu, finch: MyApp.Finch

Usage

Composing messages

Messages are built by piping through composable functions — no macros, no DSLs:

# Simple text
Anu.Message.new(to)
|> Anu.Message.text("Hello!")
|> Anu.deliver()

# Rich interactive message
Anu.Message.new(to)
|> Anu.Message.header_image("https://example.com/menu.jpg")
|> Anu.Message.body("Check out our new menu")
|> Anu.Message.footer("Open daily 8am–10pm")
|> Anu.Message.buttons([
  {"Order now", :order},
  {"View hours", :hours}
])
|> Anu.deliver()

# List message with sections
Anu.Message.new(to)
|> Anu.Message.body("What can I help you with?")
|> Anu.Message.button_text("Choose an option")
|> Anu.Message.sections([
  Anu.Section.new("Orders", [
    Anu.Row.new("order_status", "Order status"),
    Anu.Row.new("order_cancel", "Cancel order")
  ]),
  Anu.Section.new("Account", [
    Anu.Row.new("account_info", "Account info"),
    Anu.Row.new("account_help", "Get help")
  ])
])
|> Anu.deliver()

# Location
Anu.Message.new(to)
|> Anu.Message.location(-23.5505, -46.6333, name: "São Paulo", address: "SP, Brazil")
|> Anu.deliver()

# React to a message
Anu.Message.new(to)
|> Anu.Message.react("👍", message_id: original_msg_id)
|> Anu.deliver()

Templates

Anu.Message.new(to)
|> Anu.Message.template("order_confirmation", "pt_BR", [
  Anu.Template.body_param("João"),
  Anu.Template.body_param("#12345")
])
|> Anu.deliver()

Webhook handling

Drop the plug into your Phoenix router:

# lib/my_app_web/router.ex
forward "/webhooks/whatsapp", Anu.Webhook.Plug,
  handler: MyApp.WhatsAppHandler

Implement the handler behaviour:

defmodule MyApp.WhatsAppHandler do
  @behaviour Anu.Webhook.Handler

  @impl true
  def handle_event(:message_received, %Anu.Event.Message{} = msg) do
    msg.from
    |> Anu.Message.new()
    |> Anu.Message.react("👍", message_id: msg.id)
    |> Anu.deliver()
  end

  @impl true
  def handle_event(:message_status, %Anu.Event.Status{} = status) do
    # status.id, status.status (:sent, :delivered, :read, :failed)
    :ok
  end

  @impl true
  def handle_event(_event, _payload), do: :ok
end

Adapters

Like Swoosh, Anu supports multiple adapters:

# config/config.exs

# Production — Meta Cloud API (default)
config :anu, adapter: Anu.Adapters.Meta

# Development — logs messages to console
config :anu, adapter: Anu.Adapters.Local

# Test — stores messages in-process
config :anu, adapter: Anu.Adapters.Test

In tests:

import Anu.TestAssertions

test "sends order confirmation" do
  MyApp.send_confirmation(order)

  assert_message_sent(to: order.customer_phone, body: "Your order has shipped!")
end

Anu Cloud

The open source SDK handles messaging and webhooks. Anu Cloud adds AI primitives and a workflow engine as a hosted API.

# Add the cloud client
{:anu_cloud, "~> 0.1"}

AI primitives

# Classify intent
{:ok, %{intent: :order_status, confidence: 0.95}} =
  Anu.AI.classify(msg, intents: [:order_status, :complaint, :general])

# Generate contextual reply
Anu.Message.new(msg.from)
|> Anu.AI.reply(context: order_data, tone: :friendly)
|> Anu.deliver()

# Extract structured data
{:ok, %{name: "João", order_id: "12345"}} =
  Anu.AI.extract(msg, schema: %{name: :string, order_id: :string})

# Summarize conversation
{:ok, summary} = Anu.AI.summarize(conversation_id)

Workflows

Anu.Workflow.new("support")
|> Anu.Workflow.on_message(match: :any)
|> Anu.Workflow.step(:classify, &Anu.AI.classify(&1, intents: [:order, :billing, :other]))
|> Anu.Workflow.branch(%{
  order:   &Anu.AI.reply(&1, context: :orders_db),
  billing: &Anu.Workflow.handoff(&1, to: :human_agent),
  other:   &Anu.AI.reply(&1, fallback: true)
})
|> Anu.Workflow.deploy()

Zero markup pricing

Anu does not mark up Meta's messaging fees. You pay Meta's per-message cost directly. The cloud service charges only for AI usage and the platform subscription.

Other SDKs

This is the Elixir SDK. Other official SDKs are in development:

SDK Status Repo
Elixir Available zoedsoupe/anu
TypeScript Coming soon
Python Coming soon
Go Coming soon

You can also use the REST API directly from any language.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md before submitting a PR.

git clone https://github.com/zeeetech/anu_ex.git
cd anu
mix deps.get
mix test

Built with 💜 by @zoedsoupe

About

whatsapp api for devs, like slack build kit

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

  •  

Contributors

Languages