Rails Integration

Install generator

rails generate whatsapp:install

Creates:

  • config/initializers/whatsapp.rb — configuration
  • app/jobs/whatsapp_send_job.rb — ActiveJob for async sending

Model macro (destination mode)

One global WhatsApp account sends to your users’ phone numbers.

class User < ApplicationRecord
  has_whatsapp :phone  # :phone is the column containing the WhatsApp number
end
user = User.find(1)

# Text
user.whatsapp.send_message("Your verification code is 1234")

# Media
user.whatsapp.send_image("photo.jpg", caption: "Your receipt")
user.whatsapp.send_document("report.pdf", filename: "report.pdf")
user.whatsapp.send_video("clip.mp4", caption: "Watch this")
user.whatsapp.send_audio("voice.ogg")
user.whatsapp.send_sticker("sticker.webp")

# Rich messages
user.whatsapp.send_location(latitude: 48.8566, longitude: 2.3522, name: "Paris")
user.whatsapp.send_contact(name: "Alice", phone: "+33611111111")
user.whatsapp.react(message_id: "msg123", emoji: "👍")
user.whatsapp.reply(quoted_message_id: "msg123", text: "Got it!")

# Poll
user.whatsapp.send_poll(question: "Satisfied?", options: ["Yes", "No"])

# Presence & read receipts
user.whatsapp.send_composing           # typing indicator
user.whatsapp.send_recording           # recording indicator
user.whatsapp.send_paused              # clear indicator
user.whatsapp.mark_as_read("msg123")   # send read receipt

# Async (via ActiveJob)
user.whatsapp.send_later("Your order has shipped!")
user.whatsapp.send_image_later("receipt.pdf", caption: "Your invoice")
user.whatsapp.send_document_later("report.pdf", filename: "report.pdf")

Multi-session (account mode)

Each record is its own WhatsApp account — perfect for SaaS apps where each customer connects their own number.

class Hotel < ApplicationRecord
  has_whatsapp :phone, account: true
end
hotel = Hotel.find(42)

hotel.whatsapp.connect
hotel.whatsapp.qr_data              # base64 QR data (nil if not pending)
hotel.whatsapp.status                # :disconnected, :connecting, :qr_pending, :connected
hotel.whatsapp.connected?            # true/false

# Send from the hotel's own account
hotel.whatsapp.send_message(to: "+33612345678", text: "Bienvenue chez #{hotel.name}!")

# Receive messages
hotel.whatsapp.on_message { |msg| puts msg.text }

# Polls
hotel.whatsapp.send_poll(to: "+33612345678", question: "Check-in time?", options: ["14h", "15h", "16h"])
hotel.whatsapp.on_poll_vote { |data| puts data[:votes] }

# Presence & read receipts
hotel.whatsapp.send_presence("composing", to: "+33612345678")
hotel.whatsapp.subscribe_presence("+33612345678")
hotel.whatsapp.read_messages([{ remote_jid: "33612345678@s.whatsapp.net", id: "msg1" }])

# Groups
hotel.whatsapp.groups
hotel.whatsapp.create_group(subject: "VIP Guests", participants: ["+336..."])

hotel.whatsapp.disconnect

Custom session keys:

has_whatsapp :phone, account: true                                         # "Hotel_42"
has_whatsapp :phone, account: true, session: "my_key"                      # "my_key"
has_whatsapp :phone, account: true, session: -> { "hotel-#{id}-#{slug}" }  # dynamic

Session management:

Whatsapp.sessions                  # => { "Hotel_42" => #<Session>, ... }
Whatsapp.session("Hotel_42").status
Whatsapp.disconnect_all!

View helpers

<%= whatsapp_qr(current_hotel.whatsapp, size: 256) %>
<%= whatsapp_status_badge(current_hotel.whatsapp) %>
<%= whatsapp_status(current_hotel.whatsapp) %>

<% if whatsapp_connected?(current_hotel.whatsapp) %>
  <p>WhatsApp is connected!</p>
<% end %>

<%= whatsapp_rate_limit_info(current_hotel.whatsapp) %>

Webhook — receiving messages

rails generate whatsapp:webhook

Creates:

  • app/handlers/whatsapp_message_handler.rb — incoming message handler
  • app/controllers/whatsapp/sessions_controller.rb — sessions JSON API
  • Routes

Handler:

class WhatsappMessageHandler < Whatsapp::MessageHandler
  def call(message, session:)
    case message.text&.downcase
    when /\bbook/
      BookingService.create_from_whatsapp(message, session: session)
    when /\bhelp/
      Whatsapp.session(session).send_message(to: message.from, text: "How can we help?")
    end
  end
end

Called for every incoming message on all sessions.

Sessions API:

GET    /whatsapp/sessions              — list all sessions
GET    /whatsapp/sessions/:id          — session detail + QR data
POST   /whatsapp/sessions/:id/connect  — connect
POST   /whatsapp/sessions/:id/disconnect — disconnect

Notifier

For notification-style messaging without a model:

notifier = Whatsapp::Notifier.new
notifier.notify("+33612345678", "Your order has shipped!")

# With template
notifier = Whatsapp::Notifier.new(template: "Hello %{name}, your code is %{code}.")
notifier.notify("+33612345678", name: "Alice", code: "1234")

# Async
notifier = Whatsapp::Notifier.new(async: true)
notifier.notify("+33612345678", "Background notification")

# Bulk (rate-limit aware)
results = notifier.bulk([
  { to: "+33611111111", text: "Hello A" },
  { to: "+33622222222", text: "Hello B" },
])
# => { sent: 2, failed: 0, errors: [] }