Kirimi Ruby SDK

Gem Version License: MIT

Official Ruby SDK for the Kirimi WhatsApp API. Zero runtime dependencies — uses only Ruby's built-in net/http.

Installation

Add to your Gemfile:

gem 'kirimi'

Then run:

bundle install

Or install directly:

gem install kirimi

Quick Start

require 'kirimi'

client = Kirimi::Client.new(
  user_code: 'YOUR_USER_CODE',
  secret:    'YOUR_SECRET'
)

resp = client.send_message(
  device_id: 'YOUR_DEVICE_ID',
  phone:     '628111222333',
  message:   'Hello from Kirimi!'
)

puts resp.success?  # => true
puts resp.message   # => "Message sent"
puts resp.data      # => { ... }

Constructor

Kirimi::Client.new(
  user_code: 'YOUR_USER_CODE',   # required
  secret:    'YOUR_SECRET',      # required
  base_url:  'https://api.kirimi.id',  # optional, default
  timeout:   30                  # optional, seconds
)

All Methods

WhatsApp Unofficial

# Send text/media message
client.send_message(device_id:, phone:, message:, media_url: nil)

# Send file via multipart (accepts File, StringIO, or file path string)
client.send_message_file(device_id:, phone:, file:, file_name:, message: nil)

# Send message without typing indicator
client.send_message_fast(device_id:, phone:, message:, media_url: nil)

WABA (WhatsApp Business API)

client.send_waba_message(device_id:, phone:, message:)

Devices

client.list_devices
client.device_status(device_id:)
client.device_status_enhanced(device_id:)

User

client.

Contacts

client.save_contact(phone:, name: nil, email: nil)

OTP (V1)

# Generate & send OTP
client.generate_otp(
  device_id:,
  phone:,
  otp_length:        6,        # optional
  otp_type:          'numeric', # optional: numeric, alphabetic, alphanumeric
  custom_otp_message: nil      # optional
)

# Validate OTP
client.validate_otp(device_id:, phone:, otp:)

OTP (V2)

# Send OTP via WABA template or device
client.send_otp_v2(
  phone:,
  device_id:,
  method:        'device', # optional: device, waba
  app_name:      'MyApp',  # optional
  template_code: nil,      # optional, for waba method
  custom_message: nil      # optional, for device method
)

# Verify OTP
client.verify_otp_v2(phone:, otp_code:)

Broadcast

# phones accepts String or Array (Array auto-joined with comma)
client.broadcast_message(
  device_id:,
  phones:   ['628111', '628222', '628333'],
  message:  'Promo!',
  delay:    2  # optional, seconds between messages
)

Deposits

client.list_deposits(status: nil)  # status: nil, 'paid', 'unpaid', 'expired'
client.list_packages

Response Object

All methods return a Kirimi::Response instance:

resp = client.send_message(device_id: 'DEV', phone: '628xxx', message: 'hi')

resp.success?  # => true / false (boolean method)
resp.success   # => true / false (raw value)
resp.data      # => Hash or nil
resp.message   # => String
resp.raw       # => full parsed Hash

Error Handling

begin
  resp = client.send_message(device_id: 'DEV', phone: '628xxx', message: 'hi')
rescue Kirimi::ApiError => e
  puts e.status_code    # => 401
  puts e.message        # => "Unauthorized"
  puts e.response_data  # => parsed response body
rescue Kirimi::NetworkError => e
  puts "Network problem: #{e.message}"
rescue Kirimi::Error => e
  puts "SDK error: #{e.message}"
end

Rails Integration

Application configuration

# config/initializers/kirimi.rb
KIRIMI_CLIENT = Kirimi::Client.new(
  user_code: ENV.fetch('KIRIMI_USER_CODE'),
  secret:    ENV.fetch('KIRIMI_SECRET')
)

Controller example

class NotificationsController < ApplicationController
  def send_otp
    resp = KIRIMI_CLIENT.generate_otp(
      device_id: params[:device_id],
      phone:     params[:phone],
      otp_length: 6,
      otp_type:   'numeric'
    )

    if resp.success?
      render json: { sent: true }
    else
      render json: { sent: false, error: resp.message }, status: :unprocessable_entity
    end
  rescue Kirimi::ApiError => e
    render json: { error: e.message }, status: e.status_code
  end
end

Background Job example

class SendWhatsAppJob < ApplicationJob
  queue_as :default

  def perform(device_id, phone, message)
    KIRIMI_CLIENT.send_message(device_id: device_id, phone: phone, message: message)
  rescue Kirimi::ApiError, Kirimi::NetworkError => e
    Rails.logger.error "[Kirimi] #{e.class}: #{e.message}"
    raise  # re-raise to trigger job retry
  end
end

License

MIT — see LICENSE.