telnyx 5.60.0 → 5.62.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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +1 -1
  4. data/lib/telnyx/client.rb +10 -5
  5. data/lib/telnyx/errors.rb +0 -10
  6. data/lib/telnyx/lib/webhook_verification.rb +172 -0
  7. data/lib/telnyx/models/ai/assistants/{tag_delete_params.rb → tag_add_params.rb} +2 -2
  8. data/lib/telnyx/models/ai/assistants/{tag_delete_response.rb → tag_add_response.rb} +2 -2
  9. data/lib/telnyx/models/ai/assistants/{tag_create_params.rb → tag_remove_params.rb} +2 -2
  10. data/lib/telnyx/models/ai/assistants/{tag_create_response.rb → tag_remove_response.rb} +2 -2
  11. data/lib/telnyx/models/call_cost_webhook_event.rb +242 -0
  12. data/lib/telnyx/models/calls/action_start_noise_suppression_params.rb +135 -8
  13. data/lib/telnyx/models/text_to_speech_generate_params.rb +3 -3
  14. data/lib/telnyx/models/unsafe_unwrap_webhook_event.rb +3 -1
  15. data/lib/telnyx/models/unwrap_webhook_event.rb +3 -1
  16. data/lib/telnyx/models/voice_clone_create_from_design_params.rb +27 -6
  17. data/lib/telnyx/models/voice_clone_create_from_upload_params.rb +23 -2
  18. data/lib/telnyx/models/voice_clone_create_params.rb +79 -0
  19. data/lib/telnyx/models/voice_clone_create_response.rb +19 -0
  20. data/lib/telnyx/models/voice_clone_data.rb +41 -1
  21. data/lib/telnyx/models/voice_clone_list_params.rb +22 -1
  22. data/lib/telnyx/models/voice_design_create_params.rb +24 -1
  23. data/lib/telnyx/models/voice_design_data.rb +45 -1
  24. data/lib/telnyx/models/voice_design_list_response.rb +32 -1
  25. data/lib/telnyx/models/{voice_design_update_params.rb → voice_design_rename_params.rb} +2 -2
  26. data/lib/telnyx/models/{voice_design_update_response.rb → voice_design_rename_response.rb} +42 -11
  27. data/lib/telnyx/models/whatsapp/business_accounts/{phone_number_create_verification_params.rb → phone_number_initialize_verification_params.rb} +5 -5
  28. data/lib/telnyx/models/whatsapp/template_create_params.rb +530 -0
  29. data/lib/telnyx/models/whatsapp/{message_template_create_response.rb → template_create_response.rb} +2 -2
  30. data/lib/telnyx/models/whatsapp/{message_template_list_params.rb → template_list_params.rb} +5 -5
  31. data/lib/telnyx/models/whatsapp_message_template_delete_params.rb +20 -0
  32. data/lib/telnyx/models/whatsapp_message_template_retrieve_params.rb +20 -0
  33. data/lib/telnyx/models/whatsapp_message_template_retrieve_response.rb +16 -0
  34. data/lib/telnyx/models/whatsapp_message_template_update_params.rb +504 -0
  35. data/lib/telnyx/models/whatsapp_message_template_update_response.rb +16 -0
  36. data/lib/telnyx/models/whatsapp_template_data.rb +10 -3
  37. data/lib/telnyx/models/x402/{credit_account_create_payment_quote_params.rb → credit_account_create_quote_params.rb} +2 -2
  38. data/lib/telnyx/models/x402/{credit_account_create_payment_quote_response.rb → credit_account_create_quote_response.rb} +31 -32
  39. data/lib/telnyx/models/x402/{credit_account_settle_payment_params.rb → credit_account_settle_params.rb} +3 -3
  40. data/lib/telnyx/models/x402/{credit_account_settle_payment_response.rb → credit_account_settle_response.rb} +14 -15
  41. data/lib/telnyx/models.rb +12 -4
  42. data/lib/telnyx/resources/ai/assistants/tags.rb +28 -28
  43. data/lib/telnyx/resources/calls/actions.rb +1 -1
  44. data/lib/telnyx/resources/voice_clones.rb +38 -31
  45. data/lib/telnyx/resources/voice_designs.rb +27 -25
  46. data/lib/telnyx/resources/webhooks.rb +10 -183
  47. data/lib/telnyx/resources/whatsapp/business_accounts/phone_numbers.rb +5 -5
  48. data/lib/telnyx/resources/whatsapp/phone_numbers/profile.rb +0 -4
  49. data/lib/telnyx/resources/whatsapp/templates.rb +91 -0
  50. data/lib/telnyx/resources/whatsapp.rb +3 -3
  51. data/lib/telnyx/resources/whatsapp_message_templates.rb +81 -0
  52. data/lib/telnyx/resources/x402/credit_account.rb +13 -13
  53. data/lib/telnyx/version.rb +1 -1
  54. data/lib/telnyx.rb +25 -24
  55. data/rbi/telnyx/client.rbi +8 -4
  56. data/rbi/telnyx/models/ai/assistants/{tag_create_params.rbi → tag_add_params.rbi} +2 -2
  57. data/rbi/telnyx/models/ai/assistants/{tag_delete_response.rbi → tag_add_response.rbi} +2 -2
  58. data/rbi/telnyx/models/ai/assistants/{tag_delete_params.rbi → tag_remove_params.rbi} +2 -2
  59. data/rbi/telnyx/models/ai/assistants/{tag_create_response.rbi → tag_remove_response.rbi} +2 -2
  60. data/rbi/telnyx/models/call_cost_webhook_event.rbi +485 -0
  61. data/rbi/telnyx/models/calls/action_start_noise_suppression_params.rbi +338 -12
  62. data/rbi/telnyx/models/text_to_speech_generate_params.rbi +2 -1
  63. data/rbi/telnyx/models/unsafe_unwrap_webhook_event.rbi +1 -0
  64. data/rbi/telnyx/models/unwrap_webhook_event.rbi +1 -0
  65. data/rbi/telnyx/models/voice_clone_create_from_design_params.rbi +51 -0
  66. data/rbi/telnyx/models/voice_clone_create_from_upload_params.rbi +67 -2
  67. data/rbi/telnyx/models/voice_clone_create_params.rbi +142 -0
  68. data/rbi/telnyx/models/voice_clone_create_response.rbi +36 -0
  69. data/rbi/telnyx/models/voice_clone_data.rbi +57 -0
  70. data/rbi/telnyx/models/voice_clone_list_params.rbi +62 -0
  71. data/rbi/telnyx/models/voice_design_create_params.rbi +60 -0
  72. data/rbi/telnyx/models/voice_design_data.rbi +59 -0
  73. data/rbi/telnyx/models/voice_design_list_response.rbi +73 -0
  74. data/rbi/telnyx/models/{voice_design_update_params.rbi → voice_design_rename_params.rbi} +2 -2
  75. data/rbi/telnyx/models/{voice_design_update_response.rbi → voice_design_rename_response.rbi} +90 -14
  76. data/rbi/telnyx/models/whatsapp/business_accounts/{phone_number_create_verification_params.rbi → phone_number_initialize_verification_params.rbi} +10 -10
  77. data/rbi/telnyx/models/whatsapp/template_create_params.rbi +1177 -0
  78. data/rbi/telnyx/models/whatsapp/{message_template_create_response.rbi → template_create_response.rbi} +2 -2
  79. data/rbi/telnyx/models/whatsapp/{message_template_list_params.rbi → template_list_params.rbi} +11 -11
  80. data/rbi/telnyx/models/whatsapp_message_template_delete_params.rbi +38 -0
  81. data/rbi/telnyx/models/whatsapp_message_template_retrieve_params.rbi +38 -0
  82. data/rbi/telnyx/models/whatsapp_message_template_retrieve_response.rbi +33 -0
  83. data/rbi/telnyx/models/whatsapp_message_template_update_params.rbi +1178 -0
  84. data/rbi/telnyx/models/whatsapp_message_template_update_response.rbi +33 -0
  85. data/rbi/telnyx/models/whatsapp_template_data.rbi +10 -2
  86. data/rbi/telnyx/models/x402/{credit_account_create_payment_quote_params.rbi → credit_account_create_quote_params.rbi} +2 -2
  87. data/rbi/telnyx/models/x402/{credit_account_create_payment_quote_response.rbi → credit_account_create_quote_response.rbi} +41 -42
  88. data/rbi/telnyx/models/x402/{credit_account_settle_payment_params.rbi → credit_account_settle_params.rbi} +2 -2
  89. data/rbi/telnyx/models/x402/{credit_account_settle_payment_response.rbi → credit_account_settle_response.rbi} +21 -26
  90. data/rbi/telnyx/models.rbi +29 -3
  91. data/rbi/telnyx/resources/ai/assistants/tags.rbi +13 -13
  92. data/rbi/telnyx/resources/calls/actions.rbi +4 -3
  93. data/rbi/telnyx/resources/voice_clones.rbi +36 -25
  94. data/rbi/telnyx/resources/voice_designs.rbi +21 -17
  95. data/rbi/telnyx/resources/webhooks.rbi +12 -2
  96. data/rbi/telnyx/resources/whatsapp/business_accounts/phone_numbers.rbi +2 -2
  97. data/rbi/telnyx/resources/whatsapp/phone_numbers/profile.rbi +0 -5
  98. data/rbi/telnyx/resources/whatsapp/templates.rbi +85 -0
  99. data/rbi/telnyx/resources/whatsapp.rbi +2 -2
  100. data/rbi/telnyx/resources/whatsapp_message_templates.rbi +67 -0
  101. data/rbi/telnyx/resources/x402/credit_account.rbi +4 -6
  102. data/sig/telnyx/client.rbs +4 -2
  103. data/sig/telnyx/models/ai/assistants/{tag_delete_params.rbs → tag_add_params.rbs} +2 -2
  104. data/sig/telnyx/models/ai/assistants/{tag_delete_response.rbs → tag_add_response.rbs} +2 -2
  105. data/sig/telnyx/models/ai/assistants/{tag_create_params.rbs → tag_remove_params.rbs} +2 -2
  106. data/sig/telnyx/models/ai/assistants/{tag_create_response.rbs → tag_remove_response.rbs} +2 -2
  107. data/sig/telnyx/models/call_cost_webhook_event.rbs +235 -0
  108. data/sig/telnyx/models/calls/action_start_noise_suppression_params.rbs +124 -4
  109. data/sig/telnyx/models/unsafe_unwrap_webhook_event.rbs +1 -0
  110. data/sig/telnyx/models/unwrap_webhook_event.rbs +1 -0
  111. data/sig/telnyx/models/voice_clone_create_from_design_params.rbs +23 -1
  112. data/sig/telnyx/models/voice_clone_create_from_upload_params.rbs +22 -0
  113. data/sig/telnyx/models/voice_clone_create_params.rbs +75 -0
  114. data/sig/telnyx/models/voice_clone_create_response.rbs +15 -0
  115. data/sig/telnyx/models/voice_clone_data.rbs +34 -0
  116. data/sig/telnyx/models/voice_clone_list_params.rbs +22 -0
  117. data/sig/telnyx/models/voice_design_create_params.rbs +22 -0
  118. data/sig/telnyx/models/voice_design_data.rbs +30 -0
  119. data/sig/telnyx/models/voice_design_list_response.rbs +25 -0
  120. data/sig/telnyx/models/{voice_design_update_params.rbs → voice_design_rename_params.rbs} +2 -2
  121. data/sig/telnyx/models/voice_design_rename_response.rbs +104 -0
  122. data/sig/telnyx/models/whatsapp/business_accounts/{phone_number_create_verification_params.rbs → phone_number_initialize_verification_params.rbs} +9 -9
  123. data/sig/telnyx/models/whatsapp/template_create_params.rbs +479 -0
  124. data/sig/telnyx/models/whatsapp/{message_template_update_response.rbs → template_create_response.rbs} +2 -3
  125. data/sig/telnyx/models/whatsapp/{message_template_list_params.rbs → template_list_params.rbs} +9 -9
  126. data/sig/telnyx/models/whatsapp_message_template_delete_params.rbs +20 -0
  127. data/sig/telnyx/models/whatsapp_message_template_retrieve_params.rbs +20 -0
  128. data/sig/telnyx/models/whatsapp_message_template_retrieve_response.rbs +16 -0
  129. data/sig/telnyx/models/whatsapp_message_template_update_params.rbs +473 -0
  130. data/sig/telnyx/models/whatsapp_message_template_update_response.rbs +16 -0
  131. data/sig/telnyx/models/x402/{credit_account_create_payment_quote_params.rbs → credit_account_create_quote_params.rbs} +2 -2
  132. data/sig/telnyx/models/x402/{credit_account_create_payment_quote_response.rbs → credit_account_create_quote_response.rbs} +46 -48
  133. data/sig/telnyx/models/x402/{credit_account_settle_payment_params.rbs → credit_account_settle_params.rbs} +2 -2
  134. data/sig/telnyx/models/x402/{credit_account_settle_payment_response.rbs → credit_account_settle_response.rbs} +22 -22
  135. data/sig/telnyx/models.rbs +12 -4
  136. data/sig/telnyx/resources/ai/assistants/tags.rbs +8 -8
  137. data/sig/telnyx/resources/voice_clones.rbs +11 -8
  138. data/sig/telnyx/resources/voice_designs.rbs +7 -6
  139. data/sig/telnyx/resources/webhooks.rbs +5 -1
  140. data/sig/telnyx/resources/whatsapp/business_accounts/phone_numbers.rbs +2 -2
  141. data/sig/telnyx/resources/whatsapp/phone_numbers/profile.rbs +0 -2
  142. data/sig/telnyx/resources/whatsapp/templates.rbs +28 -0
  143. data/sig/telnyx/resources/whatsapp.rbs +1 -1
  144. data/sig/telnyx/resources/whatsapp_message_templates.rbs +21 -0
  145. data/sig/telnyx/resources/x402/credit_account.rbs +4 -4
  146. metadata +75 -65
  147. data/lib/telnyx/models/whatsapp/message_template_create_params.rb +0 -58
  148. data/lib/telnyx/models/whatsapp/message_template_delete_params.rb +0 -22
  149. data/lib/telnyx/models/whatsapp/message_template_retrieve_params.rb +0 -22
  150. data/lib/telnyx/models/whatsapp/message_template_retrieve_response.rb +0 -18
  151. data/lib/telnyx/models/whatsapp/message_template_update_params.rb +0 -46
  152. data/lib/telnyx/models/whatsapp/message_template_update_response.rb +0 -18
  153. data/lib/telnyx/resources/whatsapp/message_templates.rb +0 -149
  154. data/lib/telnyx/resources/whatsapp/phone_numbers/profile/models.rb +0 -20
  155. data/rbi/telnyx/models/whatsapp/message_template_create_params.rbi +0 -115
  156. data/rbi/telnyx/models/whatsapp/message_template_delete_params.rbi +0 -40
  157. data/rbi/telnyx/models/whatsapp/message_template_retrieve_params.rbi +0 -40
  158. data/rbi/telnyx/models/whatsapp/message_template_retrieve_response.rbi +0 -35
  159. data/rbi/telnyx/models/whatsapp/message_template_update_params.rbi +0 -111
  160. data/rbi/telnyx/models/whatsapp/message_template_update_response.rbi +0 -35
  161. data/rbi/telnyx/resources/whatsapp/message_templates.rbi +0 -116
  162. data/rbi/telnyx/resources/whatsapp/phone_numbers/profile/models.rbi +0 -18
  163. data/sig/telnyx/models/voice_design_update_response.rbs +0 -79
  164. data/sig/telnyx/models/whatsapp/message_template_create_params.rbs +0 -60
  165. data/sig/telnyx/models/whatsapp/message_template_create_response.rbs +0 -20
  166. data/sig/telnyx/models/whatsapp/message_template_delete_params.rbs +0 -22
  167. data/sig/telnyx/models/whatsapp/message_template_retrieve_params.rbs +0 -22
  168. data/sig/telnyx/models/whatsapp/message_template_retrieve_response.rbs +0 -20
  169. data/sig/telnyx/models/whatsapp/message_template_update_params.rbs +0 -58
  170. data/sig/telnyx/resources/whatsapp/message_templates.rbs +0 -42
  171. data/sig/telnyx/resources/whatsapp/phone_numbers/profile/models.rbs +0 -13
