sendly 3.6.0 → 3.8.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc3667b089d1fc494d8d71a8a184a448ee23040ccab772e3640da4743385b291
4
- data.tar.gz: a0ccba6bb44cdbfa5a5b01d4882731d1f56c08944b7477f45cf3b779177285c6
3
+ metadata.gz: b353bcac8423f595cc655af69df19ac4af9afd9f3d830cc7ac0c59842ae7a73f
4
+ data.tar.gz: ca2e303192d3b22856595bf9981eb28edd3c5ba5f500f544ffeda4783bd28893
5
5
  SHA512:
6
- metadata.gz: 5e59c3aadde64d289b0efca5e7658e2c248846def6233c6c181c070fefa30438d6aaa1bb1eaa25a1fb2f76336d0613d4a4c10d98ddc1d0ef7e97eea2fdc630d9
7
- data.tar.gz: 5ded3801ac0f23d66eaf86628f0e86262fe0f3d028734db22aedaa45cfce4ba3ed951bbf2cfdd4e9a7e41d4f18f053e260cea0224dfd314af33549f153411853
6
+ metadata.gz: fc1fd77a1fef96c5938c35b4dc948954e24974ae107a7744ddbcfb5d11a15fd744616b0053c2af19fd7cb7b3c8410de2751cb077e1697fb1b48061d10d52d71b
7
+ data.tar.gz: c2f010e7116ad34275cf88132cc7a8f3874c1b95081597b250d41088780f1662a5367587a7d2b76123fdc4f6d3bf25b42180183e925bfeab58c43b516ee9d78b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sendly (3.6.0)
4
+ sendly (3.8.1)
5
5
  faraday (~> 2.0)
6
6
  faraday-retry (~> 2.0)
7
7
 
data/README.md CHANGED
@@ -182,6 +182,16 @@ status = client.messages.get_batch("batch_xxx")
182
182
 
183
183
  # List all batches
184
184
  batches = client.messages.list_batches
185
+
186
+ # Preview batch (dry run) - validates without sending
187
+ preview = client.messages.preview_batch(
188
+ messages: [
189
+ { to: '+15551234567', text: 'Hello User 1!' },
190
+ { to: '+447700900123', text: 'Hello UK!' }
191
+ ]
192
+ )
193
+ puts "Total credits needed: #{preview.total_credits}"
194
+ puts "Valid: #{preview.valid}, Invalid: #{preview.invalid}"
185
195
  ```
186
196
 
187
197
  ### Iterate All Messages
@@ -256,6 +266,17 @@ result = client.account.list_api_keys
256
266
  result.data.each do |key|
257
267
  puts "#{key.name}: #{key.prefix}*** (#{key.type})"
258
268
  end
269
+
270
+ # Create a new API key
271
+ new_key = client.account.create_api_key(
272
+ name: 'Production Key',
273
+ type: 'live',
274
+ scopes: ['sms:send', 'sms:read']
275
+ )
276
+ puts "New key: #{new_key.key}" # Only shown once!
277
+
278
+ # Revoke an API key
279
+ client.account.revoke_api_key('key_xxx')
259
280
  ```
260
281
 
261
282
  ## Error Handling
@@ -66,5 +66,33 @@ module Sendly
66
66
  def api_key_usage(key_id)
67
67
  @client.get("/keys/#{key_id}/usage")
68
68
  end
69
+
70
+ # Create a new API key
71
+ #
72
+ # @param name [String] Display name for the API key
73
+ # @param expires_at [String, nil] Optional expiration date (ISO 8601)
74
+ # @return [Hash] Contains 'apiKey' (metadata) and 'key' (full secret - only shown once!)
75
+ #
76
+ # @example
77
+ # result = client.account.create_api_key("Production")
78
+ # puts "Save this key: #{result['key']}" # Only shown once!
79
+ def create_api_key(name, expires_at: nil)
80
+ raise ArgumentError, "API key name is required" if name.nil? || name.empty?
81
+
82
+ body = { name: name }
83
+ body[:expiresAt] = expires_at if expires_at
84
+
85
+ @client.post("/account/keys", body)
86
+ end
87
+
88
+ # Revoke an API key
89
+ #
90
+ # @param key_id [String] API key ID to revoke
91
+ # @return [void]
92
+ def revoke_api_key(key_id)
93
+ raise ArgumentError, "API key ID is required" if key_id.nil? || key_id.empty?
94
+
95
+ @client.delete("/account/keys/#{key_id}")
96
+ end
69
97
  end
70
98
  end
@@ -282,6 +282,44 @@ module Sendly
282
282
  client.get("/messages/batches", params.compact)
283
283
  end
284
284
 
285
+ # Preview a batch without sending (dry run)
286
+ #
287
+ # @param messages [Array<Hash>] Array of messages with :to and :text keys
288
+ # @param from [String] Sender ID or phone number (optional, applies to all)
289
+ # @param message_type [String] Message type: "marketing" (default) or "transactional"
290
+ # @return [Hash] Preview showing what would happen if batch was sent
291
+ #
292
+ # @raise [Sendly::ValidationError] If parameters are invalid
293
+ #
294
+ # @example
295
+ # preview = client.messages.preview_batch(
296
+ # messages: [
297
+ # { to: "+15551234567", text: "Hello Alice!" },
298
+ # { to: "+15559876543", text: "Hello Bob!" }
299
+ # ]
300
+ # )
301
+ # puts "Can send: #{preview['canSend']}"
302
+ # puts "Credits needed: #{preview['creditsNeeded']}"
303
+ def preview_batch(messages:, from: nil, message_type: nil)
304
+ raise ValidationError, "Messages array is required" if messages.nil? || messages.empty?
305
+
306
+ messages.each_with_index do |msg, i|
307
+ raise ValidationError, "Message at index #{i} missing 'to'" unless msg[:to] || msg["to"]
308
+ raise ValidationError, "Message at index #{i} missing 'text'" unless msg[:text] || msg["text"]
309
+
310
+ to = msg[:to] || msg["to"]
311
+ text = msg[:text] || msg["text"]
312
+ validate_phone!(to)
313
+ validate_text!(text)
314
+ end
315
+
316
+ body = { messages: messages }
317
+ body[:from] = from if from
318
+ body[:messageType] = message_type if message_type
319
+
320
+ client.post("/messages/batch/preview", body)
321
+ end
322
+
285
323
  private
286
324
 
287
325
  def validate_phone!(phone)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sendly
4
- VERSION = "3.6.0"
4
+ VERSION = "3.8.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sendly
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sendly
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-01 00:00:00.000000000 Z
11
+ date: 2026-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday