voiceml 0.9.1 → 0.9.3

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -16
  3. data/lib/voiceml/client.rb +76 -15
  4. data/lib/voiceml/errors.rb +15 -2
  5. data/lib/voiceml/hosts.rb +62 -0
  6. data/lib/voiceml/models/accounts.rb +47 -3
  7. data/lib/voiceml/models/applications.rb +6 -0
  8. data/lib/voiceml/models/assistants_v1.rb +40 -0
  9. data/lib/voiceml/models/calls.rb +4 -0
  10. data/lib/voiceml/models/common.rb +35 -4
  11. data/lib/voiceml/models/conferences.rb +8 -0
  12. data/lib/voiceml/models/conversations_v1.rb +131 -29
  13. data/lib/voiceml/models/diagnostics.rb +33 -12
  14. data/lib/voiceml/models/exports.rb +58 -0
  15. data/lib/voiceml/models/incoming_phone_numbers.rb +4 -0
  16. data/lib/voiceml/models/media.rb +4 -0
  17. data/lib/voiceml/models/messages.rb +29 -0
  18. data/lib/voiceml/models/messaging_v1.rb +73 -0
  19. data/lib/voiceml/models/monitor_v1.rb +54 -0
  20. data/lib/voiceml/models/notifications.rb +2 -0
  21. data/lib/voiceml/models/outgoing_caller_ids.rb +6 -0
  22. data/lib/voiceml/models/payments.rb +2 -0
  23. data/lib/voiceml/models/pricing.rb +265 -0
  24. data/lib/voiceml/models/queues.rb +8 -0
  25. data/lib/voiceml/models/recordings.rb +5 -1
  26. data/lib/voiceml/models/routes_v2.rb +6 -2
  27. data/lib/voiceml/models/sip.rb +34 -6
  28. data/lib/voiceml/models/sip_registrations.rb +49 -0
  29. data/lib/voiceml/models/siprec.rb +5 -17
  30. data/lib/voiceml/models/streams.rb +4 -16
  31. data/lib/voiceml/models/transcriptions.rb +35 -4
  32. data/lib/voiceml/models/usage_records.rb +48 -0
  33. data/lib/voiceml/models/user_defined_messages.rb +2 -0
  34. data/lib/voiceml/models/voice_v1.rb +29 -19
  35. data/lib/voiceml/request_validator.rb +125 -0
  36. data/lib/voiceml/resources/accounts.rb +75 -0
  37. data/lib/voiceml/resources/applications.rb +3 -1
  38. data/lib/voiceml/resources/assistants_v1.rb +53 -77
  39. data/lib/voiceml/resources/base.rb +138 -16
  40. data/lib/voiceml/resources/calls.rb +34 -49
  41. data/lib/voiceml/resources/conferences.rb +26 -5
  42. data/lib/voiceml/resources/conversations_v1.rb +147 -172
  43. data/lib/voiceml/resources/diagnostics.rb +20 -35
  44. data/lib/voiceml/resources/exports.rb +36 -0
  45. data/lib/voiceml/resources/incoming_phone_numbers.rb +53 -32
  46. data/lib/voiceml/resources/messages.rb +79 -15
  47. data/lib/voiceml/resources/messaging_v1.rb +121 -0
  48. data/lib/voiceml/resources/monitor_v1.rb +68 -0
  49. data/lib/voiceml/resources/notifications.rb +1 -1
  50. data/lib/voiceml/resources/outgoing_caller_ids.rb +77 -0
  51. data/lib/voiceml/resources/pricing.rb +148 -0
  52. data/lib/voiceml/resources/queues.rb +6 -5
  53. data/lib/voiceml/resources/recordings.rb +39 -5
  54. data/lib/voiceml/resources/routes_v2.rb +10 -4
  55. data/lib/voiceml/resources/sip.rb +30 -11
  56. data/lib/voiceml/resources/transcriptions.rb +40 -0
  57. data/lib/voiceml/resources/usage_records.rb +51 -0
  58. data/lib/voiceml/resources/voice_v1.rb +31 -38
  59. data/lib/voiceml/transport.rb +293 -206
  60. data/lib/voiceml/version.rb +1 -1
  61. data/lib/voiceml.rb +14 -15
  62. metadata +23 -6
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'common'
4
+ require_relative 'notifications'
4
5
 
5
6
  module VoiceML
6
7
  # `GET /Calls/{Sid}/Notifications` — always an empty list (Twilio-compat stub).
7
8
  class NotificationsList
8
- attr_reader :notifications, :page, :page_size, :total, :uri
9
+ include RawAttributes
10
+ include Pageable
11
+ attr_reader :notifications
9
12
 