@@ -1,213 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "base64"
4
- require "json"
5
- require "openssl"
6
-
7
3
  module Telnyx
8
4
  module Resources
9
- # Telnyx webhook verification using ED25519 signatures.
10
- #
11
- # This class provides ED25519 signature verification for Telnyx webhooks,
12
- # matching the implementation pattern used in the Python and Node SDKs.
13
- #
14
- # Example usage:
15
- #
16
- # client = Telnyx::Client.new(
17
- # api_key: ENV["TELNYX_API_KEY"],
18
- # public_key: ENV["TELNYX_PUBLIC_KEY"] # Base64 from Mission Control
19
- # )
20
- #
21
- # # In your webhook handler:
22
- # event = client.webhooks.unwrap(payload, headers)
23
- #
24
5
  class Webhooks
25
- # Telnyx webhook signature headers (case-insensitive per HTTP spec)
26
- SIGNATURE_HEADER = "telnyx-signature-ed25519"
27
- TIMESTAMP_HEADER = "telnyx-timestamp"
28
-
29
- # Tolerance for timestamp validation (5 minutes)
30
- TIMESTAMP_TOLERANCE_SECONDS = 300
31
-
32
- # Unwraps a webhook event from its JSON representation without verifying the signature.
33
- #
34
6
  # @param payload [String] The raw webhook payload as a string
