signalwire-sdk 2.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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +259 -0
  4. data/bin/swaig-test +872 -0
  5. data/lib/signalwire/agent/agent_base.rb +2134 -0
  6. data/lib/signalwire/contexts/context_builder.rb +861 -0
  7. data/lib/signalwire/core/logging_config.rb +54 -0
  8. data/lib/signalwire/datamap/data_map.rb +315 -0
  9. data/lib/signalwire/logging.rb +92 -0
  10. data/lib/signalwire/pom/prompt_object_model.rb +269 -0
  11. data/lib/signalwire/pom/section.rb +202 -0
  12. data/lib/signalwire/prefabs/concierge.rb +92 -0
  13. data/lib/signalwire/prefabs/faq_bot.rb +67 -0
  14. data/lib/signalwire/prefabs/info_gatherer.rb +79 -0
  15. data/lib/signalwire/prefabs/receptionist.rb +74 -0
  16. data/lib/signalwire/prefabs/survey.rb +75 -0
  17. data/lib/signalwire/relay/action.rb +291 -0
  18. data/lib/signalwire/relay/call.rb +523 -0
  19. data/lib/signalwire/relay/client.rb +789 -0
  20. data/lib/signalwire/relay/constants.rb +124 -0
  21. data/lib/signalwire/relay/message.rb +137 -0
  22. data/lib/signalwire/relay/relay_event.rb +670 -0
  23. data/lib/signalwire/rest/http_client.rb +159 -0
  24. data/lib/signalwire/rest/namespaces/addresses.rb +19 -0
  25. data/lib/signalwire/rest/namespaces/calling.rb +179 -0
  26. data/lib/signalwire/rest/namespaces/chat.rb +18 -0
  27. data/lib/signalwire/rest/namespaces/compat.rb +229 -0
  28. data/lib/signalwire/rest/namespaces/datasphere.rb +39 -0
  29. data/lib/signalwire/rest/namespaces/fabric.rb +235 -0
  30. data/lib/signalwire/rest/namespaces/imported_numbers.rb +18 -0
  31. data/lib/signalwire/rest/namespaces/logs.rb +46 -0
  32. data/lib/signalwire/rest/namespaces/lookup.rb +18 -0
  33. data/lib/signalwire/rest/namespaces/mfa.rb +26 -0
  34. data/lib/signalwire/rest/namespaces/number_groups.rb +32 -0
  35. data/lib/signalwire/rest/namespaces/phone_numbers.rb +124 -0
  36. data/lib/signalwire/rest/namespaces/project.rb +33 -0
  37. data/lib/signalwire/rest/namespaces/pubsub.rb +18 -0
  38. data/lib/signalwire/rest/namespaces/queues.rb +28 -0
  39. data/lib/signalwire/rest/namespaces/recordings.rb +18 -0
  40. data/lib/signalwire/rest/namespaces/registry.rb +67 -0
  41. data/lib/signalwire/rest/namespaces/short_codes.rb +26 -0
  42. data/lib/signalwire/rest/namespaces/sip_profile.rb +22 -0
  43. data/lib/signalwire/rest/namespaces/verified_callers.rb +24 -0
  44. data/lib/signalwire/rest/namespaces/video.rb +129 -0
  45. data/lib/signalwire/rest/pagination.rb +89 -0
  46. data/lib/signalwire/rest/phone_call_handler.rb +56 -0
  47. data/lib/signalwire/rest/rest_client.rb +114 -0
  48. data/lib/signalwire/runtime.rb +98 -0
  49. data/lib/signalwire/security/session_manager.rb +124 -0
  50. data/lib/signalwire/security/webhook_middleware.rb +191 -0
  51. data/lib/signalwire/security/webhook_validator.rb +327 -0
  52. data/lib/signalwire/server/agent_server.rb +413 -0
  53. data/lib/signalwire/serverless/lambda_handler.rb +251 -0
  54. data/lib/signalwire/skills/builtin/api_ninjas_trivia.rb +99 -0
  55. data/lib/signalwire/skills/builtin/claude_skills.rb +92 -0
  56. data/lib/signalwire/skills/builtin/custom_skills.rb +54 -0
  57. data/lib/signalwire/skills/builtin/datasphere.rb +153 -0
  58. data/lib/signalwire/skills/builtin/datasphere_serverless.rb +107 -0
  59. data/lib/signalwire/skills/builtin/datetime.rb +97 -0
  60. data/lib/signalwire/skills/builtin/google_maps.rb +168 -0
  61. data/lib/signalwire/skills/builtin/info_gatherer.rb +189 -0
  62. data/lib/signalwire/skills/builtin/joke.rb +65 -0
  63. data/lib/signalwire/skills/builtin/math.rb +176 -0
  64. data/lib/signalwire/skills/builtin/mcp_gateway.rb +121 -0
  65. data/lib/signalwire/skills/builtin/native_vector_search.rb +116 -0
  66. data/lib/signalwire/skills/builtin/play_background_file.rb +86 -0
  67. data/lib/signalwire/skills/builtin/spider.rb +169 -0
  68. data/lib/signalwire/skills/builtin/swml_transfer.rb +118 -0
  69. data/lib/signalwire/skills/builtin/weather_api.rb +92 -0
  70. data/lib/signalwire/skills/builtin/web_search.rb +141 -0
  71. data/lib/signalwire/skills/builtin/wikipedia_search.rb +125 -0
  72. data/lib/signalwire/skills/skill_base.rb +82 -0
  73. data/lib/signalwire/skills/skill_manager.rb +97 -0
  74. data/lib/signalwire/skills/skill_registry.rb +258 -0
  75. data/lib/signalwire/swaig/function_result.rb +777 -0
  76. data/lib/signalwire/swml/document.rb +84 -0
  77. data/lib/signalwire/swml/schema.json +12250 -0
  78. data/lib/signalwire/swml/schema.rb +81 -0
  79. data/lib/signalwire/swml/service.rb +650 -0
  80. data/lib/signalwire/utils/schema_utils.rb +298 -0
  81. data/lib/signalwire/utils/serverless.rb +19 -0
  82. data/lib/signalwire/utils/url_validator.rb +138 -0
  83. data/lib/signalwire/version.rb +5 -0
  84. data/lib/signalwire.rb +114 -0
  85. metadata +225 -0
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Standard fabric resource with CRUD + addresses.
7
+ class FabricResource < CrudResource
8
+ def list_addresses(resource_id, **params)
9
+ @http.get(_path(resource_id, 'addresses'), params.empty? ? nil : params)
10
+ end
11
+ end
12
+
13
+ # Fabric resource that uses PUT for updates.
14
+ class FabricResourcePUT < FabricResource
15
+ self.update_method = 'PUT'
16
+ end
17
+
18
+ # Fabric webhook resource that's normally auto-created by
19
+ # +phone_numbers.set_*_webhook+. Exposed for backwards compatibility.
20
+ #
21
+ # The binding model for these resources is on the phone number (see
22
+ # +phone_numbers.set_swml_webhook+ / +set_cxml_webhook+) -- setting
23
+ # +call_handler+ on a phone number auto-materializes the webhook
24
+ # Fabric resource. Calling +create+ directly here produces an orphan
25
+ # resource that isn't bound to any phone number.
26
+ class AutoMaterializedWebhook < FabricResource
27
+ # Subclasses override to advertise the correct helper in the warning.
28
+ AUTO_HELPER_NAME = 'phone_numbers.set_*_webhook'
29
+
30
+ # @deprecated Creating a webhook Fabric resource directly produces an
31
+ # orphan that isn't bound to any phone number. Use the matching
32
+ # +phone_numbers.set_*_webhook+ helper instead; it updates the
33
+ # phone number and the server auto-materializes the resource.
34
+ # See porting-sdk's +phone-binding.md+.
35
+ def create(**kwargs)
36
+ Kernel.warn(
37
+ "DEPRECATION: creating a webhook Fabric resource directly produces " \
38
+ "an orphan not bound to any phone number. Use " \
39
+ "#{self.class::AUTO_HELPER_NAME} instead; it updates the phone " \
40
+ "number and the server auto-materializes the resource. " \
41
+ "See porting-sdk's phone-binding.md.",
42
+ uplevel: 1
43
+ )
44
+ super
45
+ end
46
+ end
47
+
48
+ # SWML webhooks -- auto-materialized by +phone_numbers.set_swml_webhook+.
49
+ class SwmlWebhooksResource < AutoMaterializedWebhook
50
+ AUTO_HELPER_NAME = 'phone_numbers.set_swml_webhook(sid, url: ...)'
51
+ end
52
+
53
+ # cXML webhooks -- auto-materialized by +phone_numbers.set_cxml_webhook+.
54
+ class CxmlWebhooksResource < AutoMaterializedWebhook
55
+ AUTO_HELPER_NAME = 'phone_numbers.set_cxml_webhook(sid, url: ...)'
56
+ end
57
+
58
+ # Call flows with version management.
59
+ class CallFlowsResource < FabricResourcePUT
60
+ def list_addresses(resource_id, **params)
61
+ path = @base_path.sub('/call_flows', '/call_flow')
62
+ @http.get("#{path}/#{resource_id}/addresses", params.empty? ? nil : params)
63
+ end
64
+
65
+ def list_versions(resource_id, **params)
66
+ path = @base_path.sub('/call_flows', '/call_flow')
67
+ @http.get("#{path}/#{resource_id}/versions", params.empty? ? nil : params)
68
+ end
69
+
70
+ def deploy_version(resource_id, **kwargs)
71
+ path = @base_path.sub('/call_flows', '/call_flow')
72
+ @http.post("#{path}/#{resource_id}/versions", kwargs)
73
+ end
74
+ end
75
+
76
+ # Conference rooms -- uses singular 'conference_room' for sub-resource paths.
77
+ class ConferenceRoomsResource < FabricResourcePUT
78
+ def list_addresses(resource_id, **params)
79
+ path = @base_path.sub('/conference_rooms', '/conference_room')
80
+ @http.get("#{path}/#{resource_id}/addresses", params.empty? ? nil : params)
81
+ end
82
+ end
83
+
84
+ # Subscribers with SIP endpoint management.
85
+ class SubscribersResource < FabricResourcePUT
86
+ def list_sip_endpoints(subscriber_id, **params)
87
+ @http.get(_path(subscriber_id, 'sip_endpoints'), params.empty? ? nil : params)
88
+ end
89
+
90
+ def create_sip_endpoint(subscriber_id, **kwargs)
91
+ @http.post(_path(subscriber_id, 'sip_endpoints'), kwargs)
92
+ end
93
+
94
+ def get_sip_endpoint(subscriber_id, endpoint_id)
95
+ @http.get(_path(subscriber_id, 'sip_endpoints', endpoint_id))
96
+ end
97
+
98
+ def update_sip_endpoint(subscriber_id, endpoint_id, **kwargs)
99
+ @http.patch(_path(subscriber_id, 'sip_endpoints', endpoint_id), kwargs)
100
+ end
101
+
102
+ def delete_sip_endpoint(subscriber_id, endpoint_id)
103
+ @http.delete(_path(subscriber_id, 'sip_endpoints', endpoint_id))
104
+ end
105
+ end
106
+
107
+ # cXML applications -- no create method.
108
+ class CxmlApplicationsResource < FabricResourcePUT
109
+ def create(**_kwargs)
110
+ raise NotImplementedError, 'cXML applications cannot be created via this API'
111
+ end
112
+ end
113
+
114
+ # Generic resource operations across all fabric resource types.
115
+ class GenericResources < BaseResource
116
+ def list(**params)
117
+ @http.get(@base_path, params.empty? ? nil : params)
118
+ end
119
+
120
+ def get(resource_id)
121
+ @http.get(_path(resource_id))
122
+ end
123
+
124
+ def delete(resource_id)
125
+ @http.delete(_path(resource_id))
126
+ end
127
+
128
+ def list_addresses(resource_id, **params)
129
+ @http.get(_path(resource_id, 'addresses'), params.empty? ? nil : params)
130
+ end
131
+
132
+ # @deprecated For the common binding cases use +phone_numbers.set_*+ helpers.
133
+ #
134
+ # This endpoint (+POST /api/fabric/resources/{id}/phone_routes+) accepts
135
+ # only a narrow set of legacy resource types as the attach target. It
136
+ # *does not work* for +swml_webhook+ / +cxml_webhook+ / +ai_agent+
137
+ # bindings -- those are configured on the phone number and the Fabric
138
+ # resource is auto-materialized (see +phone_numbers.set_swml_webhook+
139
+ # etc.). The authoritative list of accepting resource types lives in
140
+ # the OpenAPI spec; routing here for those types returns 404 or 422.
141
+ def assign_phone_route(resource_id, **kwargs)
142
+ Kernel.warn(
143
+ "DEPRECATION: assign_phone_route does not bind phone numbers to " \
144
+ "swml_webhook/cxml_webhook/ai_agent resources -- those are " \
145
+ "configured via phone_numbers.set_swml_webhook / set_cxml_webhook " \
146
+ "/ set_ai_agent. This method applies only to a narrow set of " \
147
+ "legacy resource types. See porting-sdk's phone-binding.md.",
148
+ uplevel: 1
149
+ )
150
+ @http.post(_path(resource_id, 'phone_routes'), kwargs)
151
+ end
152
+
153
+ def assign_domain_application(resource_id, **kwargs)
154
+ @http.post(_path(resource_id, 'domain_applications'), kwargs)
155
+ end
156
+ end
157
+
158
+ # Read-only fabric addresses.
159
+ class FabricAddresses < BaseResource
160
+ def list(**params)
161
+ @http.get(@base_path, params.empty? ? nil : params)
162
+ end
163
+
164
+ def get(address_id)
165
+ @http.get(_path(address_id))
166
+ end
167
+ end
168
+
169
+ # Subscriber, guest, invite, and embed token creation.
170
+ class FabricTokens < BaseResource
171
+ def initialize(http)
172
+ super(http, '/api/fabric')
173
+ end
174
+
175
+ def create_subscriber_token(**kwargs)
176
+ @http.post(_path('subscribers', 'tokens'), kwargs)
177
+ end
178
+
179
+ def refresh_subscriber_token(**kwargs)
180
+ @http.post(_path('subscribers', 'tokens', 'refresh'), kwargs)
181
+ end
182
+
183
+ def create_invite_token(**kwargs)
184
+ @http.post(_path('subscriber', 'invites'), kwargs)
185
+ end
186
+
187
+ def create_guest_token(**kwargs)
188
+ @http.post(_path('guests', 'tokens'), kwargs)
189
+ end
190
+
191
+ def create_embed_token(**kwargs)
192
+ @http.post(_path('embeds', 'tokens'), kwargs)
193
+ end
194
+ end
195
+
196
+ # Fabric API namespace grouping all resource types.
197
+ class FabricNamespace
198
+ attr_reader :swml_scripts, :relay_applications, :call_flows,
199
+ :conference_rooms, :freeswitch_connectors, :subscribers,
200
+ :sip_endpoints, :cxml_scripts, :cxml_applications,
201
+ :swml_webhooks, :ai_agents, :sip_gateways, :cxml_webhooks,
202
+ :resources, :addresses, :tokens
203
+
204
+ def initialize(http)
205
+ base = '/api/fabric/resources'
206
+
207
+ # PUT-update resources
208
+ @swml_scripts = FabricResourcePUT.new(http, "#{base}/swml_scripts")
209
+ @relay_applications = FabricResourcePUT.new(http, "#{base}/relay_applications")
210
+ @call_flows = CallFlowsResource.new(http, "#{base}/call_flows")
211
+ @conference_rooms = ConferenceRoomsResource.new(http, "#{base}/conference_rooms")
212
+ @freeswitch_connectors = FabricResourcePUT.new(http, "#{base}/freeswitch_connectors")
213
+ @subscribers = SubscribersResource.new(http, "#{base}/subscribers")
214
+ @sip_endpoints = FabricResourcePUT.new(http, "#{base}/sip_endpoints")
215
+ @cxml_scripts = FabricResourcePUT.new(http, "#{base}/cxml_scripts")
216
+ @cxml_applications = CxmlApplicationsResource.new(http, "#{base}/cxml_applications")
217
+
218
+ # PATCH-update resources
219
+ # swml_webhooks and cxml_webhooks are normally auto-materialized by
220
+ # phone_numbers.set_swml_webhook / set_cxml_webhook. Direct create
221
+ # still works for backcompat but emits a deprecation warning.
222
+ @swml_webhooks = SwmlWebhooksResource.new(http, "#{base}/swml_webhooks")
223
+ @ai_agents = FabricResource.new(http, "#{base}/ai_agents")
224
+ @sip_gateways = FabricResource.new(http, "#{base}/sip_gateways")
225
+ @cxml_webhooks = CxmlWebhooksResource.new(http, "#{base}/cxml_webhooks")
226
+
227
+ # Special resources
228
+ @resources = GenericResources.new(http, base)
229
+ @addresses = FabricAddresses.new(http, '/api/fabric/addresses')
230
+ @tokens = FabricTokens.new(http)
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Import externally-hosted phone numbers.
7
+ class ImportedNumbersResource < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/relay/rest/imported_phone_numbers')
10
+ end
11
+
12
+ def create(**kwargs)
13
+ @http.post(@base_path, kwargs)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Message log queries.
7
+ class MessageLogs < BaseResource
8
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
9
+ def get(log_id) = @http.get(_path(log_id))
10
+ end
11
+
12
+ # Voice log queries.
13
+ class VoiceLogs < BaseResource
14
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
15
+ def get(log_id) = @http.get(_path(log_id))
16
+
17
+ def list_events(log_id, **params)
18
+ @http.get(_path(log_id, 'events'), params.empty? ? nil : params)
19
+ end
20
+ end
21
+
22
+ # Fax log queries.
23
+ class FaxLogs < BaseResource
24
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
25
+ def get(log_id) = @http.get(_path(log_id))
26
+ end
27
+
28
+ # Conference log queries.
29
+ class ConferenceLogs < BaseResource
30
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
31
+ end
32
+
33
+ # Logs API namespace.
34
+ class LogsNamespace
35
+ attr_reader :messages, :voice, :fax, :conferences
36
+
37
+ def initialize(http)
38
+ @messages = MessageLogs.new(http, '/api/messaging/logs')
39
+ @voice = VoiceLogs.new(http, '/api/voice/logs')
40
+ @fax = FaxLogs.new(http, '/api/fax/logs')
41
+ @conferences = ConferenceLogs.new(http, '/api/logs/conferences')
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Phone number lookup (carrier, CNAM).
7
+ class LookupResource < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/relay/rest/lookup')
10
+ end
11
+
12
+ def phone_number(e164, **params)
13
+ @http.get(_path('phone_number', e164), params.empty? ? nil : params)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Multi-factor authentication via SMS or phone call.
7
+ class MfaResource < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/relay/rest/mfa')
10
+ end
11
+
12
+ def sms(**kwargs)
13
+ @http.post(_path('sms'), kwargs)
14
+ end
15
+
16
+ def call(**kwargs)
17
+ @http.post(_path('call'), kwargs)
18
+ end
19
+
20
+ def verify(request_id, **kwargs)
21
+ @http.post(_path(request_id, 'verify'), kwargs)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Number group management with membership operations.
7
+ class NumberGroupsResource < CrudResource
8
+ self.update_method = 'PUT'
9
+
10
+ def initialize(http)
11
+ super(http, '/api/relay/rest/number_groups')
12
+ end
13
+
14
+ def list_memberships(group_id, **params)
15
+ @http.get(_path(group_id, 'number_group_memberships'), params.empty? ? nil : params)
16
+ end
17
+
18
+ def add_membership(group_id, **kwargs)
19
+ @http.post(_path(group_id, 'number_group_memberships'), kwargs)
20
+ end
21
+
22
+ def get_membership(membership_id)
23
+ @http.get("/api/relay/rest/number_group_memberships/#{membership_id}")
24
+ end
25
+
26
+ def delete_membership(membership_id)
27
+ @http.delete("/api/relay/rest/number_group_memberships/#{membership_id}")
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../phone_call_handler'
4
+
5
+ module SignalWire
6
+ module REST
7
+ module Namespaces
8
+ # Phone number management.
9
+ #
10
+ # Supports the standard CRUD surface plus typed helpers for binding an
11
+ # inbound call to a handler (SWML webhook, cXML webhook, AI agent, call
12
+ # flow, RELAY application/topic). The binding model is: set
13
+ # +call_handler+ and the handler-specific companion field on the phone
14
+ # number; the server auto-materializes the matching Fabric resource.
15
+ # See +SignalWire::REST::PhoneCallHandler+ for the enum, and the
16
+ # porting-sdk's +phone-binding.md+ for the full model.
17
+ class PhoneNumbersResource < CrudResource
18
+ self.update_method = 'PUT'
19
+
20
+ def initialize(http)
21
+ super(http, '/api/relay/rest/phone_numbers')
22
+ end
23
+
24
+ def search(**params)
25
+ @http.get(_path('search'), params.empty? ? nil : params)
26
+ end
27
+
28
+ # -- Typed binding helpers -----------------------------------------
29
+ #
30
+ # Each helper is a one-line wrapper over +update+ with the right
31
+ # +call_handler+ value and companion field already set. Pass extra
32
+ # kwargs through for cases the helper doesn't name explicitly (e.g.
33
+ # +call_fallback_url+ on cXML webhooks).
34
+
35
+ # Route inbound calls to an SWML webhook URL.
36
+ #
37
+ # Your backend returns an SWML document per call. The server
38
+ # auto-creates a +swml_webhook+ Fabric resource keyed off this URL.
39
+ #
40
+ # @param sid [String] the phone number SID (e.g. +pn-...+)
41
+ # @param url [String] the SWML webhook URL
42
+ # @param extra [Hash] additional fields passed to +update+
43
+ # @return [Hash] the updated phone number representation
44
+ def set_swml_webhook(sid, url:, **extra)
45
+ update(
46
+ sid,
47
+ call_handler: PhoneCallHandler::RELAY_SCRIPT,
48
+ call_relay_script_url: url,
49
+ **extra
50
+ )
51
+ end
52
+
53
+ # Route inbound calls to a cXML (Twilio-compat / LAML) webhook.
54
+ #
55
+ # Despite the wire value +laml_webhooks+ being plural, this creates a
56
+ # single +cxml_webhook+ Fabric resource. +fallback_url+ is used when
57
+ # the primary URL fails; +status_callback_url+ receives call status
58
+ # updates.
59
+ def set_cxml_webhook(sid, url:, fallback_url: nil, status_callback_url: nil, **extra)
60
+ body = {
61
+ call_handler: PhoneCallHandler::LAML_WEBHOOKS,
62
+ call_request_url: url
63
+ }
64
+ body[:call_fallback_url] = fallback_url unless fallback_url.nil?
65
+ body[:call_status_callback_url] = status_callback_url unless status_callback_url.nil?
66
+ update(sid, **body, **extra)
67
+ end
68
+
69
+ # Route inbound calls to an existing cXML application by ID.
70
+ def set_cxml_application(sid, application_id:, **extra)
71
+ update(
72
+ sid,
73
+ call_handler: PhoneCallHandler::LAML_APPLICATION,
74
+ call_laml_application_id: application_id,
75
+ **extra
76
+ )
77
+ end
78
+
79
+ # Route inbound calls to an AI Agent Fabric resource by ID.
80
+ def set_ai_agent(sid, agent_id:, **extra)
81
+ update(
82
+ sid,
83
+ call_handler: PhoneCallHandler::AI_AGENT,
84
+ call_ai_agent_id: agent_id,
85
+ **extra
86
+ )
87
+ end
88
+
89
+ # Route inbound calls to a Call Flow by ID.
90
+ #
91
+ # +version+ accepts +"working_copy"+ or +"current_deployed"+ (server
92
+ # default when omitted).
93
+ def set_call_flow(sid, flow_id:, version: nil, **extra)
94
+ body = {
95
+ call_handler: PhoneCallHandler::CALL_FLOW,
96
+ call_flow_id: flow_id
97
+ }
98
+ body[:call_flow_version] = version unless version.nil?
99
+ update(sid, **body, **extra)
100
+ end
101
+
102
+ # Route inbound calls to a named RELAY application.
103
+ def set_relay_application(sid, name:, **extra)
104
+ update(
105
+ sid,
106
+ call_handler: PhoneCallHandler::RELAY_APPLICATION,
107
+ call_relay_application: name,
108
+ **extra
109
+ )
110
+ end
111
+
112
+ # Route inbound calls to a RELAY topic (client subscription).
113
+ def set_relay_topic(sid, topic:, status_callback_url: nil, **extra)
114
+ body = {
115
+ call_handler: PhoneCallHandler::RELAY_TOPIC,
116
+ call_relay_topic: topic
117
+ }
118
+ body[:call_relay_topic_status_callback_url] = status_callback_url unless status_callback_url.nil?
119
+ update(sid, **body, **extra)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Project API token management.
7
+ class ProjectTokens < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/project/tokens')
10
+ end
11
+
12
+ def create(**kwargs) = @http.post(@base_path, kwargs)
13
+
14
+ def update(token_id, **kwargs)
15
+ @http.patch(_path(token_id), kwargs)
16
+ end
17
+
18
+ def delete(token_id)
19
+ @http.delete(_path(token_id))
20
+ end
21
+ end
22
+
23
+ # Project API namespace.
24
+ class ProjectNamespace
25
+ attr_reader :tokens
26
+
27
+ def initialize(http)
28
+ @tokens = ProjectTokens.new(http)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # PubSub token generation.
7
+ class PubSubResource < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/pubsub/tokens')
10
+ end
11
+
12
+ def create_token(**kwargs)
13
+ @http.post(@base_path, kwargs)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Queue management with member operations.
7
+ class QueuesResource < CrudResource
8
+ self.update_method = 'PUT'
9
+
10
+ def initialize(http)
11
+ super(http, '/api/relay/rest/queues')
12
+ end
13
+
14
+ def list_members(queue_id, **params)
15
+ @http.get(_path(queue_id, 'members'), params.empty? ? nil : params)
16
+ end
17
+
18
+ def get_next_member(queue_id)
19
+ @http.get(_path(queue_id, 'members', 'next'))
20
+ end
21
+
22
+ def get_member(queue_id, member_id)
23
+ @http.get(_path(queue_id, 'members', member_id))
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # Recording management (read-only + delete).
7
+ class RecordingsResource < BaseResource
8
+ def initialize(http)
9
+ super(http, '/api/relay/rest/recordings')
10
+ end
11
+
12
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
13
+ def get(recording_id) = @http.get(_path(recording_id))
14
+ def delete(recording_id) = @http.delete(_path(recording_id))
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SignalWire
4
+ module REST
5
+ module Namespaces
6
+ # 10DLC brand management.
7
+ class RegistryBrands < BaseResource
8
+ def list(**params) = @http.get(@base_path, params.empty? ? nil : params)
9
+ def create(**kwargs) = @http.post(@base_path, kwargs)
10
+ def get(brand_id) = @http.get(_path(brand_id))
11
+
12
+ def list_campaigns(brand_id, **params)
13
+ @http.get(_path(brand_id, 'campaigns'), params.empty? ? nil : params)
14
+ end
15
+
16
+ def create_campaign(brand_id, **kwargs)
17
+ @http.post(_path(brand_id, 'campaigns'), kwargs)
18
+ end
19
+ end
20
+
21
+ # 10DLC campaign management.
22
+ class RegistryCampaigns < BaseResource
23
+ def get(campaign_id) = @http.get(_path(campaign_id))
24
+ def update(campaign_id, **kwargs) = @http.put(_path(campaign_id), kwargs)
25
+
26
+ def list_numbers(campaign_id, **params)
27
+ @http.get(_path(campaign_id, 'numbers'), params.empty? ? nil : params)
28
+ end
29
+
30
+ def list_orders(campaign_id, **params)
31
+ @http.get(_path(campaign_id, 'orders'), params.empty? ? nil : params)
32
+ end
33
+
34
+ def create_order(campaign_id, **kwargs)
35
+ @http.post(_path(campaign_id, 'orders'), kwargs)
36
+ end
37
+ end
38
+
39
+ # 10DLC assignment order management.
40
+ class RegistryOrders < BaseResource
41
+ def get(order_id)
42
+ @http.get(_path(order_id))
43
+ end
44
+ end
45
+
46
+ # 10DLC number assignment management.
47
+ class RegistryNumbers < BaseResource
48
+ def delete(number_id)
49
+ @http.delete(_path(number_id))
50
+ end
51
+ end
52
+
53
+ # 10DLC Campaign Registry namespace.
54
+ class RegistryNamespace
55
+ attr_reader :brands, :campaigns, :orders, :numbers
56
+
57
+ def initialize(http)
58
+ base = '/api/relay/rest/registry/beta'
59
+ @brands = RegistryBrands.new(http, "#{base}/brands")
60
+ @campaigns = RegistryCampaigns.new(http, "#{base}/campaigns")
61
+ @orders = RegistryOrders.new(http, "#{base}/orders")
62
+ @numbers = RegistryNumbers.new(http, "#{base}/numbers")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end