10
13
  def initialize(hash = {})
11
- @notifications = hash['notifications'] || []
12
- @page = hash['page'] || 0
13
- @page_size = hash['page_size'] || 0
14
- @total = hash['total'] || 0
15
- @uri = hash['uri']
14
+ @raw_attributes = hash
15
+ assign_page_fields(hash)
16
+ @notifications = (hash['notifications'] || []).map { |n| Notification.from_hash(n) }
16
17
  end
17
18
 
18
19
  def self.from_hash(hash)
@@ -23,14 +24,14 @@ module VoiceML
23
24
  # `GET /Calls/{Sid}/Events` — always an empty list (Twilio-compat stub).
24
25
  # The canonical event source is the customer's StatusCallback URL.
25
26
  class EventsList
26
- attr_reader :events, :page, :page_size, :total, :uri
27
+ include RawAttributes
28
+ include Pageable
29
+ attr_reader :events
27
30
 
28
31
  def initialize(hash = {})
29
- @events = hash['events'] || []
30
- @page = hash['page'] || 0
31
- @page_size = hash['page_size'] || 0
32
- @total = hash['total'] || 0
33
- @uri = hash['uri']
32
+ @raw_attributes = hash
33
+ assign_page_fields(hash)
34
+ @events = (hash['events'] || []).map { |event| CallEvent.from_hash(event) }
34
35
  end
35
36
 
36
37
  def self.from_hash(hash)
@@ -38,12 +39,32 @@ module VoiceML
38
39
  end
39
40
  end
40
41
 
42
+ # Request/response pair from a call's event log.
43
+ class CallEvent
44
+ include RawAttributes
45
+ ATTRIBUTES = %w[request response].freeze
46
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
47
+
48
+ def initialize(attrs = {})
49
+ @raw_attributes = attrs
50
+ ATTRIBUTES.each do |field|
51
+ instance_variable_set("@#{field}", attrs.key?(field) ? attrs[field] : attrs[field.to_sym])
52
+ end
53
+ end
54
+
55
+ def self.from_hash(hash)
56
+ hash.nil? ? nil : new(hash)
57
+ end
58
+ end
59
+
41
60
  # `GET /health` response. Hard-check failures flip `ok` to false (server returns 503);
42
61
  # soft-check warnings surface in `warnings` only.
43
62
  class HealthStatus
63
+ include RawAttributes
44
64
  attr_reader :ok, :warnings, :failures
45
65
 
46
66
  def initialize(hash = {})
67
+ @raw_attributes = hash
47
68
  @ok = hash['ok']
48
69
  @warnings = (hash['warnings'] || []).map { |w| HealthFailure.from_hash(w) }
49
70
  @failures = (hash['failures'] || []).map { |f| HealthFailure.from_hash(f) }
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module VoiceML
6
+ # One day's archive entry from `GET /Exports`.
7
+ class Export
8
+ include RawAttributes
9
+ ATTRIBUTES = %w[date size uri].freeze
10
+
11
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
12
+
13
+ def initialize(attrs = {})
14
+ @raw_attributes = attrs
15
+ ATTRIBUTES.each do |field|
16
+ value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
17
+ instance_variable_set("@#{field}", value)
18
+ end
19
+ end
20
+
21
+ def self.from_hash(hash)
22
+ return nil if hash.nil?
23
+
24
+ new(hash)
25
+ end
26
+ end
27
+
28
+ # `GET /Exports` response — the account's available archives, newest first.
29
+ class ExportList
30
+ include RawAttributes
31
+
32
+ attr_reader :account_sid, :uri, :exports
33
+
34
+ def initialize(hash = {})
35
+ @raw_attributes = hash
36
+ @account_sid = hash['account_sid']
37
+ @uri = hash['uri']
38
+ @exports = (hash['exports'] || []).map { |e| Export.from_hash(e) }
39
+ end
40
+
41
+ def self.from_hash(hash)
42
+ new(hash || {})
43
+ end
44
+ end
45
+
46
+ # Result of `GET /Exports/{Date}` — the archive bytes, following the same
47
+ # 302 -> presigned-object redirect recording audio uses.
48
+ class ExportDownload
49
+ attr_reader :date, :content, :content_type, :via_redirect
50
+
51
+ def initialize(date:, content:, content_type:, via_redirect:)
52
+ @date = date
53
+ @content = content
54
+ @content_type = content_type
55
+ @via_redirect = via_redirect
56
+ end
57
+ end
58
+ end
@@ -12,6 +12,7 @@ module VoiceML
12
12
  # Twilio-compat fields VoiceML doesn't track (regulatory, SMS, emergency, trunking) are