35
7
  #
36
- # @return [Telnyx::Models::UnsafeUnwrapWebhookEvent]
8
+ # @return [Telnyx::Models::CallAIGatherEndedWebhookEvent, Telnyx::Models::CallAIGatherMessageHistoryUpdatedWebhookEvent, Telnyx::Models::CallAIGatherPartialResultsWebhookEvent, Telnyx::Models::CallAnsweredWebhookEvent, Telnyx::Models::CallBridgedWebhookEvent, Telnyx::Models::CallConversationEndedWebhookEvent, Telnyx::Models::CallConversationInsightsGeneratedWebhookEvent, Telnyx::Models::CallCostWebhookEvent, Telnyx::Models::CallDtmfReceivedWebhookEvent, Telnyx::Models::CallEnqueuedWebhookEvent, Telnyx::Models::CallForkStartedWebhookEvent, Telnyx::Models::CallForkStoppedWebhookEvent, Telnyx::Models::CallGatherEndedWebhookEvent, Telnyx::Models::CallHangupWebhookEvent, Telnyx::Models::CallInitiatedWebhookEvent, Telnyx::Models::CallLeftQueueWebhookEvent, Telnyx::Models::CallMachineDetectionEndedWebhookEvent, Telnyx::Models::CallMachineGreetingEndedWebhookEvent, Telnyx::Models::CallMachinePremiumDetectionEndedWebhookEvent, Telnyx::Models::CallMachinePremiumGreetingEndedWebhookEvent, Telnyx::Models::CallPlaybackEndedWebhookEvent, Telnyx::Models::CallPlaybackStartedWebhookEvent, Telnyx::Models::CallRecordingErrorWebhookEvent, Telnyx::Models::CallRecordingSavedWebhookEvent, Telnyx::Models::CallRecordingTranscriptionSavedWebhookEvent, Telnyx::Models::CallReferCompletedWebhookEvent, Telnyx::Models::CallReferFailedWebhookEvent, Telnyx::Models::CallReferStartedWebhookEvent, Telnyx::Models::CallSiprecFailedWebhookEvent, Telnyx::Models::CallSiprecStartedWebhookEvent, Telnyx::Models::CallSiprecStoppedWebhookEvent, Telnyx::Models::CallSpeakEndedWebhookEvent, Telnyx::Models::CallSpeakStartedWebhookEvent, Telnyx::Models::CallStreamingFailedWebhookEvent, Telnyx::Models::CallStreamingStartedWebhookEvent, Telnyx::Models::CallStreamingStoppedWebhookEvent, Telnyx::Models::CampaignStatusUpdate, Telnyx::Models::ConferenceCreatedWebhookEvent, Telnyx::Models::ConferenceEndedWebhookEvent, Telnyx::Models::ConferenceFloorChanged, Telnyx::Models::ConferenceParticipantJoinedWebhookEvent, Telnyx::Models::ConferenceParticipantLeftWebhookEvent, Telnyx::Models::ConferenceParticipantPlaybackEndedWebhookEvent, Telnyx::Models::ConferenceParticipantPlaybackStartedWebhookEvent, Telnyx::Models::ConferenceParticipantSpeakEndedWebhookEvent, Telnyx::Models::ConferenceParticipantSpeakStartedWebhookEvent, Telnyx::Models::ConferencePlaybackEndedWebhookEvent, Telnyx::Models::ConferencePlaybackStartedWebhookEvent, Telnyx::Models::ConferenceRecordingSavedWebhookEvent, Telnyx::Models::ConferenceSpeakEndedWebhookEvent, Telnyx::Models::ConferenceSpeakStartedWebhookEvent, Telnyx::Models::DeliveryUpdateWebhookEvent, Telnyx::Models::FaxDelivered, Telnyx::Models::FaxFailed, Telnyx::Models::FaxMediaProcessed, Telnyx::Models::FaxQueued, Telnyx::Models::FaxSendingStarted, Telnyx::Models::InboundMessageWebhookEvent, Telnyx::Models::NumberOrderStatusUpdate, Telnyx::Models::ReplacedLinkClickWebhookEvent, Telnyx::Models::TranscriptionWebhookEvent]
37
9
  def unsafe_unwrap(payload)
