hellio-messaging 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 45de36c0b40d47f5073fcce914ac1f18583a7ef9a13ad128deed76abdc6205f7
4
+ data.tar.gz: 4e68b72f61d9c5431807c4797b81a75ad445ba1ed5b941f3fa8b69e384ebf98b
5
+ SHA512:
6
+ metadata.gz: '09058b69a323ccdafc77293a97f0fcadb8567c4bf3cfa3f01c97b675ef7690eff30515da914bdc050f637d8b25092367d3bd844c1d7898beaebded4c2fa621b3'
7
+ data.tar.gz: 244a062620713196303429e28b74db4073f9120b7a9d818e3bc00862198c944a4c998b5fd206cd018a74897f237945d0cca9775681e3dbceaa977f74fef9e116
data/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ All notable changes to `hellio-messaging` are documented here.
4
+ This project follows [Semantic Versioning](https://semver.org).
5
+
6
+ ## [1.0.0] - 2026-07-05
7
+
8
+ Initial release of the official Ruby SDK for the Hellio Messaging API v1.
9
+
10
+ ### Added
11
+ - `Hellio::Client` with Bearer-token auth and one method per endpoint:
12
+ - Account: `balance`, `pricing`.
13
+ - SMS: `sms`, `message`, `campaign`.
14
+ - OTP: `otp`, `verify_otp`, `verify` (channels `sms`, `email`, `voice`).
15
+ - Voice: `voice`, `voice_status`.
16
+ - Number lookup (HLR): `lookup`, `lookups`, `lookup_result`.
17
+ - Email verification: `verify_email`.
18
+ - Webhooks: `webhooks`, `create_webhook`, `delete_webhook`.
19
+ - Recipient normalization: methods accept a single string, a comma-separated
20
+ string, or an array.
21
+ - Typed errors: `Hellio::InvalidApiTokenError` (401),
22
+ `Hellio::InsufficientBalanceError` (402), `Hellio::ValidationError` (422, with
23
+ `#errors`), `Hellio::RateLimitError` (429), and `Hellio::Error` (base). Each
24
+ carries `status_code` and the parsed `response` body.
25
+ - Configuration via constructor or the `HELLIO_API_TOKEN`, `HELLIO_BASE_URL`,
26
+ and `HELLIO_DEFAULT_SENDER` environment variables.
27
+ - Pluggable HTTP adapter (defaults to the standard library `net/http`) so tests
28
+ can inject a fake transport.
29
+ - RSpec suite with WebMock and a GitHub Actions matrix (Ruby 3.1, 3.2, 3.3).
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Albert Ninyeh, Hellio Solutions
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Hellio Messaging - Official Ruby SDK
2
+
3
+ [![tests](https://github.com/HellioSolutions/hellio-ruby/actions/workflows/tests.yml/badge.svg)](https://github.com/HellioSolutions/hellio-ruby/actions/workflows/tests.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/hellio-messaging.svg)](https://rubygems.org/gems/hellio-messaging)
5
+ [![Gem Downloads](https://img.shields.io/gem/dt/hellio-messaging.svg)](https://rubygems.org/gems/hellio-messaging)
6
+ [![License](https://img.shields.io/github/license/HellioSolutions/hellio-ruby.svg)](LICENSE)
7
+
8
+ Ruby client for the [Hellio Messaging](https://helliomessaging.com) API v1:
9
+ **SMS**, **OTP** (SMS / email / voice), **Voice broadcasts**, **Number Lookup (HLR)**,
10
+ **Email Verification**, **Pricing**, **Balance**, and **Webhooks**. It uses only
11
+ the Ruby standard library (`net/http` and `json`), so there are no runtime
12
+ dependencies.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ gem install hellio-messaging
18
+ ```
19
+
20
+ Or with Bundler, add to your `Gemfile`:
21
+
22
+ ```ruby
23
+ gem "hellio-messaging"
24
+ ```
25
+
26
+ then run `bundle install`.
27
+
28
+ ## Configure
29
+
30
+ Generate a token in your dashboard (**Settings -> API -> Generate API token**),
31
+ then create a client. You can pass values directly or set environment variables.
32
+
33
+ ```ruby
34
+ require "hellio"
35
+
36
+ client = Hellio::Client.new(
37
+ token: "your-token-here",
38
+ default_sender: "HellioSMS"
39
+ )
40
+ ```
41
+
42
+ Environment variables are read as fallbacks when an option is omitted:
43
+
44
+ ```dotenv
45
+ HELLIO_BASE_URL=https://api.helliomessaging.com/v1
46
+ HELLIO_API_TOKEN=your-token-here
47
+ HELLIO_DEFAULT_SENDER=HellioSMS
48
+ ```
49
+
50
+ ```ruby
51
+ client = Hellio::Client.new # reads HELLIO_API_TOKEN, HELLIO_BASE_URL, HELLIO_DEFAULT_SENDER
52
+ ```
53
+
54
+ Optional constructor options: `base_url` (defaults to
55
+ `https://api.helliomessaging.com/v1`), `timeout` (seconds, default 30), and
56
+ `http` (a custom HTTP adapter, mainly for tests).
57
+
58
+ Every call returns the decoded JSON as a `Hash` with string keys (payloads are
59
+ under the `"data"` key). Non-2xx responses raise a typed error (see below).
60
+
61
+ ## Usage
62
+
63
+ ```ruby
64
+ # Account
65
+ client.balance # {"data" => {"balance" => "195.0000", "available" => "194.65", ...}}
66
+ client.pricing("GH") # optional ISO-2 country filter
67
+
68
+ # SMS (recipients: string, comma list, or array)
69
+ client.sms("233241234567", "Hello!")
70
+ client.sms(["233241234567", "233201234567"], "Hi all", sender: "HellioSMS")
71
+ client.message(1024) # delivery status
72
+ client.campaign(1024) # campaign summary
73
+
74
+ # OTP - sender (Sender ID) is REQUIRED for sms/voice and must be approved on your account.
75
+ # Optional length (4-10 digits) and expiry (minutes). Returns status "queued".
76
+ client.otp("233241234567", sender: "HellioSMS") # SMS
77
+ client.otp("233241234567", sender: "HellioSMS", channel: "voice") # Voice (TTS reads the code)
78
+ client.otp("233241234567", sender: "HellioSMS", length: 6, expiry: 10)
79
+ client.otp("user@example.com", channel: "email") # Email (no sender)
80
+ client.verify("233241234567", "123456") # true / false
81
+ client.verify_otp("user@example.com", "123456", channel: "email") # full response
82
+
83
+ # Voice broadcast - text (we TTS it) or a hosted audio_url
84
+ client.voice("233241234567", "HELLIO", text: "Your code is 1 2 3 4")
85
+ client.voice(["233241234567"], "HELLIO", audio_url: "https://cdn.example.com/promo.mp3")
86
+
87
+ # Number lookup (HLR) - async; poll results
88
+ client.lookup(["233241234567"])
89
+ client.lookups
90
+ client.lookup_result(5)
91
+
92
+ # Email verification
93
+ client.verify_email(["user@gmail.com", "bad@nodomain.invalid"])
94
+
95
+ # Webhooks (receive delivery reports)
96
+ client.create_webhook("https://your-app.com/hooks/hellio", events: ["message.delivered", "message.failed"])
97
+ client.webhooks
98
+ client.delete_webhook(1)
99
+ ```
100
+
101
+ Recipient inputs (`sms`, `voice`, `lookup`, `verify_email`) accept a single
102
+ string, a comma-separated string, or an array. They are normalized to a list
103
+ before the request is sent.
104
+
105
+ ## Error handling
106
+
107
+ Non-2xx responses raise typed errors (all subclass `Hellio::Error`). Each error
108
+ carries `status_code` and the parsed `response` body; `ValidationError` also
109
+ exposes field-level details through `#errors`.
110
+
111
+ | Error | Status |
112
+ |---|---|
113
+ | `Hellio::InvalidApiTokenError` | 401 |
114
+ | `Hellio::InsufficientBalanceError` | 402 |
115
+ | `Hellio::ValidationError` (`#errors`) | 422 |
116
+ | `Hellio::RateLimitError` | 429 |
117
+ | `Hellio::Error` | other |
118
+
119
+ ```ruby
120
+ begin
121
+ client.sms("233241234567", "Hi")
122
+ rescue Hellio::InsufficientBalanceError => e
123
+ # top up
124
+ rescue Hellio::ValidationError => e
125
+ e.errors # field-level messages
126
+ e.status_code # 422
127
+ e.response # full parsed body
128
+ end
129
+ ```
130
+
131
+ Rate limit: **120 requests/minute** per token.
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ bundle install
137
+ bundle exec rake spec
138
+ ```
139
+
140
+ Tests use RSpec and WebMock to mock the HTTP layer.
141
+
142
+ ## License
143
+
144
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,266 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "uri"
5
+
6
+ require "hellio/errors"
7
+ require "hellio/http"
8
+
9
+ module Hellio
10
+ # Hellio Messaging API v1 client. Authenticates with a Bearer token and exposes
11
+ # one method per endpoint. Every call returns the decoded JSON as a Hash with
12
+ # string keys (payloads are under "data"); non-2xx responses raise a typed
13
+ # Hellio::Error subclass.
14
+ class Client
15
+ DEFAULT_BASE_URL = "https://api.helliomessaging.com/v1"
16
+ DEFAULT_TIMEOUT = 30
17
+
18
+ attr_reader :base_url, :timeout, :default_sender
19
+
20
+ # token - API token (falls back to HELLIO_API_TOKEN).
21
+ # base_url - API base URL (falls back to HELLIO_BASE_URL, then default).
22
+ # timeout - request timeout in seconds (default 30).
23
+ # default_sender - Sender ID used by #sms (falls back to HELLIO_DEFAULT_SENDER).
24
+ # http - HTTP adapter; inject a fake in tests. Defaults to net/http.
25
+ def initialize(token: nil, base_url: nil, timeout: nil, default_sender: nil, http: nil)
26
+ @token = token || ENV["HELLIO_API_TOKEN"]
27
+ @base_url = (base_url || ENV["HELLIO_BASE_URL"] || DEFAULT_BASE_URL).sub(%r{/+\z}, "")
28
+ @timeout = timeout || DEFAULT_TIMEOUT
29
+ @default_sender = default_sender || ENV["HELLIO_DEFAULT_SENDER"]
30
+ @http = http || NetHttpAdapter.new
31
+ end
32
+
33
+ # ---------------------------------------------------------------- Account
34
+
35
+ # Current account balance and available credit.
36
+ def balance
37
+ get("balance")
38
+ end
39
+
40
+ # Per-network SMS pricing. Pass an ISO-2 country code to narrow by country.
41
+ def pricing(country = nil)
42
+ get("pricing", country.nil? ? {} : { "country" => country })
43
+ end
44
+
45
+ # -------------------------------------------------------------------- SMS
46
+
47
+ # Send an SMS. recipients may be a single string, a comma-separated string,
48
+ # or an array of numbers.
49
+ def sms(recipients, message, sender: nil, gateway: nil)
50
+ post("sms/send", compact(
51
+ "recipients" => to_list(recipients),
52
+ "sender" => sender || default_sender,
53
+ "message" => message,
54
+ "gateway" => gateway
55
+ ))
56
+ end
57
+
58
+ # Delivery status for a single message.
59
+ def message(id)
60
+ get("messages/#{id}")
61
+ end
62
+
63
+ # Summary for a single campaign.
64
+ def campaign(id)
65
+ get("campaigns/#{id}")
66
+ end
67
+
68
+ # -------------------------------------------------------------------- OTP
69
+
70
+ # Send a one-time passcode. `to` is a phone number (sms/voice/whatsapp) or an
71
+ # email (email). `sender` (Sender ID) is required for sms/voice and must be
72
+ # approved on your account; it is ignored for whatsapp and email. Optional
73
+ # `length` (4-10 digits) and `expiry` (validity in minutes).
74
+ def otp(to, sender: nil, channel: "sms", purpose: nil, length: nil, expiry: nil, gateway: nil)
75
+ destination_key = (channel == "email" ? "email" : "mobile_number")
76
+
77
+ post("otp/send", compact(
78
+ "channel" => channel,
79
+ destination_key => to,
80
+ "sender" => sender,
81
+ "purpose" => purpose,
82
+ "length" => length,
83
+ "expiry" => expiry,
84
+ "gateway" => gateway
85
+ ))
86
+ end
87
+
88
+ # Verify a one-time passcode and return the full response.
89
+ def verify_otp(to, code, channel: "sms")
90
+ destination_key = (channel == "email" ? "email" : "mobile_number")
91
+
92
+ post("otp/verify", compact(
93
+ "channel" => channel,
94
+ destination_key => to,
95
+ "code" => code
96
+ ))
97
+ end
98
+
99
+ # Convenience wrapper: true when the code is valid, false otherwise.
100
+ # A 422 validation failure is treated as "not verified".
101
+ def verify(to, code, channel: "sms")
102
+ result = verify_otp(to, code, channel: channel)
103
+ truthy?(result.is_a?(Hash) ? result.dig("data", "verified") : nil)
104
+ rescue ValidationError
105
+ false
106
+ end
107
+
108
+ # ------------------------------------------------------------------ Voice
109
+
110
+ # Voice broadcast. Provide `text` (read with TTS) OR `audio_url` (fetched
111
+ # and played). recipients accepts the same shapes as #sms.
112
+ def voice(recipients, caller_id, text: nil, audio_url: nil, name: nil)
113
+ post("voice/send", compact(
114
+ "recipients" => to_list(recipients),
115
+ "caller_id" => caller_id,
116
+ "text" => text,
117
+ "audio_url" => audio_url,
118
+ "name" => name
119
+ ))
120
+ end
121
+
122
+ # Status for a single voice broadcast.
123
+ def voice_status(id)
124
+ get("voice/#{id}")
125
+ end
126
+
127
+ # ----------------------------------------------------------- Number lookup
128
+
129
+ # Submit numbers for HLR lookup. numbers accepts a string, comma list, or array.
130
+ def lookup(numbers)
131
+ post("lookup", "numbers" => to_list(numbers))
132
+ end
133
+
134
+ # List previously submitted lookups.
135
+ def lookups
136
+ get("lookups")
137
+ end
138
+
139
+ # Result for a single lookup.
140
+ def lookup_result(id)
141
+ get("lookup/#{id}")
142
+ end
143
+
144
+ # ------------------------------------------------------- Email verification
145
+
146
+ # Verify one or more email addresses. emails accepts a string, comma list, or array.
147
+ def verify_email(emails)
148
+ post("email/verify", "emails" => to_list(emails))
149
+ end
150
+
151
+ # --------------------------------------------------------------- Webhooks
152
+
153
+ # List registered webhooks.
154
+ def webhooks
155
+ get("webhooks")
156
+ end
157
+
158
+ # Register a webhook. Pass `events` to subscribe to specific event types.
159
+ def create_webhook(url, events: [])
160
+ post("webhooks", compact(
161
+ "url" => url,
162
+ "events" => (events.nil? || events.empty? ? nil : events)
163
+ ))
164
+ end
165
+
166
+ # Delete a webhook by id.
167
+ def delete_webhook(id)
168
+ delete("webhooks/#{id}")
169
+ end
170
+
171
+ # --------------------------------------------------------------- internals
172
+
173
+ private
174
+
175
+ def get(path, query = {})
176
+ request(:get, path, query: query)
177
+ end
178
+
179
+ def post(path, body = {})
180
+ request(:post, path, body: body)
181
+ end
182
+
183
+ def delete(path)
184
+ request(:delete, path)
185
+ end
186
+
187
+ def request(method, path, query: {}, body: nil)
188
+ response = @http.call(
189
+ method: method,
190
+ url: build_url(path, query),
191
+ headers: headers,
192
+ body: body.nil? ? nil : JSON.generate(body),
193
+ timeout: timeout
194
+ )
195
+
196
+ data = parse(response.body)
197
+ return data if response.status.to_i.between?(200, 299)
198
+
199
+ raise error_for(response.status.to_i, data)
200
+ end
201
+
202
+ def headers
203
+ {
204
+ "Authorization" => "Bearer #{@token}",
205
+ "Accept" => "application/json",
206
+ "Content-Type" => "application/json"
207
+ }
208
+ end
209
+
210
+ def build_url(path, query)
211
+ url = "#{base_url}/#{path.sub(%r{\A/+}, "")}"
212
+ return url if query.nil? || query.empty?
213
+
214
+ "#{url}?#{URI.encode_www_form(query)}"
215
+ end
216
+
217
+ def parse(body)
218
+ return {} if body.nil? || body.to_s.empty?
219
+
220
+ JSON.parse(body)
221
+ rescue JSON::ParserError
222
+ {}
223
+ end
224
+
225
+ def error_for(status, data)
226
+ message =
227
+ if data.is_a?(Hash) && data["message"].is_a?(String)
228
+ data["message"]
229
+ else
230
+ "Hellio API request failed."
231
+ end
232
+
233
+ error_class =
234
+ case status
235
+ when 401 then InvalidApiTokenError
236
+ when 402 then InsufficientBalanceError
237
+ when 422 then ValidationError
238
+ when 429 then RateLimitError
239
+ when 503 then ServiceUnavailableError
240
+ else Error
241
+ end
242
+
243
+ error_class.new(message, status_code: status, response: data)
244
+ end
245
+
246
+ # Normalize a recipient/number/email input into an array of strings.
247
+ def to_list(value)
248
+ return value.map(&:to_s) if value.is_a?(Array)
249
+
250
+ value.to_s.split(",").map(&:strip).reject(&:empty?)
251
+ end
252
+
253
+ # Drop keys whose value is nil so they are omitted from the request body.
254
+ def compact(hash)
255
+ hash.reject { |_, v| v.nil? }
256
+ end
257
+
258
+ def truthy?(value)
259
+ return false if value.nil? || value == false
260
+ return false if value == 0
261
+ return false if value.is_a?(String) && (value.empty? || value == "0")
262
+
263
+ true
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hellio
4
+ # Base error for every failure returned by the Hellio Messaging API.
5
+ # Carries the HTTP status code and the parsed response body so callers can
6
+ # inspect the details (for 422, read #errors for field-level messages).
7
+ class Error < StandardError
8
+ attr_reader :status_code, :response
9
+
10
+ def initialize(message = nil, status_code: nil, response: nil)
11
+ super(message)
12
+ @status_code = status_code
13
+ @response = response
14
+ end
15
+
16
+ # Field-level validation details, present on 422 responses.
17
+ def errors
18
+ return nil unless response.is_a?(Hash)
19
+
20
+ response["errors"]
21
+ end
22
+ end
23
+
24
+ # 401: the API token is missing, malformed, or revoked.
25
+ class InvalidApiTokenError < Error; end
26
+
27
+ # 402: the account balance is too low to complete the request.
28
+ class InsufficientBalanceError < Error; end
29
+
30
+ # 422: the request failed validation. See #errors for the details.
31
+ class ValidationError < Error; end
32
+
33
+ # 429: too many requests. The limit is 120 requests per minute per token.
34
+ class RateLimitError < Error; end
35
+
36
+ # 503: the service is temporarily unavailable, because an admin switched it off
37
+ # (SMS, OTP, voice, WhatsApp, lookup, email) or the API is paused. Retry later.
38
+ class ServiceUnavailableError < Error; end
39
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+
6
+ module Hellio
7
+ # A minimal HTTP response value object returned by an adapter.
8
+ Response = Struct.new(:status, :body)
9
+
10
+ # Default HTTP adapter built on the standard library `net/http`. Tests (or
11
+ # advanced users) can inject any object that responds to #call with the same
12
+ # keyword arguments and returns an object exposing #status and #body.
13
+ class NetHttpAdapter
14
+ def call(method:, url:, headers:, body:, timeout:)
15
+ uri = URI.parse(url)
16
+
17
+ http = Net::HTTP.new(uri.host, uri.port)
18
+ http.use_ssl = (uri.scheme == "https")
19
+ http.open_timeout = timeout
20
+ http.read_timeout = timeout
21
+
22
+ request_class =
23
+ case method
24
+ when :get then Net::HTTP::Get
25
+ when :post then Net::HTTP::Post
26
+ when :delete then Net::HTTP::Delete
27
+ else raise ArgumentError, "Unsupported HTTP method: #{method}"
28
+ end
29
+
30
+ request = request_class.new(uri.request_uri)
31
+ headers.each { |key, value| request[key] = value }
32
+ request.body = body unless body.nil?
33
+
34
+ response = http.request(request)
35
+ Response.new(response.code.to_i, response.body.to_s)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hellio
4
+ VERSION = "1.0.0"
5
+ end
data/lib/hellio.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hellio/version"
4
+ require "hellio/errors"
5
+ require "hellio/http"
6
+ require "hellio/client"
7
+
8
+ # Official Ruby SDK for the Hellio Messaging API v1.
9
+ #
10
+ # Quick start:
11
+ #
12
+ # client = Hellio::Client.new(token: "your-token")
13
+ # client.sms("233241234567", "Hello!")
14
+ #
15
+ module Hellio
16
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hellio-messaging
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Albert Ninyeh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-07-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '13.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.19'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.19'
55
+ description: 'Ruby client for the Hellio Messaging API v1: SMS, OTP (SMS / email /
56
+ voice), voice broadcasts, number lookup (HLR), email verification, pricing, balance,
57
+ and webhooks.'
58
+ email:
59
+ - eaglesecurity0@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - CHANGELOG.md
65
+ - LICENSE
66
+ - README.md
67
+ - lib/hellio.rb
68
+ - lib/hellio/client.rb
69
+ - lib/hellio/errors.rb
70
+ - lib/hellio/http.rb
71
+ - lib/hellio/version.rb
72
+ homepage: https://github.com/HellioSolutions/hellio-ruby
73
+ licenses:
74
+ - MIT
75
+ metadata:
76
+ source_code_uri: https://github.com/HellioSolutions/hellio-ruby
77
+ changelog_uri: https://github.com/HellioSolutions/hellio-ruby/blob/main/CHANGELOG.md
78
+ bug_tracker_uri: https://github.com/HellioSolutions/hellio-ruby/issues
79
+ documentation_uri: https://helliomessaging.com
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '3.1'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.0.3.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Official Ruby SDK for the Hellio Messaging API v1.
99
+ test_files: []