voiceml 0.7.1.1 → 0.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: 7644aa34cf82b78bbc8744567b54be9a00115a4715bb490da3974c28cf40f990
4
- data.tar.gz: 5133a70ebe35ac5ad190fcb3f2ffb61dfe7197e697ea98bbc78dd672f6c02bfe
3
+ metadata.gz: 15e4cbe52a1e5c8c9373bc3b9f636c5637915cf7827abd08c87512998f7fafe4
4
+ data.tar.gz: bc844da7b2b3289c072d7f5b3ef130a90eace33a0fa7f1794235e3bb096b986c
5
5
  SHA512:
6
- metadata.gz: 3a5017e8cd3263cb6b32c8c28c8291d5e6f94b71472350fefec20362dc54dfb825195f1693344dca599bf8313cc7a1a16c7ace2d85ee9a733093ec71d1a37b33
7
- data.tar.gz: cba24d62dbda0ff451f0cd1c23173bf45be879675f6afa86cb9dc3faa98a34583ef144955f180674f60d667a4fb67eab1ec189deee558df655e8d6a152ec12cd
6
+ metadata.gz: fa0180df722300f7dc736fb67eccd89fd2369c8528d43569eb06e369321d75989a4daee80612c8899354e163ee99fbeda8092bef2e6d561670a94b872fa0b8dc
7
+ data.tar.gz: a1ca825eac62aa31cb2367340e666a521251055500d0736975ff4a6f5061d9e4e6254d5c4b0e7d643f523cbd03029dc5b4e9840bfd22b7cf07c42775d23ae8fb
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The official Ruby client for the [VoiceML REST API](https://voicetel.com/docs/api/v0.7/voiceml/) — Twilio-compatible outbound voice and answering-machine-detection from VoiceTel, with idiomatic snake_case kwargs, structured errors, and a Twilio-compatible wire format.
4
4
 
5
- ![Version](https://img.shields.io/badge/version-0.7.1.1-blue)
5
+ ![Version](https://img.shields.io/badge/version-0.8.1-blue)
6
6
  ![Ruby](https://img.shields.io/badge/ruby-3.0%2B-red)
7
7
  ![License](https://img.shields.io/badge/license-MIT-green)
8
8
  ![Tests](https://img.shields.io/badge/tests-65%20specs-brightgreen)
@@ -47,10 +47,12 @@ The official Ruby client for the [VoiceML REST API](https://voicetel.com/docs/ap
47
47
  - **Messages** — create, fetch, list (To/From/DateSent filters + pagination), update (Body redaction; Status=canceled), delete.
48
48
  - **IncomingPhoneNumbers** — list, fetch, update.
49
49
  - **Notifications** — fetch, list.
50
+ - **SIP** — SIP Trunking: Domains (CRUD), CredentialLists + Credentials (CRUD), IpAccessControlLists + IpAddresses (CRUD), Domain↔ACL/CredentialList mappings (historical, Auth/Calls, Auth/Registrations namespaces).
51
+ - **Routes V2** — Twilio Inbound Processing Region API: `client.routes_v2.sip_domains.fetch(name)` / `update(name, voice_region:, friendly_name:)`.
50
52
  - **Diagnostics** — `/health` deep probe, OpenAPI spec.
51
53
 
52
54
  ### 🧪 Tested
53
- - **65 specs** with mocked HTTP layer (`webmock`) covering every resource and pagination edge cases — spec drift gets caught at parse time.
55
+ - **81 specs** with mocked HTTP layer (`webmock`) covering every resource and pagination edge cases — spec drift gets caught at parse time.
54
56
  - Integration smoke spec gated by env vars — safe for CI.
55
57
 
56
58
  ### 📦 Clean Distribution
@@ -10,6 +10,8 @@ require_relative 'resources/incoming_phone_numbers'
10
10
  require_relative 'resources/notifications'
11
11
  require_relative 'resources/diagnostics'
12
12
  require_relative 'resources/messages'
13
+ require_relative 'resources/sip'
14
+ require_relative 'resources/routes_v2'
13
15
 
14
16
  module VoiceML
15
17
  # Synchronous client for the VoiceML REST API.
@@ -28,7 +30,8 @@ module VoiceML
28
30
  # puts call.sid, call.status
29
31
  class Client
30
32
  attr_reader :calls, :conferences, :queues, :applications, :recordings,
31
- :incoming_phone_numbers, :notifications, :diagnostics, :messages
33
+ :incoming_phone_numbers, :notifications, :diagnostics, :messages,
34
+ :sip, :routes_v2
32
35
 
33
36
  # @param account_sid [String] Twilio-format AccountSid (`AC` + 32 hex).
34
37
  # @param api_key [String, nil] per-tenant API key. Pass either `api_key:` or the
@@ -70,6 +73,8 @@ module VoiceML
70
73
  @notifications = NotificationsResource.new(@transport)
71
74
  @diagnostics = DiagnosticsResource.new(@transport)
72
75
  @messages = MessagesResource.new(@transport)
76
+ @sip = SipResource.new(@transport)
77
+ @routes_v2 = RoutesV2Resource.new(@transport)
73
78
  end
74
79
 
75
80
  def account_sid
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VoiceML
4
+ # Twilio routes/v2 Inbound Processing Region binding. SID is `QQ...`.
5
+ # Keyed by SIP domain name (not the SipDomain SID).
6
+ class RoutesV2SipDomain
7
+ ATTRIBUTES = %w[
8
+ sid sip_domain account_sid friendly_name voice_region url
9
+ date_created date_updated
10
+ ].freeze
11
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
12
+ def initialize(attrs = {})
13
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
14
+ end
15
+ def self.from_hash(h); h.nil? ? nil : new(h); end
16
+ end
17
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common'
4
+
5
+ module VoiceML
6
+ # SIP Trunking resources — the Twilio-compatible /SIP/* REST surface.
7
+ #
8
+ # Three top-level sub-trees:
9
+ # - Domains (SD...) — SIP ingress endpoints
10
+ # - CredentialLists (CL...) holding Credentials (CR...) — SIP-digest auth
11
+ # - IpAccessControlLists (AL...) holding IpAddresses (IP...) — CIDR allowlists
12
+ #
13
+ # Mappings bind CredentialLists / IpAccessControlLists to a SipDomain via
14
+ # four endpoints: historical (no /Auth/) + /Auth/Calls/ + /Auth/Registrations/.
15
+
16
+ # SipDomain — `SD...` resource.
17
+ class SipDomain
18
+ ATTRIBUTES = %w[
19
+ sid account_sid domain_name api_version friendly_name auth_type
20
+ voice_url voice_method voice_fallback_url voice_fallback_method
21
+ voice_status_callback_url voice_status_callback_method
22
+ sip_registration emergency_calling_enabled secure
23
+ byoc_trunk_sid emergency_caller_sid
24
+ date_created date_updated uri subresource_uris
25
+ ].freeze
26
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
27
+ def initialize(attrs = {})
28
+ ATTRIBUTES.each { |f| instance_variable_set("@#{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
+ class SipDomainList
34
+ include Pageable
35
+ attr_reader :domains
36
+ def initialize(hash = {})
37
+ assign_page_fields(hash)
38
+ @domains = (hash['domains'] || []).map { |h| SipDomain.from_hash(h) }
39
+ end
40
+ end
41
+
42
+ # SipCredentialList — `CL...`.
43
+ class SipCredentialList
44
+ ATTRIBUTES = %w[
45
+ sid account_sid friendly_name date_created date_updated uri subresource_uris
46
+ ].freeze
47
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
48
+ def initialize(attrs = {})
49
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
50
+ end
51
+ def self.from_hash(h); h.nil? ? nil : new(h); end
52
+ end
53
+
54
+ class SipCredentialListList
55
+ include Pageable
56
+ attr_reader :credential_lists
57
+ def initialize(hash = {})
58
+ assign_page_fields(hash)
59
+ @credential_lists = (hash['credential_lists'] || []).map { |h| SipCredentialList.from_hash(h) }
60
+ end
61
+ end
62
+
63
+ # SipCredential — `CR...`. Password is write-only (never returned).
64
+ class SipCredential
65
+ ATTRIBUTES = %w[
66
+ sid account_sid credential_list_sid username
67
+ date_created date_updated uri
68
+ ].freeze
69
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
70
+ def initialize(attrs = {})
71
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
72
+ end
73
+ def self.from_hash(h); h.nil? ? nil : new(h); end
74
+ end
75
+
76
+ # SipCredentialListPage — spec name is `SipCredentialListPage` but it's a page of
77
+ # CREDENTIALS (not credential-lists), mirroring Twilio.
78
+ class SipCredentialListPage
79
+ include Pageable
80
+ attr_reader :credentials
81
+ def initialize(hash = {})
82
+ assign_page_fields(hash)
83
+ @credentials = (hash['credentials'] || []).map { |h| SipCredential.from_hash(h) }
84
+ end
85
+ end
86
+
87
+ # SipIpAccessControlList — `AL...`.
88
+ class SipIpAccessControlList
89
+ ATTRIBUTES = %w[
90
+ sid account_sid friendly_name date_created date_updated uri subresource_uris
91
+ ].freeze
92
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
93
+ def initialize(attrs = {})
94
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
95
+ end
96
+ def self.from_hash(h); h.nil? ? nil : new(h); end
97
+ end
98
+
99
+ class SipIpAccessControlListList
100
+ include Pageable
101
+ attr_reader :ip_access_control_lists
102
+ def initialize(hash = {})
103
+ assign_page_fields(hash)
104
+ @ip_access_control_lists = (hash['ip_access_control_lists'] || []).map { |h| SipIpAccessControlList.from_hash(h) }
105
+ end
106
+ end
107
+
108
+ # SipIpAddress — `IP...`.
109
+ class SipIpAddress
110
+ ATTRIBUTES = %w[
111
+ sid account_sid ip_access_control_list_sid
112
+ friendly_name ip_address cidr_prefix_length
113
+ date_created date_updated uri
114
+ ].freeze
115
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
116
+ def initialize(attrs = {})
117
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
118
+ end
119
+ def self.from_hash(h); h.nil? ? nil : new(h); end
120
+ end
121
+
122
+ class SipIpAddressList
123
+ include Pageable
124
+ attr_reader :ip_addresses
125
+ def initialize(hash = {})
126
+ assign_page_fields(hash)
127
+ @ip_addresses = (hash['ip_addresses'] || []).map { |h| SipIpAddress.from_hash(h) }
128
+ end
129
+ end
130
+
131
+ # SipDomainMapping — round-trip shape for every domain mapping sub-resource.
132
+ # `sid` echoes the bound resource (CL... for credential mappings, AL... for IP-ACL);
133
+ # `domain_sid` records which domain the binding is attached to.
134
+ class SipDomainMapping
135
+ ATTRIBUTES = %w[
136
+ sid account_sid friendly_name domain_sid date_created date_updated uri
137
+ ].freeze
138
+ attr_reader(*ATTRIBUTES.map(&:to_sym))
139
+ def initialize(attrs = {})
140
+ ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs[f] || attrs[f.to_sym]) }
141
+ end
142
+ def self.from_hash(h); h.nil? ? nil : new(h); end
143
+ end
144
+
145
+ class SipCredentialListMappingList
146
+ include Pageable
147
+ attr_reader :credential_list_mappings
148
+ def initialize(hash = {})
149
+ assign_page_fields(hash)
150
+ @credential_list_mappings = (hash['credential_list_mappings'] || []).map { |h| SipDomainMapping.from_hash(h) }
151
+ end
152
+ end
153
+
154
+ class SipIpAccessControlListMappingList
155
+ include Pageable
156
+ attr_reader :ip_access_control_list_mappings
157
+ def initialize(hash = {})
158
+ assign_page_fields(hash)
159
+ @ip_access_control_list_mappings = (hash['ip_access_control_list_mappings'] || []).map { |h| SipDomainMapping.from_hash(h) }
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../models/routes_v2'
4
+
5
+ module VoiceML
6
+ # `client.routes_v2` — Twilio routes/v2 Inbound Processing Region API.
7
+ # Sits outside the /2010-04-01/Accounts/... namespace.
8
+ class RoutesV2Resource
9
+ attr_reader :sip_domains
10
+ def initialize(transport)
11
+ @sip_domains = RoutesV2SipDomainsResource.new(transport)
12
+ end
13
+ end
14
+
15
+ # Operations on /v2/SipDomains/{SipDomain}. Keyed by domain name; account
16
+ # is resolved from HTTP Basic auth.
17
+ class RoutesV2SipDomainsResource
18
+ def initialize(transport)
19
+ @transport = transport
20
+ end
21
+
22
+ def fetch(domain_name)
23
+ RoutesV2SipDomain.from_hash(@transport.request(:get, "/v2/SipDomains/#{domain_name}"))
24
+ end
25
+
26
+ def update(domain_name, voice_region: nil, friendly_name: nil)
27
+ form = {}
28
+ form['VoiceRegion'] = voice_region unless voice_region.nil?
29
+ form['FriendlyName'] = friendly_name unless friendly_name.nil?
30
+ RoutesV2SipDomain.from_hash(@transport.request(:post, "/v2/SipDomains/#{domain_name}", form: form))
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative '../models/sip'
5
+
6
+ module VoiceML
7
+ # `client.sip` — top-level SIP Trunking holder.
8
+ class SipResource
9
+ attr_reader :domains, :credential_lists, :ip_access_control_lists
10
+
11
+ def initialize(transport)
12
+ @domains = SipDomainsResource.new(transport)
13
+ @credential_lists = SipCredentialListsResource.new(transport)
14
+ @ip_access_control_lists = SipIpAccessControlListsResource.new(transport)
15
+ end
16
+ end
17
+
18
+ # /SIP/Domains plus the four mapping endpoints.
19
+ class SipDomainsResource < BaseResource
20
+ DOMAIN_FIELDS = {
21
+ 'FriendlyName' => :friendly_name,
22
+ 'VoiceUrl' => :voice_url,
23
+ 'VoiceMethod' => :voice_method,
24
+ 'VoiceFallbackUrl' => :voice_fallback_url,
25
+ 'VoiceFallbackMethod' => :voice_fallback_method,
26
+ 'VoiceStatusCallbackUrl' => :voice_status_callback_url,
27
+ 'VoiceStatusCallbackMethod' => :voice_status_callback_method,
28
+ 'SipRegistration' => :sip_registration,
29
+ 'Secure' => :secure,
30
+ 'EmergencyCallingEnabled' => :emergency_calling_enabled,
31
+ 'ByocTrunkSid' => :byoc_trunk_sid,
32
+ 'EmergencyCallerSid' => :emergency_caller_sid
33
+ }.freeze
34
+
35
+ PAGE_FIELDS = { 'Page' => :page, 'PageSize' => :page_size, 'PageToken' => :page_token }.freeze
36
+
37
+ def list(**kwargs)
38
+ SipDomainList.new(@transport.request(:get, path('SIP', 'Domains'), params: form_params(PAGE_FIELDS, kwargs)))
39
+ end
40
+
41
+ def create(domain_name:, **kwargs)
42
+ body = { 'DomainName' => domain_name }.merge(form_params(DOMAIN_FIELDS, kwargs))
43
+ SipDomain.from_hash(@transport.request(:post, path('SIP', 'Domains'), form: body))
44
+ end
45
+
46
+ def fetch(domain_sid)
47
+ SipDomain.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid)))
48
+ end
49
+
50
+ def update(domain_sid, **kwargs)
51
+ SipDomain.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid), form: form_params(DOMAIN_FIELDS, kwargs)))
52
+ end
53
+
54
+ def delete(domain_sid)
55
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid))
56
+ nil
57
+ end
58
+
59
+ # --- Historical CredentialList mappings ---
60
+ def list_credential_list_mappings(domain_sid, **kwargs)
61
+ SipCredentialListMappingList.new(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'CredentialListMappings'), params: form_params(PAGE_FIELDS, kwargs)))
62
+ end
63
+ def create_credential_list_mapping(domain_sid, credential_list_sid:)
64
+ SipDomainMapping.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid, 'CredentialListMappings'), form: { 'CredentialListSid' => credential_list_sid }))
65
+ end
66
+ def fetch_credential_list_mapping(domain_sid, mapping_sid)
67
+ SipDomainMapping.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'CredentialListMappings', mapping_sid)))
68
+ end
69
+ def delete_credential_list_mapping(domain_sid, mapping_sid)
70
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid, 'CredentialListMappings', mapping_sid)); nil
71
+ end
72
+
73
+ # --- Historical IpAccessControlList mappings ---
74
+ def list_ip_access_control_list_mappings(domain_sid, **kwargs)
75
+ SipIpAccessControlListMappingList.new(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'IpAccessControlListMappings'), params: form_params(PAGE_FIELDS, kwargs)))
76
+ end
77
+ def create_ip_access_control_list_mapping(domain_sid, ip_access_control_list_sid:)
78
+ SipDomainMapping.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid, 'IpAccessControlListMappings'), form: { 'IpAccessControlListSid' => ip_access_control_list_sid }))
79
+ end
80
+ def fetch_ip_access_control_list_mapping(domain_sid, mapping_sid)
81
+ SipDomainMapping.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'IpAccessControlListMappings', mapping_sid)))
82
+ end
83
+ def delete_ip_access_control_list_mapping(domain_sid, mapping_sid)
84
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid, 'IpAccessControlListMappings', mapping_sid)); nil
85
+ end
86
+
87
+ # --- Auth/Calls/CredentialListMappings ---
88
+ def list_auth_calls_credential_list_mappings(domain_sid, **kwargs)
89
+ SipCredentialListMappingList.new(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'CredentialListMappings'), params: form_params(PAGE_FIELDS, kwargs)))
90
+ end
91
+ def create_auth_calls_credential_list_mapping(domain_sid, credential_list_sid:)
92
+ SipDomainMapping.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'CredentialListMappings'), form: { 'CredentialListSid' => credential_list_sid }))
93
+ end
94
+ def fetch_auth_calls_credential_list_mapping(domain_sid, mapping_sid)
95
+ SipDomainMapping.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'CredentialListMappings', mapping_sid)))
96
+ end
97
+ def delete_auth_calls_credential_list_mapping(domain_sid, mapping_sid)
98
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'CredentialListMappings', mapping_sid)); nil
99
+ end
100
+
101
+ # --- Auth/Calls/IpAccessControlListMappings ---
102
+ def list_auth_calls_ip_access_control_list_mappings(domain_sid, **kwargs)
103
+ SipIpAccessControlListMappingList.new(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'IpAccessControlListMappings'), params: form_params(PAGE_FIELDS, kwargs)))
104
+ end
105
+ def create_auth_calls_ip_access_control_list_mapping(domain_sid, ip_access_control_list_sid:)
106
+ SipDomainMapping.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'IpAccessControlListMappings'), form: { 'IpAccessControlListSid' => ip_access_control_list_sid }))
107
+ end
108
+ def fetch_auth_calls_ip_access_control_list_mapping(domain_sid, mapping_sid)
109
+ SipDomainMapping.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'IpAccessControlListMappings', mapping_sid)))
110
+ end
111
+ def delete_auth_calls_ip_access_control_list_mapping(domain_sid, mapping_sid)
112
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid, 'Auth', 'Calls', 'IpAccessControlListMappings', mapping_sid)); nil
113
+ end
114
+
115
+ # --- Auth/Registrations/CredentialListMappings ---
116
+ def list_auth_registrations_credential_list_mappings(domain_sid, **kwargs)
117
+ SipCredentialListMappingList.new(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Registrations', 'CredentialListMappings'), params: form_params(PAGE_FIELDS, kwargs)))
118
+ end
119
+ def create_auth_registrations_credential_list_mapping(domain_sid, credential_list_sid:)
120
+ SipDomainMapping.from_hash(@transport.request(:post, path('SIP', 'Domains', domain_sid, 'Auth', 'Registrations', 'CredentialListMappings'), form: { 'CredentialListSid' => credential_list_sid }))
121
+ end
122
+ def fetch_auth_registrations_credential_list_mapping(domain_sid, mapping_sid)
123
+ SipDomainMapping.from_hash(@transport.request(:get, path('SIP', 'Domains', domain_sid, 'Auth', 'Registrations', 'CredentialListMappings', mapping_sid)))
124
+ end
125
+ def delete_auth_registrations_credential_list_mapping(domain_sid, mapping_sid)
126
+ @transport.request(:delete, path('SIP', 'Domains', domain_sid, 'Auth', 'Registrations', 'CredentialListMappings', mapping_sid)); nil
127
+ end
128
+ end
129
+
130
+ # /SIP/CredentialLists + /Credentials sub-resource.
131
+ class SipCredentialListsResource < BaseResource
132
+ PAGE_FIELDS = { 'Page' => :page, 'PageSize' => :page_size, 'PageToken' => :page_token }.freeze
133
+
134
+ def list(**kwargs)
135
+ SipCredentialListList.new(@transport.request(:get, path('SIP', 'CredentialLists'), params: form_params(PAGE_FIELDS, kwargs)))
136
+ end
137
+ def create(friendly_name:)
138
+ SipCredentialList.from_hash(@transport.request(:post, path('SIP', 'CredentialLists'), form: { 'FriendlyName' => friendly_name }))
139
+ end
140
+ def fetch(credential_list_sid)
141
+ SipCredentialList.from_hash(@transport.request(:get, path('SIP', 'CredentialLists', credential_list_sid)))
142
+ end
143
+ def update(credential_list_sid, friendly_name: nil)
144
+ form = friendly_name.nil? ? {} : { 'FriendlyName' => friendly_name }
145
+ SipCredentialList.from_hash(@transport.request(:post, path('SIP', 'CredentialLists', credential_list_sid), form: form))
146
+ end
147
+ def delete(credential_list_sid)
148
+ @transport.request(:delete, path('SIP', 'CredentialLists', credential_list_sid)); nil
149
+ end
150
+
151
+ # /Credentials sub-resource
152
+ def list_credentials(credential_list_sid, **kwargs)
153
+ SipCredentialListPage.new(@transport.request(:get, path('SIP', 'CredentialLists', credential_list_sid, 'Credentials'), params: form_params(PAGE_FIELDS, kwargs)))
154
+ end
155
+ def create_credential(credential_list_sid, username:, password:)
156
+ SipCredential.from_hash(@transport.request(:post, path('SIP', 'CredentialLists', credential_list_sid, 'Credentials'), form: { 'Username' => username, 'Password' => password }))
157
+ end
158
+ def fetch_credential(credential_list_sid, credential_sid)
159
+ SipCredential.from_hash(@transport.request(:get, path('SIP', 'CredentialLists', credential_list_sid, 'Credentials', credential_sid)))
160
+ end
161
+ def update_credential(credential_list_sid, credential_sid, password:)
162
+ SipCredential.from_hash(@transport.request(:post, path('SIP', 'CredentialLists', credential_list_sid, 'Credentials', credential_sid), form: { 'Password' => password }))
163
+ end
164
+ def delete_credential(credential_list_sid, credential_sid)
165
+ @transport.request(:delete, path('SIP', 'CredentialLists', credential_list_sid, 'Credentials', credential_sid)); nil
166
+ end
167
+ end
168
+
169
+ # /SIP/IpAccessControlLists + /IpAddresses sub-resource.
170
+ class SipIpAccessControlListsResource < BaseResource
171
+ PAGE_FIELDS = { 'Page' => :page, 'PageSize' => :page_size, 'PageToken' => :page_token }.freeze
172
+ IP_FIELDS = { 'FriendlyName' => :friendly_name, 'IpAddress' => :ip_address, 'CidrPrefixLength' => :cidr_prefix_length }.freeze
173
+
174
+ def list(**kwargs)
175
+ SipIpAccessControlListList.new(@transport.request(:get, path('SIP', 'IpAccessControlLists'), params: form_params(PAGE_FIELDS, kwargs)))
176
+ end
177
+ def create(friendly_name:)
178
+ SipIpAccessControlList.from_hash(@transport.request(:post, path('SIP', 'IpAccessControlLists'), form: { 'FriendlyName' => friendly_name }))
179
+ end
180
+ def fetch(acl_sid)
181
+ SipIpAccessControlList.from_hash(@transport.request(:get, path('SIP', 'IpAccessControlLists', acl_sid)))
182
+ end
183
+ def update(acl_sid, friendly_name: nil)
184
+ form = friendly_name.nil? ? {} : { 'FriendlyName' => friendly_name }
185
+ SipIpAccessControlList.from_hash(@transport.request(:post, path('SIP', 'IpAccessControlLists', acl_sid), form: form))
186
+ end
187
+ def delete(acl_sid)
188
+ @transport.request(:delete, path('SIP', 'IpAccessControlLists', acl_sid)); nil
189
+ end
190
+
191
+ # /IpAddresses sub-resource
192
+ def list_ip_addresses(acl_sid, **kwargs)
193
+ SipIpAddressList.new(@transport.request(:get, path('SIP', 'IpAccessControlLists', acl_sid, 'IpAddresses'), params: form_params(PAGE_FIELDS, kwargs)))
194
+ end
195
+ def create_ip_address(acl_sid, friendly_name:, ip_address:, cidr_prefix_length: nil)
196
+ form = { 'FriendlyName' => friendly_name, 'IpAddress' => ip_address }
197
+ form['CidrPrefixLength'] = cidr_prefix_length unless cidr_prefix_length.nil?
198
+ SipIpAddress.from_hash(@transport.request(:post, path('SIP', 'IpAccessControlLists', acl_sid, 'IpAddresses'), form: form))
199
+ end
200
+ def fetch_ip_address(acl_sid, ip_address_sid)
201
+ SipIpAddress.from_hash(@transport.request(:get, path('SIP', 'IpAccessControlLists', acl_sid, 'IpAddresses', ip_address_sid)))
202
+ end
203
+ def update_ip_address(acl_sid, ip_address_sid, **kwargs)
204
+ SipIpAddress.from_hash(@transport.request(:post, path('SIP', 'IpAccessControlLists', acl_sid, 'IpAddresses', ip_address_sid), form: form_params(IP_FIELDS, kwargs)))
205
+ end
206
+ def delete_ip_address(acl_sid, ip_address_sid)
207
+ @transport.request(:delete, path('SIP', 'IpAccessControlLists', acl_sid, 'IpAddresses', ip_address_sid)); nil
208
+ end
209
+ end
210
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VoiceML
4
- VERSION = '0.7.1.1'
4
+ VERSION = '0.8.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voiceml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - VoiceTel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-13 00:00:00.000000000 Z
11
+ date: 2026-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -74,6 +74,8 @@ files:
74
74
  - lib/voiceml/models/payments.rb
75
75
  - lib/voiceml/models/queues.rb
76
76
  - lib/voiceml/models/recordings.rb
77
+ - lib/voiceml/models/routes_v2.rb
78
+ - lib/voiceml/models/sip.rb
77
79
  - lib/voiceml/models/siprec.rb
78
80
  - lib/voiceml/models/streams.rb
79
81
  - lib/voiceml/models/transcriptions.rb
@@ -87,6 +89,8 @@ files:
87
89
  - lib/voiceml/resources/notifications.rb
88
90
  - lib/voiceml/resources/queues.rb
89
91
  - lib/voiceml/resources/recordings.rb
92
+ - lib/voiceml/resources/routes_v2.rb
93
+ - lib/voiceml/resources/sip.rb
90
94
  - lib/voiceml/transport.rb
91
95
  - lib/voiceml/version.rb
92
96
  homepage: https://voiceml.voicetel.com