38
10
  parsed = JSON.parse(payload, symbolize_names: true)
39
11
  Telnyx::Internal::Type::Converter.coerce(Telnyx::Models::UnsafeUnwrapWebhookEvent, parsed)
40
12
  end
41
13
 
42
- # Unwraps a webhook event from its JSON representation, verifying the signature if headers are provided.
43
- #
44
- # When headers are provided and the client has a public_key configured, this method will verify
45
- # the ED25519 signature to ensure the webhook came from Telnyx.
46
- #
47
14
  # @param payload [String] The raw webhook payload as a string
48
- # @param headers [Hash, nil] Optional HTTP headers from the webhook request
49
- # @param key [String, nil] Optional public key override (base64-encoded)
50
15
  #
51
- # @return [Telnyx::Models::UnwrapWebhookEvent]
16
+ # @param headers [Hash{String=>String}] The raw HTTP headers that came with the payload
52
17
  #
53
- # @raise [Telnyx::Errors::WebhookVerificationError] If signature verification fails
54
- def unwrap(payload, headers = nil, key: nil)
55
- # Get public key from argument or client
56
- public_key = key || @client.public_key
57
-
58
- # If we have headers and a public key, verify the signature
59
- if headers && !headers.empty? && public_key && !public_key.empty?
60
- verify_signature(payload, headers, public_key)
18
+ # @param key [String, nil] The webhook signing key
19
+ #
20
+ # @return [Telnyx::Models::CallAIGatherEndedWebhookEvent, Telnyx::Models::CallAIGatherMessageHistoryUpdatedWebhookEvent, Telnyx::Models::CallAIGatherPartialResultsWebhookEvent, Telnyx::Models::CallAnsweredWebhookEvent, Telnyx::Models::CallBridgedWebhookEvent, Telnyx::Models::CallConversationEndedWebhookEvent, Telnyx::Models::CallConversationInsightsGeneratedWebhookEvent, Telnyx::Models::CallCostWebhookEvent, Telnyx::Models::CallDtmfReceivedWebhookEvent, Telnyx::Models::CallEnqueuedWebhookEvent, Telnyx::Models::CallForkStartedWebhookEvent, Telnyx::Models::CallForkStoppedWebhookEvent, Telnyx::Models::CallGatherEndedWebhookEvent, Telnyx::Models::CallHangupWebhookEvent, Telnyx::Models::CallInitiatedWebhookEvent, Telnyx::Models::CallLeftQueueWebhookEvent, Telnyx::Models::CallMachineDetectionEndedWebhookEvent, Telnyx::Models::CallMachineGreetingEndedWebhookEvent, Telnyx::Models::CallMachinePremiumDetectionEndedWebhookEvent, Telnyx::Models::CallMachinePremiumGreetingEndedWebhookEvent, Telnyx::Models::CallPlaybackEndedWebhookEvent, Telnyx::Models::CallPlaybackStartedWebhookEvent, Telnyx::Models::CallRecordingErrorWebhookEvent, Telnyx::Models::CallRecordingSavedWebhookEvent, Telnyx::Models::CallRecordingTranscriptionSavedWebhookEvent, Telnyx::Models::CallReferCompletedWebhookEvent, Telnyx::Models::CallReferFailedWebhookEvent, Telnyx::Models::CallReferStartedWebhookEvent, Telnyx::Models::CallSiprecFailedWebhookEvent, Telnyx::Models::CallSiprecStartedWebhookEvent, Telnyx::Models::CallSiprecStoppedWebhookEvent, Telnyx::Models::CallSpeakEndedWebhookEvent, Telnyx::Models::CallSpeakStartedWebhookEvent, Telnyx::Models::CallStreamingFailedWebhookEvent, Telnyx::Models::CallStreamingStartedWebhookEvent, Telnyx::Models::CallStreamingStoppedWebhookEvent, Telnyx::Models::CampaignStatusUpdate, Telnyx::Models::ConferenceCreatedWebhookEvent, Telnyx::Models::ConferenceEndedWebhookEvent, Telnyx::Models::ConferenceFloorChanged, Telnyx::Models::ConferenceParticipantJoinedWebhookEvent, Telnyx::Models::ConferenceParticipantLeftWebhookEvent, Telnyx::Models::ConferenceParticipantPlaybackEndedWebhookEvent, Telnyx::Models::ConferenceParticipantPlaybackStartedWebhookEvent, Telnyx::Models::ConferenceParticipantSpeakEndedWebhookEvent, Telnyx::Models::ConferenceParticipantSpeakStartedWebhookEvent, Telnyx::Models::ConferencePlaybackEndedWebhookEvent, Telnyx::Models::ConferencePlaybackStartedWebhookEvent, Telnyx::Models::ConferenceRecordingSavedWebhookEvent, Telnyx::Models::ConferenceSpeakEndedWebhookEvent, Telnyx::Models::ConferenceSpeakStartedWebhookEvent, Telnyx::Models::DeliveryUpdateWebhookEvent, Telnyx::Models::FaxDelivered, Telnyx::Models::FaxFailed, Telnyx::Models::FaxMediaProcessed, Telnyx::Models::FaxQueued, Telnyx::Models::FaxSendingStarted, Telnyx::Models::InboundMessageWebhookEvent, Telnyx::Models::NumberOrderStatusUpdate, Telnyx::Models::ReplacedLinkClickWebhookEvent, Telnyx::Models::TranscriptionWebhookEvent]
21
+ def unwrap(payload, headers:, key: @client.public_key)
22
+ if key.nil?
23
+ raise ArgumentError.new("Cannot verify a webhook without a key on either the client's public_key or passed in as an argument")
61
24
  end
