Tutorial

How to Send WhatsApp Messages from Ruby (No Gem Required)

Send WhatsApp messages from Ruby using only Net::HTTP — no gem or SDK dependency required. Session setup, QR auth, sending text/images/files, and production error handling.

August 24, 2026By Retention Stack
Open in AI

Meta Description: Send WhatsApp messages from Ruby using only Net::HTTP — no gem or SDK required. Session setup, QR auth, sending text/images/files, and production error handling.


Introduction

Search "WhatsApp API Ruby" and every result reaches for a gem first — ruby_whatsapp_sdk, a vendor wrapper, or a Rails initializer wired to a Business Account. None of that is necessary. The WhatsApp Messaging API is plain REST over HTTPS, and Ruby's standard library (net/http, json) is all you need to talk to it.

In this guide, you'll send a real WhatsApp message from Ruby in under 5 minutes, with zero external dependencies — no Gemfile entry, no bundle install.

What you'll need:

  • Ruby 3.0+ (ships with net/http and json in the standard library)
  • A RapidAPI account (free)
  • 5 minutes

Let's send a message.


Step 1: Get Your API Key (30 seconds)

  1. 1.Go to RapidAPI Hub
  2. 2.Search for "Whatsapp messaging bot"
  3. 3.Click Subscribe (Free plan available, no card required)
  4. 4.Open API Settings and copy your X-RapidAPI-Key

That key authenticates every request below.


Step 2: Create a WhatsApp Session

Before sending a message, pair a session — this is the WhatsApp account the API sends on behalf of. Sessions authenticate the same way WhatsApp Web does: scan a QR code once, and the API keeps that connection alive.

ruby
# session.rb
require 'net/http'
require 'json'
require 'uri'

API_HOST = 'whatsapp-messaging-bot.p.rapidapi.com'
API_KEY  = ENV.fetch('RAPIDAPI_KEY')
SESSION_NAME = 'my-session'

def call_api(method, path, body = nil)
  uri = URI("https://#{API_HOST}#{path}")

  request = case method
            when :post then Net::HTTP::Post.new(uri)
            when :get  then Net::HTTP::Get.new(uri)
            end

  request['x-rapidapi-key']  = API_KEY
  request['x-rapidapi-host'] = API_HOST
  request['Content-Type']    = 'application/json'
  request.body = body.to_json if body

  response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  [response.code.to_i, JSON.parse(response.body || '{}')]
end

# Create the session
status, created = call_api(:post, '/v1/sessions', { name: SESSION_NAME })
puts "Session created: #{created}"

# Get the QR code to authenticate
status, qr = call_api(:get, "/v1/sessions/#{SESSION_NAME}/auth/qr")
puts "Scan this QR with WhatsApp → Linked Devices:"
puts qr['qr'] || 'QR not ready yet, retry in a second'

Run it:

bash
RAPIDAPI_KEY=your_key_here ruby session.rb

Open WhatsApp on your phone → Settings → Linked Devices → Link a Device, and scan the printed QR code.


Step 3: Send Your First Message

Once the session shows as authenticated, sending is a single request:

ruby
# send.rb
require_relative 'session' # reuses call_api() and SESSION_NAME above

def send_whatsapp_message(chat_id, text)
  call_api(:post, '/v1/sendText', {
    chatId: chat_id,   # just the number: "14155552671"
    text: text,
    session: SESSION_NAME
  })
end

status, result = send_whatsapp_message('14155552671', 'Hello from Ruby!')

if [200, 201].include?(status)
  puts 'Message sent.'
else
  puts "Send failed: #{result}"
end
bash
ruby send.rb

Check your phone. That's a real WhatsApp message sent from Ruby with zero dependencies.


Step 4: Sending Images, Files, and Voice Notes

Same call_api helper, different endpoint and payload:

ruby
def send_image(chat_id, image_url, caption = '')
  call_api(:post, '/v1/sendImage', {
    chatId: chat_id,
    image: image_url,
    caption: caption,
    session: SESSION_NAME
  })
end

def send_file(chat_id, file_url, filename)
  call_api(:post, '/v1/sendFile', {
    chatId: chat_id,
    file: file_url,
    filename: filename,
    session: SESSION_NAME
  })
end

Both take a public URL — the API fetches and delivers it, no upload step needed. Full parameter reference for every message type (including voice, video, location, and contact cards) is in the interactive API reference.


Production Best Practices

1. Retry with backoff

A single failed request shouldn't fail the whole job:

ruby
def send_with_retry(chat_id, text, max_retries: 3)
  status, result = nil

  (1..max_retries).each do |attempt|
    status, result = send_whatsapp_message(chat_id, text)
    return [status, result] if status < 400

    sleep(attempt * 2) # 2s, 4s, 6s backoff
  end

  [status, result]
end

2. Reuse the HTTP connection, don't recreate sessions per request

Net::HTTP.start opens a new TCP connection per call above, which is fine for a script but wasteful in a request loop. In a Rails app or worker, wrap the block in a persistent Net::HTTP.start(...) do |http| ... end and pass http into call_api instead of opening a new one each time. Either way, the WhatsApp session itself (SESSION_NAME) is separate from the HTTP connection — create it once, store the name in ENV or a config table, and reuse it across every subsequent send.

3. Confirm delivery with a webhook, not the HTTP response

A 200 from /v1/sendText means "accepted," not "delivered" — a number that isn't on WhatsApp can still return success. Register a webhook and read the message.ack event for real delivery/read status:

ruby
call_api(:post, "/v1/sessions/#{SESSION_NAME}/webhooks", {
  webhookUrl: 'https://yourapp.com/webhooks/whatsapp',
  events: ['message.ack']
})

Troubleshooting

IssueFix
401 UnauthorizedRAPIDAPI_KEY environment variable isn't set, or the key's been rotated in the RapidAPI dashboard.
OpenSSL::SSL::SSLErrorOlder Ruby installs (via rbenv/rvm) can ship a stale CA bundle — update the openssl gem or point SSL_CERT_FILE at your system's cert store.
QR code expires before you scan itQR codes are short-lived — fetch it right before you're ready to scan, not minutes ahead.
Message accepted but never arrivesCheck message.ack via webhook — a 200 only means the API accepted the send, not that WhatsApp delivered it.

Next Steps

External references:


Try Free on RapidAPI → Get your API key in 30 seconds → Send your first Ruby message in 5 minutes.

Ready to Get Started?

Try the WhatsApp API free on RapidAPI with no credit card required.

Try Free on RapidAPI