13
13
  # surfaced verbatim so strict-binding consumers can read e.g. `.capabilities['voice']`.
14
14
  class IncomingPhoneNumber
15
+ include RawAttributes
15
16
  ATTRIBUTES = %w[
16
17
  sid account_sid phone_number friendly_name api_version uri
17
18
  voice_url voice_method voice_fallback_url voice_fallback_method
@@ -27,6 +28,7 @@ module VoiceML
27
28
  attr_reader(*ATTRIBUTES.map(&:to_sym))
28
29
 
29
30
  def initialize(attrs = {})
31
+ @raw_attributes = attrs
30
32
  ATTRIBUTES.each do |field|
31
33
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
32
34
  instance_variable_set("@#{field}", value)
@@ -42,11 +44,13 @@ module VoiceML
42
44
 
43
45
  # Paginated `GET /IncomingPhoneNumbers` response. Same envelope shape as `CallList`.
44
46
  class IncomingPhoneNumberList
47
+ include RawAttributes
45
48
  include Pageable
46
49
 
47
50
  attr_reader :incoming_phone_numbers
48
51
 
49
52
  def initialize(hash = {})
53
+ @raw_attributes = hash
50
54
  assign_page_fields(hash)
51
55
  @incoming_phone_numbers =
52
56
  (hash['incoming_phone_numbers'] || []).map { |n| IncomingPhoneNumber.from_hash(n) }
@@ -8,6 +8,7 @@ module VoiceML
8
8
  # shape conformance and to round-trip migrated tooling. `parent_sid` ties
9
9
  # the media back to its parent Message (SM... sid).
10
10
  class Media
11
+ include RawAttributes
11
12
  ATTRIBUTES = %w[
12
13
  sid account_sid parent_sid content_type
13
14
  date_created date_updated uri
@@ -16,6 +17,7 @@ module VoiceML
16
17
  attr_reader(*ATTRIBUTES.map(&:to_sym))
17
18
 
18
19
  def initialize(attrs = {})
20
+ @raw_attributes = attrs
19
21
  ATTRIBUTES.each do |field|
20
22
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
21
23
  instance_variable_set("@#{field}", value)
@@ -32,11 +34,13 @@ module VoiceML
32
34
  # Paginated `GET /Messages/{Sid}/Media` response. Twilio's envelope key is
33
35
  # `media_list` (not `media`) — the SDK preserves that on the wire.
34
36
  class MediaList
37
+ include RawAttributes
35
38
  include Pageable
36
39
 
37
40
  attr_reader :media_list
38
41
 
39
42
  def initialize(hash = {})
43
+ @raw_attributes = hash
40
44
  assign_page_fields(hash)
41
45
  @media_list = (hash['media_list'] || []).map { |m| Media.from_hash(m) }
42
46
  end
@@ -16,6 +16,7 @@ module VoiceML
16
16
  # - `error_code` is a nullable integer; `error_message`, `price`, `price_unit`,
17
17
  # `date_sent`, and `messaging_service_sid` are nullable strings.
18
18
  class Message
19
+ include RawAttributes
19
20
  ATTRIBUTES = %w[
20
21
  sid account_sid api_version to from body status num_segments num_media
21
22
  direction price price_unit error_code error_message messaging_service_sid
@@ -25,6 +26,7 @@ module VoiceML
25
26
  attr_reader(*ATTRIBUTES.map(&:to_sym))
26
27
 
27
28
  def initialize(attrs = {})
29
+ @raw_attributes = attrs
28
30
  ATTRIBUTES.each do |field|
29
31
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
30
32
  instance_variable_set("@#{field}", value)
@@ -40,11 +42,13 @@ module VoiceML
40
42
 
41
43
  # Paginated `GET /Messages` response.
42
44
  class MessageList
45
+ include RawAttributes
43
46
  include Pageable
44
47
 
45
48
  attr_reader :messages
46
49
 
47
50
  def initialize(hash = {})
51
+ @raw_attributes = hash
48
52
  assign_page_fields(hash)
49
53
  @messages = (hash['messages'] || []).map { |m| Message.from_hash(m) }
50
54
  end
@@ -53,4 +57,29 @@ module VoiceML
53
57
  new(hash || {})
54
58
  end
55
59
  end
60
+
61
+ # Delivery-quality feedback echoed back on a Message
62
+ # (`POST /Messages/{Sid}/Feedback.json`). VoiceML records the outcome on
63
+ # the response only; there is no separate downstream analytics surface.
64
+ # Any submitted `Outcome` other than `confirmed` echoes as `unconfirmed`.
65
+ class MessageFeedback
66
+ include RawAttributes
67
+ ATTRIBUTES = %w[account_sid message_sid outcome date_created date_updated uri].freeze
68
+
69
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
70
+
71
+ def initialize(attrs = {})
72
+ @raw_attributes = attrs
73
+ ATTRIBUTES.each do |field|
74
+ value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
75
+ instance_variable_set("@#{field}", value)
76
+ end
77
+ end
78
+
79
+ def self.from_hash(hash)
80
+ return nil if hash.nil?
81
+
82
+ new(hash)
83
+ end
84
+ end
56
85
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+ require_relative 'voice_v1' # V1Pageable lives here; Messaging v1 reuses the same `meta` envelope
5
+
6
+ module VoiceML
7
+ # Twilio Messaging v1 (messaging.twilio.com/v1) resources.
8
+ #
9
+ # A Messaging Service (`MG...`) shares the `/v1/Services` path shape with the
10
+ # Conversations Service (`IS...`); the two are disambiguated on the wire by host
11
+ # (`messaging.voicetel.com` vs `conversations.voicetel.com`). This SDK routes
12
+ # `client.messaging_v1.*` at the messaging host automatically — see VoiceML::Hosts.
13
+
14
+ # MessagingService — `MG...`. The feature-toggle fields are accept-and-echo on
15
+ # VoiceML; the service's operative role is gating scheduled sends.
16
+ class MessagingService
17
+ include RawAttributes
18
+ ATTRIBUTES = %w[
19
+ sid account_sid friendly_name date_created date_updated
20
+ inbound_request_url inbound_method fallback_url fallback_method status_callback
21
+ sticky_sender mms_converter smart_encoding scan_message_content
22
+ fallback_to_long_code area_code_geomatch synchronous_validation validity_period
23
+ url usecase use_inbound_webhook_on_number advanced_opt_out
24
+ ].freeze
25
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
26
+ def initialize(attrs = {})
27
+ @raw_attributes = attrs
28
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
29
+ end
30
+ def self.from_hash(h); h.nil? ? nil : new(h); end
31
+ end
32
+
33
+ # List envelope for `GET /v1/Services` on the messaging host.
34
+ class MessagingServiceList
35
+ include RawAttributes
36
+ include V1Pageable
37
+ attr_reader :services
38
+ def initialize(hash = {})
39
+ @raw_attributes = hash
40
+ assign_meta_fields(hash)
41
+ @services = (hash['services'] || []).map { |h| MessagingService.from_hash(h) }
42
+ end
43
+ end
44
+
45
+ # MessagingServicePhoneNumber — a sender-pool phone number attached to a
46
+ # Messaging Service (`/v1/Services/{ChatServiceSid}/PhoneNumbers`). Lives on
47
+ # the messaging host.
48
+ class MessagingServicePhoneNumber
49
+ include RawAttributes
50
+ ATTRIBUTES = %w[
51
+ sid account_sid service_sid date_created date_updated
52
+ phone_number country_code capabilities url
53
+ ].freeze
54
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
55
+ def initialize(attrs = {})
56
+ @raw_attributes = attrs
57
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
58
+ end
59
+ def self.from_hash(h); h.nil? ? nil : new(h); end
60
+ end
61
+
62
+ # List envelope for `GET /v1/Services/{ChatServiceSid}/PhoneNumbers`.
63
+ class MessagingServicePhoneNumberList
64
+ include RawAttributes
65
+ include V1Pageable
66
+ attr_reader :phone_numbers
67
+ def initialize(hash = {})
68
+ @raw_attributes = hash
69
+ assign_meta_fields(hash)
70
+ @phone_numbers = (hash['phone_numbers'] || []).map { |h| MessagingServicePhoneNumber.from_hash(h) }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module VoiceML
6
+ # Monitor v1 (`/v1/Alerts`) — failure events rendered in the Monitor Alert
7
+ # shape: call-scoped errors and messaging delivery failures alike.
8
+ #
9
+ # List rows omit the request/response detail; `fetch` includes it when the
10
+ # underlying event stored any (`request_headers`, `request_variables`,
11
+ # `response_body`, `response_headers`).
12
+ class MonitorAlert
13
+ include RawAttributes
14
+ ATTRIBUTES = %w[
15
+ sid account_sid alert_text api_version error_code log_level more_info
16
+ request_method request_url request_headers request_variables
17
+ response_body response_headers resource_sid service_sid
18
+ date_created date_generated date_updated url
19
+ ].freeze
20
+
21
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
22
+
23
+ def initialize(attrs = {})
24
+ @raw_attributes = attrs
25
+ ATTRIBUTES.each do |field|
26
+ value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
27
+ instance_variable_set("@#{field}", value)
28
+ end
29
+ end
30
+
31
+ def self.from_hash(hash)
32
+ return nil if hash.nil?
33
+
34
+ new(hash)
35
+ end
36
+ end
37
+
38
+ # Paginated `GET /v1/Alerts` response: `alerts` plus the standard `/v1`
39
+ # `meta` envelope. The server serves a single page
40
+ # (`meta.next_page_url` is always `null`); `PageSize` does limit this
41
+ # collection (default 50, capped at 1000).
42
+ class MonitorAlertList
43
+ include RawAttributes
44
+ include V1Pageable
45
+
46
+ attr_reader :alerts
47
+
48
+ def initialize(hash = {})
49
+ @raw_attributes = hash
50
+ assign_meta_fields(hash)
51
+ @alerts = (hash['alerts'] || []).map { |h| MonitorAlert.from_hash(h) }
52
+ end
53
+ end
54
+ end
@@ -13,6 +13,7 @@ module VoiceML
13
13
  #
14
14
  # The same resource shape backs both account-scoped and call-scoped fetches.
15
15
  class Notification
16
+ include RawAttributes
16
17
  ATTRIBUTES = %w[
17
18
  sid account_sid call_sid api_version
18
19
  error_code more_info message_date message_text log
@@ -24,6 +25,7 @@ module VoiceML
24
25
  attr_reader(*ATTRIBUTES.map(&:to_sym))
25
26
 
26
27
  def initialize(attrs = {})
28
+ @raw_attributes = attrs
27
29
  ATTRIBUTES.each do |field|
28
30
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
29
31
  instance_variable_set("@#{field}", value)
@@ -7,6 +7,7 @@ module VoiceML
7
7
  # to mirror Twilio (caller-id resources share the IncomingPhoneNumber SID
8
8
  # space upstream); `phone_number` carries the verified E.164 number.
9
9
  class OutgoingCallerId
10
+ include RawAttributes
10
11
  ATTRIBUTES = %w[
11
12
  sid account_sid friendly_name phone_number
12
13
  date_created date_updated uri
@@ -15,6 +16,7 @@ module VoiceML
15
16
  attr_reader(*ATTRIBUTES.map(&:to_sym))
16
17
 
17
18
  def initialize(attrs = {})
19
+ @raw_attributes = attrs
18
20
  ATTRIBUTES.each do |field|
19
21
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
20
22
  instance_variable_set("@#{field}", value)
@@ -30,11 +32,13 @@ module VoiceML
30
32
 
31
33
  # Paginated `GET /OutgoingCallerIds` response.
32
34
  class OutgoingCallerIdList
35
+ include RawAttributes
33
36
  include Pageable
34
37
 
35
38
  attr_reader :outgoing_caller_ids
36
39
 
37
40
  def initialize(hash = {})
41
+ @raw_attributes = hash
38
42
  assign_page_fields(hash)
39
43
  @outgoing_caller_ids =
40
44
  (hash['outgoing_caller_ids'] || []).map { |o| OutgoingCallerId.from_hash(o) }
@@ -50,11 +54,13 @@ module VoiceML
50
54
  # doesn't exist until the validation_code is dialled back); the
51
55
  # `validation_code` is what the user is prompted to enter on the live call.
52
56
  class ValidationRequest
57
+ include RawAttributes
53
58
  ATTRIBUTES = %w[account_sid call_sid friendly_name phone_number validation_code].freeze
54
59
 
55
60
  attr_reader(*ATTRIBUTES.map(&:to_sym))
56
61
 
57
62
  def initialize(attrs = {})
63
+ @raw_attributes = attrs
58
64
  ATTRIBUTES.each do |field|
59
65
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
60
66
  instance_variable_set("@#{field}", value)
@@ -10,6 +10,7 @@ module VoiceML
10
10
  # account must have `pay_enabled = true` AND a `stripe_secret_key` set, or
11
11
  # the call fails 403.
12
12
  class CallPayment
13
+ include RawAttributes
13
14
  ATTRIBUTES = %w[
14
15
  sid account_sid call_sid api_version
15
16
  date_created date_updated uri
@@ -18,6 +19,7 @@ module VoiceML
18
19
  attr_reader(*ATTRIBUTES.map(&:to_sym))
19
20
 
20
21
  def initialize(attrs = {})
22
+ @raw_attributes = attrs
21
23
  ATTRIBUTES.each do |field|
22
24
  value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
23
25
  instance_variable_set("@#{field}", value)