62
25
 
26
+ ::StandardWebhooks::Webhook.new(key).verify(payload, headers)
27
+
63
28
  parsed = JSON.parse(payload, symbolize_names: true)
64
29
  Telnyx::Internal::Type::Converter.coerce(Telnyx::Models::UnwrapWebhookEvent, parsed)
65
30
  end
66
31
 
67
- # Verify webhook signature without parsing the payload.
68
- #
69
- # This method is consistent with the Node SDK's verify() method, allowing
70
- # signature verification without parsing the webhook payload. The bang (!)
71
- # indicates this method raises an exception on failure (Ruby convention).
72
- #
73
- # @param payload [String] The raw webhook payload
74
- # @param headers [Hash] The webhook headers
75
- # @param key [String, nil] Optional public key override (base64-encoded)
76
- #
77
- # @return [void]
78
- #
79
- # @raise [Telnyx::Errors::WebhookVerificationError] If verification fails or no public key available
80
- def verify!(payload, headers, key: nil)
81
- public_key = key || @client.public_key
82
-
83
- unless public_key && !public_key.empty?
84
- raise Telnyx::Errors::WebhookVerificationError.new(
85
- message: "No public key configured. Provide key parameter or configure client with public_key."
86
- )
87
- end
88
-
89
- verify_signature(payload, headers, public_key)
90
- end
91
-
92
32
  # @api private
93
33
  #
94
34
  # @param client [Telnyx::Client]
95
35
  def initialize(client:)
96
36
  @client = client
97
37
  end
