Project

possinote

0.0
The project is in a healthy, maintained state
A comprehensive Ruby SDK for sending SMS, emails, and scheduling messages via the PossiNote API
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 13.0
~> 3.12
~> 1.50
~> 3.18

Runtime

~> 0.21
~> 2.6
 Project Readme

Possinote Ruby SDK

Official Ruby SDK for the PossiNote API - Send SMS, emails, and schedule messages with ease.

Installation

Add this line to your application's Gemfile:

gem 'possinote'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install possinote

Quick Start

require 'possinote'

# Initialize the client with your API key
client = Possinote::Client.new(api_key: 'your_api_key_here')

# Send a single SMS
response = client.sms.send(
  to: '+233244123456',
  message: 'Hello from Possinote!',
  sender_id: 'YourSenderID'
)

# Send a single email
response = client.email.send(
  recipient: 'user@example.com',
  subject: 'Welcome to Possinote',
  content: '<h1>Hello!</h1><p>Welcome to our platform.</p>',
  sender_name: 'Your Company'
)

API Reference

Authentication

All API requests require authentication using your API key:

client = Possinote::Client.new(api_key: 'your_api_key_here')

SMS Operations

Send Single SMS

response = client.sms.send(
  to: '+233244123456',
  message: 'Your message here',
  sender_id: 'YourSenderID'
)

# Response
{
  "success" => true,
  "data" => {
    "message_id" => "msg_123456789",
    "to" => "+233244123456",
    "status" => "queued",
    "cost" => 1.0,
    "created_at" => "2025-08-11T11:30:00Z"
  }
}

Send Bulk SMS

response = client.sms.send_bulk(
  sender_id: 'YourSenderID',
  messages: [
    { to: '+233244123456', message: 'Message 1' },
    { to: '+233244123457', message: 'Message 2' }
  ]
)

# Response
{
  "success" => true,
  "data" => {
    "batch_id" => "batch_123456789",
    "total_messages" => 2,
    "successful" => 2,
    "failed" => 0,
    "total_cost" => 2.0,
    "messages" => [
      { "message_id" => "msg_1", "to" => "+233244123456", "status" => "queued" },
      { "message_id" => "msg_2", "to" => "+233244123457", "status" => "queued" }
    ]
  }
}

Schedule Single SMS

response = client.sms.schedule(
  recipient: '+233244123456',
  message: 'Scheduled message',
  sender_id: 'YourSenderID',
  scheduled_at: '2025-08-11T12:00:00Z'
)

# Response
{
  "success" => true,
  "data" => {
    "id" => "schedule_123456789",
    "recipient" => "+233244123456",
    "message" => "Scheduled message",
    "scheduled_at" => "2025-08-11T12:00:00Z",
    "status" => "pending",
    "cost" => "1.0"
  }
}

Schedule Bulk SMS

response = client.sms.schedule_bulk(
  sender_id: 'YourSenderID',
  messages: [
    { recipient: '+233244123456', message: 'Scheduled message 1' },
    { recipient: '+233244123457', message: 'Scheduled message 2' }
  ],
  scheduled_at: '2025-08-11T12:00:00Z'
)

# Response
{
  "success" => true,
  "data" => {
    "batch_id" => "batch_123456789",
    "scheduled_count" => 2,
    "total_cost" => 2.0,
    "scheduled_at" => "2025-08-11T12:00:00Z",
    "messages" => [
      { "id" => "schedule_1", "recipient" => "+233244123456", "status" => "pending" },
      { "id" => "schedule_2", "recipient" => "+233244123457", "status" => "pending" }
    ]
  }
}

Email Operations

Send Single Email

response = client.email.send(
  recipient: 'user@example.com',
  subject: 'Welcome Email',
  content: '<h1>Welcome!</h1><p>Thank you for joining us.</p>',
  sender_name: 'Your Company'
)

# Response
{
  "success" => true,
  "message" => "Email queued for delivery",
  "recipient" => "user@example.com",
  "message_id" => "email_123456789"
}

Send Bulk Email

response = client.email.send_bulk(
  subject: 'Newsletter',
  content: '<h1>Newsletter</h1><p>This is our monthly newsletter.</p>',
  recipients: ['user1@example.com', 'user2@example.com'],
  sender_name: 'Your Company'
)

