├── .rspec ├── .gitignore ├── lib ├── messagebird │ ├── version.rb │ ├── balance.rb │ ├── call_flow │ │ └── step.rb │ ├── contact_reference.rb │ ├── group_reference.rb │ ├── message_reference.rb │ ├── verify_email_message.rb │ ├── conversation_webhook.rb │ ├── voice │ │ ├── webhook.rb │ │ ├── call_leg.rb │ │ ├── transcription.rb │ │ ├── base.rb │ │ ├── client.rb │ │ ├── call.rb │ │ ├── call_leg_recording.rb │ │ └── list.rb │ ├── custom_details.rb │ ├── conversation_message.rb │ ├── recipient.rb │ ├── error.rb │ ├── number.rb │ ├── number_client.rb │ ├── conversation_channel.rb │ ├── hlr.rb │ ├── conversation_client.rb │ ├── call_flow.rb │ ├── lookup.rb │ ├── list.rb │ ├── voice_client.rb │ ├── group.rb │ ├── verify.rb │ ├── voicemessage.rb │ ├── base.rb │ ├── message.rb │ ├── contact.rb │ ├── conversation.rb │ ├── callflow.rb │ ├── signed_request.rb │ ├── http_client.rb │ └── request_validator.rb └── messagebird.rb ├── .github └── workflows │ ├── publish.yml │ ├── test.yml │ ├── gh-release.yml │ └── release.yml ├── Rakefile ├── spec ├── balance_spec.rb ├── http_client_spec.rb ├── base_spec.rb ├── error_spec.rb ├── hlr_spec.rb ├── request_validator_spec.rb ├── message_spec.rb ├── conversation_client_spec.rb ├── voicemessage_spec.rb ├── verify_spec.rb ├── lookup_spec.rb ├── voice_spec.rb ├── spec_helper.rb ├── signed_request_spec.rb ├── data │ └── conversations │ │ └── list.json ├── call_flow_spec.rb ├── group_spec.rb ├── number_spec.rb ├── contact_spec.rb └── conversation_spec.rb ├── CHANGELOG.md ├── Gemfile ├── examples ├── signed_request_validation.rb ├── voice_webhook_delete.rb ├── conversation_webhook_delete.rb ├── call.rb ├── balance.rb ├── verify_delete.rb ├── number_cancel.rb ├── send_conversation_message.rb ├── voice_webhook_create.rb ├── hlr_create.rb ├── voice_webhook_update.rb ├── group_create.rb ├── verify_email_message.rb ├── number_search.rb ├── conversation_webhook.rb ├── hlr.rb ├── verify_create.rb ├── number_fetch.rb ├── conversation_webhook_create.rb ├── conversation_message.rb ├── conversation_webhook_update.rb ├── number_fetch_all.rb ├── lookup_hlr.rb ├── conversation_reply.rb ├── verify.rb ├── lookup_hlr_create.rb ├── call_legs.rb ├── voice_message_create.rb ├── number_update.rb ├── voice_webhooks_list.rb ├── group_list.rb ├── verify_token.rb ├── conversation_update.rb ├── message_create.rb ├── conversation_webhooks_list.rb ├── voice_message.rb ├── call_leg_recordings.rb ├── voice_transcription.rb ├── verify_create_email.rb ├── contact_create.rb ├── number_purchase.rb ├── message.rb ├── conversation_messages_list.rb ├── lookup.rb ├── contact_list.rb ├── message_list.rb ├── conversation.rb ├── start_conversation.rb ├── conversation_list.rb └── start_hsm_conversation.rb ├── .rubocop.yml ├── messagebird-rest.gemspec ├── LICENSE ├── RELEASE.md └── README.md /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.gem 3 | /Gemfile.lock 4 | .rbenv-gemsets 5 | .ruby-version 6 | .byebug_history -------------------------------------------------------------------------------- /lib/messagebird/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MessageBird 4 | module Version 5 | STRING = '5.0.0' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/messagebird/balance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class Balance < MessageBird::Base 7 | attr_accessor :payment, :type, :amount 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/call_flow/step.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class CallFlowStep < MessageBird::Base 7 | attr_accessor :id, :action, :options 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/contact_reference.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class ContactReference < MessageBird::Base 7 | attr_accessor :href, :total_count 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/group_reference.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class GroupReference < MessageBird::Base 7 | attr_accessor :href, :total_count 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/message_reference.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class MessageReference < MessageBird::Base 7 | attr_accessor :href, :total_count 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/verify_email_message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class VerifyEmailMessage < MessageBird::Base 7 | attr_accessor :id, :status 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/conversation_webhook.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class ConversationWebhook < MessageBird::Base 7 | attr_accessor :id, :events, :channel_id, :url, :status, :created_datetime, :updated_datetime 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/messagebird/voice/webhook.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/voice/base' 4 | 5 | module MessageBird 6 | module Voice 7 | class Webhook < MessageBird::Voice::Base 8 | attr_accessor :id, :url, :token, :created_at, :updated_at 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/messagebird/custom_details.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class CustomDetails < MessageBird::Base 7 | # CustomDetails holds free-input fields for the Contact object. 8 | attr_accessor :custom1, :custom2, :custom3, :custom4 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/messagebird/conversation_message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class ConversationMessage < MessageBird::Base 7 | attr_accessor :id, :conversation_id, :channel_id, :direction, :status, 8 | :type, :content, :created_datetime, :updated_datetime, :fallback 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/messagebird/recipient.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class Recipient < MessageBird::Base 7 | attr_accessor :recipient, :status 8 | attr_reader :status_date_time 9 | 10 | def status_date_time=(value) 11 | @status_date_time = value_to_time(value) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: RubyGems release 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v1 13 | 14 | - name: Publish gem 15 | uses: dawidd6/action-publish-gem@v1 16 | with: 17 | api_key: ${{secrets.RUBYGEMS_API_KEY}} 18 | -------------------------------------------------------------------------------- /lib/messagebird/voice/call_leg.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/voice/base' 4 | 5 | module MessageBird 6 | module Voice 7 | class CallLeg < MessageBird::Voice::Base 8 | attr_accessor :id, :call_id, :source, :destination, :status, :direction, :cost, :currency, :duration, :created_at, :updated_at, :answered_at, :ended_at 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/messagebird/voice/transcription.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | module Voice 7 | class Transcription < MessageBird::Voice::Base 8 | attr_accessor :id, :recording_id, :error, :created_at, :updated_at, :_links, :uri 9 | 10 | def handle_links(links_object) 11 | @uri = links_object['file'] 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/messagebird/error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class Error < MessageBird::Base 7 | attr_accessor :code, :description, :parameter 8 | 9 | def message 10 | if parameter 11 | "#{description} (error code: #{code}, parameter: #{parameter})" 12 | else 13 | "#{description} (error code: #{code})" 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/messagebird/voice/base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module MessageBird 4 | module Voice 5 | class Base < MessageBird::Base 6 | def initialize(json) 7 | params = json.include?('data') ? json['data'].first : json 8 | super(params) 9 | handle_links(json['_links']) 10 | end 11 | 12 | # intentional empty method, objects may not want to deal with _links 13 | def handle_links(json) end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/messagebird/number.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class Number < MessageBird::Base 7 | attr_accessor :number, :country, :region, :locality, :features, :tags, :type, :status 8 | attr_reader :created_at, :renewal_at 9 | 10 | def created_at=(value) 11 | @created_at = Time.parse(value) 12 | end 13 | 14 | def renewal_at=(value) 15 | @renewal_at = Time.parse(value) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rake/testtask' 4 | require 'rspec/core/rake_task' 5 | 6 | RSpec::Core::RakeTask.new(:spec) do |t| 7 | t.pattern = Dir.glob('spec/**/*_spec.rb') 8 | end 9 | 10 | namespace :gem do 11 | desc 'Build the messagebird API gem' 12 | task :build do 13 | sh 'gem build messagebird-rest.gemspec' 14 | end 15 | 16 | desc 'Upload the gem to rubygems.org' 17 | task :upload do 18 | sh 'gem push messagebird-rest-*.gem' 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/balance_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Balance' do 4 | it 'reads' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'balance', {}) 11 | .and_return('{"payment":"prepaid","type":"credits","amount":12.34}') 12 | 13 | balance = client.balance 14 | 15 | expect(balance.payment).to eq 'prepaid' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/messagebird/number_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/https' 4 | require 'uri' 5 | require 'pp' 6 | require 'json' 7 | require 'messagebird/http_client' 8 | 9 | module MessageBird 10 | class NumberClient < HttpClient 11 | ENDPOINT = 'https://numbers.messagebird.com/v1/' 12 | 13 | def endpoint 14 | ENDPOINT 15 | end 16 | 17 | def prepare_request(request, params = {}) 18 | request.body = params.to_json 19 | request 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/messagebird/conversation_channel.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class ConversationChannel < MessageBird::Base 7 | attr_accessor :id, :name, :platform_id, :status 8 | attr_reader :created_datetime, :updated_datetime 9 | 10 | def created_datetime=(value) 11 | @created_datetime = value_to_time(value) 12 | end 13 | 14 | def updated_datetime=(value) 15 | @updated_datetime = value_to_time(value) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 5.0.0 4 | 5 | * [CHANGED] Update dev dependencies 6 | * [CHANGED] Target new rubies 7 | 8 | 9 | ## 4.0.0 10 | 11 | * [CHANGED] Update dev dependencies 12 | * [CHANGED] Target new rubies (3.x.x) 13 | * [CHANGED] remove camelCase attrs from api 14 | 15 | ## 3.1.1 16 | 17 | * [ADDED] Add release tagging workflow. 18 | 19 | ## 3.1.0 20 | 21 | * [CHANGED] Deprecate old signed request validation. 22 | * [ADDED] New request validator with JWT webhook signature. 23 | * [ADDED] Add release and publish GitHub actions. 24 | -------------------------------------------------------------------------------- /lib/messagebird/hlr.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'time' 4 | 5 | require 'messagebird/base' 6 | 7 | module MessageBird 8 | class HLR < MessageBird::Base 9 | attr_accessor :id, :href, :msisdn, :network, :reference, :status, :details 10 | attr_reader :created_datetime, :status_datetime 11 | 12 | def created_datetime=(value) 13 | @created_datetime = value_to_time(value) 14 | end 15 | 16 | def status_datetime=(value) 17 | @status_datetime = value_to_time(value) 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/messagebird/voice/client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/https' 4 | require 'uri' 5 | require 'json' 6 | require 'messagebird/http_client' 7 | 8 | module MessageBird 9 | class VoiceClient < HttpClient 10 | ENDPOINT = 'https://voice.messagebird.com/' 11 | 12 | def endpoint 13 | ENDPOINT 14 | end 15 | 16 | def prepare_request(request, params = {}) 17 | request['Content-Type'] = 'application/json' 18 | request.body = params.to_json 19 | request 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/messagebird/conversation_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/https' 4 | require 'uri' 5 | require 'json' 6 | require 'messagebird/http_client' 7 | 8 | module MessageBird 9 | class ConversationClient < HttpClient 10 | ENDPOINT = 'https://conversations.messagebird.com/v1/' 11 | 12 | def prepare_request(request, params = {}) 13 | request['Content-Type'] = 'application/json' 14 | request.body = params.to_json 15 | request 16 | end 17 | 18 | def endpoint 19 | ENDPOINT 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/messagebird/call_flow.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class CallFlow < MessageBird::Base 7 | attr_accessor :id, :title, :record, :default 8 | attr_reader :steps, :created_at, :updated_at 9 | 10 | def steps=(json) 11 | @steps = json.map { |s| MessageBird::CallFlowStep.new(s) } 12 | end 13 | 14 | def created_at=(value) 15 | @created_at = value_to_time(value) 16 | end 17 | 18 | def updated_at=(value) 19 | @updated_at = value_to_time(value) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/messagebird/lookup.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'time' 4 | 5 | require 'messagebird/base' 6 | 7 | module MessageBird 8 | class Lookup < MessageBird::Base 9 | attr_accessor :href, :country_code, :country_prefix, :phone_number, :type 10 | attr_reader :formats, :hlr 11 | 12 | def formats=(new_formats) 13 | @formats = Formats.new(new_formats) 14 | end 15 | 16 | def hlr=(new_hlr) 17 | @hlr = HLR.new(new_hlr) 18 | end 19 | end 20 | 21 | class Formats < MessageBird::Base 22 | attr_accessor :e164, :international, :national, :rfc3966 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/messagebird/list.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class List < MessageBird::Base 7 | attr_accessor :offset, :limit, :count, :total_count, :links 8 | attr_reader :items 9 | 10 | # type will be used to create objects for the items, e.g. 11 | # List.new(Contact, {}). 12 | def initialize(type, json) 13 | @type = type 14 | 15 | super(json) 16 | end 17 | 18 | def items=(value) 19 | @items = value.map { |i| @type.new i } 20 | end 21 | 22 | def [](index) 23 | @items[index] 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/messagebird/voice_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/https' 4 | require 'uri' 5 | require 'json' 6 | require 'messagebird/http_client' 7 | 8 | module MessageBird 9 | class VoiceClient < HttpClient 10 | attr_reader :endpoint 11 | 12 | BASE_ENDPOINT = 'https://voice.messagebird.com/' 13 | 14 | def initialize(access_key) 15 | super(access_key) 16 | @endpoint = BASE_ENDPOINT 17 | end 18 | 19 | def prepare_request(request, params = {}) 20 | request['Content-Type'] = 'application/json' 21 | request.body = params.to_json 22 | request 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/messagebird/group.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | require 'messagebird/contact_reference' 5 | 6 | module MessageBird 7 | class Group < MessageBird::Base 8 | attr_accessor :id, :href, :name 9 | attr_reader :contacts, :created_datetime, :updated_datetime 10 | 11 | def contacts=(value) 12 | @contacts = MessageBird::ContactReference.new(value) 13 | end 14 | 15 | def created_datetime=(value) 16 | @created_datetime = value_to_time(value) 17 | end 18 | 19 | def updated_datetime=(value) 20 | @updated_datetime = value_to_time(value) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/messagebird/voice/call.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/voice/base' 4 | require 'messagebird/voice/webhook' 5 | 6 | module MessageBird 7 | module Voice 8 | class Call < MessageBird::Base 9 | attr_accessor :id, :status, :source, :destination, :created_at, :updated_at, :ended_at, :call_flow 10 | attr_reader :webhook 11 | 12 | def initialize(json) 13 | params = json.include?('data') ? json['data'].first : json 14 | super(params) 15 | end 16 | 17 | def webhook=(webhook) 18 | @webhook = Voice::Webhook.new(webhook) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | # Declare your gem's dependencies in messagebird-rest.gemspec. 5 | # Bundler will treat runtime dependencies like base dependencies, and 6 | # development dependencies will be added by default to the :development group. 7 | gemspec 8 | 9 | # Declare any dependencies that are still in development here instead of in 10 | # your gemspec. These might include edge Rails or gems from your path or 11 | # Git. Remember to move these dependencies to your gemspec before releasing 12 | # your gem to rubygems.org. 13 | 14 | # To use a debugger 15 | # gem 'byebug', group: [:development, :test] 16 | -------------------------------------------------------------------------------- /lib/messagebird/verify.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'time' 4 | require 'messagebird/base' 5 | 6 | module MessageBird 7 | class Verify < MessageBird::Base 8 | attr_accessor :id, 9 | :href, 10 | :recipient, 11 | :reference, 12 | :messages, 13 | :status 14 | attr_reader :created_datetime, 15 | :valid_until_datetime 16 | 17 | def created_datetime=(value) 18 | @created_datetime = value_to_time(value) 19 | end 20 | 21 | def valid_until_datetime=(value) 22 | @valid_until_datetime = value_to_time(value) 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/messagebird/voice/call_leg_recording.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/voice/base' 4 | 5 | module MessageBird 6 | module Voice 7 | class CallLegRecording < MessageBird::Voice::Base 8 | # default attributes from the API 9 | attr_accessor :id, :format, :type, :leg_id, :status, :duration 10 | attr_accessor :created_at, :updated_at 11 | 12 | # further processed attributes for convenience 13 | attr_accessor :_links, :uri 14 | 15 | # Grab the URI to the downloadable file and provide it as a direct attribute 16 | def handle_links(links_object) 17 | @uri = links_object['file'] 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /examples/signed_request_validation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | SIGNING_KEY = 'PlLrKaqvZNRR5zAjm42ZT6q1SQxgbbGd' 8 | 9 | url = 'https://FULL_REQUEST_URL/path?query=1' 10 | signature = 'YOUR_REQUEST_SIGNATURE' 11 | body = '' 12 | 13 | request_validator = MessageBird::RequestValidator.new(SIGNING_KEY) 14 | 15 | begin 16 | # Verify the signed request. 17 | request_validator.validate_signature(signature, url, body.bytes.to_a) 18 | rescue MessageBird::ValidationError => e 19 | puts 20 | puts 'An error occurred while verifying the signed request:' 21 | puts e 22 | end 23 | -------------------------------------------------------------------------------- /lib/messagebird/voice/list.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/list' 4 | 5 | module MessageBird 6 | module Voice 7 | class List < List 8 | attr_accessor :per_page, :current_page, :page_count, :total_count 9 | 10 | PER_PAGE = 20 11 | CURRENT_PAGE = 1 12 | def data=(value) 13 | # Call List API retruns data object instead of items 14 | # to make it consistence with the rest of the SDK we shall 15 | # propagate it to items= method 16 | self.items = value.nil? ? [] : value 17 | end 18 | 19 | # map the pagination data to root level properties 20 | def pagination=(value) 21 | map_hash_elements_to_self(value) 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/messagebird/voicemessage.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | require 'messagebird/recipient' 5 | 6 | module MessageBird 7 | class VoiceMessage < MessageBird::Base 8 | attr_accessor :id, :href, :originator, :body, :reference, :language, :voice, :repeat, :if_machine 9 | attr_reader :scheduled_date_time, :created_datetime, :recipients 10 | 11 | def scheduled_date_time=(value) 12 | @scheduled_date_time = value_to_time(value) 13 | end 14 | 15 | def created_datetime=(value) 16 | @created_datetime = value_to_time(value) 17 | end 18 | 19 | def recipients=(json) 20 | json['items'] = json['items'].map { |r| Recipient.new(r) } 21 | @recipients = json 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master, main] 7 | 8 | jobs: 9 | ci: 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | ruby-version: [ "3.0.7", "3.1.6", "3.2.6", "3.3.7", "3.4.1" ] 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Ruby ${{ matrix.ruby-version }} 20 | uses: ruby/setup-ruby@v1 21 | with: 22 | ruby-version: ${{ matrix.ruby-version }} 23 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 24 | 25 | - name: Lint ${{ matrix.ruby-version }} 26 | run: bundle exec rubocop 27 | 28 | - name: Test ${{ matrix.ruby-version }} 29 | run: bundle exec rspec 30 | -------------------------------------------------------------------------------- /lib/messagebird/base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require 'time' 5 | 6 | module MessageBird 7 | class Base 8 | # takes each element from the given hash and apply it to ourselves through an assignment method 9 | def map_hash_elements_to_self(hash) 10 | return if hash.nil? 11 | 12 | hash.each do |key, value| 13 | method_name = key.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase # convert came case to snake case 14 | method_name += '=' 15 | send(method_name, value) if respond_to?(method_name) 16 | end 17 | end 18 | 19 | def initialize(json) 20 | map_hash_elements_to_self(json) 21 | end 22 | 23 | def value_to_time(value) 24 | value ? Time.parse(value) : nil 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/http_client_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'HttpClient' do 4 | context 'build_request' do 5 | let(:url) { URI::HTTP.build(path: '/foo/bar', query: 'test=true') } 6 | it 'check not not_allowed_method' do 7 | http_client = MessageBird::HttpClient.new('some_key') 8 | expect { http_client.build_request(:not_allowed_method, url, {}) }.to raise_error(MessageBird::MethodNotAllowedException) 9 | end 10 | 11 | [:get, :post, :delete, :get, :patch].each do |method| 12 | http_client = MessageBird::HttpClient.new('some_key') 13 | it "check allowed method #{method}" do 14 | expect(http_client.build_request(method, url, {})).to be_an_instance_of Class.const_get("Net::HTTP::#{method.to_s.capitalize}") 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/messagebird/message.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | require 'messagebird/recipient' 5 | 6 | module MessageBird 7 | class Message < MessageBird::Base 8 | attr_accessor :id, :href, :direction, :type, :originator, :body, :reference, 9 | :validity, :gateway, :type_details, :datacoding, :mclass 10 | attr_reader :scheduled_date_time, :created_datetime, :recipients 11 | 12 | def scheduled_date_time=(value) 13 | @scheduled_date_time = value_to_time(value) 14 | end 15 | 16 | def created_datetime=(value) 17 | @created_datetime = value_to_time(value) 18 | end 19 | 20 | def recipients=(json) 21 | json['items'] = json['items'].map { |r| Recipient.new(r) } 22 | @recipients = json 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /examples/voice_webhook_delete.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Delete a webhook 19 | client.voice_webhook_delete('00000000000000000000') 20 | rescue MessageBird::ErrorException => e 21 | puts 22 | puts 'An error occured while deleting a voice:' 23 | puts 24 | 25 | e.errors.each do |error| 26 | puts " code : #{error.code}" 27 | puts " description : #{error.description}" 28 | puts " parameter : #{error.parameter}" 29 | puts 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /examples/conversation_webhook_delete.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Delete a webhook 19 | client.conversation_webhook_delete('00000000000000000000000000000000') 20 | rescue MessageBird::ErrorException => e 21 | puts 22 | puts 'An error occured while creating a conversation:' 23 | puts 24 | 25 | e.errors.each do |error| 26 | puts " code : #{error.code}" 27 | puts " description : #{error.description}" 28 | puts " parameter : #{error.parameter}" 29 | puts 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/messagebird.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | libdir = File.dirname(__FILE__) 4 | $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir) 5 | 6 | require 'messagebird/version' 7 | require 'messagebird/balance' 8 | require 'messagebird/client' 9 | require 'messagebird/contact' 10 | require 'messagebird/error' 11 | require 'messagebird/group_reference' 12 | require 'messagebird/hlr' 13 | require 'messagebird/http_client' 14 | require 'messagebird/message_reference' 15 | require 'messagebird/signed_request' # @deprecated 16 | require 'messagebird/request_validator' 17 | require 'messagebird/verify' 18 | require 'messagebird/message' 19 | require 'messagebird/voicemessage' 20 | require 'messagebird/callflow' 21 | require 'messagebird/voice/call' 22 | require 'messagebird/voice/call_leg' 23 | require 'messagebird/voice/call_leg_recording' 24 | require 'messagebird/voice/transcription' 25 | require 'messagebird/voice/webhook' 26 | -------------------------------------------------------------------------------- /examples/call.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 6 | require 'messagebird' 7 | 8 | ACCESS_KEY = 'YOUR ACCESS KEY HERE' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | begin 16 | # Create a MessageBird client with the specified ACCESS_KEY. 17 | client = MessageBird::Client.new(ACCESS_KEY) 18 | 19 | # Start a conversation 20 | calls = client.call_list(10, 0) 21 | 22 | calls.items.each do |call| 23 | puts "Call ID: #{call.id}" 24 | end 25 | rescue MessageBird::ErrorException => e 26 | puts 27 | puts 'An error occured while listing the calls:' 28 | puts 29 | 30 | e.errors.each do |error| 31 | puts " code : #{error.code}" 32 | puts " description : #{error.description}" 33 | puts " parameter : #{error.parameter}" 34 | puts 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/messagebird/contact.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | require 'messagebird/custom_details' 5 | require 'messagebird/group_reference' 6 | require 'messagebird/message_reference' 7 | 8 | module MessageBird 9 | class Contact < MessageBird::Base 10 | attr_accessor :id, :href, :msisdn, :first_name, :last_name 11 | attr_reader :custom_details, :groups, :messages, :created_datetime, :updated_datetime 12 | 13 | def custom_details=(value) 14 | @custom_details = MessageBird::CustomDetails.new(value) 15 | end 16 | 17 | def groups=(value) 18 | @groups = MessageBird::GroupReference.new(value) 19 | end 20 | 21 | def messages=(value) 22 | @messages = MessageBird::MessageReference.new(value) 23 | end 24 | 25 | def created_datetime=(value) 26 | @created_datetime = value_to_time(value) 27 | end 28 | 29 | def updated_datetime=(value) 30 | @updated_datetime = value_to_time(value) 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/base_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe '#map_hash_elements_to_self' do 4 | context 'hash is nil' do 5 | it 'doesnt raise errors' do 6 | expect { @contact = MessageBird::Contact.new(nil) }.not_to raise_error 7 | end 8 | end 9 | 10 | context 'hash is a contact' do 11 | before(:all) do 12 | @contact = MessageBird::Contact.new( 13 | 'id' => '03dfc27855c3475b953d6200a1b7eaf7', 14 | 'msisdn' => '+31600000000', 15 | 'firstName' => 'John', 16 | 'lastName' => 'Doe' 17 | ) 18 | end 19 | 20 | it 'contains an id' do 21 | expect(@contact.id).to be('03dfc27855c3475b953d6200a1b7eaf7') 22 | end 23 | 24 | it 'contains a msisdn' do 25 | expect(@contact.msisdn).to be('+31600000000') 26 | end 27 | 28 | it 'contains a first name' do 29 | expect(@contact.first_name).to be('John') 30 | end 31 | 32 | it 'contains a last name' do 33 | expect(@contact.last_name).to be('Doe') 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | NewCops: enable 3 | TargetRubyVersion: 3.0.3 4 | # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop 5 | # to ignore them, so only the ones explicitly set in this file are enabled. 6 | # DisabledByDefault: true 7 | Exclude: 8 | - Gemfile 9 | - "*.gemspec" 10 | - "vendor/**/*" 11 | Metrics/ClassLength: 12 | Enabled: false 13 | Metrics/MethodLength: 14 | Enabled: false 15 | Layout/LineLength: 16 | Enabled: false 17 | Metrics/AbcSize: 18 | Enabled: false 19 | Metrics/CyclomaticComplexity: 20 | Enabled: false 21 | Metrics/BlockLength: 22 | Enabled: false 23 | Style/Documentation: 24 | Enabled: false 25 | Style/GuardClause: 26 | Enabled: false 27 | Style/ConditionalAssignment: 28 | Enabled: false 29 | Style/IfUnlessModifier: 30 | Enabled: false 31 | Style/WordArray: 32 | Enabled: false 33 | Layout/ClosingParenthesisIndentation: 34 | Enabled: false 35 | Style/PercentLiteralDelimiters: 36 | Enabled: false 37 | Style/SymbolArray: 38 | Enabled: false 39 | -------------------------------------------------------------------------------- /spec/error_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Error' do 4 | it 'raises returned errors' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .and_return('{"errors":[{"code": 2,"description": "Request not allowed (incorrect access_key)","parameter": "access_key"}]}') 11 | 12 | expect { client.message('some-id') }.to raise_error(MessageBird::ErrorException, 'Request not allowed (incorrect access_key) (error code: 2, parameter: access_key)') 13 | end 14 | 15 | context 'server responds with an invalid HTTP status code' do 16 | it 'raises ServerException' do 17 | stub_request(:any, /#{MessageBird::HttpClient::ENDPOINT}/) 18 | .to_return(status: 500) 19 | 20 | client = MessageBird::Client.new 21 | 22 | expect { client.message('some-id') }.to raise_error(MessageBird::ServerException, 'Unknown response from server') 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /examples/balance.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'test_gshuPaZoeEG6ovbc8M79w0QyM' 8 | 9 | begin 10 | # Create a MessageBird client with the specified ACCESS_KEY. 11 | client = MessageBird::Client.new(ACCESS_KEY) 12 | 13 | # Fetch the Balance object. 14 | balance = client.balance 15 | 16 | # Print the object information. 17 | puts 18 | puts 'The following information was returned as a Balance object:' 19 | puts 20 | puts " payment : #{balance.payment}" 21 | puts " type : #{balance.type}" 22 | puts " amount : #{balance.amount}" 23 | puts 24 | rescue MessageBird::ErrorException => e 25 | puts 26 | puts 'An error occured while requesting a Balance object:' 27 | puts 28 | 29 | e.errors.each do |error| 30 | puts " code : #{error.code}" 31 | puts " description : #{error.description}" 32 | puts " parameter : #{error.parameter}" 33 | puts 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/hlr_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'HLR' do 4 | it 'views an existing' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'hlr/hlr-id', {}) 11 | .and_return('{"id":"hlr-id","href":"https://rest.messagebird.com/hlr/hlr-id","msisdn":31612345678,"network":20406,"reference":"MyReference","status": "sent","createdDatetime": "2015-01-04T13:14:08+00:00","statusDatetime": "2015-01-04T13:14:09+00:00"}') 12 | 13 | hlr = client.hlr('hlr-id') 14 | 15 | expect(hlr.id).to eq 'hlr-id' 16 | end 17 | 18 | it 'requests a HLR' do 19 | http_client = double(MessageBird::HttpClient) 20 | client = MessageBird::Client.new('', http_client) 21 | 22 | expect(http_client) 23 | .to receive(:request) 24 | .with(:post, 'hlr', { msisdn: 31_612_345_678, reference: 'MyReference' }) 25 | .and_return('{}') 26 | 27 | client.hlr_create(31_612_345_678, 'MyReference') 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /.github/workflows/gh-release.yml: -------------------------------------------------------------------------------- 1 | name: Github Release 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | create-release: 9 | name: Create Release 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | - name: Setup git 15 | run: | 16 | git config user.email "developers@messagebird.com" 17 | git config user.name "MessageBird CI" 18 | - name: Prepare description 19 | run: | 20 | csplit -s CHANGELOG.md "/##/" {1} 21 | cat xx01 > CHANGELOG.tmp 22 | - name: Prepare tag 23 | run: | 24 | export TAG=$(head -1 CHANGELOG.tmp | cut -d' ' -f2) 25 | echo "TAG=$TAG" >> $GITHUB_ENV 26 | - name: Create Release 27 | uses: actions/create-release@v1 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | with: 31 | tag_name: ${{ env.TAG }} 32 | release_name: ${{ env.TAG }} 33 | body_path: CHANGELOG.tmp 34 | draft: false 35 | prerelease: false 36 | -------------------------------------------------------------------------------- /examples/verify_delete.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # VERIFY_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(VERIFY_ID) 16 | puts 'You need to set a VERIFY_ID constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Delete the verify 25 | client.verify_delete(VERIFY_ID) 26 | 27 | # Print the object information. 28 | puts 29 | puts 'Success. The delete method has empty return.' 30 | puts 31 | rescue MessageBird::ErrorException => e 32 | puts 33 | puts 'An error occured while requesting an OTP object:' 34 | puts 35 | 36 | e.errors.each do |error| 37 | puts " code : #{error.code}" 38 | puts " description : #{error.description}" 39 | puts " parameter : #{error.parameter}" 40 | puts 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /examples/number_cancel.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = "31612345670" 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the HLR object for the specified HLR_ID. 24 | response = client.number_cancel(PHONE_NUMBER) 25 | 26 | unless response.nil? 27 | puts 'Number was cancelled' 28 | end 29 | rescue MessageBird::ErrorException => e 30 | puts 31 | puts 'An error occured while requesting the lookup:' 32 | puts 33 | 34 | e.errors.each do |error| 35 | puts " code : #{error.code}" 36 | puts " description : #{error.description}" 37 | puts " parameter : #{error.parameter}" 38 | puts 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /examples/send_conversation_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Send a message 19 | message = client.send_conversation_message('channelID', '+31617100000', type: 'text', content: { text: 'Hi there!' }) 20 | 21 | # Print the object information. 22 | puts 23 | puts 'The following information was returned as a response:' 24 | puts " id : #{message.id}" 25 | puts " status : #{message.status}" 26 | puts " fallback : #{message.fallback}" unless message.fallback.nil? 27 | 28 | puts 29 | rescue MessageBird::ErrorException => e 30 | puts 31 | puts 'An error occured while sending a message:' 32 | puts 33 | 34 | e.errors.each do |error| 35 | puts " code : #{error.code}" 36 | puts " description : #{error.description}" 37 | puts " parameter : #{error.parameter}" 38 | puts 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/request_validator_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'RequestValidator' do 4 | error_map = { 5 | 'invalid jwt: claim nbf is in the future' => 'Signature nbf has not been reached', 6 | 'invalid jwt: claim exp is in the past' => 'Signature has expired', 7 | 'invalid jwt: signing method none is invalid' => 'Expected a different algorithm', 8 | 'invalid jwt: signature is invalid' => 'Signature verification failed' 9 | }.freeze 10 | 11 | path = File.join(File.dirname(__FILE__), './data/webhook_signature_test_data.json') 12 | test_cases = JSON.parse(File.read(path)) 13 | 14 | test_cases.each do |t| 15 | before do 16 | allow(Time).to receive(:now).and_return Time.parse(t['timestamp']) 17 | end 18 | 19 | it t['name'] do 20 | request_validator = MessageBird::RequestValidator.new(t['secret']) 21 | 22 | do_verify = -> { request_validator.validate_signature(t['token'], t['url'], t['payload']) } 23 | 24 | if t['valid'] 25 | expect(do_verify.call).not_to be_empty && include(:iss, :nbf, :exp, :url_hash) 26 | else 27 | err = error_map[t['reason']] || t['reason'] 28 | expect { do_verify.call }.to raise_error(MessageBird::ValidationError, err) 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /examples/voice_webhook_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Create a webhook 19 | webhook = client.voice_webhook_create('https://test.com', token: 'sometoken') 20 | 21 | # Print the object information. 22 | puts 'Webhook:' 23 | puts " id : #{webhook.id}" 24 | puts " url : #{webhook.url}" 25 | puts " status : #{webhook.token}" 26 | puts " createdAt : #{webhook.created_at}" 27 | puts " updatedAt : #{webhook.updated_at}" 28 | rescue MessageBird::ErrorException => e 29 | puts 30 | puts 'An error occured while creating a voice webhook:' 31 | puts 32 | 33 | e.errors.each do |error| 34 | puts " code : #{error.code}" 35 | puts " description : #{error.description}" 36 | puts " parameter : #{error.parameter}" 37 | puts 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /examples/hlr_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'test_gshuPaZoeEG6ovbc8M79w0QyM' 8 | 9 | begin 10 | # Create a MessageBird client with the specified ACCESS_KEY. 11 | client = MessageBird::Client.new(ACCESS_KEY) 12 | 13 | # Create a new HLR object. 14 | hlr = client.hlr_create('31612345678', 'MyReference') 15 | 16 | # Print the object information. 17 | puts 18 | puts 'The following information was returned as an HLR object:' 19 | puts 20 | puts " id : #{hlr.id}" 21 | puts " href : #{hlr.href}" 22 | puts " msisdn : #{hlr.msisdn}" 23 | puts " reference : #{hlr.reference}" 24 | puts " status : #{hlr.status}" 25 | puts " createdDatetime : #{hlr.created_datetime}" 26 | puts " statusDatetime : #{hlr.status_datetime}" 27 | puts 28 | rescue MessageBird::ErrorException => e 29 | puts 30 | puts 'An error occured while requesting an HLR object:' 31 | puts 32 | 33 | e.errors.each do |error| 34 | puts " code : #{error.code}" 35 | puts " description : #{error.description}" 36 | puts " parameter : #{error.parameter}" 37 | puts 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /examples/voice_webhook_update.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Create a webhook 19 | webhook = client.voice_webhook_update('00000000000000000000', url: 'https://other.com', token: 'othertoken') 20 | 21 | # Print the object information. 22 | puts 'Webhook:' 23 | puts " id : #{webhook.id}" 24 | puts " url : #{webhook.url}" 25 | puts " status : #{webhook.token}" 26 | puts " createdAt : #{webhook.created_at}" 27 | puts " updatedAt : #{webhook.updated_at}" 28 | rescue MessageBird::ErrorException => e 29 | puts 30 | puts 'An error occured while updating a voice webhook:' 31 | puts 32 | 33 | e.errors.each do |error| 34 | puts " code : #{error.code}" 35 | puts " description : #{error.description}" 36 | puts " parameter : #{error.parameter}" 37 | puts 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /messagebird-rest.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('../lib', __FILE__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | 6 | require 'messagebird/version' 7 | 8 | Gem::Specification.new do |s| 9 | s.name = 'messagebird-rest' 10 | s.version = MessageBird::Version::STRING 11 | s.platform = Gem::Platform::RUBY 12 | s.required_ruby_version = '>= 3.0' 13 | s.date = Time.now 14 | s.summary = "MessageBird's REST API" 15 | s.description = 'A simple REST API for MessageBird in Ruby' 16 | s.author = 'Maurice Nonnekes' 17 | s.email = 'maurice@messagebird.com' 18 | s.files = `git ls-files lib LICENSE README.md` 19 | .split($RS) 20 | s.homepage = 'https://github.com/messagebird/ruby-rest-api' 21 | s.license = 'BSD-2-Clause' 22 | 23 | s.files = Dir.glob('lib/**/*') + %w(LICENSE README.md) 24 | s.require_path = 'lib' 25 | 26 | # This code works with at least version 3.0.0.beta1 of jwt, 27 | # so we are supporting up to version 4 to help reduce 28 | # the necessity for future version bumps 29 | s.add_dependency "jwt", "< 4" 30 | 31 | s.add_development_dependency "rspec", "~> 3.11.0" 32 | s.add_development_dependency "rubocop", "~> 1.26.1" 33 | s.add_development_dependency 'webmock', '~> 3.14.0' 34 | end 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, MessageBird 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /examples/group_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # GROUP_NAME = 'YOUR GROUP NAME HERE' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(GROUP_NAME) 16 | puts 'You need to set an GROUP_NAME constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Create a new Group object. 25 | group = client.group_create(GROUP_NAME) 26 | 27 | # Print the object information. 28 | puts 29 | puts ' Group :' 30 | puts " id : #{group.id}" 31 | puts " href : #{group.href}" 32 | puts " name : #{group.name}" 33 | puts " contacts : #{group.contacts.href}" 34 | puts 35 | rescue MessageBird::ErrorException => e 36 | puts 37 | puts 'An error occurred while creating a group:' 38 | puts 39 | 40 | e.errors.each do |error| 41 | puts " code : #{error.code}" 42 | puts " description : #{error.description}" 43 | puts " parameter : #{error.parameter}" 44 | puts 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /examples/verify_email_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # MESSAGE_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(MESSAGE_ID) 16 | puts 'You need to set a MESSAGE_ID constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Generate a new OTP message using an email as recipient 25 | verify_message = client.verify_email_message(MESSAGE_ID) 26 | 27 | # Print the object information. 28 | puts 29 | puts 'The following information was returned as Verify Email Message object:' 30 | puts 31 | puts " id : #{verify_message.id}" 32 | puts " status : #{verify_message.status}" 33 | puts 34 | rescue MessageBird::ErrorException => e 35 | puts 36 | puts 'An error occured while requesting an OTP object:' 37 | puts 38 | 39 | e.errors.each do |error| 40 | puts " code : #{error.code}" 41 | puts " description : #{error.description}" 42 | puts " parameter : #{error.parameter}" 43 | puts 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /examples/number_search.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the HLR object for the specified HLR_ID. 19 | numbers = client.number_search('NL', limit: 5) 20 | 21 | # Print the object information. 22 | puts 'The folling numbers was returned as a list of Number objects' 23 | puts 24 | numbers.items.each do |number| 25 | puts " number : #{number.number}" 26 | puts " country : #{number.country}" 27 | puts " region : #{number.region}" 28 | puts " locality : #{number.locality}" 29 | puts " features : #{number.features}" 30 | puts " type : #{number.type}" 31 | end 32 | rescue MessageBird::ErrorException => e 33 | puts 34 | puts 'An error occured while requesting the lookup:' 35 | puts 36 | 37 | e.errors.each do |error| 38 | puts " code : #{error.code}" 39 | puts " description : #{error.description}" 40 | puts " parameter : #{error.parameter}" 41 | puts 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/messagebird/conversation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | require 'messagebird/contact' 5 | require 'messagebird/conversation_channel' 6 | 7 | module MessageBird 8 | class Conversation < MessageBird::Base 9 | attr_accessor :id, :status, :last_used_channel_id, :contact_id 10 | attr_reader :contact, :channels, :messages, :created_datetime, 11 | :updated_datetime, :last_received_datetime 12 | 13 | CONVERSATION_STATUS_ACTIVE = 'active' 14 | CONVERSATION_STATUS_ARCHIVED = 'archived' 15 | WEBHOOK_EVENT_CONVERSATION_CREATED = 'conversation.created' 16 | WEBHOOK_EVENT_CONVERSATION_UPDATED = 'conversation.updated' 17 | WEBHOOK_EVENT_MESSAGE_CREATED = 'message.created' 18 | WEBHOOK_EVENT_MESSAGE_UPDATED = 'message.updated' 19 | 20 | def contact=(value) 21 | @contact = Contact.new(value) 22 | end 23 | 24 | def channels=(json) 25 | @channels = json.map { |c| MessageBird::ConversationChannel.new(c) } 26 | end 27 | 28 | def messages=(value) 29 | @messages = MessageBird::MessageReference.new(value) 30 | end 31 | 32 | def created_datetime=(value) 33 | @created_datetime = value_to_time(value) 34 | end 35 | 36 | def updated_datetime=(value) 37 | @updated_datetime = value_to_time(value) 38 | end 39 | 40 | def last_received_datetime=(value) 41 | @last_received_datetime = value_to_time(value) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/message_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Message' do 4 | it 'reads an existing' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'messages/message-id', {}) 11 | .and_return('{"body": "Hello World","createdDatetime": "2015-01-05T10:02:59+00:00","datacoding": "plain","direction": "mt","gateway": 239,"href": "https://rest.messagebird.com/messages/message-id","id": "message-id","mclass": 1,"originator": "TestName","recipients": {"items": [{"recipient": 31612345678,"status": "sent","statusDatetime": "2015-01-05T10:02:59+00:00"}],"totalCount": 1,"totalDeliveredCount": 0,"totalDeliveryFailedCount": 0,"totalSentCount": 1},"reference": null,"scheduled_date_time": null,"type": "sms","typeDetails": {},"validity": null}') 12 | 13 | message = client.message('message-id') 14 | 15 | expect(message.id).to eq 'message-id' 16 | end 17 | 18 | it 'creates' do 19 | http_client = double(MessageBird::HttpClient) 20 | client = MessageBird::Client.new('', http_client) 21 | 22 | expect(http_client) 23 | .to receive(:request) 24 | .with(:post, 'messages', { originator: 'MBTest', recipients: 31_612_345_678, body: 'Hello world', reference: 'Foo' }) 25 | .and_return('{}') 26 | 27 | client.message_create('MBTest', 31_612_345_678, 'Hello world', reference: 'Foo') 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /examples/conversation_webhook.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Get a webhook 19 | webhook = client.conversation_webhook('00000000000000000000000000000000') 20 | 21 | # Print the object information. 22 | puts 'The following information was returned as a Webhook object' 23 | puts " id : #{webhook.id}" 24 | puts " events : #{webhook.events}" 25 | puts " channelId : #{webhook.channel_id}" 26 | puts " url : #{webhook.url}" 27 | puts " status : #{webhook.status}" 28 | puts " createdDatetime : #{webhook.created_datetime}" 29 | puts " updatedDatetime : #{webhook.updated_datetime}" 30 | rescue MessageBird::ErrorException => e 31 | puts 32 | puts 'An error occured while creating a conversation:' 33 | puts 34 | 35 | e.errors.each do |error| 36 | puts " code : #{error.code}" 37 | puts " description : #{error.description}" 38 | puts " parameter : #{error.parameter}" 39 | puts 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /examples/hlr.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # HLR_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | puts 'You need to set an HLR_ID constant in this file' unless defined?(HLR_ID) 16 | 17 | begin 18 | # Create a MessageBird client with the specified ACCESS_KEY. 19 | client = MessageBird::Client.new(ACCESS_KEY) 20 | 21 | # Fetch the HLR object for the specified HLR_ID. 22 | hlr = client.hlr(HLR_ID) 23 | 24 | # Print the object information. 25 | puts 26 | puts 'The following information was returned as an HLR object:' 27 | puts 28 | puts " id : #{hlr.id}" 29 | puts " href : #{hlr.href}" 30 | puts " msisdn : #{hlr.msisdn}" 31 | puts " reference : #{hlr.reference}" 32 | puts " status : #{hlr.status}" 33 | puts " createdDatetime : #{hlr.created_datetime}" 34 | puts " statusDatetime : #{hlr.status_datetime}" 35 | puts 36 | rescue MessageBird::ErrorException => e 37 | puts 38 | puts 'An error occured while requesting an HLR object:' 39 | puts 40 | 41 | e.errors.each do |error| 42 | puts " code : #{error.code}" 43 | puts " description : #{error.description}" 44 | puts " parameter : #{error.parameter}" 45 | puts 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /examples/verify_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Generate a new OTP message 19 | otp = client.verify_create(31_612_345_678, reference: 'MessageBirdReference') 20 | 21 | # Print the object information. 22 | puts 23 | puts 'The following information was returned as an OTP object:' 24 | puts 25 | puts " id : #{otp.id}" 26 | puts " href : #{otp.href}" 27 | puts " recipient : #{otp.recipient}" 28 | puts " reference : #{otp.reference}" 29 | puts " messages : #{otp.messages}" 30 | puts " status : #{otp.status}" 31 | puts " createdDatetime : #{otp.created_datetime}" 32 | puts " validUntilDatetime : #{otp.valid_until_datetime}" 33 | puts 34 | rescue MessageBird::ErrorException => e 35 | puts 36 | puts 'An error occured while requesting an OTP object:' 37 | puts 38 | 39 | e.errors.each do |error| 40 | puts " code : #{error.code}" 41 | puts " description : #{error.description}" 42 | puts " parameter : #{error.parameter}" 43 | puts 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /examples/number_fetch.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = "31612345670" 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the HLR object for the specified HLR_ID. 24 | number = client.number_fetch(PHONE_NUMBER) 25 | 26 | # Print the object information. 27 | puts 'The folling number was returned as a Number object' 28 | puts 29 | puts " number : #{number.number}" 30 | puts " country : #{number.country}" 31 | puts " region : #{number.region}" 32 | puts " locality : #{number.locality}" 33 | puts " features : #{number.features}" 34 | puts " tags : #{number.tags}" 35 | puts " type : #{number.type}" 36 | puts " status : #{number.status}" 37 | rescue MessageBird::ErrorException => e 38 | puts 39 | puts 'An error occured while requesting the lookup:' 40 | puts 41 | 42 | e.errors.each do |error| 43 | puts " code : #{error.code}" 44 | puts " description : #{error.description}" 45 | puts " parameter : #{error.parameter}" 46 | puts 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /examples/conversation_webhook_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Create a webhook 19 | webhook = client.conversation_webhook_create('00000000000000000000000000000000', 'https://test.com', [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_UPDATED]) 20 | 21 | # Print the object information. 22 | puts 'The following information was returned as a Webhook object' 23 | puts " id : #{webhook.id}" 24 | puts " events : #{webhook.events}" 25 | puts " channelId : #{webhook.channel_id}" 26 | puts " url : #{webhook.url}" 27 | puts " status : #{webhook.status}" 28 | puts " createdDatetime : #{webhook.created_datetime}" 29 | puts " updatedDatetime : #{webhook.updated_datetime}" 30 | rescue MessageBird::ErrorException => e 31 | puts 32 | puts 'An error occured while creating a conversation:' 33 | puts 34 | 35 | e.errors.each do |error| 36 | puts " code : #{error.code}" 37 | puts " description : #{error.description}" 38 | puts " parameter : #{error.parameter}" 39 | puts 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /examples/conversation_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch a message 19 | msg = client.conversation_message('00000000000000000000000000000000') 20 | 21 | # Print the object information. 22 | puts <<~INFO 23 | The following information was returned as a Message object: 24 | id : #{msg.id} 25 | conversationId : #{msg.conversation_id} 26 | channelId : #{msg.channel_id} 27 | direction : #{msg.direction} 28 | type : #{msg.type} 29 | status : #{msg.status} 30 | content : #{msg.content} 31 | createdDatetime : #{msg.created_datetime} 32 | updatedDatetime : #{msg.updated_datetime} 33 | INFO 34 | rescue MessageBird::ErrorException => e 35 | puts 36 | puts 'An error occured while creating a conversation:' 37 | puts 38 | 39 | e.errors.each do |error| 40 | puts " code : #{error.code}" 41 | puts " description : #{error.description}" 42 | puts " parameter : #{error.parameter}" 43 | puts 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /examples/conversation_webhook_update.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Update a webhook 19 | webhook = client.conversation_webhook_update('00000000000000000000000000000000', url: 'https://test.com', events: [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_CREATED]) 20 | 21 | # Print the object information. 22 | puts 'The following information was returned as a Webhook object' 23 | puts " id : #{webhook.id}" 24 | puts " events : #{webhook.events}" 25 | puts " channelId : #{webhook.channel_id}" 26 | puts " url : #{webhook.url}" 27 | puts " status : #{webhook.status}" 28 | puts " createdDatetime : #{webhook.created_datetime}" 29 | puts " updatedDatetime : #{webhook.updated_datetime}" 30 | rescue MessageBird::ErrorException => e 31 | puts 32 | puts 'An error occured while creating a conversation:' 33 | puts 34 | 35 | e.errors.each do |error| 36 | puts " code : #{error.code}" 37 | puts " description : #{error.description}" 38 | puts " parameter : #{error.parameter}" 39 | puts 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /examples/number_fetch_all.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the HLR object for the specified HLR_ID. 19 | numbers = client.number_fetch_all(limit: 5) 20 | 21 | # Print the object information. 22 | puts 'The folling number was returned as a Number object' 23 | puts 24 | 25 | if numbers.positive? 26 | numbers.items.each do |number| 27 | puts " number : #{number.number}" 28 | puts " country : #{number.country}" 29 | puts " region : #{number.region}" 30 | puts " locality : #{number.locality}" 31 | puts " features : #{number.features}" 32 | puts " tags : #{number.tags}" 33 | puts " type : #{number.type}" 34 | puts " status : #{number.status}" 35 | end 36 | else 37 | puts 'No records returned' 38 | end 39 | rescue MessageBird::ErrorException => e 40 | puts 41 | puts 'An error occured while requesting the lookup:' 42 | puts 43 | 44 | e.errors.each do |error| 45 | puts " code : #{error.code}" 46 | puts " description : #{error.description}" 47 | puts " parameter : #{error.parameter}" 48 | puts 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /examples/lookup_hlr.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = '+31612345678' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Do a new HLR lookup. 25 | hlr = client.lookup_hlr(PHONE_NUMBER) 26 | 27 | # Print the object information. 28 | puts 29 | puts 'The following information was returned as an HLR object:' 30 | puts 31 | puts " id : #{hlr.id}" 32 | puts " href : #{hlr.href}" 33 | puts " msisdn : #{hlr.msisdn}" 34 | puts " reference : #{hlr.reference}" 35 | puts " status : #{hlr.status}" 36 | puts " details : #{hlr.details}" 37 | puts " createdDatetime : #{hlr.created_datetime}" 38 | puts " statusDatetime : #{hlr.status_datetime}" 39 | puts 40 | rescue MessageBird::ErrorException => e 41 | puts 42 | puts 'An error occured while requesting an HLR object:' 43 | puts 44 | 45 | e.errors.each do |error| 46 | puts " code : #{error.code}" 47 | puts " description : #{error.description}" 48 | puts " parameter : #{error.parameter}" 49 | puts 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/conversation_reply.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Reply to a conversation 19 | msg = client.conversation_reply('00000000000000000000000000000000', type: 'text', content: { text: 'Hi there' }) 20 | 21 | # Print the object information. 22 | puts <<~INFO 23 | The following information was returned as a Message object: 24 | id : #{msg.id} 25 | conversationId : #{msg.conversation_id} 26 | channelId : #{msg.channel_id} 27 | direction : #{msg.direction} 28 | type : #{msg.type} 29 | status : #{msg.status} 30 | content : #{msg.content} 31 | createdDatetime : #{msg.created_datetime} 32 | updatedDatetime : #{msg.updated_datetime} 33 | INFO 34 | rescue MessageBird::ErrorException => e 35 | puts 36 | puts 'An error occured while updating a conversation:' 37 | puts 38 | 39 | e.errors.each do |error| 40 | puts " code : #{error.code}" 41 | puts " description : #{error.description}" 42 | puts " parameter : #{error.parameter}" 43 | puts 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /examples/verify.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # VERIFY_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(VERIFY_ID) 16 | puts 'You need to set a VERIFY_ID constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Generate a new OTP message using an email as recipient 25 | otp = client.verify(VERIFY_ID) 26 | 27 | # Print the object information. 28 | puts 29 | puts 'The following information was returned as an OTP object:' 30 | puts 31 | puts " id : #{otp.id}" 32 | puts " href : #{otp.href}" 33 | puts " recipient : #{otp.recipient}" 34 | puts " reference : #{otp.reference}" 35 | puts " messages : #{otp.messages}" 36 | puts " status : #{otp.status}" 37 | puts " createdDatetime : #{otp.created_datetime}" 38 | puts " validUntilDatetime : #{otp.valid_until_datetime}" 39 | puts 40 | rescue MessageBird::ErrorException => e 41 | puts 42 | puts 'An error occured while requesting an OTP object:' 43 | puts 44 | 45 | e.errors.each do |error| 46 | puts " code : #{error.code}" 47 | puts " description : #{error.description}" 48 | puts " parameter : #{error.parameter}" 49 | puts 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/lookup_hlr_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = '+31612345678' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Create a new HLR object. 25 | hlr = client.lookup_hlr_create(PHONE_NUMBER, reference: 'Reference') 26 | 27 | # Print the object information. 28 | puts 29 | puts 'The following information was returned as an HLR object:' 30 | puts 31 | puts " id : #{hlr.id}" 32 | puts " href : #{hlr.href}" 33 | puts " msisdn : #{hlr.msisdn}" 34 | puts " reference : #{hlr.reference}" 35 | puts " status : #{hlr.status}" 36 | puts " details : #{hlr.details}" 37 | puts " createdDatetime : #{hlr.created_datetime}" 38 | puts " statusDatetime : #{hlr.status_datetime}" 39 | puts 40 | rescue MessageBird::ErrorException => e 41 | puts 42 | puts 'An error occured while requesting an HLR object:' 43 | puts 44 | 45 | e.errors.each do |error| 46 | puts " code : #{error.code}" 47 | puts " description : #{error.description}" 48 | puts " parameter : #{error.parameter}" 49 | puts 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/call_legs.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 6 | require 'messagebird' 7 | 8 | ACCESS_KEY = 'YOUR ACCESS KEY HERE' 9 | CALL_ID = 'YOUR CALL ID HERE' 10 | 11 | unless defined?(ACCESS_KEY) 12 | puts 'You need to set an ACCESS_KEY constant in this file' 13 | exit 1 14 | end 15 | 16 | begin 17 | # Create a MessageBird client with the specified ACCESS_KEY. 18 | client = MessageBird::Client.new(ACCESS_KEY) 19 | 20 | # Start a conversation 21 | legs = client.call_leg_list(CALL_ID, 10, 0) 22 | 23 | legs.items.each do |leg_obj| 24 | puts "leg ID: #{leg_obj.id}" 25 | puts " callId : #{leg_obj.call_id}" 26 | puts " source : #{leg_obj.source}" 27 | puts " destination : #{leg_obj.destination}" 28 | puts " status : #{leg_obj.status}" 29 | puts " direction : #{leg_obj.direction}" 30 | puts " cost : #{leg_obj.cost}" 31 | puts " currency : #{leg_obj.currency}" 32 | puts " duration : #{leg_obj.duration}" 33 | puts " createdAt : #{leg_obj.created_at}" 34 | puts " updatedAt : #{leg_obj.updated_at}" 35 | puts " answeredAt : #{leg_obj.answered_at}" 36 | puts " endedAt : #{leg_obj.ended_at}" 37 | end 38 | rescue MessageBird::ErrorException => e 39 | puts 40 | puts 'An error occured while listing the calls:' 41 | puts 42 | 43 | e.errors.each do |error| 44 | puts " code : #{error.code}" 45 | puts " description : #{error.description}" 46 | puts " parameter : #{error.parameter}" 47 | puts 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /examples/voice_message_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'test_gshuPaZoeEG6ovbc8M79w0QyM' 8 | 9 | begin 10 | # Create a MessageBird client with the specified ACCESS_KEY. 11 | client = MessageBird::Client.new(ACCESS_KEY) 12 | 13 | # Send a new voice message. 14 | vmsg = client.voice_message_create('31612345678', 'Hello World', reference: 'Foobar') 15 | 16 | # Print the object information. 17 | puts 18 | puts 'The following information was returned as a VoiceMessage object:' 19 | puts 20 | puts " id : #{vmsg.id}" 21 | puts " href : #{vmsg.href}" 22 | puts " originator : #{vmsg.originator}" 23 | puts " body : #{vmsg.body}" 24 | puts " reference : #{vmsg.reference}" 25 | puts " language : #{vmsg.language}" 26 | puts " voice : #{vmsg.voice}" 27 | puts " repeat : #{vmsg.repeat}" 28 | puts " ifMachine : #{vmsg.if_machine}" 29 | puts " scheduledDateTime : #{vmsg.scheduled_date_time}" 30 | puts " createdDatetime : #{vmsg.created_datetime}" 31 | puts " recipients : #{vmsg.recipients}" 32 | puts 33 | rescue MessageBird::ErrorException => e 34 | puts 35 | puts 'An error occured while requesting an VoiceMessage object:' 36 | puts 37 | 38 | e.errors.each do |error| 39 | puts " code : #{error.code}" 40 | puts " description : #{error.description}" 41 | puts " parameter : #{error.parameter}" 42 | puts 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /examples/number_update.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = "31612345670" 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the HLR object for the specified HLR_ID. 24 | number = client.number_update(PHONE_NUMBER, ['tag1', 'tag2']) 25 | 26 | # Print the object information. 27 | puts 'The folling number was returned as a Number object' 28 | puts 29 | puts " number : #{number.number}" 30 | puts " country : #{number.country}" 31 | puts " region : #{number.region}" 32 | puts " locality : #{number.locality}" 33 | puts " features : #{number.features}" 34 | puts " tags : #{number.tags}" 35 | puts " type : #{number.type}" 36 | puts " status : #{number.status}" 37 | puts " createdAt : #{number.createdAt}" 38 | puts " renewalAt : #{number.renewalAt}" 39 | rescue MessageBird::ErrorException => e 40 | puts 41 | puts 'An error occured while requesting the lookup:' 42 | puts 43 | 44 | e.errors.each do |error| 45 | puts " code : #{error.code}" 46 | puts " description : #{error.description}" 47 | puts " parameter : #{error.parameter}" 48 | puts 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /examples/voice_webhooks_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the Webhooks list 19 | # page start from 1 20 | page = 1 21 | per_page = 10 22 | webhooks = client.voice_webhooks_list(per_page, page) 23 | 24 | # Print the object information. 25 | puts 'The following information was returned as a Webhooks list:' 26 | puts 27 | puts " pageCount : #{webhooks.page_count}" 28 | puts " currentPage : #{webhooks.current_page}" 29 | puts " perPage : #{webhooks.per_page}" 30 | puts " totalCount : #{webhooks.total_count}" 31 | puts 32 | webhooks.items.each do |webhook| 33 | puts 'Webhook:' 34 | puts " id : #{webhook.id}" 35 | puts " url : #{webhook.url}" 36 | puts " status : #{webhook.token}" 37 | puts " createdAt : #{webhook.created_at}" 38 | puts " updatedAt : #{webhook.updated_at}" 39 | end 40 | rescue MessageBird::ErrorException => e 41 | puts 42 | puts 'An error occured while creating a voice:' 43 | puts 44 | 45 | e.errors.each do |error| 46 | puts " code : #{error.code}" 47 | puts " description : #{error.description}" 48 | puts " parameter : #{error.parameter}" 49 | puts 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/messagebird/callflow.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'messagebird/base' 4 | 5 | module MessageBird 6 | class CallFlow < MessageBird::Base 7 | attr_accessor :id, :title, :record, :default 8 | attr_reader :steps, :created_at, :updated_at 9 | 10 | def initialize(json) 11 | params = json.include?('data') ? json['data'].first : json 12 | super(params) 13 | end 14 | 15 | def steps=(json) 16 | @steps = json.map { |c| MessageBird::CallFlowStep.new(c) } 17 | end 18 | 19 | def created_at=(value) 20 | @created_at = value_to_time(value) 21 | end 22 | 23 | def updated_at=(value) 24 | @updated_at = value_to_time(value) 25 | end 26 | end 27 | 28 | class CallFlowList < List 29 | attr_accessor :per_page, :current_page, :page_count, :total_count 30 | 31 | PER_PAGE = 20 32 | CURRENT_PAGE = 1 33 | 34 | def data=(value) 35 | self.items = value 36 | end 37 | 38 | def pagination=(value) 39 | value.each do |k, v| 40 | send("#{k}=", v) 41 | rescue NoMethodError 42 | puts 'An error occurred while listing callflows' 43 | end 44 | end 45 | end 46 | 47 | class CallFlowStep < MessageBird::Base 48 | attr_accessor :id, :action 49 | 50 | def options=(json) 51 | @options = CallFlowStepOption.new(json) 52 | end 53 | end 54 | 55 | class CallFlowStepOption < MessageBird::Base 56 | attr_accessor :destination, :payload, :language, :voice, :repeat, 57 | :media, :length, :max_length, :timeout, :finish_on_key, :transcribe, 58 | :transcribe_language, :record, :url, :if_machine, :machine_timeout, 59 | :on_finish, :mask 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /examples/group_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'YOUR KEY HERE' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the Group list with pagination options (skip the first 5 objects and take 10). 19 | limit = 10 20 | offset = 5 21 | groups = client.group_list(limit, offset) 22 | 23 | # Print the object information. 24 | puts 25 | puts 'The following information was returned as a Group list:' 26 | puts 27 | puts " count : #{groups.count}" 28 | puts " limit : #{groups.limit}" 29 | puts " offset : #{groups.offset}" 30 | puts " totalCount : #{groups.total_count}" 31 | puts " links : #{groups.links}" 32 | 33 | unless groups.items.empty? 34 | group = groups[0] # Equivalent to groups.items[0] 35 | 36 | puts ' Group :' 37 | puts " id : #{group.id}" 38 | puts " href : #{group.href}" 39 | puts " name : #{group.name}" 40 | puts " contacts : #{group.contacts.href}" 41 | end 42 | rescue MessageBird::ErrorException => e 43 | puts 44 | puts 'An error occurred while listing your groups:' 45 | puts 46 | 47 | e.errors.each do |error| 48 | puts " code : #{error.code}" 49 | puts " description : #{error.description}" 50 | puts " parameter : #{error.parameter}" 51 | puts 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /examples/verify_token.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # VERIFY_ID = '' 9 | # TOKEN = '' 10 | 11 | unless defined?(ACCESS_KEY) 12 | puts 'You need to set an ACCESS_KEY constant in this file' 13 | exit 1 14 | end 15 | 16 | unless defined?(VERIFY_ID) 17 | puts 'You need to set an VERIFY_ID constant in this file' 18 | exit 1 19 | end 20 | 21 | unless defined?(TOKEN) 22 | puts 'You need to set an TOKEN constant in this file' 23 | exit 1 24 | end 25 | 26 | begin 27 | # Create a MessageBird client with the specified ACCESS_KEY. 28 | client = MessageBird::Client.new(ACCESS_KEY) 29 | 30 | # Verify an OTP message with a token 31 | otp = client.verify_token(VERIFY_ID, TOKEN) 32 | 33 | # Print the object information. 34 | puts 35 | puts 'The following information was returned as an OTP object:' 36 | puts 37 | puts " id : #{otp.id}" 38 | puts " href : #{otp.href}" 39 | puts " recipient : #{otp.recipient}" 40 | puts " reference : #{otp.reference}" 41 | puts " messages : #{otp.messages}" 42 | puts " status : #{otp.status}" 43 | puts " createdDatetime : #{otp.created_datetime}" 44 | puts " validUntilDatetime : #{otp.valid_until_datetime}" 45 | puts 46 | rescue MessageBird::ErrorException => e 47 | puts 48 | puts 'An error occured while requesting an OTP object:' 49 | puts 50 | 51 | e.errors.each do |error| 52 | puts " code : #{error.code}" 53 | puts " description : #{error.description}" 54 | puts " parameter : #{error.parameter}" 55 | puts 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /examples/conversation_update.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Update a conversation 19 | conversation = client.conversation_update('57b96dbe0fda40f0a814f5e3268c30a9', MessageBird::Conversation::CONVERSATION_STATUS_ACTIVE) 20 | 21 | # Print the object information. 22 | puts <<~INFO 23 | The following information was returned as an updated conversation object: 24 | id : #{conversation.id} 25 | status : #{conversation.status} 26 | contactId : #{conversation.contact_id} 27 | createdDatetime : #{conversation.created_datetime} 28 | updatedDatetime : #{conversation.updated_datetime} 29 | lastReceivedDateklme : #{conversation.last_received_datetime} 30 | lastUsedChannelId : #{conversation.last_used_channel_id} 31 | Messages : 32 | href : #{conversation.messages.href} 33 | totalCount : #{conversation.messages.total_count} 34 | INFO 35 | rescue MessageBird::ErrorException => e 36 | puts 37 | puts 'An error occured while updating a conversation:' 38 | puts 39 | 40 | e.errors.each do |error| 41 | puts " code : #{error.code}" 42 | puts " description : #{error.description}" 43 | puts " parameter : #{error.parameter}" 44 | puts 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /examples/message_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'test_gshuPaZoeEG6ovbc8M79w0QyM' 8 | 9 | begin 10 | # Create a MessageBird client with the specified ACCESS_KEY. 11 | client = MessageBird::Client.new(ACCESS_KEY) 12 | 13 | # Send a new message. 14 | msg = client.message_create('FromMe', '31612345678', 'Hello World', reference: 'Foobar') 15 | 16 | # Print the object information. 17 | puts 18 | puts 'The following information was returned as a Message object:' 19 | puts 20 | puts " id : #{msg.id}" 21 | puts " href : #{msg.href}" 22 | puts " direction : #{msg.direction}" 23 | puts " type : #{msg.type}" 24 | puts " originator : #{msg.originator}" 25 | puts " body : #{msg.body}" 26 | puts " reference : #{msg.reference}" 27 | puts " validity : #{msg.validity}" 28 | puts " gateway : #{msg.gateway}" 29 | puts " typeDetails : #{msg.typeDetails}" 30 | puts " datacoding : #{msg.datacoding}" 31 | puts " mclass : #{msg.mclass}" 32 | puts " scheduledDateTime : #{msg.scheduled_date_time}" 33 | puts " createdDatetime : #{msg.created_datetime}" 34 | puts " recipients : #{msg.recipients}" 35 | puts 36 | rescue MessageBird::ErrorException => e 37 | puts 38 | puts 'An error occured while requesting a Message object:' 39 | puts 40 | 41 | e.errors.each do |error| 42 | puts " code : #{error.code}" 43 | puts " description : #{error.description}" 44 | puts " parameter : #{error.parameter}" 45 | puts 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /examples/conversation_webhooks_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the Webhooks list 19 | offset = 0 20 | limit = 10 21 | webhooks = client.conversation_webhooks_list(limit, offset) 22 | 23 | # Print the object information. 24 | puts 'The following information was returned as a Webhooks list:' 25 | puts 26 | puts " count : #{webhooks.count}" 27 | puts " limit : #{webhooks.limit}" 28 | puts " offset : #{webhooks.offset}" 29 | puts " totalCount : #{webhooks.total_count}" 30 | puts 31 | webhooks.items.each do |webhook| 32 | puts 'Webhook:' 33 | puts " id : #{webhook.id}" 34 | puts " events : #{webhook.events}" 35 | puts " channelId : #{webhook.channel_id}" 36 | puts " url : #{webhook.url}" 37 | puts " status : #{webhook.status}" 38 | puts " createdDatetime : #{webhook.created_datetime}" 39 | puts " updatedDatetime : #{webhook.updated_datetime}" 40 | end 41 | rescue MessageBird::ErrorException => e 42 | puts 43 | puts 'An error occured while creating a conversation:' 44 | puts 45 | 46 | e.errors.each do |error| 47 | puts " code : #{error.code}" 48 | puts " description : #{error.description}" 49 | puts " parameter : #{error.parameter}" 50 | puts 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /examples/voice_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # MESSAGE_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(MESSAGE_ID) 16 | puts 'You need to set an MESSAGE_ID constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the VoiceMessage object for the specified MESSAGE_ID. 24 | vmsg = client.voice_message(MESSAGE_ID) 25 | 26 | # Print the object information. 27 | puts 28 | puts 'The following information was returned as a VoiceMessage object:' 29 | puts 30 | puts " id : #{vmsg.id}" 31 | puts " href : #{vmsg.href}" 32 | puts " originator : #{vmsg.originator}" 33 | puts " body : #{vmsg.body}" 34 | puts " reference : #{vmsg.reference}" 35 | puts " language : #{vmsg.language}" 36 | puts " voice : #{vmsg.voice}" 37 | puts " repeat : #{vmsg.repeat}" 38 | puts " ifMachine : #{vmsg.if_machine}" 39 | puts " scheduledDateTime : #{vmsg.scheduled_date_time}" 40 | puts " createdDatetime : #{vmsg.created_datetime}" 41 | puts " recipients : #{vmsg.recipients}" 42 | puts 43 | rescue MessageBird::ErrorException => e 44 | puts 45 | puts 'An error occured while requesting an VoiceMessage object:' 46 | puts 47 | 48 | e.errors.each do |error| 49 | puts " code : #{error.code}" 50 | puts " description : #{error.description}" 51 | puts " parameter : #{error.parameter}" 52 | puts 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /examples/call_leg_recordings.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 6 | require 'messagebird' 7 | 8 | ACCESS_KEY = 'YOUR KEY HERE' 9 | CALL_ID = 'YOUR CALL ID HERE' 10 | 11 | unless defined?(ACCESS_KEY) 12 | puts 'You need to set an ACCESS_KEY constant in this file' 13 | exit 1 14 | end 15 | 16 | begin 17 | # Create a MessageBird client with the specified ACCESS_KEY. 18 | client = MessageBird::Client.new(ACCESS_KEY) 19 | 20 | # Request the legs (overview of inbound/outbound portions of this call) 21 | puts "Retrieving legs for call #{CALL_ID}" 22 | legs = client.call_leg_list(CALL_ID) 23 | 24 | legs.items.each do |leg| 25 | puts " Retrieving recordings for leg #{leg.id}" 26 | recordings = client.call_leg_recording_list(CALL_ID, leg.id) 27 | 28 | recordings.items.each do |recording| 29 | client.call_leg_recording_view(CALL_ID, leg.id, recording.id) 30 | 31 | puts ' --------------------------------------------------' 32 | puts " recording ID : #{recording.id}" 33 | puts " recording URI : #{recording.uri}" 34 | print ' downloading : ' 35 | client.call_leg_recording_download(recording.uri) do |response| 36 | File.open("#{recording.id}.wav", 'w') do |io| 37 | response.read_body do |chunk| 38 | putc '.' 39 | io.write(chunk) 40 | end 41 | end 42 | end 43 | puts ' DONE!' 44 | puts 45 | end 46 | end 47 | rescue MessageBird::ErrorException => e 48 | puts 49 | puts 'An error occured while listing the calls:' 50 | puts 51 | 52 | e.errors.each do |error| 53 | puts " code : #{error.code}" 54 | puts " description : #{error.description}" 55 | puts " parameter : #{error.parameter}" 56 | puts 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /examples/voice_transcription.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'test_gshuPaZoeEG6ovbc8M79w0QyM' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Start a conversation 19 | calls = client.call_list(10, 0) 20 | call_id = calls[0].id 21 | legs = client.call_leg_list(call_id) 22 | legs.items.each do |leg| 23 | recordings = client.call_leg_recording_list(call_id, leg.id) 24 | recordings.items.each do |recording| 25 | transcriptions = client.voice_transcriptions_list(call_id, leg.id, recording.id) 26 | transcriptions.items.each do |transcription| 27 | puts ' --------------------------------------------------' 28 | puts " transcriptionId : #{transcription.id}" 29 | puts " recordingId : #{transcription.recording_id}" 30 | puts " createdAt : #{transcription.created_at}" 31 | puts " updatedAt : #{transcription.updated_at}" 32 | puts " links : #{transcription._links}" 33 | client.voice_transcription_download(call_id, leg.id, recording.id, transcription.id) do |response| 34 | puts " transcription : #{response.body}" 35 | end 36 | end 37 | end 38 | end 39 | rescue MessageBird::ErrorException => e 40 | puts 41 | puts 'An error occured while listing the calls:' 42 | puts 43 | 44 | e.errors.each do |error| 45 | puts " code : #{error.code}" 46 | puts " description : #{error.description}" 47 | puts " parameter : #{error.parameter}" 48 | puts 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /examples/verify_create_email.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Generate a new OTP message using an email as recipient 19 | otp = client.verify_create('Recipient Name ', # RECIPIENT EMAIL HERE 20 | originator: 'sender@example.com', # SENDER EMAIL HERE 21 | type: 'email', 22 | subject: 'Your Verify test token', 23 | template: '%token - Use this code to validate your Verify token.', 24 | reference: 'MessageBirdReference') 25 | 26 | # Print the object information. 27 | puts 28 | puts 'The following information was returned as an OTP object:' 29 | puts 30 | puts " id : #{otp.id}" 31 | puts " href : #{otp.href}" 32 | puts " recipient : #{otp.recipient}" 33 | puts " reference : #{otp.reference}" 34 | puts " messages : #{otp.messages}" 35 | puts " status : #{otp.status}" 36 | puts " createdDatetime : #{otp.created_datetime}" 37 | puts " validUntilDatetime : #{otp.valid_until_datetime}" 38 | puts 39 | rescue MessageBird::ErrorException => e 40 | puts 41 | puts 'An error occured while requesting an OTP object:' 42 | puts 43 | 44 | e.errors.each do |error| 45 | puts " code : #{error.code}" 46 | puts " description : #{error.description}" 47 | puts " parameter : #{error.parameter}" 48 | puts 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/conversation_client_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe MessageBird::ConversationClient do 4 | before(:all) do 5 | @client = MessageBird::ConversationClient.new('secret-access-key') 6 | end 7 | 8 | context 'initialization' do 9 | it 'uses Conversations API base URL' do 10 | expect(@client.endpoint).to eq('https://conversations.messagebird.com/v1/') 11 | end 12 | 13 | it 'uses the provided access key' do 14 | expect(@client.access_key).to eq('secret-access-key') 15 | end 16 | end 17 | 18 | context 'performing a HTTP request' do 19 | before(:each) do 20 | stub_request(:get, 'https://conversations.messagebird.com/v1/conversations') 21 | .with( 22 | headers: { 23 | 'Accept' => 'application/json', 24 | 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 25 | 'Authorization' => "AccessKey #{@client.access_key}", 26 | 'User-Agent' => "MessageBird/ApiClient/#{MessageBird::Version::STRING} Ruby/#{RUBY_VERSION}" 27 | } 28 | ) 29 | .to_return(status: 200, body: File.new(File.join(File.dirname(__FILE__), './data/conversations/list.json')), headers: {}) 30 | 31 | @response = JSON.parse(@client.request(:get, 'conversations'), symbolize_names: true) 32 | end 33 | 34 | it 'contains an offset in the HTTP response body' do 35 | expect(@response[:offset]).to be(0) 36 | end 37 | 38 | it 'contains a limit in the HTTP response body' do 39 | expect(@response[:limit]).to be(20) 40 | end 41 | 42 | it 'contains a count in the HTTP response body' do 43 | expect(@response[:count]).to be(2) 44 | end 45 | 46 | it 'contains a totalCount in the HTTP response body' do 47 | expect(@response[:totalCount]).to be(2) 48 | end 49 | 50 | it 'contains two items' do 51 | expect(@response[:items].length).to be(2) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/voicemessage_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Voice message' do 4 | it 'reads an existing' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'voicemessages/voicemessage-id', {}) 11 | .and_return('{"body": "Hello World","createdDatetime": "2015-01-05T16:11:24+00:00","href": "https://rest.messagebird.com/voicemessages/voicemessage-id","id": "voicemessage-id","ifMachine": "continue","language": "en-gb","originator": "MessageBird","recipients": {"items": [{"recipient": 31612345678,"status": "calling","statusDatetime": "2015-01-05T16:11:24+00:00"}],"totalCount": 1,"totalDeliveredCount": 0,"totalDeliveryFailedCount": 0,"totalSentCount": 1},"reference": null,"repeat": 1,"scheduledDatetime": null,"voice": "female"}') 12 | 13 | voice_message = client.voice_message('voicemessage-id') 14 | 15 | expect(voice_message.id).to eq 'voicemessage-id' 16 | end 17 | 18 | it 'creates with a single recipient' do 19 | http_client = double(MessageBird::HttpClient) 20 | client = MessageBird::Client.new('', http_client) 21 | 22 | expect(http_client) 23 | .to receive(:request) 24 | .with(:post, 'voicemessages', { recipients: 31_612_345_678, body: 'Body', repeat: 3 }) 25 | .and_return('{}') 26 | 27 | client.voice_message_create(31_612_345_678, 'Body', repeat: 3) 28 | end 29 | 30 | it 'creates with multiple recipients' do 31 | http_client = double(MessageBird::HttpClient) 32 | client = MessageBird::Client.new('', http_client) 33 | 34 | expect(http_client) 35 | .to receive(:request) 36 | .with(:post, 'voicemessages', { recipients: '31612345678,31687654321', body: 'Body', repeat: 3 }) 37 | .and_return('{}') 38 | 39 | client.voice_message_create([31_612_345_678, 31_687_654_321], 'Body', repeat: 3) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /examples/contact_create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = 'YOUR PHONE NUMBER HERE' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | exit 1 18 | end 19 | 20 | begin 21 | # Create a MessageBird client with the specified ACCESS_KEY. 22 | client = MessageBird::Client.new(ACCESS_KEY) 23 | 24 | # Create a new Contact object. 25 | contact = client.contact_create(PHONE_NUMBER, firstName: 'Foo', lastName: 'Bar') 26 | 27 | # Print the object information. 28 | puts 29 | puts ' Contact :' 30 | puts 31 | puts " id : #{contact.id}" 32 | puts " href : #{contact.href}" 33 | puts " msisdn : #{contact.msisdn}" 34 | puts " firstName : #{contact.first_name}" 35 | puts " lastName : #{contact.last_name}" 36 | puts " groups : #{contact.groups.href}" # contact.groups.total_count is also available. 37 | puts " messages : #{contact.messages.href}" # contact.messages.total_count is also available. 38 | puts " custom1 : #{contact.custom_details.custom1}" 39 | puts " custom2 : #{contact.custom_details.custom2}" 40 | puts " custom3 : #{contact.custom_details.custom3}" 41 | puts " custom4 : #{contact.custom_details.custom4}" 42 | puts 43 | rescue MessageBird::ErrorException => e 44 | puts 45 | puts 'An error occurred while creating a contact:' 46 | puts 47 | 48 | e.errors.each do |error| 49 | puts " code : #{error.code}" 50 | puts " description : #{error.description}" 51 | puts " parameter : #{error.parameter}" 52 | puts 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /examples/number_purchase.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = "31612345670" 9 | # COUNTRY_CODE = 'NL' 10 | # BILLING_PERIOD = 1 11 | 12 | unless defined?(ACCESS_KEY) 13 | puts 'You need to set an ACCESS_KEY constant in this file' 14 | exit 1 15 | end 16 | 17 | unless defined?(PHONE_NUMBER) 18 | puts 'You need to set an PHONE_NUMBER constant in this file' 19 | end 20 | 21 | unless defined?(COUNTRY_CODE) 22 | puts 'You need to set an COUNTRY_CODE constant in this file' 23 | end 24 | 25 | unless defined?(BILLING_PERIOD) 26 | puts 'You need to set an BILLING_PERIOD constant in this file' 27 | end 28 | 29 | begin 30 | # Create a MessageBird client with the specified ACCESS_KEY. 31 | client = MessageBird::Client.new(ACCESS_KEY) 32 | 33 | # Fetch the HLR object for the specified HLR_ID. 34 | number = client.number_purchase(PHONE_NUMBER, COUNTRY_CODE, BILLING_PERIOD) 35 | 36 | # Print the object information. 37 | puts 'The folling number was returned as a Number object' 38 | puts 39 | puts " number : #{number.number}" 40 | puts " country : #{number.country}" 41 | puts " region : #{number.region}" 42 | puts " locality : #{number.locality}" 43 | puts " features : #{number.features}" 44 | puts " tags : #{number.tags}" 45 | puts " type : #{number.type}" 46 | puts " status : #{number.status}" 47 | puts " createdAt : #{number.createdAt}" 48 | puts " renewalAt : #{number.renewalAt}" 49 | rescue MessageBird::ErrorException => e 50 | puts 51 | puts 'An error occured while requesting the lookup:' 52 | puts 53 | 54 | e.errors.each do |error| 55 | puts " code : #{error.code}" 56 | puts " description : #{error.description}" 57 | puts " parameter : #{error.parameter}" 58 | puts 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /examples/message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | # MESSAGE_ID = '' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(MESSAGE_ID) 16 | puts 'You need to set an MESSAGE_ID constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the Message object for the specified MESSAGE_ID. 24 | msg = client.message(MESSAGE_ID) 25 | 26 | # Print the object information. 27 | puts 28 | puts 'The following information was returned as a Message object:' 29 | puts 30 | puts " id : #{msg.id}" 31 | puts " href : #{msg.href}" 32 | puts " direction : #{msg.direction}" 33 | puts " type : #{msg.type}" 34 | puts " originator : #{msg.originator}" 35 | puts " body : #{msg.body}" 36 | puts " reference : #{msg.reference}" 37 | puts " validity : #{msg.validity}" 38 | puts " gateway : #{msg.gateway}" 39 | puts " typeDetails : #{msg.typeDetails}" 40 | puts " datacoding : #{msg.datacoding}" 41 | puts " mclass : #{msg.mclass}" 42 | puts " scheduledDateTime : #{msg.scheduled_date_time}" 43 | puts " createdDatetime : #{msg.created_datetime}" 44 | puts " recipients : #{msg.recipients}" 45 | puts 46 | rescue MessageBird::ErrorException => e 47 | puts 48 | puts 'An error occured while requesting an Message object:' 49 | puts 50 | 51 | e.errors.each do |error| 52 | puts " code : #{error.code}" 53 | puts " description : #{error.description}" 54 | puts " parameter : #{error.parameter}" 55 | puts 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /examples/conversation_messages_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the messages list 19 | offset = 0 20 | limit = 10 21 | list = client.conversation_messages_list('00000000000000000000000000000000', limit, offset) 22 | 23 | # Print the object information. 24 | # 25 | puts 'The following information was returned as a messages list:' 26 | puts 27 | puts " count : #{list.count}" 28 | puts " limit : #{list.limit}" 29 | puts " offset : #{list.offset}" 30 | puts " totalCount : #{list.total_count}" 31 | puts " links : #{list.links}" 32 | puts 33 | 34 | list.items.each do |msg| 35 | puts 'Message:' 36 | puts " id : #{msg.id}" 37 | puts " conversationId : #{msg.conversation_id}" 38 | puts " channelId : #{msg.channel_id}" 39 | puts " direction : #{msg.direction}" 40 | puts " type : #{msg.type}" 41 | puts " status : #{msg.status}" 42 | puts " content : #{msg.content}" 43 | puts " createdDatetime : #{msg.created_datetime}" 44 | puts " updatedDatetime : #{msg.updated_datetime}" 45 | puts 46 | end 47 | rescue MessageBird::ErrorException => e 48 | puts 49 | puts 'An error occured while creating a conversation:' 50 | puts 51 | 52 | e.errors.each do |error| 53 | puts " code : #{error.code}" 54 | puts " description : #{error.description}" 55 | puts " parameter : #{error.parameter}" 56 | puts 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/verify_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Verify' do 4 | before :each do 5 | @http_client = double(MessageBird::HttpClient) 6 | @client = MessageBird::Client.new('', @http_client) 7 | end 8 | 9 | it 'reads an existing' do 10 | expect(@http_client) 11 | .to receive(:request) 12 | .with(:get, 'verify/verify-id', {}) 13 | .and_return('{"id": "verify-id","href": "https://rest.messagebird.com/verify/verify-id","recipient": 31612345678,"reference": "MyReference","messages": {"href": "https://rest.messagebird.com/messages/message-id"},"status": "verified","createdDatetime": "2017-05-30T12:39:50+00:00","validUntilDatetime": "2017-05-30T12:40:20+00:00"}') 14 | 15 | verify = @client.verify('verify-id') 16 | 17 | expect(verify.id).to eq 'verify-id' 18 | expect(verify.status).to eq 'verified' 19 | end 20 | 21 | it 'verifies token for existing verify' do 22 | expect(@http_client) 23 | .to receive(:request) 24 | .with(:get, 'verify/verify-id?token=verify-token', {}) 25 | .and_return('{}') 26 | 27 | @client.verify_token('verify-id', 'verify-token') 28 | end 29 | 30 | it 'creates a verify and sends token' do 31 | expect(@http_client) 32 | .to receive(:request) 33 | .with(:post, 'verify', { recipient: 31_612_345_678, originator: 'MessageBird' }) 34 | .and_return('{}') 35 | 36 | @client.verify_create(31_612_345_678, originator: 'MessageBird') 37 | end 38 | 39 | it 'creates a verify and sends token via email' do 40 | expect(@http_client) 41 | .to receive(:request) 42 | .with(:post, 'verify', { type: 'email', recipient: 'verify@example.com', subject: 'Your verification code', originator: 'MessageBird' }) 43 | .and_return('{}') 44 | 45 | @client.verify_create('verify@example.com', originator: 'MessageBird', type: 'email', subject: 'Your verification code') 46 | end 47 | 48 | it 'deletes a verify' do 49 | expect(@http_client) 50 | .to receive(:request) 51 | .with(:delete, 'verify/verify-id', {}) 52 | .and_return('{}') 53 | 54 | @client.verify_delete('verify-id') 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/messagebird/signed_request.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'base64' 4 | require 'digest' 5 | require 'time' 6 | 7 | module MessageBird 8 | ## 9 | # @deprecated Use {MessageBird::RequestValidator::ValidationError} instead. 10 | class ValidationException < TypeError 11 | end 12 | 13 | ## 14 | # @deprecated Use {MessageBird::RequestValidator} instead. 15 | class SignedRequest 16 | ## 17 | # @deprecated Use {MessageBird::RequestValidator} instead. 18 | def initialize(query_parameters, signature, request_timestamp, body) 19 | unless query_parameters.is_a? Hash 20 | raise ValidationException, 'The "query_parameters" value is invalid.' 21 | end 22 | unless signature.is_a? String 23 | raise ValidationException, 'The "signature" value is invalid.' 24 | end 25 | unless request_timestamp.is_a? Integer 26 | raise ValidationException, 'The "request_timestamp" value is invalid.' 27 | end 28 | unless body.is_a? String 29 | raise ValidationException, 'The "body" value is invalid.' 30 | end 31 | 32 | @query_parameters = query_parameters 33 | @signature = signature 34 | @request_timestamp = request_timestamp 35 | @body = body 36 | end 37 | 38 | ## 39 | # @deprecated Use {MessageBird::RequestValidator::validateSignature} instead. 40 | def verify(signing_key) 41 | calculated_signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), signing_key, build_payload) 42 | expected_signature = Base64.decode64(@signature) 43 | calculated_signature.bytes == expected_signature.bytes 44 | end 45 | 46 | ## 47 | # @deprecated Use {MessageBird::RequestValidator} instead. 48 | def build_payload 49 | parts = [] 50 | parts.push(@request_timestamp) 51 | parts.push(URI.encode_www_form(@query_parameters.sort)) 52 | parts.push(Digest::SHA256.new.digest(@body)) 53 | parts.join("\n") 54 | end 55 | 56 | ## 57 | # @deprecated Use {MessageBird::RequestValidator} instead. 58 | def recent?(offset = 10) 59 | (Time.now.getutc.to_i - @request_timestamp) < offset 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /examples/lookup.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = 'YOUR KEY HERE' 8 | # PHONE_NUMBER = '+31612345678' 9 | 10 | unless defined?(ACCESS_KEY) 11 | puts 'You need to set an ACCESS_KEY constant in this file' 12 | exit 1 13 | end 14 | 15 | unless defined?(PHONE_NUMBER) 16 | puts 'You need to set an PHONE_NUMBER constant in this file' 17 | end 18 | 19 | begin 20 | # Create a MessageBird client with the specified ACCESS_KEY. 21 | client = MessageBird::Client.new(ACCESS_KEY) 22 | 23 | # Fetch the HLR object for the specified HLR_ID. 24 | lookup = client.lookup(PHONE_NUMBER) 25 | 26 | # Print the object information. 27 | puts 28 | puts 'The following information was returned as an HLR object:' 29 | puts 30 | puts " href : #{lookup.href}" 31 | puts " countryCode : #{lookup.country_code}" 32 | puts " countryPrefix : #{lookup.country_prefix}" 33 | puts " phoneNumber : #{lookup.phone_number}" 34 | puts " type : #{lookup.type}" 35 | 36 | puts ' formats :' 37 | puts " e164 : #{lookup.formats.e164}" 38 | puts " international : #{lookup.formats.international}" 39 | puts " national : #{lookup.formats.national}" 40 | puts " rfc3966 : #{lookup.formats.rfc3966}" 41 | 42 | unless lookup.hlr.nil? 43 | puts ' hlr :' 44 | puts " id : #{lookup.hlr.id}" 45 | puts " href : #{lookup.hlr.href}" 46 | puts " msisdn : #{lookup.hlr.msisdn}" 47 | puts " reference : #{lookup.hlr.reference}" 48 | puts " status : #{lookup.hlr.status}" 49 | puts " createdDatetime : #{lookup.hlr.created_datetime}" 50 | puts " statusDatetime : #{lookup.hlr.status_datetime}" 51 | end 52 | rescue MessageBird::ErrorException => e 53 | puts 54 | puts 'An error occured while requesting the lookup:' 55 | puts 56 | 57 | e.errors.each do |error| 58 | puts " code : #{error.code}" 59 | puts " description : #{error.description}" 60 | puts " parameter : #{error.parameter}" 61 | puts 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /examples/contact_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | ACCESS_KEY = 'YOUR KEY HERE' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the Contact list with pagination options (skip the first 5 objects and take 10). 19 | limit = 10 20 | offset = 0 21 | contacts = client.contact_list(limit, offset) 22 | 23 | # Print the object information. 24 | puts 25 | puts 'The following information was returned as a Contact list:' 26 | puts 27 | puts " count : #{contacts.count}" 28 | puts " limit : #{contacts.limit}" 29 | puts " offset : #{contacts.offset}" 30 | puts " totalCount : #{contacts.total_count}" 31 | puts " links : #{contacts.links}" 32 | 33 | unless contacts.items.empty? 34 | contact = contacts[0] # Equivalent to contacts.items[0] 35 | 36 | puts ' Contact :' 37 | puts " id : #{contact.id}" 38 | puts " href : #{contact.href}" 39 | puts " msisdn : #{contact.msisdn}" 40 | puts " firstName : #{contact.first_name}" 41 | puts " lastName : #{contact.last_name}" 42 | puts " groups : #{contact.groups.href}" # contact.groups.total_count is also available. 43 | puts " messages : #{contact.messages.href}" # contact.messages.total_count is also available. 44 | puts " custom1 : #{contact.custom_details.custom1}" 45 | puts " custom2 : #{contact.custom_details.custom2}" 46 | puts " custom3 : #{contact.custom_details.custom3}" 47 | puts " custom4 : #{contact.custom_details.custom4}" 48 | 49 | end 50 | rescue MessageBird::ErrorException => e 51 | puts 52 | puts 'An error occurred while listing your contacts:' 53 | puts 54 | 55 | e.errors.each do |error| 56 | puts " code : #{error.code}" 57 | puts " description : #{error.description}" 58 | puts " parameter : #{error.parameter}" 59 | puts 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /examples/message_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | messages = client.message_list(status: 'scheduled') 19 | 20 | # Print the object information. 21 | puts 22 | puts 'The following information was returned as a Message list:' 23 | puts 24 | puts " count : #{messages.count}" 25 | puts " limit : #{messages.limit}" 26 | puts " offset : #{messages.offset}" 27 | puts " totalCount : #{messages.total_count}" 28 | puts " links : #{messages.links}" 29 | unless messages.items.empty? 30 | msg = messages[0] # Equivalent to messages.items[0] 31 | # Print the object information. 32 | puts 33 | puts 'The following information was returned as a Message object:' 34 | puts 35 | puts " id : #{msg.id}" 36 | puts " href : #{msg.href}" 37 | puts " direction : #{msg.direction}" 38 | puts " type : #{msg.type}" 39 | puts " originator : #{msg.originator}" 40 | puts " body : #{msg.body}" 41 | puts " reference : #{msg.reference}" 42 | puts " validity : #{msg.validity}" 43 | puts " gateway : #{msg.gateway}" 44 | puts " typeDetails : #{msg.typeDetails}" 45 | puts " datacoding : #{msg.datacoding}" 46 | puts " mclass : #{msg.mclass}" 47 | puts " scheduledDateTime : #{msg.scheduled_date_time}" 48 | puts " createdDatetime : #{msg.created_datetime}" 49 | puts " recipients : #{msg.recipients}" 50 | puts 51 | end 52 | rescue MessageBird::ErrorException => e 53 | puts 54 | puts 'An error occurred while listing your messages:' 55 | puts 56 | e.errors.each do |error| 57 | puts " code : #{error.code}" 58 | puts " description : #{error.description}" 59 | puts " parameter : #{error.parameter}" 60 | puts 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Releasing things 2 | 3 | In April 2025 the current way we do releases in this repo is not great. 4 | Fixing it for real will take some time that the team doesn't have it today. 5 | 6 | So here is a step by step half automated, half manual way to release a new version: 7 | 8 | * Someone makes a PR that changes things for the better. 9 | * The PR gets reviewed, approved and merged to `master`. 10 | * Someone from the team (from now called: Marcel) decides to make a release 11 | * Marcel creates a new branch from master called `new-release` 12 | * Marcel makes a PR for that new branch. 13 | * Marcel adds one of the release labels (release-major, release-minor, release-patch) to the PR. He decides to add `release-major`. 14 | * Marcel reads [version.rb](https://github.com/messagebird/ruby-rest-api/blob/master/lib/messagebird/version.rb#L5) and sees that the version is `5.0.0`. 15 | * Marcel thinks: if I'm doing a *major* release the next one will be `6.0.0`. 16 | * Marcel manually changes the versions on these files: 17 | * [version.rb](https://github.com/messagebird/ruby-rest-api/blob/master/lib/messagebird/version.rb#L5) 18 | * Gemfile.lock (not on git. not sure if it's important but :shrug: ) 19 | * Commit. Push to the `new-release` branch. 20 | * Back to that release PR. Marcel writes a nice body on the PR. It's important to do a markdon title with `##` somewhere. Everything after that double pound will be put on the body of the release. 21 | * Put the changelog in there, man. 22 | * Check (this PR)[https://github.com/messagebird/ruby-rest-api/pull/95] out for an example. 23 | * Be sure that the CI is not faling at anything. 24 | * Goto ruby gems 25 | * Login using the (messagebird account)[https://rubygems.org/profiles/messagebird]. If you don't have access to it ask Jeremy, Marcel, Rene or Bob. 26 | * Goto (settings)[https://rubygems.org/settings/edit] 27 | * Change the MFA level to "UI and gem signin". 28 | * Merge that PR 29 | * Check that 30 | * a new release got (published on github)[https://github.com/messagebird/ruby-rest-api/releases] 31 | * that a new release got push to the (rubygems page)[https://rubygems.org/gems/messagebird-rest] 32 | * Great success 33 | * Let's revert that dangerous config on rubygems 34 | * Goto (settings)[https://rubygems.org/settings/edit] 35 | * Change the MFA level to "UI and API (Recommended)". 36 | * Greatest success -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | types: [ labeled ] 6 | branches: 7 | - master 8 | 9 | jobs: 10 | prepare-release: 11 | name: Prepare release 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Set major release 16 | if: ${{ github.event.label.name == 'release-major' }} 17 | run: echo "RELEASE=major" >> $GITHUB_ENV 18 | - name: Set minor release 19 | if: ${{ github.event.label.name == 'release-minor' }} 20 | run: echo "RELEASE=minor" >> $GITHUB_ENV 21 | - name: Set patch release 22 | if: ${{ github.event.label.name == 'release-patch' }} 23 | run: echo "RELEASE=patch" >> $GITHUB_ENV 24 | - name: Check release env 25 | run: | 26 | if [[ -z "${{ env.RELEASE }}" ]]; 27 | then 28 | echo "You need to set a release label on PRs to the main branch" 29 | exit 1 30 | else 31 | exit 0 32 | fi 33 | - name: Install semver-tool 34 | run: | 35 | export DIR=$(mktemp -d) 36 | cd $DIR 37 | curl https://github.com/fsaintjacques/semver-tool/archive/3.2.0.tar.gz -L -o semver.tar.gz 38 | tar -xvf semver.tar.gz 39 | sudo cp semver-tool-3.2.0/src/semver /usr/local/bin 40 | - name: Bump version 41 | run: | 42 | export CURRENT=$(gem info messagebird-rest --remote --exact | grep -o "messagebird-rest ([0-9]*\.[0-9]*\.[0-9]*)" | awk -F '[()]' '{print $2}') 43 | export NEW_VERSION=$(semver bump ${{ env.RELEASE }} $CURRENT) 44 | echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV 45 | - name: Checkout code 46 | uses: actions/checkout@v2 47 | - name: Setup git 48 | run: | 49 | git config user.email "developers@messagebird.com" 50 | git config user.name "MessageBird CI" 51 | git fetch 52 | git checkout ${{ github.event.pull_request.head.ref }} 53 | - name: Prepare CHANGELOG 54 | run: | 55 | echo "${{ github.event.pull_request.body }}" | csplit -s - "/##/" 56 | echo -e "\n\n## ${{ env.VERSION }} 57 | " >> CHANGELOG.tmp 58 | grep "^*" xx01 >> CHANGELOG.tmp 59 | grep -v "^# " CHANGELOG.md >> CHANGELOG.tmp 60 | cp CHANGELOG.tmp CHANGELOG.md 61 | - name: Prepare version.rb 62 | run: | 63 | sed -i "s|STRING = '[^']*'|STRING = '${{ env.VERSION }}'|" lib/messagebird/version.rb 64 | - name: Commit changes 65 | run: | 66 | git add CHANGELOG.md lib/messagebird/version.rb 67 | git commit -m "Bump to version ${{ env.VERSION }}" 68 | - name: Push 69 | run: git push 70 | -------------------------------------------------------------------------------- /spec/lookup_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Lookup' do 4 | it 'performs a new international lookup' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'lookup/31612345678', {}) 11 | .and_return('{"href": "https://rest.messagebird.com/lookup/31612345678","countryCode": "NL","countryPrefix": 31,"phoneNumber": 31612345678,"type": "mobile","formats": {"e164": "+31612345678","international": "+31 6 12345678","national": "06 12345678","rfc3966": "tel:+31-6-12345678"},"hlr": {"id": "hlr-id","network": 20416,"reference": "reference2000","status": "active","createdDatetime": "2015-12-15T08:19:24+00:00","statusDatetime": "2015-12-15T08:19:25+00:00"}}') 12 | 13 | lookup = client.lookup(31_612_345_678) 14 | 15 | expect(lookup.country_code).to eq 'NL' 16 | expect(lookup.hlr.id).to eq 'hlr-id' 17 | end 18 | 19 | it 'performs a new national lookup' do 20 | http_client = double(MessageBird::HttpClient) 21 | client = MessageBird::Client.new('', http_client) 22 | 23 | expect(http_client) 24 | .to receive(:request) 25 | .with(:get, 'lookup/0612345678', { country_code: 'NL' }) 26 | .and_return('{"href": "https://rest.messagebird.com/lookup/31612345678","countryCode": "NL","countryPrefix": 31,"phoneNumber": 31612345678,"type": "mobile","formats": {"e164": "+31612345678","international": "+31 6 12345678","national": "06 12345678","rfc3966": "tel:+31-6-12345678"},"hlr": {"id": "hlr-id","network": 20416,"reference": "reference2000","status": "active","createdDatetime": "2015-12-15T08:19:24+00:00","statusDatetime": "2015-12-15T08:19:25+00:00"}}') 27 | 28 | lookup = client.lookup('0612345678', country_code: 'NL') 29 | 30 | expect(lookup.country_code).to eq 'NL' 31 | expect(lookup.hlr.id).to eq 'hlr-id' 32 | end 33 | end 34 | 35 | describe 'Lookup HLR' do 36 | it 'views an existing' do 37 | http_client = double(MessageBird::HttpClient) 38 | client = MessageBird::Client.new('', http_client) 39 | 40 | expect(http_client) 41 | .to receive(:request) 42 | .with(:get, 'lookup/31612345678/hlr', {}) 43 | .and_return('{"id": "hlr-id","network": 20416,"reference": "reference2000","status": "active","createdDatetime": "2015-12-15T08:19:24+00:00","statusDatetime": "2015-12-15T08:19:25+00:00"}') 44 | 45 | hlr = client.lookup_hlr(31_612_345_678) 46 | 47 | expect(hlr.id).to eq 'hlr-id' 48 | end 49 | 50 | it 'requests a HLR' do 51 | http_client = double(MessageBird::HttpClient) 52 | client = MessageBird::Client.new('', http_client) 53 | 54 | expect(http_client) 55 | .to receive(:request) 56 | .with(:post, 'lookup/31612345678/hlr', { reference: 'MyReference' }) 57 | .and_return('{}') 58 | 59 | client.lookup_hlr_create(31_612_345_678, reference: 'MyReference') 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /examples/conversation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Start a conversation 19 | conversation = client.conversation('conversation_id') 20 | 21 | # Print the object information. 22 | puts 23 | puts 'The following information was returned as a conversation object:' 24 | puts " id : #{conversation.id}" 25 | puts " status : #{conversation.status}" 26 | puts " createdDatetime : #{conversation.created_datetime}" 27 | puts " updatedDatetime : #{conversation.updated_datetime}" 28 | puts " lastReceivedDateklme : #{conversation.last_received_datetime}" 29 | puts " lastUsedChannelId : #{conversation.last_used_channel_id}" 30 | 31 | puts ' Contact :' 32 | puts " id : #{conversation.contact.id}" 33 | puts " href : #{conversation.contact.href}" 34 | puts " msisdn : #{conversation.contact.msisdn}" 35 | puts " firstName : #{conversation.contact.first_name}" 36 | puts " lastName : #{conversation.contact.last_name}" 37 | puts " custom1 : #{conversation.contact.custom_details.custom1}" 38 | puts " custom2 : #{conversation.contact.custom_details.custom2}" 39 | puts " custom3 : #{conversation.contact.custom_details.custom3}" 40 | puts " custom4 : #{conversation.contact.custom_details.custom4}" 41 | puts " createdDatetime : #{conversation.contact.created_datetime}" 42 | puts " updatedDatetime : #{conversation.contact.updated_datetime}" 43 | 44 | puts ' Channels :' 45 | conversation.channels.each do |channel| 46 | puts " id : #{channel.id}" 47 | puts " name : #{channel.name}" 48 | puts " platformId : #{channel.platform_id}" 49 | puts " createdDatetime : #{channel.created_datetime}" 50 | puts " updatedDatetime : #{channel.updated_datetime}" 51 | puts 52 | end 53 | 54 | puts ' Messages :' 55 | puts " href : #{conversation.messages.href}" 56 | puts " total_count : #{conversation.messages.total_count}" 57 | rescue MessageBird::ErrorException => e 58 | puts 59 | puts 'An error occured while creating a conversation:' 60 | puts 61 | 62 | e.errors.each do |error| 63 | puts " code : #{error.code}" 64 | puts " description : #{error.description}" 65 | puts " parameter : #{error.parameter}" 66 | puts 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/voice_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Voice' do 4 | it 'creates a webhook' do 5 | voice_client = double(MessageBird::VoiceClient) 6 | client = MessageBird::Client.new('', nil, nil, voice_client) 7 | 8 | expect(voice_client) 9 | .to receive(:request) 10 | .with(:post, 'webhooks', { url: 'https://test.com', token: 'sometoken' }) 11 | .and_return('{"data":[{"id":"00000000000000000000000000000000", "url": "https://test.com", "token": "sometoken"}]}') 12 | 13 | webhook = client.voice_webhook_create('https://test.com', token: 'sometoken') 14 | 15 | expect(webhook.id).to eq '00000000000000000000000000000000' 16 | expect(webhook.url).to eq 'https://test.com' 17 | expect(webhook.token).to eq 'sometoken' 18 | end 19 | 20 | it 'reads a list of webhooks' do 21 | voice_client = double(MessageBird::VoiceClient) 22 | client = MessageBird::Client.new('', nil, nil, voice_client) 23 | 24 | expect(voice_client) 25 | .to receive(:request) 26 | .with(:get, 'webhooks?perPage=10&page=1', {}) 27 | .and_return('{"pagination":{"perPage":10, "currentPage":1, "pageCount":1, "totalCount":2}, "data":[{"id":"1111111111", "url": "url_1", "token": "token_1"},{"id":"2222222222", "url": "url_2", "token": "token_2"}]}') 28 | 29 | list = client.voice_webhooks_list(10, 1) 30 | 31 | expect(list.items.count).to eq 2 32 | expect(list[0].id).to eq '1111111111' 33 | expect(list[1].id).to eq '2222222222' 34 | end 35 | 36 | it 'reads a webhook' do 37 | voice_client = double(MessageBird::VoiceClient) 38 | client = MessageBird::Client.new('', nil, nil, voice_client) 39 | 40 | expect(voice_client) 41 | .to receive(:request) 42 | .with(:get, 'webhooks/webhook-id', {}) 43 | .and_return('{"data":[{"id":"00000000000000000000000000000000"}]}') 44 | 45 | webhook = client.voice_webhook('webhook-id') 46 | 47 | expect(webhook.id).to eq '00000000000000000000000000000000' 48 | end 49 | 50 | it 'updates a webhook' do 51 | voice_client = double(MessageBird::VoiceClient) 52 | client = MessageBird::Client.new('', nil, nil, voice_client) 53 | 54 | expect(voice_client) 55 | .to receive(:request) 56 | .with(:put, 'webhooks/webhook-id', { url: 'https://test.com', token: 'sometoken' }) 57 | .and_return('{"data":[{"id":"00000000000000000000000000000000", "url": "https://test.com", "token": "sometoken"}]}') 58 | 59 | webhook = client.voice_webhook_update('webhook-id', url: 'https://test.com', token: 'sometoken') 60 | 61 | expect(webhook.id).to eq '00000000000000000000000000000000' 62 | expect(webhook.url).to eq 'https://test.com' 63 | expect(webhook.token).to eq 'sometoken' 64 | end 65 | 66 | it 'deletes a webhook' do 67 | voice_client = double(MessageBird::VoiceClient) 68 | client = MessageBird::Client.new('', nil, nil, voice_client) 69 | 70 | expect(voice_client) 71 | .to receive(:request) 72 | .with(:delete, 'webhooks/webhook-id', {}) 73 | .and_return('') 74 | 75 | client.voice_webhook_delete('webhook-id') 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is always be loaded, without a need to explicitly require it in any 4 | # files. 5 | # 6 | # Given that it is always loaded, you are encouraged to keep this file as 7 | # light-weight as possible. 8 | # 9 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 10 | 11 | require 'rspec' 12 | require 'rspec/mocks' 13 | require 'messagebird' 14 | require 'webmock/rspec' 15 | 16 | RSpec.configure do |config| 17 | config.expect_with :rspec do |expectations| 18 | # Makes the `description` and `failure_message` of custom matchers include 19 | # text for helper methods defined using `chain`, e.g.: 20 | # be_bigger_than(2).and_smaller_than(4).description 21 | # # => "be bigger than 2 and smaller than 4" 22 | # ...rather than: 23 | # # => "be bigger than 2" 24 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 25 | end 26 | 27 | config.mock_with :rspec do |mocks| 28 | # Prevents you from mocking or stubbing a method that does not exist on 29 | # a real object. 30 | mocks.verify_partial_doubles = true 31 | end 32 | 33 | # Causes shared context metadata to be inherited by the metadata hash of host 34 | # groups and examples, rather than triggering implicit auto-inclusion in 35 | # groups with matching metadata. 36 | config.shared_context_metadata_behavior = :apply_to_host_groups 37 | 38 | # Limits the available syntax to the non-monkey patched syntax that is 39 | # recommended. For more details, see: 40 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 41 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 42 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 43 | # config.disable_monkey_patching! 44 | 45 | # This setting enables warnings. It's recommended, but in some cases may 46 | # be too noisy due to issues in dependencies. 47 | config.warnings = true 48 | 49 | # Turns deprecation warnings into errors. 50 | config.raise_errors_for_deprecations! 51 | 52 | # Use the documentation formatter for detailed output, 53 | # unless a formatter has already been configured 54 | # (e.g. via a command-line flag). 55 | config.default_formatter = 'doc' 56 | 57 | # Print the 10 slowest examples and example groups at the 58 | # end of the spec run, to help surface which specs are running 59 | # particularly slow. 60 | config.profile_examples = 3 61 | 62 | # Run specs in random order to surface order dependencies. If you find an 63 | # order dependency and want to debug it, you can fix the order by providing 64 | # the seed, which is printed after each run. 65 | # --seed 1234 66 | config.order = :random 67 | 68 | # Seed global randomization in this process using the `--seed` CLI option. 69 | # Setting this allows you to use `--seed` to deterministically reproduce 70 | # test failures related to randomization by passing the same `--seed` value 71 | # as the one that triggered the failure. 72 | Kernel.srand config.seed 73 | end 74 | -------------------------------------------------------------------------------- /examples/start_conversation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Start a conversation 19 | conversation = client.start_conversation('+31617000000', 'channel_id', type: 'text', content: { text: "Let's start a conversation" }) 20 | 21 | # Print the object information. 22 | puts 23 | puts 'The following information was returned as a conversation object:' 24 | puts " id : #{conversation.id}" 25 | puts " status : #{conversation.status}" 26 | puts " created_datetime : #{conversation.created_datetime}" 27 | puts " updated_datetime : #{conversation.updated_datetime}" 28 | puts " lastReceivedDateklme : #{conversation.last_received_datetime}" 29 | puts " lastUsedChannelId : #{conversation.last_used_channel_id}" 30 | 31 | puts ' Contact :' 32 | puts " id : #{conversation.contact.id}" 33 | puts " href : #{conversation.contact.href}" 34 | puts " msisdn : #{conversation.contact.msisdn}" 35 | puts " firstName : #{conversation.contact.first_name}" 36 | puts " lastName : #{conversation.contact.last_name}" 37 | puts " custom1 : #{conversation.contact.custom_details.custom1}" 38 | puts " custom2 : #{conversation.contact.custom_details.custom2}" 39 | puts " custom3 : #{conversation.contact.custom_details.custom3}" 40 | puts " custom4 : #{conversation.contact.custom_details.custom4}" 41 | puts " createdDatetime : #{conversation.contact.created_datetime}" 42 | puts " updatedDatetime : #{conversation.contact.updated_datetime}" 43 | 44 | puts ' Channels :' 45 | conversation.channels.each do |channel| 46 | puts " id : #{channel.id}" 47 | puts " name : #{channel.name}" 48 | puts " platformId : #{channel.platform_id}" 49 | puts " createdDatetime : #{channel.created_datetime}" 50 | puts " updatedDatetime : #{channel.updated_datetime}" 51 | puts 52 | end 53 | 54 | puts ' Messages :' 55 | puts " href : #{conversation.messages.href}" 56 | puts " totalCount : #{conversation.messages.total_count}" 57 | rescue MessageBird::ErrorException => e 58 | puts 59 | puts 'An error occured while creating a conversation:' 60 | puts 61 | 62 | e.errors.each do |error| 63 | puts " code : #{error.code}" 64 | puts " description : #{error.description}" 65 | puts " parameter : #{error.parameter}" 66 | puts 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/signed_request_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | SIGNING_KEY = 'PlLrKaqvZNRR5zAjm42ZT6q1SQxgbbGd' 4 | 5 | describe 'SignedRequest' do 6 | it 'verifies a correctly signed request without a body' do 7 | query = { 8 | 'recipient' => '31612345678', 9 | 'reference' => 'FOO', 10 | 'statusDatetime' => '2019-01-11T09:17:11+00:00', 11 | 'id' => 'eef0ab57a9e049be946f3821568c2b2e', 12 | 'status' => 'delivered', 13 | 'mccmnc' => '20408', 14 | 'ported' => '1' 15 | } 16 | signature = 'KVBdcVdz2lYMwcBLZCRITgxUfA/WkwSi+T3Wxl2HL6w=' 17 | request_timestamp = 1_547_198_231 18 | body = '' 19 | 20 | # Create a MessageBird signed request. 21 | signed_request = MessageBird::SignedRequest.new(query, signature, request_timestamp, body) 22 | 23 | expect(signed_request.verify(SIGNING_KEY)).to eq true 24 | end 25 | 26 | it 'verifies a correctly signed request with a body' do 27 | query = { 28 | 'recipient' => '31612345678', 29 | 'reference' => 'FOO', 30 | 'statusDatetime' => '2019-01-11T09:17:11+00:00', 31 | 'id' => 'eef0ab57a9e049be946f3821568c2b2e', 32 | 'status' => 'delivered', 33 | 'mccmnc' => '20408', 34 | 'ported' => '1' 35 | } 36 | signature = '2bl+38H4oHVg03pC3bk2LvCB0IHFgfC4cL5HPQ0LdmI=' 37 | request_timestamp = 1_547_198_231 38 | body = '{"foo":"bar"}' 39 | 40 | # Create a MessageBird signed request. 41 | signed_request = MessageBird::SignedRequest.new(query, signature, request_timestamp, body) 42 | 43 | expect(signed_request.verify(SIGNING_KEY)).to eq true 44 | end 45 | 46 | it 'fails to verify an incorrectly signed request' do 47 | query = { 48 | 'recipient' => '31612345678', 49 | 'reference' => 'BAR', 50 | 'statusDatetime' => '2019-01-11T09:17:11+00:00', 51 | 'id' => 'eef0ab57a9e049be946f3821568c2b2e', 52 | 'status' => 'delivered', 53 | 'mccmnc' => '20408', 54 | 'ported' => '1' 55 | } 56 | signature = 'KVBdcVdz2lYMwcBLZCRITgxUfA/WkwSi+T3Wxl2HL6w=' 57 | request_timestamp = 1_547_198_231 58 | body = '' 59 | 60 | # Create a MessageBird signed request. 61 | signed_request = MessageBird::SignedRequest.new(query, signature, request_timestamp, body) 62 | 63 | expect(signed_request.verify(SIGNING_KEY)).to eq false 64 | end 65 | 66 | it 'correctly identifies a request as recent' do 67 | query = {} 68 | signature = 'KVBdcVdz2lYMwcBLZCRITgxUfA/WkwSi+T3Wxl2HL6w=' 69 | request_timestamp = Time.now.getutc.to_i - 1 70 | body = '' 71 | 72 | # Create a MessageBird signed request. 73 | signed_request = MessageBird::SignedRequest.new(query, signature, request_timestamp, body) 74 | 75 | expect(signed_request.recent?).to eq true 76 | end 77 | 78 | it 'correctly identifies a request as not recent' do 79 | query = {} 80 | signature = 'KVBdcVdz2lYMwcBLZCRITgxUfA/WkwSi+T3Wxl2HL6w=' 81 | request_timestamp = Time.now.getutc.to_i - 100 82 | body = '' 83 | 84 | # Create a MessageBird signed request. 85 | signed_request = MessageBird::SignedRequest.new(query, signature, request_timestamp, body) 86 | 87 | expect(signed_request.recent?).to eq false 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/messagebird/http_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/https' 4 | require 'uri' 5 | 6 | module MessageBird 7 | class ServerException < StandardError; end 8 | class InvalidResponseException < StandardError; end 9 | class MethodNotAllowedException < ArgumentError; end 10 | 11 | class HttpClient 12 | attr_reader :access_key 13 | 14 | VALID_RESPONSE_CODES = [200, 201, 202, 204, 401, 404, 405, 422].freeze 15 | ENDPOINT = 'https://rest.messagebird.com/' 16 | SUBMIT_METHODS = [:patch, :post, :put].freeze 17 | ALLOWED_METHODS = SUBMIT_METHODS.dup + [:get, :delete].freeze 18 | 19 | def initialize(access_key) 20 | @access_key = access_key 21 | end 22 | 23 | def endpoint 24 | ENDPOINT 25 | end 26 | 27 | def build_http_client(uri) 28 | http = Net::HTTP.new(uri.host, uri.port) 29 | http.use_ssl = true 30 | 31 | http.set_debug_output($stdout) unless ENV['DEBUG_MB_HTTP_CLIENT'].nil? 32 | 33 | http 34 | end 35 | 36 | def request(method, path, params = {}, check_json: true) 37 | uri = URI.join(endpoint, path) 38 | http = build_http_client(uri) 39 | request = build_request(method, uri, params) 40 | 41 | # Execute the request and fetch the response. 42 | response = http.request(request) 43 | 44 | assert_valid_response_code(response.code.to_i) 45 | assert_json_response_type(response['Content-Type']) unless check_json 46 | 47 | response.body 48 | end 49 | 50 | def request_block(method, path, params = {}, &block) 51 | uri = URI.join(endpoint, path) 52 | http = build_http_client(uri) 53 | request = build_request(method, uri, params) 54 | 55 | http.request(request, block) 56 | end 57 | 58 | def prepare_request(request, params = {}) 59 | request.set_form_data(params) 60 | 61 | request 62 | end 63 | 64 | def build_request(method, uri, params = {}) 65 | # Construct the HTTP request. 66 | raise MethodNotAllowedException unless ALLOWED_METHODS.include?(method) 67 | 68 | request = Class.const_get("Net::HTTP::#{method.to_s.capitalize}").new(uri.request_uri) 69 | 70 | request['Accept'] = 'application/json' 71 | request['Authorization'] = "AccessKey #{@access_key}" 72 | request['User-Agent'] = "MessageBird/ApiClient/#{Version::STRING} Ruby/#{RUBY_VERSION}" 73 | 74 | if SUBMIT_METHODS.include?(method) && !params.empty? 75 | prepare_request(request, params) 76 | end 77 | 78 | request 79 | end 80 | 81 | # Throw an exception if the response code is not one we expect from the 82 | # MessageBird API. 83 | def assert_valid_response_code(code) 84 | raise ServerException, 'Unknown response from server' unless VALID_RESPONSE_CODES.include? code 85 | end 86 | 87 | # Throw an exception if the response's content type is not JSON. This only 88 | # checks the header: it doesn't inspect the actual body. 89 | def assert_json_response_type(content_type) 90 | # Check whether the header starts with application/json and don't check 91 | # for equality: some API's may append the charset to this header. 92 | raise InvalidResponseException, 'Response is not JSON' unless content_type.start_with? 'application/json' 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /examples/conversation_list.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Fetch the Conversation list 19 | offset = 0 20 | limit = 10 21 | conversations = client.conversation_list(limit, offset) 22 | 23 | # Print the object information. 24 | puts 'The following information was returned as a Conversation list:' 25 | puts 26 | puts " count : #{conversations.count}" 27 | puts " limit : #{conversations.limit}" 28 | puts " offset : #{conversations.offset}" 29 | puts " totalCount : #{conversations.total_count}" 30 | puts " links : #{conversations.links}" 31 | puts 32 | conversations.items.each do |conversation| 33 | puts 'Conversation:' 34 | puts " id : #{conversation.id}" 35 | puts " status : #{conversation.status}" 36 | puts " createdDatetime : #{conversation.created_datetime}" 37 | puts " updatedDatetime : #{conversation.updated_datetime}" 38 | puts " lastReceivedDateklme : #{conversation.last_received_datetime}" 39 | puts " lastUsedChannelId : #{conversation.last_used_channel_id}" 40 | 41 | puts ' Contact :' 42 | puts " id : #{conversation.contact.id}" 43 | puts " href : #{conversation.contact.href}" 44 | puts " msisdn : #{conversation.contact.msisdn}" 45 | puts " firstName : #{conversation.contact.first_name}" 46 | puts " lastName : #{conversation.contact.last_name}" 47 | puts " custom1 : #{conversation.contact.custom_details.custom1}" 48 | puts " custom2 : #{conversation.contact.custom_details.custom2}" 49 | puts " custom3 : #{conversation.contact.custom_details.custom3}" 50 | puts " custom4 : #{conversation.contact.custom_details.custom4}" 51 | puts " createdDatetime : #{conversation.contact.created_datetime}" 52 | puts " updatedDatetime : #{conversation.contact.updated_datetime}" 53 | 54 | puts ' Channels :' 55 | conversation.channels.each do |channel| 56 | puts " id : #{channel.id}" 57 | puts " name : #{channel.name}" 58 | puts " platformId : #{channel.platform_id}" 59 | puts " createdDatetime : #{channel.created_datetime}" 60 | puts " updatedDatetime : #{channel.updated_datetime}" 61 | puts 62 | end 63 | 64 | puts ' Messages :' 65 | puts " href : #{conversation.messages.href}" 66 | puts " totalCount : #{conversation.messages.total_count}" 67 | puts 68 | end 69 | rescue MessageBird::ErrorException => e 70 | puts 71 | puts 'An error occured while creating a conversation:' 72 | puts 73 | 74 | e.errors.each do |error| 75 | puts " code : #{error.code}" 76 | puts " description : #{error.description}" 77 | puts " parameter : #{error.parameter}" 78 | puts 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /examples/start_hsm_conversation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../lib/") 5 | require 'messagebird' 6 | 7 | # ACCESS_KEY = '' 8 | 9 | unless defined?(ACCESS_KEY) 10 | puts 'You need to set an ACCESS_KEY constant in this file' 11 | exit 1 12 | end 13 | 14 | begin 15 | # Create a MessageBird client with the specified ACCESS_KEY. 16 | client = MessageBird::Client.new(ACCESS_KEY) 17 | 18 | # Start a conversation 19 | conversation = client.start_conversation('+31617000000', 'channel_id', type: 'hsm', content: { hsm: { 20 | namespace: 'namespace', 21 | templateName: 'templateName', 22 | language: { 23 | policy: 'deterministic', 24 | code: 'en' 25 | }, 26 | params: [ 27 | default: 'Lorem Ipsum' 28 | ] 29 | } }) 30 | 31 | # Print the object information. 32 | puts 33 | puts 'The following information was returned as a conversation object:' 34 | puts " id : #{conversation.id}" 35 | puts " status : #{conversation.status}" 36 | puts " createdDatetime : #{conversation.created_datetime}" 37 | puts " updatedDatetime : #{conversation.updated_datetime}" 38 | puts " lastReceivedDatetime : #{conversation.last_received_datetime}" 39 | puts " lastUsedChannelId : #{conversation.last_used_channel_id}" 40 | 41 | puts ' Contact :' 42 | puts " id : #{conversation.contact.id}" 43 | puts " href : #{conversation.contact.href}" 44 | puts " msisdn : #{conversation.contact.msisdn}" 45 | puts " firstName : #{conversation.contact.first_name}" 46 | puts " lastName : #{conversation.contact.last_name}" 47 | puts " custom1 : #{conversation.contact.custom_details.custom1}" 48 | puts " custom2 : #{conversation.contact.custom_details.custom2}" 49 | puts " custom3 : #{conversation.contact.custom_details.custom3}" 50 | puts " custom4 : #{conversation.contact.custom_details.custom4}" 51 | puts " createdDatetime : #{conversation.contact.created_datetime}" 52 | puts " updatedDatetime : #{conversation.contact.updated_datetime}" 53 | 54 | puts ' Channels :' 55 | conversation.channels.each do |channel| 56 | puts " id : #{channel.id}" 57 | puts " name : #{channel.name}" 58 | puts " platformId : #{channel.platform_id}" 59 | puts " createdDatetime : #{channel.created_datetime}" 60 | puts " updatedDatetime : #{channel.updated_datetime}" 61 | puts 62 | end 63 | 64 | puts ' Messages :' 65 | puts " href : #{conversation.messages.href}" 66 | puts " totalCount : #{conversation.messages.total_count}" 67 | rescue MessageBird::ErrorException => e 68 | puts 69 | puts 'An error occured while creating a conversation:' 70 | puts 71 | 72 | e.errors.each do |error| 73 | puts " code : #{error.code}" 74 | puts " description : #{error.description}" 75 | puts " parameter : #{error.parameter}" 76 | puts 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /spec/data/conversations/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "offset": 0, 3 | "limit": 20, 4 | "count": 2, 5 | "totalCount": 2, 6 | "items": [ 7 | { 8 | "id": "fbbdde79129f45e3a179458a91e2ead6", 9 | "contactId": "03dfc27855c3475b953d6200a1b7eaf7", 10 | "contact": { 11 | "id": "03dfc27855c3475b953d6200a1b7eaf7", 12 | "href": "https://rest.messagebird.com/contacts/03dfc27855c3475b953d6200a1b7eaf7", 13 | "msisdn": 31612345678, 14 | "firstName": "John", 15 | "lastName": "Doe", 16 | "customDetails": { 17 | "custom1": null, 18 | "custom2": null, 19 | "custom3": null, 20 | "custom4": null 21 | }, 22 | "createdDatetime": "2018-08-01T09:45:52Z", 23 | "updatedDatetime": "2018-08-28T12:37:35Z" 24 | }, 25 | "channels": [ 26 | { 27 | "id": "619747f69cf940a98fb443140ce9aed2", 28 | "name": "My WhatsApp", 29 | "platformId": "whatsapp", 30 | "status": "active", 31 | "createdDatetime": "2018-08-28T11:56:57Z", 32 | "updatedDatetime": "2018-08-29T08:16:33Z" 33 | } 34 | ], 35 | "status": "active", 36 | "createdDatetime": "2018-08-29T08:52:54Z", 37 | "updatedDatetime": "2018-08-29T08:52:54Z", 38 | "lastReceivedDatetime": "2018-08-29T08:52:54Z", 39 | "lastUsedChannelId": "619747f69cf940a98fb443140ce9aed2", 40 | "lastUsedPlatformId": "whatsapp", 41 | "messages": { 42 | "totalCount": 10, 43 | "href": "https://conversations.messagebird.com/v1/conversations/fbbdde79129f45e3a179458a91e2ead6/messages" 44 | } 45 | }, 46 | { 47 | "id": "2e15efafec384e1c82e9842075e87beb", 48 | "contactId": "a621095fa44947a28b441cfdf85cb802", 49 | "contact": { 50 | "id": "a621095fa44947a28b441cfdf85cb802", 51 | "href": "https://rest.messagebird.com/1/contacts/a621095fa44947a28b441cfdf85cb802", 52 | "msisdn": 316123456789, 53 | "firstName": "Jen", 54 | "lastName": "Smith", 55 | "customDetails": { 56 | "custom1": null, 57 | "custom2": null, 58 | "custom3": null, 59 | "custom4": null 60 | }, 61 | "createdDatetime": "2018-06-03T20:06:03Z", 62 | "updatedDatetime": null 63 | }, 64 | "channels": [ 65 | { 66 | "id": "853eeb5348e541a595da93b48c61a1ae", 67 | "name": "SMS", 68 | "platformId": "sms", 69 | "status": "active", 70 | "createdDatetime": "2018-08-28T11:56:57Z", 71 | "updatedDatetime": "2018-08-29T08:16:33Z" 72 | }, 73 | { 74 | "id": "619747f69cf940a98fb443140ce9aed2", 75 | "name": "My WhatsApp", 76 | "platformId": "whatsapp", 77 | "status": "active", 78 | "createdDatetime": "2018-08-28T11:56:57Z", 79 | "updatedDatetime": "2018-08-29T08:16:33Z" 80 | } 81 | ], 82 | "status": "active", 83 | "createdDatetime": "2018-08-13T09:17:22Z", 84 | "updatedDatetime": "2018-08-29T07:35:48Z", 85 | "lastReceivedDatetime": "2018-08-29T07:35:48Z", 86 | "lastUsedChannelId": "853eeb5348e541a595da93b48c61a1ae", 87 | "lastUsedPlatformId": "sms", 88 | "messages": { 89 | "totalCount": 23, 90 | "href": "https://conversations.messagebird.com/v1/conversations/2e15efafec384e1c82e9842075e87beb/messages" 91 | } 92 | } 93 | ] 94 | } -------------------------------------------------------------------------------- /spec/call_flow_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'CallFlow' do 4 | let(:voice_client) { double(MessageBird::VoiceClient) } 5 | let(:client) { MessageBird::Client.new('', nil, nil, voice_client) } 6 | let(:call_flow_id) { '7355a691-381d-42b0-a037-9df5dab19e8e' } 7 | let(:step_id) { 'dd33982b-2c51-4a38-8975-fb8725e57c5d' } 8 | let(:title) { '' } 9 | let(:record) { true } 10 | let(:default) { false } 11 | 12 | it 'creates a call flow' do 13 | steps = [ 14 | { 15 | action: 'transfer', 16 | options: { 17 | destination: '31612345678' 18 | } 19 | } 20 | ] 21 | 22 | mock_data = { 23 | data: [ 24 | { 25 | id: call_flow_id, 26 | title: title, 27 | steps: [ 28 | { 29 | id: step_id, 30 | action: 'transfer', 31 | options: { 32 | destination: '31612345678' 33 | } 34 | } 35 | ], 36 | record: true, 37 | default: false, 38 | createdAt: '2019-11-07T12:37:59Z', 39 | updatedAt: '2019-11-07T12:37:59Z' 40 | } 41 | ] 42 | } 43 | expect(voice_client) 44 | .to receive(:request) 45 | .with(:post, 'call-flows', { steps: steps, default: default, record: record }) 46 | .and_return(mock_data.to_json) 47 | 48 | call_flow = client.call_flow_create(steps, default, record) 49 | expect(call_flow.id).to eq call_flow_id 50 | end 51 | 52 | it 'lists call flows' do 53 | voice_client = double(MessageBird::VoiceClient) 54 | client = MessageBird::Client.new('', nil, nil, voice_client) 55 | 56 | mock_data = { 57 | data: [ 58 | { 59 | id: 'cfid-0000', 60 | title: 'another title', 61 | steps: [ 62 | { 63 | id: 'sf001', 64 | action: 'transfer', 65 | options: { 66 | destination: '31612345678' 67 | } 68 | } 69 | ], 70 | record: true, 71 | default: false, 72 | createdAt: '2019-11-07T12:37:59Z', 73 | updatedAt: '2019-11-07T12:37:59Z' 74 | }, 75 | { 76 | id: 'cfid-0001', 77 | title: 'the title', 78 | steps: [ 79 | { 80 | id: 's000000000', 81 | action: 'transfer', 82 | options: { 83 | destination: '31612345678' 84 | } 85 | } 86 | ], 87 | record: true, 88 | default: false, 89 | createdAt: '2019-11-07T12:37:59Z', 90 | updatedAt: '2019-11-07T12:37:59Z' 91 | } 92 | ], 93 | perPage: 2, 94 | currentPage: 1, 95 | totalCount: 111 96 | } 97 | 98 | expect(voice_client) 99 | .to receive(:request) 100 | .with(:get, 'call-flows?perPage=2&page=1', {}) 101 | .and_return(mock_data.to_json) 102 | 103 | list = client.call_flow_list(2, 1) 104 | 105 | expect(list.items.count).to eq 2 106 | expect(list.items[0].id).to eq 'cfid-0000' 107 | expect(list.per_page).to eq 2 108 | expect(list.current_page).to eq 1 109 | expect(list.total_count).to eq 111 110 | end 111 | 112 | it 'view a call flow' do 113 | voice_client = double(MessageBird::VoiceClient) 114 | client = MessageBird::Client.new('', nil, nil, voice_client) 115 | 116 | mock_data = { 117 | data: [ 118 | { 119 | id: 'cfid-1', 120 | title: 'the title', 121 | steps: [ 122 | { 123 | id: 'sfid-1', 124 | action: 'transfer', 125 | options: { 126 | destination: '31612345678' 127 | } 128 | } 129 | ], 130 | record: true, 131 | default: false, 132 | createdAt: '2019-11-07T12:37:59Z', 133 | updatedAt: '2019-11-07T12:37:59Z' 134 | } 135 | ] 136 | } 137 | 138 | expect(voice_client) 139 | .to receive(:request) 140 | .with(:get, 'call-flows/cfid-1', {}) 141 | .and_return(mock_data.to_json) 142 | call_flow = client.call_flow_view('cfid-1') 143 | expect(call_flow.id).to eq 'cfid-1' 144 | end 145 | 146 | it 'delete a call flow' do 147 | voice_client = double(MessageBird::VoiceClient) 148 | client = MessageBird::Client.new('', nil, nil, voice_client) 149 | 150 | expect(voice_client) 151 | .to receive(:request) 152 | .with(:delete, 'call-flows/cfid-1', {}) 153 | .and_return('') 154 | client.call_flow_delete('cfid-1') 155 | end 156 | end 157 | -------------------------------------------------------------------------------- /spec/group_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Group' do 4 | it 'creates' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:post, 'groups', { name: 'friends' }) 11 | .and_return('{}') 12 | 13 | client.group_create('friends') 14 | end 15 | 16 | it 'deletes' do 17 | http_client = double(MessageBird::HttpClient) 18 | client = MessageBird::Client.new('', http_client) 19 | 20 | expect(http_client) 21 | .to receive(:request) 22 | .with(:delete, 'groups/group-id', {}) 23 | .and_return('') 24 | 25 | client.group_delete('group-id') 26 | end 27 | 28 | it 'lists' do 29 | http_client = double(MessageBird::HttpClient) 30 | client = MessageBird::Client.new('', http_client) 31 | 32 | expect(http_client) 33 | .to receive(:request) 34 | .with(:get, 'groups?limit=0&offset=0', {}) 35 | .and_return('{"offset": 0,"limit": 10,"count": 2,"totalCount": 2,"links": {"first": "https://rest.messagebird.com/groups?offset=0&limit=10","previous": null,"next": null,"last": "https://rest.messagebird.com/groups?offset=0&limit=10"},"items": [{"id": "first-id","href": "https://rest.messagebird.com/groups/first-id","name": "First","contacts": {"totalCount": 3,"href": "https://rest.messagebird.com/groups/first-id/contacts"},"createdDatetime": "2018-07-25T11:47:42+00:00","updatedDatetime": "2018-07-25T14:03:09+00:00"},{"id": "second-id","href": "https://rest.messagebird.com/groups/second-id","name": "Second","contacts": {"totalCount": 4,"href": "https://rest.messagebird.com/groups/second-id/contacts"},"createdDatetime": "2018-07-25T11:47:39+00:00","updatedDatetime": "2018-07-25T14:03:09+00:00"}]}') 36 | 37 | list = client.group_list 38 | 39 | expect(list.count).to eq 2 40 | expect(list[0].id).to eq 'first-id' 41 | end 42 | 43 | it 'reads an existing' do 44 | http_client = double(MessageBird::HttpClient) 45 | client = MessageBird::Client.new('', http_client) 46 | 47 | expect(http_client) 48 | .to receive(:request) 49 | .with(:get, 'groups/group-id', {}) 50 | .and_return('{"id": "group-id","href": "https://rest.messagebird.com/groups/group-id","name": "Friends","contacts": {"totalCount": 3,"href": "https://rest.messagebird.com/groups/group-id"},"createdDatetime": "2018-07-25T12:16:10+00:00","updatedDatetime": "2018-07-25T12:16:23+00:00"}') 51 | 52 | group = client.group('group-id') 53 | 54 | expect(group.id).to eq 'group-id' 55 | expect(group.name).to eq 'Friends' 56 | end 57 | 58 | it 'reads the contact reference' do 59 | http_client = double(MessageBird::HttpClient) 60 | client = MessageBird::Client.new('', http_client) 61 | 62 | expect(http_client) 63 | .to receive(:request) 64 | .with(:get, 'groups/group-id', {}) 65 | .and_return('{"id": "group-id","href": "https://rest.messagebird.com/groups/group-id","name": "Friends","contacts": {"totalCount": 3,"href": "https://rest.messagebird.com/groups/group-id/contacts"},"createdDatetime": "2018-07-25T12:16:10+00:00","updatedDatetime": "2018-07-25T12:16:23+00:00"}') 66 | 67 | group = client.group('group-id') 68 | 69 | expect(group.contacts.href).to eq 'https://rest.messagebird.com/groups/group-id/contacts' 70 | expect(group.contacts.total_count).to eq 3 71 | end 72 | 73 | it 'updates' do 74 | http_client = double(MessageBird::HttpClient) 75 | client = MessageBird::Client.new('', http_client) 76 | 77 | expect(http_client) 78 | .to receive(:request) 79 | .with(:patch, 'groups/group-id', { name: 'family' }) 80 | .and_return('{}') 81 | 82 | client.group_update('group-id', 'family') 83 | end 84 | 85 | it 'adds contacts' do 86 | http_client = double(MessageBird::HttpClient) 87 | client = MessageBird::Client.new('', http_client) 88 | 89 | expect(http_client) 90 | .to receive(:request) 91 | .with(:get, 'groups/group-id?_method=PUT&ids[]=first-contact-id&ids[]=second-contact-id', {}) 92 | .and_return('{}') 93 | 94 | client.group_add_contacts('group-id', ['first-contact-id', 'second-contact-id']) 95 | end 96 | 97 | it 'adds single contact' do 98 | http_client = double(MessageBird::HttpClient) 99 | client = MessageBird::Client.new('', http_client) 100 | 101 | expect(http_client) 102 | .to receive(:request) 103 | .with(:get, 'groups/group-id?_method=PUT&ids[]=contact-id', {}) 104 | .and_return('{}') 105 | 106 | client.group_add_contacts('group-id', 'contact-id') 107 | end 108 | 109 | it 'removes contact' do 110 | http_client = double(MessageBird::HttpClient) 111 | client = MessageBird::Client.new('', http_client) 112 | 113 | expect(http_client) 114 | .to receive(:request) 115 | .with(:delete, 'groups/group-id/contacts/contact-id', {}) 116 | .and_return('{}') 117 | 118 | client.group_delete_contact('group-id', 'contact-id') 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /lib/messagebird/request_validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'base64' 4 | require 'digest' 5 | require 'time' 6 | require 'jwt' 7 | 8 | module MessageBird 9 | class ValidationError < StandardError 10 | end 11 | 12 | ## 13 | # RequestValidator validates request signature signed by MessageBird services. 14 | # 15 | # @see https://developers.messagebird.com/docs/verify-http-requests 16 | class RequestValidator 17 | ALLOWED_ALGOS = %w[HS256 HS384 HS512].freeze 18 | 19 | ## 20 | # 21 | # @param [string] signature_key customer signature key. Can be retrieved through Developer Settings. This is NOT your API key. 22 | # @param [bool] skip_url_validation whether url_hash claim validation should be skipped. Note that when true, no query parameters should be trusted. 23 | def initialize(signature_key, skip_url_validation: false) 24 | @signature_key = signature_key 25 | @skip_url_validation = skip_url_validation 26 | end 27 | 28 | ## 29 | # This method validates provided request signature, which is a JWT token. 30 | # This JWT is signed with a MessageBird account unique secret key, ensuring the request is from MessageBird and a specific account. 31 | # The JWT contains the following claims: 32 | # * "url_hash" - the raw URL hashed with SHA256 ensuring the URL wasn't altered. 33 | # * "payload_hash" - the raw payload hashed with SHA256 ensuring the payload wasn't altered. 34 | # * "jti" - a unique token ID to implement an optional non-replay check (NOT validated by default). 35 | # * "nbf" - the not before timestamp. 36 | # * "exp" - the expiration timestamp is ensuring that a request isn't captured and used at a later time. 37 | # * "iss" - the issuer name, always MessageBird. 38 | # @param [String] signature the actual signature taken from request header "MessageBird-Signature-JWT". 39 | # @param [String] url the raw url including the protocol, hostname and query string, e.g. "https://example.com/?example=42". 40 | # @param [Array] request_body the raw request body. 41 | # @return [Array] raw signature payload 42 | # @raise [ValidationError] if signature is invalid 43 | # @see https://developers.messagebird.com/docs/verify-http-requests 44 | def validate_signature(signature, url, request_body) 45 | raise ValidationError, 'Signature can not be empty' if signature.to_s.empty? 46 | raise ValidationError, 'URL can not be empty' if !@skip_url_validation && url.to_s.empty? 47 | 48 | claims = decode_signature signature 49 | validate_url(url, claims['url_hash']) unless @skip_url_validation 50 | validate_payload(request_body, claims['payload_hash']) 51 | 52 | claims 53 | end 54 | 55 | private # Applies to every method below this line 56 | 57 | def decode_signature(signature) 58 | begin 59 | claims, * = JWT.decode signature, @signature_key, true, 60 | algorithm: ALLOWED_ALGOS, 61 | iss: 'MessageBird', 62 | required_claims: %w[iss nbf exp], 63 | verify_iss: true, 64 | leeway: 1 65 | rescue JWT::DecodeError => e 66 | raise ValidationError, e 67 | end 68 | 69 | claims 70 | end 71 | 72 | def validate_url(url, url_hash) 73 | expected_url_hash = Digest::SHA256.hexdigest url 74 | unless secure_compare(expected_url_hash, url_hash) 75 | raise ValidationError, 'invalid jwt: claim url_hash is invalid' 76 | end 77 | end 78 | 79 | def validate_payload(body, payload_hash) 80 | if !body.to_s.empty? && !payload_hash.to_s.empty? 81 | unless secure_compare(Digest::SHA256.hexdigest(body), payload_hash) 82 | raise ValidationError, 'invalid jwt: claim payload_hash is invalid' 83 | end 84 | elsif !body.to_s.empty? 85 | raise ValidationError, 'invalid jwt: claim payload_hash is not set but payload is present' 86 | elsif !payload_hash.to_s.empty? 87 | raise ValidationError, 'invalid jwt: claim payload_hash is set but actual payload is missing' 88 | end 89 | end 90 | 91 | # Adaption of https://github.com/rails/rails/blob/cf6ff17e9a3c6c1139040b519a341f55f0be16cf/activesupport/lib/active_support/security_utils.rb#L33 92 | # Copied here so as to avoid adding a dependency on ActiveSupport to this gem 93 | # 94 | # Note that unlike `fixed_length_secure_compare` in the above url we don't fall back to a custom implementation 95 | # of fixed_length_secure_compare, since OpenSSL.fixed_length_secure_compare is present in OpenSSL 2.2 96 | # https://github.com/ruby/openssl/blob/master/History.md#version-220 which is included in Ruby 3.0 and above 97 | def secure_compare(first, second) 98 | first.bytesize == second.bytesize && OpenSSL.fixed_length_secure_compare(first, second) 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /spec/number_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Numbers API' do 4 | it 'performs a number search' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:get, 'available-phone-numbers/NL?limit=5', { limit: 5 }) 11 | .and_return('{"items": [{"number": "3197010260188","country": "NL","region": "","locality": "","features": ["sms","voice"],"type": "mobile"},{"number": "3197010260188","country": "NL","region": "","locality": "","features": ["sms","voice"],"type": "mobile"}],"limit": 5,"count": 2}') 12 | 13 | numbers = client.number_search('NL', limit: 5) 14 | 15 | expect(numbers.count).to eq 2 16 | expect(numbers.limit).to eq 5 17 | expect(numbers[0].number).to eq '3197010260188' 18 | expect(numbers[1].country).to eq 'NL' 19 | end 20 | 21 | it 'performs a purchase' do 22 | http_client = double(MessageBird::HttpClient) 23 | client = MessageBird::Client.new('', http_client) 24 | 25 | expect(http_client) 26 | .to receive(:request) 27 | .with(:post, 'phone-numbers', { number: '31971234567', countryCode: 'NL', billingIntervalMonths: 1 }) 28 | .and_return('{"number": "31971234567","country": "NL","region": "Haarlem","locality": "Haarlem","features": ["sms","voice"],"tags": [],"type": "landline_or_mobile","status": "active","createdAt": "2019-04-25T14:04:04Z","renewalAt": "2019-05-25T00:00:00Z"}') 29 | 30 | number = client.number_purchase('31971234567', 'NL', 1) 31 | 32 | expect(number.number).to eq '31971234567' 33 | expect(number.country).to eq 'NL' 34 | expect(number.region).to eq 'Haarlem' 35 | expect(number.locality).to eq 'Haarlem' 36 | expect(number.features).to eq ['sms', 'voice'] 37 | expect(number.tags).to eq [] 38 | expect(number.type).to eq 'landline_or_mobile' 39 | expect(number.status).to eq 'active' 40 | expect(number.created_at).to eq Time.parse('2019-04-25T14:04:04Z') 41 | expect(number.renewal_at).to eq Time.parse('2019-05-25T00:00:00Z') 42 | end 43 | 44 | it 'performs a fetch all numbers' do 45 | http_client = double(MessageBird::HttpClient) 46 | client = MessageBird::Client.new('', http_client) 47 | 48 | expect(http_client) 49 | .to receive(:request) 50 | .with(:get, 'phone-numbers?type=mobile&features=sms&features=voice', { type: 'mobile', features: ['sms', 'voice'] }) 51 | .and_return('{"offset": 0,"limit": 20,"count": 1,"totalCount": 1,"items": [{"number": "31612345670","country": "NL","region": "Texel","locality": "Texel","features": ["sms","voice"],"tags": [],"type": "mobile","status": "active"}]}') 52 | 53 | numbers = client.number_fetch_all(type: 'mobile', features: ['sms', 'voice']) 54 | 55 | expect(numbers.count).to eq 1 56 | expect(numbers[0].number).to eq '31612345670' 57 | expect(numbers[0].country).to eq 'NL' 58 | expect(numbers[0].region).to eq 'Texel' 59 | expect(numbers[0].locality).to eq 'Texel' 60 | expect(numbers[0].features).to eq ['sms', 'voice'] 61 | expect(numbers[0].tags).to eq [] 62 | expect(numbers[0].type).to eq 'mobile' 63 | expect(numbers[0].status).to eq 'active' 64 | end 65 | 66 | it 'performs a fetch purchased' do 67 | http_client = double(MessageBird::HttpClient) 68 | client = MessageBird::Client.new('', http_client) 69 | 70 | expect(http_client) 71 | .to receive(:request) 72 | .with(:get, 'phone-numbers/31612345670', {}) 73 | .and_return('{"number": "31612345670","country": "NL","region": "Texel","locality": "Texel","features": ["sms","voice"],"tags": [],"type": "mobile","status": "active"}') 74 | 75 | number = client.number_fetch('31612345670') 76 | 77 | expect(number.number).to eq '31612345670' 78 | expect(number.country).to eq 'NL' 79 | expect(number.region).to eq 'Texel' 80 | expect(number.locality).to eq 'Texel' 81 | expect(number.features).to eq ['sms', 'voice'] 82 | expect(number.tags).to eq [] 83 | expect(number.type).to eq 'mobile' 84 | expect(number.status).to eq 'active' 85 | end 86 | 87 | it 'performs a update' do 88 | http_client = double(MessageBird::HttpClient) 89 | client = MessageBird::Client.new('', http_client) 90 | 91 | expect(http_client) 92 | .to receive(:request) 93 | .with(:patch, 'phone-numbers/31612345670', { tags: ['tag1'] }) 94 | .and_return('{"number": "31612345670","country": "NL","region": "Texel","locality": "Texel","features": ["sms","voice"],"tags": ["tag1"],"type": "mobile","status": "active"}') 95 | 96 | number = client.number_update('31612345670', ['tag1']) 97 | 98 | expect(number.number).to eq '31612345670' 99 | expect(number.country).to eq 'NL' 100 | expect(number.region).to eq 'Texel' 101 | expect(number.locality).to eq 'Texel' 102 | expect(number.features).to eq ['sms', 'voice'] 103 | expect(number.tags).to eq ['tag1'] 104 | expect(number.type).to eq 'mobile' 105 | expect(number.status).to eq 'active' 106 | end 107 | 108 | it 'performs a cancel' do 109 | http_client = double(MessageBird::HttpClient) 110 | client = MessageBird::Client.new('', http_client) 111 | 112 | expect(http_client) 113 | .to receive(:request) 114 | .with(:delete, 'phone-numbers/31612345670', {}) 115 | 116 | client.number_cancel('31612345670') 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MessageBird's REST API for Ruby 2 | =============================== 3 | This repository contains the open source Ruby client for MessageBird's REST API. Documentation can be found at: https://developers.messagebird.com/ 4 | 5 | [![Build Status](https://github.com/messagebird/ruby-rest-api/actions/workflows/test.yml/badge.svg)](https://github.com/messagebird/ruby-rest-api/actions) 6 | 7 | Requirements 8 | ------------ 9 | - [Sign up](https://dashboard.messagebird.com/app/en/sign-up) for a free MessageBird account 10 | - Create a new `access_key` in the developers sections 11 | - MessageBird's API client for Ruby requires Ruby >= 1.9 12 | 13 | Installation 14 | ------------ 15 | You can either include the following line in your Gemfile: 16 | 17 | ```ruby 18 | gem 'messagebird-rest', require: 'messagebird' 19 | ``` 20 | 21 | Or you can just manually install it from the command line: 22 | 23 | ```sh 24 | $ gem install messagebird-rest 25 | ``` 26 | 27 | Examples 28 | -------- 29 | We have put some self-explanatory examples in the *examples* directory, but here is a quick breakdown on how it works. First, you need to create an instance of **MessageBird::Client**. Be sure to replace **YOUR_ACCESS_KEY** with something real in the bottom example. 30 | 31 | ```ruby 32 | require 'pp' # Only needed for this example 33 | require 'messagebird' 34 | 35 | client = MessageBird::Client.new(YOUR_ACCESS_KEY) 36 | ``` 37 | 38 | That's easy enough. Now we can query the server for information. 39 | 40 | ##### Balance 41 | Lets start with out with an overview of our balance. 42 | 43 | ```ruby 44 | pp client.balance 45 | 46 | # 50 | ``` 51 | 52 | ##### Messages 53 | Chances are that the most common use you'll have for this API client is the ability to send out text messages. For that purpose we have created the **message_create** method, which takes the required *originator*, one or more *recipients* and a *body* text for parameters. 54 | 55 | Optional parameters can be specified as a hash. 56 | 57 | ```ruby 58 | pp client.message_create('FromMe', '31612345678', 'Hello World', reference: 'MyReference') 59 | 60 | #1, 73 | "totalSentCount"=>1, 74 | "totalDeliveredCount"=>0, 75 | "totalDeliveryFailedCount"=>0, 76 | "items"=> 77 | [#]}, 81 | @reference="MyReference", 82 | @scheduled_datetime=nil, 83 | @type="sms", 84 | @type_details={}, 85 | @validity=nil> 86 | ``` 87 | 88 | As a possible follow-up, you can use the **message** method with the above mentioned batch-id to query the status of the message that you just created. It will return a similar Message object. 89 | 90 | ```ruby 91 | client.message('211e6280453ba746e8eeff7b12582146') 92 | ``` 93 | 94 | ##### HLR 95 | To perform HLR lookups we have created the **hlr_create** method, which takes a number and a reference for parameters. 96 | 97 | ```ruby 98 | pp client.hlr_create('31612345678', 'MyReference') 99 | 100 | # 109 | ``` 110 | 111 | Similar to the **message_create** and **message** methods, the **hlr_create** method has an accompanying **hlr** method to poll the HLR object. 112 | 113 | ```ruby 114 | client.hlr('4933bed0453ba7455031712h16830892') 115 | ``` 116 | 117 | ##### Verify (One-Time Password) 118 | You can send and verify One-Time Passwords through the MessageBird API using the **verify_create** and **verify_token** methods. 119 | 120 | ```ruby 121 | # verify_create requires a recipient as a required parameter, and other optional paramaters 122 | client.verify_create(31612345678, reference: "YourReference") 123 | 124 | #"https://rest.messagebird.com/messages/67d42f004555213679416f0b13254392"}, 130 | @created_datetime=2015-05-12 16:51:19 +0200, 131 | @validUntilDatetime=2015-05-12 16:51:49 +0200> 132 | ``` 133 | 134 | This sends a token to the recipient, which can be verified with the **verify_token** method. 135 | 136 | ```ruby 137 | # verify_token requires the id of the verify request and a token as required parameters. 138 | client.verify_token('080b7f804555213678f14f6o24607735', 123456) 139 | ``` 140 | 141 | ##### Voice Message 142 | MessageBird also offers the ability to send out a text message as a voice message, or text-to-speech. For that purpose we have created the **voice_message_create** method, which takes one or more required *recipients* and a *body* text for parameters. 143 | 144 | Optional parameters can be specified as a hash. 145 | 146 | ```ruby 147 | pp client.voice_message_create('31612345678', 'Hello World', reference: 'MyReference') 148 | 149 | #1, 159 | "totalSentCount"=>1, 160 | "totalDeliveredCount"=>0, 161 | "totalDeliveryFailedCount"=>0, 162 | "items"=> 163 | [#]}, 167 | @reference="MyReference", 168 | @repeat=1, 169 | @scheduledDatetime=nil, 170 | @voice="female"> 171 | ``` 172 | 173 | Similar to regular messaging and HLR lookups, there is a method available to fetch the VoiceMessage object by using an *id*. 174 | 175 | ```ruby 176 | client.voice_message('a08e51a0353bd16cea7f298a37405850') 177 | ``` 178 | 179 | ##### Numbers 180 | There is also a Numbers API that allow you to search for and purchase number subscriptions to use as originator in other services. 181 | 182 | ```ruby 183 | pp client.number_search("NL", limit: 52) 184 | 185 | #, 195 | #, 202 | #, 209 | #, 216 | #], 223 | @limit=5, 224 | @type=MessageBird::Number> 225 | ```` 226 | 227 | Documentation 228 | ------------- 229 | Complete documentation, instructions, and examples are available at: 230 | [https://developers.messagebird.com/](https://developers.messagebird.com/). 231 | 232 | Releasing this gem 233 | ------------------ 234 | [RELEASE.md](./RELEASE.md). 235 | 236 | License 237 | ------- 238 | The MessageBird REST Client for Ruby is licensed under [The BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause). Copyright (c) 2025, MessageBird 239 | -------------------------------------------------------------------------------- /spec/contact_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Contact' do 4 | it 'creates' do 5 | http_client = double(MessageBird::HttpClient) 6 | client = MessageBird::Client.new('', http_client) 7 | 8 | expect(http_client) 9 | .to receive(:request) 10 | .with(:post, 'contacts', { msisdn: '31612345678', first_name: 'Foo', last_name: 'Bar', custom1: 'First', custom4: 'Fourth' }) 11 | .and_return('{}') 12 | 13 | client.contact_create(31_612_345_678, first_name: 'Foo', last_name: 'Bar', custom1: 'First', custom4: 'Fourth') 14 | end 15 | 16 | it 'deletes' do 17 | http_client = double(MessageBird::HttpClient) 18 | client = MessageBird::Client.new('', http_client) 19 | 20 | expect(client) 21 | .to receive(:request) 22 | .with(:delete, 'contacts/contact-id') 23 | .and_return('') 24 | 25 | client.contact_delete('contact-id') 26 | end 27 | 28 | it 'lists' do 29 | http_client = double(MessageBird::HttpClient) 30 | client = MessageBird::Client.new('', http_client) 31 | 32 | expect(http_client) 33 | .to receive(:request) 34 | .with(:get, 'contacts?limit=0&offset=0', {}) 35 | .and_return('{"offset": 0,"limit": 20,"count": 2,"totalCount": 2,"links": {"first": "https://rest.messagebird.com/contacts?offset=0","previous": null,"next": null,"last": "https://rest.messagebird.com/contacts?offset=0"},"items": [{"id": "first-id","href": "https://rest.messagebird.com/contacts/first-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:34:08+00:00"},{"id": "second-id","href": "https://rest.messagebird.com/contacts/second-id","msisdn": 49612345678,"firstName": "Hello","lastName": "World","custom_details": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/messages"},"created_datetime": "2018-07-13T10:33:52+00:00","updatedDatetime": null}]}') 36 | 37 | list = client.contact_list 38 | 39 | expect(list.offset).to eq 0 40 | expect(list.limit).to eq 20 41 | expect(list.count).to eq 2 42 | expect(list.total_count).to eq 2 43 | 44 | expect(list.items[0].id).to eq 'first-id' 45 | end 46 | 47 | it 'lists and allows array access' do 48 | http_client = double(MessageBird::HttpClient) 49 | client = MessageBird::Client.new('', http_client) 50 | 51 | expect(http_client) 52 | .to receive(:request) 53 | .with(:get, 'contacts?limit=10&offset=0', {}) 54 | .and_return('{"offset": 0,"limit": 20,"count": 2,"totalCount": 2,"links": {"first": "https://rest.messagebird.com/contacts?offset=0","previous": null,"next": null,"last": "https://rest.messagebird.com/contacts?offset=0"},"items": [{"id": "first-id","href": "https://rest.messagebird.com/contacts/first-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:34:08+00:00"},{"id": "second-id","href": "https://rest.messagebird.com/contacts/second-id","msisdn": 49612345678,"firstName": "Hello","lastName": "World","custom_details": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/messages"},"created_datetime": "2018-07-13T10:33:52+00:00","updatedDatetime": null}]}') 55 | 56 | list = client.contact_list(10) 57 | 58 | expect(list[1].id).to eq 'second-id' 59 | end 60 | 61 | it 'lists with pagination' do 62 | http_client = double(MessageBird::HttpClient) 63 | client = MessageBird::Client.new('', http_client) 64 | 65 | expect(http_client) 66 | .to receive(:request) 67 | .with(:get, 'contacts?limit=10&offset=20', {}) 68 | .and_return('{}') 69 | 70 | client.contact_list(10, 20) 71 | end 72 | 73 | it 'reads an existing' do 74 | http_client = double(MessageBird::HttpClient) 75 | client = MessageBird::Client.new('', http_client) 76 | 77 | expect(http_client) 78 | .to receive(:request) 79 | .with(:get, 'contacts/contact-id', {}) 80 | .and_return('{"id": "contact-id","href": "https://rest.messagebird.com/contacts/contact-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": "First","custom2": "Second","custom3": "Third","custom4": "Fourth"},"groups": {"totalCount": 3,"href": "https://rest.messagebird.com/contacts/contact-id/groups"},"messages": {"totalCount": 5,"href": "https://rest.messagebird.com/contacts/contact-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:44:08+00:00"}') 81 | 82 | contact = client.contact('contact-id') 83 | 84 | expect(contact.id).to eq 'contact-id' 85 | expect(contact.msisdn).to eq 31_612_345_678 86 | end 87 | 88 | it 'reads custom details' do 89 | http_client = double(MessageBird::HttpClient) 90 | client = MessageBird::Client.new('', http_client) 91 | 92 | expect(http_client) 93 | .to receive(:request) 94 | .with(:get, 'contacts/contact-id', {}) 95 | .and_return('{"id": "contact-id","href": "https://rest.messagebird.com/contacts/contact-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": "First","custom2": "Second","custom3": "Third","custom4": "Fourth"},"groups": {"totalCount": 3,"href": "https://rest.messagebird.com/contacts/contact-id/groups"},"messages": {"totalCount": 5,"href": "https://rest.messagebird.com/contacts/contact-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:44:08+00:00"}') 96 | 97 | contact = client.contact('contact-id') 98 | 99 | expect(contact.custom_details).to be_an_instance_of(MessageBird::CustomDetails) 100 | 101 | expect(contact.custom_details.custom1).to eq 'First' 102 | expect(contact.custom_details.custom4).to eq 'Fourth' 103 | end 104 | 105 | it 'updates' do 106 | http_client = double(MessageBird::HttpClient) 107 | client = MessageBird::Client.new('', http_client) 108 | 109 | expect(http_client) 110 | .to receive(:request) 111 | .with(:patch, 'contacts/contact-id', { msisdn: 31_687_654_321, custom3: 'Third' }) 112 | .and_return('') 113 | 114 | client.contact_update('contact-id', msisdn: 31_687_654_321, custom3: 'Third') 115 | end 116 | 117 | it 'lists groups' do 118 | http_client = double(MessageBird::HttpClient) 119 | client = MessageBird::Client.new('', http_client) 120 | 121 | expect(http_client) 122 | .to receive(:request) 123 | .with(:get, 'contacts/contact-id', {}) 124 | .and_return('{"id": "contact-id","href": "https://rest.messagebird.com/contacts/contact-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": "First","custom2": "Second","custom3": "Third","custom4": "Fourth"},"groups": {"totalCount": 3,"href": "https://rest.messagebird.com/contacts/contact-id/groups"},"messages": {"totalCount": 5,"href": "https://rest.messagebird.com/contacts/contact-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:44:08+00:00"}') 125 | 126 | contact = client.contact('contact-id') 127 | 128 | expect(contact.groups.href).to eq 'https://rest.messagebird.com/contacts/contact-id/groups' 129 | expect(contact.groups.total_count).to eq 3 130 | end 131 | 132 | it 'lists messages' do 133 | http_client = double(MessageBird::HttpClient) 134 | client = MessageBird::Client.new('', http_client) 135 | 136 | expect(http_client) 137 | .to receive(:request) 138 | .with(:get, 'contacts/contact-id', {}) 139 | .and_return('{"id": "contact-id","href": "https://rest.messagebird.com/contacts/contact-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","custom_details": {"custom1": "First","custom2": "Second","custom3": "Third","custom4": "Fourth"},"groups": {"totalCount": 3,"href": "https://rest.messagebird.com/contacts/contact-id/groups"},"messages": {"totalCount": 5,"href": "https://rest.messagebird.com/contacts/contact-id/messages"},"created_datetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:44:08+00:00"}') 140 | 141 | contact = client.contact('contact-id') 142 | 143 | expect(contact.messages.href).to eq 'https://rest.messagebird.com/contacts/contact-id/messages' 144 | expect(contact.messages.total_count).to eq 5 145 | end 146 | end 147 | -------------------------------------------------------------------------------- /spec/conversation_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Conversation' do 4 | it 'sends a message' do 5 | conversation_client = double(MessageBird::ConversationClient) 6 | client = MessageBird::Client.new('', nil, conversation_client) 7 | 8 | expect(conversation_client) 9 | .to receive(:request) 10 | .with(:post, 'send', { from: 'MBTest', to: 31_612_345_678, type: 'text', content: { text: 'Hi there!' } }) 11 | .and_return('{}') 12 | 13 | client.send_conversation_message('MBTest', 31_612_345_678, type: 'text', content: { text: 'Hi there!' }) 14 | end 15 | 16 | it 'starts a conversation' do 17 | conversation_client = double(MessageBird::ConversationClient) 18 | client = MessageBird::Client.new('', nil, conversation_client) 19 | 20 | expect(conversation_client) 21 | .to receive(:request) 22 | .with(:post, 'conversations/start', { channel_id: 'c0dae31e440145e094c4708b7d000000', to: 31_612_345_678, type: 'text', content: { text: 'Hi there!' } }) 23 | .and_return('{}') 24 | 25 | client.start_conversation(31_612_345_678, 'c0dae31e440145e094c4708b7d000000', type: 'text', content: { text: 'Hi there!' }) 26 | end 27 | 28 | it 'lists' do 29 | conversation_client = double(MessageBird::ConversationClient) 30 | client = MessageBird::Client.new('', nil, conversation_client) 31 | 32 | expect(conversation_client) 33 | .to receive(:request) 34 | .with(:get, 'conversations?limit=2&offset=0', {}) 35 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 36 | 37 | list = client.conversation_list(2, 0) 38 | 39 | expect(list.count).to eq 2 40 | expect(list[0].id).to eq '00000000000000000000000000000000' 41 | end 42 | 43 | it 'list without args' do 44 | conversation_client = double(MessageBird::ConversationClient) 45 | client = MessageBird::Client.new('', nil, conversation_client) 46 | 47 | expect(conversation_client) 48 | .to receive(:request) 49 | .with(:get, 'conversations?', {}) 50 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 51 | 52 | list = client.conversation_list 53 | 54 | expect(list.count).to eq 2 55 | expect(list[0].id).to eq '00000000000000000000000000000000' 56 | end 57 | 58 | it 'list messages' do 59 | conversation_client = double(MessageBird::ConversationClient) 60 | client = MessageBird::Client.new('', nil, conversation_client) 61 | 62 | conversation_id = '5f3437fdb8444583aea093a047ac014b' 63 | 64 | expect(conversation_client) 65 | .to receive(:request) 66 | .with(:get, "conversations/#{conversation_id}/messages?limit=2&offset=0", {}) 67 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 68 | 69 | list = client.conversation_messages_list(conversation_id, 2, 0) 70 | 71 | expect(list.count).to eq 2 72 | expect(list[0].id).to eq '00000000000000000000000000000000' 73 | end 74 | 75 | it 'list messages without args' do 76 | conversation_client = double(MessageBird::ConversationClient) 77 | client = MessageBird::Client.new('', nil, conversation_client) 78 | 79 | conversation_id = '5f3437fdb8444583aea093a047ac014b' 80 | 81 | expect(conversation_client) 82 | .to receive(:request) 83 | .with(:get, "conversations/#{conversation_id}/messages?", {}) 84 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 85 | 86 | list = client.conversation_messages_list(conversation_id) 87 | 88 | expect(list.count).to eq 2 89 | expect(list[0].id).to eq '00000000000000000000000000000000' 90 | end 91 | 92 | it 'reads an existing' do 93 | conversation_client = double(MessageBird::ConversationClient) 94 | client = MessageBird::Client.new('', nil, conversation_client) 95 | 96 | expect(conversation_client) 97 | .to receive(:request) 98 | .with(:get, 'conversations/conversation-id', {}) 99 | .and_return('{"id": "conversation-id","href": "https://conversations.messagebird.com/v1/conversations/conversation-id"}') 100 | 101 | conversation = client.conversation('conversation-id') 102 | 103 | expect(conversation.id).to eq 'conversation-id' 104 | end 105 | 106 | it 'updates a conversation' do 107 | conversation_client = double(MessageBird::ConversationClient) 108 | client = MessageBird::Client.new('', nil, conversation_client) 109 | 110 | expect(conversation_client) 111 | .to receive(:request) 112 | .with(:patch, 'conversations/conversation-id', { status: MessageBird::Conversation::CONVERSATION_STATUS_ARCHIVED }) 113 | .and_return('{"id":"conversation-id", "contactId": "contact-id"}') 114 | conversation = client.conversation_update('conversation-id', MessageBird::Conversation::CONVERSATION_STATUS_ARCHIVED) 115 | 116 | expect(conversation.id).to eq 'conversation-id' 117 | expect(conversation.contact_id).to eq 'contact-id' 118 | end 119 | 120 | it 'replies to a conversation' do 121 | conversation_client = double(MessageBird::ConversationClient) 122 | client = MessageBird::Client.new('', nil, conversation_client) 123 | 124 | expect(conversation_client) 125 | .to receive(:request) 126 | .with(:post, 'conversations/conversation-id/messages', { type: 'text', content: { text: 'Hi there' } }) 127 | .and_return({ id: 'message-id', channel_id: 'channel-id', conversationId: 'conversation-id' }.to_json) 128 | 129 | msg = client.conversation_reply('conversation-id', type: 'text', content: { text: 'Hi there' }) 130 | 131 | expect(msg.id).to eq 'message-id' 132 | expect(msg.channel_id).to eq 'channel-id' 133 | expect(msg.conversation_id).to eq 'conversation-id' 134 | end 135 | 136 | it 'reads messages in a conversation' do 137 | conversation_client = double(MessageBird::ConversationClient) 138 | client = MessageBird::Client.new('', nil, conversation_client) 139 | 140 | expect(conversation_client) 141 | .to receive(:request) 142 | .with(:get, 'conversations/conversation-id/messages?limit=2&offset=0', {}) 143 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 144 | 145 | list = client.conversation_messages_list('conversation-id', 2, 0) 146 | 147 | expect(list.count).to eq 2 148 | expect(list[0].id).to eq '00000000000000000000000000000000' 149 | end 150 | 151 | it 'reads a message' do 152 | conversation_client = double(MessageBird::ConversationClient) 153 | client = MessageBird::Client.new('', nil, conversation_client) 154 | 155 | expect(conversation_client) 156 | .to receive(:request) 157 | .with(:get, 'messages/message-id', {}) 158 | .and_return('{"id":"00000000000000000000000000000000"}') 159 | 160 | msg = client.conversation_message('message-id') 161 | 162 | expect(msg.id).to eq '00000000000000000000000000000000' 163 | end 164 | 165 | it 'creates a webhook' do 166 | conversation_client = double(MessageBird::ConversationClient) 167 | client = MessageBird::Client.new('', nil, conversation_client) 168 | 169 | expect(conversation_client) 170 | .to receive(:request) 171 | .with(:post, 'webhooks', { channel_id: 'channel-id', events: [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_CREATED, MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_UPDATED], url: 'url' }) 172 | .and_return('{"id":"00000000000000000000000000000000", "events": ["message.created", "message.updated"]}') 173 | 174 | webhook = client.conversation_webhook_create('channel-id', 'url', [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_CREATED, MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_UPDATED]) 175 | 176 | expect(webhook.id).to eq '00000000000000000000000000000000' 177 | expect(webhook.events.count).to eq 2 178 | end 179 | 180 | it 'reads a list of webhooks' do 181 | conversation_client = double(MessageBird::ConversationClient) 182 | client = MessageBird::Client.new('', nil, conversation_client) 183 | 184 | expect(conversation_client) 185 | .to receive(:request) 186 | .with(:get, 'webhooks?limit=10&offset=0', {}) 187 | .and_return('{"offset":0,"limit":10,"count":2,"totalCount":2,"items":[{"id":"00000000000000000000000000000000"},{"id":"11111111111111111111111111111111"}]}') 188 | 189 | list = client.conversation_webhooks_list(10, 0) 190 | 191 | expect(list.count).to eq 2 192 | expect(list[0].id).to eq '00000000000000000000000000000000' 193 | end 194 | 195 | it 'reads a webhook' do 196 | conversation_client = double(MessageBird::ConversationClient) 197 | client = MessageBird::Client.new('', nil, conversation_client) 198 | 199 | expect(conversation_client) 200 | .to receive(:request) 201 | .with(:get, 'webhooks/webhook-id', {}) 202 | .and_return('{"id":"00000000000000000000000000000000"}') 203 | 204 | webhook = client.conversation_webhook('webhook-id') 205 | 206 | expect(webhook.id).to eq '00000000000000000000000000000000' 207 | end 208 | 209 | it 'updates a webhook' do 210 | conversation_client = double(MessageBird::ConversationClient) 211 | client = MessageBird::Client.new('', nil, conversation_client) 212 | 213 | expect(conversation_client) 214 | .to receive(:request) 215 | .with(:patch, 'webhooks/webhook-id', { events: [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_CREATED], url: 'url' }) 216 | .and_return('{"id":"00000000000000000000000000000000", "events": ["message.created"]}') 217 | 218 | webhook = client.conversation_webhook_update('webhook-id', events: [MessageBird::Conversation::WEBHOOK_EVENT_MESSAGE_CREATED], url: 'url') 219 | 220 | expect(webhook.id).to eq '00000000000000000000000000000000' 221 | expect(webhook.events.count).to eq 1 222 | end 223 | 224 | it 'deletes a webhook' do 225 | conversation_client = double(MessageBird::ConversationClient) 226 | client = MessageBird::Client.new('', nil, conversation_client) 227 | 228 | expect(conversation_client) 229 | .to receive(:request) 230 | .with(:delete, 'webhooks/webhook-id', {}) 231 | .and_return('') 232 | 233 | client.conversation_webhook_delete('webhook-id') 234 | end 235 | end 236 | --------------------------------------------------------------------------------