98
-
99
- private
100
-
101
- # Get header value case-insensitively
102
- #
103
- # @param headers [Hash] The headers hash
104
- # @param key [String] The header key to find
105
- #
106
- # @return [String, nil]
107
- def get_header(headers, key)
108
- key_lower = key.downcase
109
- headers.each do |header_key, header_value|
110
- return header_value if header_key.to_s.downcase == key_lower
111
- end
112
- nil
113
- end
114
-
115
- # Verify the webhook signature using ED25519 cryptography
116
- #
117
- # @param payload [String] The raw webhook payload
118
- # @param headers [Hash] The webhook headers
119
- # @param public_key [String] The ED25519 public key (base64-encoded)
120
- #
121
- # @raise [Telnyx::Errors::WebhookVerificationError] If verification fails
122
- def verify_signature(payload, headers, public_key)
123
- # Extract required headers (case-insensitive)
124
- signature_header = get_header(headers, SIGNATURE_HEADER)
125
- timestamp_header = get_header(headers, TIMESTAMP_HEADER)
126
-
127
- unless signature_header
128
- raise Telnyx::Errors::WebhookVerificationError.new(
129
- message: "Missing required header: #{SIGNATURE_HEADER}"
130
- )
131
- end
132
-
133
- unless timestamp_header
134
- raise Telnyx::Errors::WebhookVerificationError.new(
135
- message: "Missing required header: #{TIMESTAMP_HEADER}"
136
- )
137
- end
138
-
139
- # Validate timestamp to prevent replay attacks (5 minute tolerance)
140
- begin
141
- webhook_time = Integer(timestamp_header)
142
- current_time = Time.now.to_i
143
- time_diff = (current_time - webhook_time).abs
144
-
145
- if time_diff > TIMESTAMP_TOLERANCE_SECONDS
146
- raise Telnyx::Errors::WebhookVerificationError.new(
147
- message: "Webhook timestamp is too old or too new (#{time_diff}s difference)"
148
- )
149
- end
150
- rescue ArgumentError
151
- raise Telnyx::Errors::WebhookVerificationError.new(
152
- message: "Invalid timestamp format: #{timestamp_header}"
153
- )
154
- end
155
-
156
- # Decode public key from base64
157
- begin
158
- public_key_bytes = Base64.strict_decode64(public_key)
159
-
160
- if public_key_bytes.bytesize != 32
161
- raise Telnyx::Errors::WebhookVerificationError.new(
162
- message: "Invalid public key: expected 32 bytes, got #{public_key_bytes.bytesize} bytes"
163
- )
164
- end
165
- rescue ArgumentError => e
166
- raise Telnyx::Errors::WebhookVerificationError.new(
167
- message: "Invalid public key format: #{e.message}"
168
- )
169
- end
170
-
171
- # Decode signature from base64
172
- begin
173
- signature_bytes = Base64.strict_decode64(signature_header)
174
-
175
- if signature_bytes.bytesize != 64
176
- raise Telnyx::Errors::WebhookVerificationError.new(
177
- message: "Invalid signature length: expected 64 bytes, got #{signature_bytes.bytesize} bytes"
178
- )
179
- end
180
- rescue ArgumentError => e
181
- raise Telnyx::Errors::WebhookVerificationError.new(
182
- message: "Invalid signature format: #{e.message}"
183
- )
184
- end
185
-
186
- # Create the signed payload: timestamp|payload
187
- signed_payload = "#{timestamp_header}|#{payload}"
188
-
189
- # Build ED25519 public key for verification
190
- # The raw 32-byte key needs to be wrapped in X.509 SubjectPublicKeyInfo format
191
- # ED25519 OID: 1.3.101.112 = 06 03 2b 65 70
192
- # X.509 SPKI header for ED25519: 30 2a 30 05 06 03 2b 65 70 03 21 00
193
- ed25519_spki_header = [0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00].pack("C*")
194
- der_key = ed25519_spki_header + public_key_bytes
195
-
196
- begin
197
- pkey = OpenSSL::PKey.read(der_key)
198
- valid = pkey.verify(nil, signature_bytes, signed_payload)
199
-
200
- unless valid
201
- raise Telnyx::Errors::WebhookVerificationError.new(
202
- message: "Signature verification failed: signature does not match payload"
203
- )
204
- end
205
- rescue OpenSSL::PKey::PKeyError => e
206
- raise Telnyx::Errors::WebhookVerificationError.new(
207
- message: "Signature verification failed: #{e.message}"
208
- )
209
- end
210
- end
211
38
  end
212
39
  end
213
40
  end
@@ -35,7 +35,7 @@ module Telnyx
35
35
 
36
36
  # Initialize Whatsapp phone number verification
37
37
  #
38
- # @overload create_verification(id, display_name:, phone_number:, language: nil, verification_method: nil, request_options: {})
38
+ # @overload initialize_verification(id, display_name:, phone_number:, language: nil, verification_method: nil, request_options: {})
39
39
  #
40
40
  # @param id [String] Whatsapp Business Account ID
41
41
  #
@@ -45,16 +45,16 @@ module Telnyx
45
45
  #
46
46
  # @param language [String]
47
47
  #
48
- # @param verification_method [Symbol, Telnyx::Models::Whatsapp::BusinessAccounts::PhoneNumberCreateVerificationParams::VerificationMethod]
48
+ # @param verification_method [Symbol, Telnyx::Models::Whatsapp::BusinessAccounts::PhoneNumberInitializeVerificationParams::VerificationMethod]
49
49
  #
50
50
  # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
51
51
  #
52
52
  # @return [nil]
53
53
  #
54
- # @see Telnyx::Models::Whatsapp::BusinessAccounts::PhoneNumberCreateVerificationParams
55
- def create_verification(id, params)
54
+ # @see Telnyx::Models::Whatsapp::BusinessAccounts::PhoneNumberInitializeVerificationParams
55
+ def initialize_verification(id, params)
56
56
  parsed, options =