# Response
{
  "success" => true,
  "message" => "Bulk emails queued for delivery",
  "queued_count" => 2,
  "total_count" => 2,
  "batch_id" => "batch_123456789",
  "emails" => [
    { "message_id" => "email_1", "recipient" => "user1@example.com", "status" => "queued" },
    { "message_id" => "email_2", "recipient" => "user2@example.com", "status" => "queued" }
  ]
}

Scheduling Operations

Schedule Single Email

response = client.scheduling.schedule_email(
  recipient: 'user@example.com',
  subject: 'Scheduled Email',
  content: '<h1>Scheduled Content</h1>',
  scheduled_at: '2025-08-11T12:00:00Z',
  sender_name: 'Your Company'
)

# Response
{
  "success" => true,
  "data" => {
    "id" => "email_schedule_123456789",
    "recipient" => "user@example.com",
    "subject" => "Scheduled Email",
    "scheduled_at" => "2025-08-11T12:00:00Z",
    "status" => "pending",
    "cost" => "1.0"
  }
}

Schedule Bulk Individual Emails

response = client.scheduling.schedule_multiple_emails([
  {
    recipient: 'user1@example.com',
    subject: 'Personalized Email 1',
    content: '<h1>Hello User 1!</h1>',
    scheduled_at: '2025-08-11T12:00:00Z',
    sender_name: 'Your Company'
  },
  {
    recipient: 'user2@example.com',
    subject: 'Personalized Email 2',
    content: '<h1>Hello User 2!</h1>',
    scheduled_at: '2025-08-11T12:00:00Z',
    sender_name: 'Your Company'
  }
])

# Response
{
  "success" => true,
  "data" => {
    "batch_id" => "batch_123456789",
    "total_scheduled" => 2,
    "total_cost" => 2.0,
    "scheduled_emails" => [
      { "id" => "email_1", "recipient" => "user1@example.com", "status" => "pending" },
      { "id" => "email_2", "recipient" => "user2@example.com", "status" => "pending" }
    ]
  }
}

Framework Integration

Rails Integration

1. Add to Gemfile

# Gemfile
gem 'possinote'

2. Configure in Application

# config/initializers/possinote.rb
require 'possinote'

# Initialize the client
POSSINOTE_CLIENT = Possinote::Client.new(
  api_key: Rails.application.credentials.possinote[:api_key]
)

3. Use in Controllers

# app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
  def send_sms
    begin
      response = POSSINOTE_CLIENT.sms.send(
        to: params[:phone_number],
        message: params[:message],
        sender_id: 'YourBrand'
      )
      
      if response['success']
        render json: { message: 'SMS sent successfully', data: response['data'] }
      else
        render json: { error: 'Failed to send SMS' }, status: :unprocessable_entity
      end
    rescue Possinote::AuthenticationError => e
      render json: { error: 'Authentication failed' }, status: :unauthorized
    rescue Possinote::PaymentRequiredError => e
      render json: { error: 'Insufficient credits' }, status: :payment_required
    rescue Possinote::ValidationError => e
      render json: { error: e.message }, status: :bad_request
    rescue => e
      render json: { error: 'An error occurred' }, status: :internal_server_error
    end
  end

  def send_bulk_sms
    begin
      response = POSSINOTE_CLIENT.sms.send_bulk(
        sender_id: 'YourBrand',
        messages: params[:messages] # Array of { to: phone, message: text }
      )
      
      render json: { message: 'Bulk SMS sent', data: response['data'] }
    rescue => e
      render json: { error: e.message }, status: :internal_server_error
    end
  end

  def send_email
    begin
      response = POSSINOTE_CLIENT.email.send(
        recipient: params[:email],
        subject: params[:subject],
        content: params[:content],
        sender_name: 'Your Company'
      )
      
      render json: { message: 'Email sent successfully', data: response }
    rescue => e
      render json: { error: e.message }, status: :internal_server_error
    end
  end
end

4. Use in Services

# app/services/notification_service.rb
class NotificationService
  def initialize
    @client = POSSINOTE_CLIENT
  end

  def send_welcome_sms(user)
    @client.sms.send(
      to: user.phone_number,
      message: "Welcome #{user.name}! Your account has been created successfully.",
      sender_id: 'YourBrand'
    )
  end

  def send_password_reset_email(user, reset_token)
    @client.email.send(
      recipient: user.email,
      subject: 'Password Reset Request',
      content: generate_password_reset_html(user, reset_token),
      sender_name: 'Your Company'
    )
  end

  def send_bulk_newsletter(users, newsletter_content)
    messages = users.map do |user|
      {
        to: user.phone_number,
        message: "Newsletter: #{newsletter_content[:title]}"
      }
    end

    @client.sms.send_bulk(
      sender_id: 'YourBrand',
      messages: messages
    )
  end

  def schedule_reminder_email(user, appointment)
    @client.scheduling.schedule_email(
      recipient: user.email,
      subject: 'Appointment Reminder',
      content: generate_appointment_reminder_html(appointment),
      scheduled_at: appointment.datetime - 1.hour,
      sender_name: 'Your Company'
    )
  end

  private

  def generate_password_reset_html(user, token)
    <<~HTML
      <h1>Password Reset Request</h1>
      <p>Hello #{user.name},</p>
      <p>You requested a password reset. Click the link below to reset your password:</p>
      <a href="#{Rails.application.routes.url_helpers.reset_password_url(token: token)}">
        Reset Password
      </a>
      <p>This link will expire in 1 hour.</p>
    HTML
  end

  def generate_appointment_reminder_html(appointment)
    <<~HTML
      <h1>Appointment Reminder</h1>
      <p>Hello #{appointment.user.name},</p>
      <p>This is a reminder for your appointment:</p>
      <ul>
        <li><strong>Date:</strong> #{appointment.datetime.strftime('%B %d, %Y')}</li>
        <li><strong>Time:</strong> #{appointment.datetime.strftime('%I:%M %p')}</li>
        <li><strong>Location:</strong> #{appointment.location}</li>
      </ul>
    HTML
  end
end

5. Use in Background Jobs

# app/jobs/send_notification_job.rb
class SendNotificationJob < ApplicationJob
  queue_as :default

  def perform(notification_type, user_id, options = {})
    user = User.find(user_id)
    service = NotificationService.new

    case notification_type
    when 'welcome_sms'
      service.send_welcome_sms(user)
    when 'password_reset_email'
      service.send_password_reset_email(user, options[:reset_token])
    when 'bulk_newsletter'
      service.send_bulk_newsletter(options[:users], options[:content])
    when 'scheduled_reminder'
      service.schedule_reminder_email(user, options[:appointment])
    end
  end
end

# Usage in controller
SendNotificationJob.perform_later('welcome_sms', user.id)
SendNotificationJob.perform_later('password_reset_email', user.id, reset_token: token)

6. Environment Configuration

# config/credentials.yml.enc
possinote:
  api_key: your_api_key_here

# Or use environment variables
# config/initializers/possinote.rb
POSSINOTE_CLIENT = Possinote::Client.new(
  api_key: ENV['POSSINOTE_API_KEY']
)

Error Handling

The SDK provides specific exception classes for different error types:

begin
  response = client.sms.send(to: '+233244123456', message: 'Hello', sender_id: 'SenderID')
rescue Possinote::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
rescue Possinote::PaymentRequiredError => e
  puts "Payment required: #{e.message}"
rescue Possinote::RateLimitError => e
  puts "Rate limit exceeded: #{e.message}"
rescue Possinote::ValidationError => e
  puts "Validation error: #{e.message}"
rescue Possinote::APIError => e
  puts "API error: #{e.message}"
end

Error Types

  • Possinote::AuthenticationError - Invalid API key (401)
  • Possinote::PaymentRequiredError - Insufficient credits (402)
  • Possinote::RateLimitError - Rate limit exceeded (429)
  • Possinote::ValidationError - Invalid request data (400)
  • Possinote::APIError - Other API errors

Configuration

Base URL

The SDK uses the production API by default. For testing, you can modify the base URL:

# In lib/possinote/client.rb
BASE_URI = 'https://notifyapi.possitech.net/api/v1'

Timeout Settings

HTTP requests use default timeout settings. You can customize them in the client:

# The SDK uses HTTParty defaults
# You can modify timeout settings in lib/possinote/client.rb

Requirements

  • Ruby >= 2.6.0
  • HTTParty gem
  • JSON gem

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/possitech/possinote-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Support

For support, email support@possitech.net or visit our documentation.

Changelog

1.0.0

  • Initial release
  • SMS sending and scheduling
  • Email sending and scheduling
  • Comprehensive error handling
  • Full API coverage