57
- Telnyx::Whatsapp::BusinessAccounts::PhoneNumberCreateVerificationParams.dump_request(params)
57
+ Telnyx::Whatsapp::BusinessAccounts::PhoneNumberInitializeVerificationParams.dump_request(params)
58
58
  @client.request(
59
59
  method: :post,
60
60
  path: ["v2/whatsapp/business_accounts/%1$s/phone_numbers", id],
@@ -10,9 +10,6 @@ module Telnyx
10
10
  # @return [Telnyx::Resources::Whatsapp::PhoneNumbers::Profile::Photo]
11
11
  attr_reader :photo
12
12
 
13
- # @return [Telnyx::Resources::Whatsapp::PhoneNumbers::Profile::Models]
14
- attr_reader :models
15
-
16
13
  # Get phone number business profile
17
14
  #
18
15
  # @overload retrieve(phone_number, request_options: {})
@@ -75,7 +72,6 @@ module Telnyx
75
72
  def initialize(client:)
76
73
  @client = client
77
74
  @photo = Telnyx::Resources::Whatsapp::PhoneNumbers::Profile::Photo.new(client: client)
78
- @models = Telnyx::Resources::Whatsapp::PhoneNumbers::Profile::Models.new(client: client)
79
75
  end
80
76
  end
81
77
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telnyx
4
+ module Resources
5
+ class Whatsapp
6
+ # Manage Whatsapp message templates
7
+ class Templates
8
+ # Some parameter documentations has been truncated, see
9
+ # {Telnyx::Models::Whatsapp::TemplateCreateParams} for more details.
10
+ #
11
+ # Create a Whatsapp message template
12
+ #
13
+ # @overload create(category:, components:, language:, name:, waba_id:, request_options: {})
14
+ #
15
+ # @param category [Symbol, Telnyx::Models::Whatsapp::TemplateCreateParams::Category] Template category: AUTHENTICATION, UTILITY, or MARKETING.
16
+ #
17
+ # @param components [Array<Telnyx::Models::Whatsapp::TemplateCreateParams::Component::WhatsappTemplateHeaderComponent, Telnyx::Models::Whatsapp::TemplateCreateParams::Component::WhatsappTemplateBodyComponent, Telnyx::Models::Whatsapp::TemplateCreateParams::Component::WhatsappTemplateFooterComponent, Telnyx::Models::Whatsapp::TemplateCreateParams::Component::WhatsappTemplateButtonsComponent, Telnyx::Models::Whatsapp::TemplateCreateParams::Component::WhatsappTemplateCarouselComponent>] Template components defining message structure. Passed through to Meta Graph API
18
+ #
19
+ # @param language [String] Template language code (e.g. en_US, es, pt_BR).
20
+ #
21
+ # @param name [String] Template name. Lowercase letters, numbers, and underscores only.
22
+ #
23
+ # @param waba_id [String] The WhatsApp Business Account ID.
24
+ #
25
+ # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
26
+ #
27
+ # @return [Telnyx::Models::Whatsapp::TemplateCreateResponse]
28
+ #
29
+ # @see Telnyx::Models::Whatsapp::TemplateCreateParams
30
+ def create(params)
31
+ parsed, options = Telnyx::Whatsapp::TemplateCreateParams.dump_request(params)
32
+ @client.request(
33
+ method: :post,
34
+ path: "v2/whatsapp/message_templates",
35
+ body: parsed,
36
+ model: Telnyx::Models::Whatsapp::TemplateCreateResponse,
37
+ options: options
38
+ )
39
+ end
40
+
41
+ # List Whatsapp message templates
42
+ #
43
+ # @overload list(filter_category: nil, filter_search: nil, filter_status: nil, filter_waba_id: nil, page_number: nil, page_size: nil, request_options: {})
44
+ #
45
+ # @param filter_category [Symbol, Telnyx::Models::Whatsapp::TemplateListParams::FilterCategory] Filter by category
46
+ #
47
+ # @param filter_search [String] Search templates by name
48
+ #
49
+ # @param filter_status [String] Filter by template status
50
+ #
51
+ # @param filter_waba_id [String] Filter by WABA ID
52
+ #
53
+ # @param page_number [Integer]
54
+ #
55
+ # @param page_size [Integer]
56
+ #
57
+ # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
58
+ #
59
+ # @return [Telnyx::Internal::DefaultFlatPagination<Telnyx::Models::WhatsappTemplateData>]
60
+ #
61
+ # @see Telnyx::Models::Whatsapp::TemplateListParams
62
+ def list(params = {})
63
+ parsed, options = Telnyx::Whatsapp::TemplateListParams.dump_request(params)
64
+ query = Telnyx::Internal::Util.encode_query_params(parsed)
65
+ @client.request(
66
+ method: :get,
67
+ path: "v2/whatsapp/message_templates",
68
+ query: query.transform_keys(
69
+ filter_category: "filter[category]",
70
+ filter_search: "filter[search]",
71
+ filter_status: "filter[status]",
72
+ filter_waba_id: "filter[waba_id]",
73
+ page_number: "page[number]",
74
+ page_size: "page[size]"
75
+ ),
76
+ page: Telnyx::Internal::DefaultFlatPagination,
77
+ model: Telnyx::WhatsappTemplateData,
78
+ options: options
79
+ )
80
+ end
81
+
82
+ # @api private
83
+ #
84
+ # @param client [Telnyx::Client]
85
+ def initialize(client:)
86
+ @client = client
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -8,8 +8,8 @@ module Telnyx
8
8
  attr_reader :business_accounts
9
9
 
10
10
  # Manage Whatsapp message templates
11
- # @return [Telnyx::Resources::Whatsapp::MessageTemplates]
12
- attr_reader :message_templates
11
+ # @return [Telnyx::Resources::Whatsapp::Templates]
12
+ attr_reader :templates
13
13
 
14
14
  # Manage Whatsapp phone numbers
15
15
  # @return [Telnyx::Resources::Whatsapp::PhoneNumbers]
@@ -21,7 +21,7 @@ module Telnyx
21
21
  def initialize(client:)
22
22
  @client = client
23
23
  @business_accounts = Telnyx::Resources::Whatsapp::BusinessAccounts.new(client: client)
24
- @message_templates = Telnyx::Resources::Whatsapp::MessageTemplates.new(client: client)
24
+ @templates = Telnyx::Resources::Whatsapp::Templates.new(client: client)
25
25
  @phone_numbers = Telnyx::Resources::Whatsapp::PhoneNumbers.new(client: client)
26
26
  end
27
27
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telnyx
4
+ module Resources
5
+ # Manage Whatsapp message templates
6
+ class WhatsappMessageTemplates
7
+ # Get a Whatsapp message template by ID
8
+ #
9
+ # @overload retrieve(id, request_options: {})
10
+ #
11
+ # @param id [String] Whatsapp message template ID
12
+ #
13
+ # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
14
+ #
15
+ # @return [Telnyx::Models::WhatsappMessageTemplateRetrieveResponse]
16
+ #
17
+ # @see Telnyx::Models::WhatsappMessageTemplateRetrieveParams
18
+ def retrieve(id, params = {})
19
+ @client.request(
20
+ method: :get,
21
+ path: ["v2/whatsapp_message_templates/%1$s", id],
22
+ model: Telnyx::Models::WhatsappMessageTemplateRetrieveResponse,
23
+ options: params[:request_options]
24
+ )
25
+ end
26
+
27
+ # Update a Whatsapp message template
28
+ #
29
+ # @overload update(id, category: nil, components: nil, request_options: {})
30
+ #
31
+ # @param id [String] Whatsapp message template ID
32
+ #
33
+ # @param category [Symbol, Telnyx::Models::WhatsappMessageTemplateUpdateParams::Category]
34
+ #
35
+ # @param components [Array<Telnyx::Models::WhatsappMessageTemplateUpdateParams::Component::WhatsappTemplateHeaderComponent, Telnyx::Models::WhatsappMessageTemplateUpdateParams::Component::WhatsappTemplateBodyComponent, Telnyx::Models::WhatsappMessageTemplateUpdateParams::Component::WhatsappTemplateFooterComponent, Telnyx::Models::WhatsappMessageTemplateUpdateParams::Component::WhatsappTemplateButtonsComponent, Telnyx::Models::WhatsappMessageTemplateUpdateParams::Component::WhatsappTemplateCarouselComponent>] Updated template components. Same structure as the create request.
36
+ #
37
+ # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
38
+ #
39
+ # @return [Telnyx::Models::WhatsappMessageTemplateUpdateResponse]
40
+ #
41
+ # @see Telnyx::Models::WhatsappMessageTemplateUpdateParams
42
+ def update(id, params = {})
43
+ parsed, options = Telnyx::WhatsappMessageTemplateUpdateParams.dump_request(params)
44
+ @client.request(
45
+ method: :patch,
46
+ path: ["v2/whatsapp_message_templates/%1$s", id],
47
+ body: parsed,
48
+ model: Telnyx::Models::WhatsappMessageTemplateUpdateResponse,
49
+ options: options
50
+ )
51
+ end
52
+
53
+ # Delete a Whatsapp message template
54
+ #
55
+ # @overload delete(id, request_options: {})
56
+ #
57
+ # @param id [String] Whatsapp message template ID
58
+ #
59
+ # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
60
+ #
61
+ # @return [nil]
62
+ #
63
+ # @see Telnyx::Models::WhatsappMessageTemplateDeleteParams
64
+ def delete(id, params = {})
65
+ @client.request(
66
+ method: :delete,
67
+ path: ["v2/whatsapp_message_templates/%1$s", id],
68
+ model: NilClass,
69
+ options: params[:request_options]
70
+ )
71
+ end
72
+
73
+ # @api private
74
+ #
75
+ # @param client [Telnyx::Client]
76
+ def initialize(client:)
77
+ @client = client
78
+ end
79
+ end
80
+ end
81
+ end
@@ -10,35 +10,35 @@ module Telnyx
10
10
  # including the x402 payment requirements, network, and expiration time. The quote
11
11
  # must be settled before it expires.
12
12
  #
13
- # @overload create_payment_quote(amount_usd:, request_options: {})
13
+ # @overload create_quote(amount_usd:, request_options: {})
14
14
  #
15
15
  # @param amount_usd [String] Amount in USD to fund (minimum 5.00, maximum 10000.00).
16
16
  #
17
17
  # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
18
18
  #
19
- # @return [Telnyx::Models::X402::CreditAccountCreatePaymentQuoteResponse]
19
+ # @return [Telnyx::Models::X402::CreditAccountCreateQuoteResponse]
20
20
  #
21
- # @see Telnyx::Models::X402::CreditAccountCreatePaymentQuoteParams
22
- def create_payment_quote(params)
23
- parsed, options = Telnyx::X402::CreditAccountCreatePaymentQuoteParams.dump_request(params)
21
+ # @see Telnyx::Models::X402::CreditAccountCreateQuoteParams
22
+ def create_quote(params)
23
+ parsed, options = Telnyx::X402::CreditAccountCreateQuoteParams.dump_request(params)
24
24
  @client.request(
25
25
  method: :post,
26
26
  path: "v2/x402/credit_account/quote",
27
27
  body: parsed,
28
- model: Telnyx::Models::X402::CreditAccountCreatePaymentQuoteResponse,
28
+ model: Telnyx::Models::X402::CreditAccountCreateQuoteResponse,
29
29
  options: options
30
30
  )
31
31
  end
32
32
 
33
33
  # Some parameter documentations has been truncated, see
34
- # {Telnyx::Models::X402::CreditAccountSettlePaymentParams} for more details.
34
+ # {Telnyx::Models::X402::CreditAccountSettleParams} for more details.
35
35
  #
36
36
  # Settles an x402 payment using the quote ID and a signed payment authorization.
37
37
  # The payment signature can be provided via the `PAYMENT-SIGNATURE` header or the
38
38
  # `payment_signature` body parameter. Settlement is idempotent — submitting the
39
39
  # same quote ID multiple times returns the existing transaction.
40
40
  #
41
- # @overload settle_payment(id:, body_payment_signature: nil, header_payment_signature: nil, request_options: {})
41
+ # @overload settle(id:, body_payment_signature: nil, header_payment_signature: nil, request_options: {})
42
42
  #
43
43
  # @param id [String] Body param: The quote ID to settle.
44
44
  #
@@ -48,18 +48,18 @@ module Telnyx
48
48
  #
49
49
  # @param request_options [Telnyx::RequestOptions, Hash{Symbol=>Object}, nil]
50
50
  #
51
- # @return [Telnyx::Models::X402::CreditAccountSettlePaymentResponse]
51
+ # @return [Telnyx::Models::X402::CreditAccountSettleResponse]
52
52
  #
53
- # @see Telnyx::Models::X402::CreditAccountSettlePaymentParams
54
- def settle_payment(params)
55
- parsed, options = Telnyx::X402::CreditAccountSettlePaymentParams.dump_request(params)
53
+ # @see Telnyx::Models::X402::CreditAccountSettleParams
54
+ def settle(params)
55
+ parsed, options = Telnyx::X402::CreditAccountSettleParams.dump_request(params)
56
56
  header_params = {header_payment_signature: "payment-signature"}
57
57
  @client.request(
58
58
  method: :post,
59
59
  path: "v2/x402/credit_account",
60
60
  headers: parsed.slice(*header_params.keys).transform_keys(header_params),
61
61
  body: parsed.except(*header_params.keys),
62
- model: Telnyx::Models::X402::CreditAccountSettlePaymentResponse,
62
+ model: Telnyx::Models::X402::CreditAccountSettleResponse,
63
63
  options: options
64
64
  )
65
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Telnyx
4
- VERSION = "5.60.0"
4
+ VERSION = "5.62.0"
5
5
  end