diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 28a64b708..8e79f95c6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.180.0" + ".": "4.181.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d0e375fdc..52f1034fa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 1256 +configured_endpoints: 1268 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fc124d9a..c87690b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [4.181.0](https://github.com/team-telnyx/telnyx-python/compare/v4.180.0...v4.181.0) (2026-09-23) + + +### Features + +* promote from staging f1f53a1 ([fde2e3f](https://github.com/team-telnyx/telnyx-python/commit/fde2e3fa65abf37492695ecea1e646dbfab87c28)) + ## [4.180.0](https://github.com/team-telnyx/telnyx-python/compare/v4.179.0...v4.180.0) (2026-09-13) diff --git a/api.md b/api.md index e1e4fdd12..d3663fb39 100644 --- a/api.md +++ b/api.md @@ -326,6 +326,7 @@ from telnyx.types import ( FaxSendingStarted, InboundMessage, InboundSipHeader, + MessagingInboundMessage, NumberOrderStatusUpdate, OutboundMessage, ReplacedLinkClick, @@ -844,7 +845,7 @@ Methods: Types: ```python -from telnyx.types.ai import AudioTranscribeResponse +from telnyx.types.ai import AudioTranscriptionResponseWord, AudioTranscribeResponse ``` Methods: @@ -1286,7 +1287,7 @@ Methods: Types: ```python -from telnyx.types.ai.openai import ChatCreateCompletionResponse +from telnyx.types.ai.openai import FunctionDefinition, ChatCreateCompletionResponse ``` Methods: @@ -1337,6 +1338,20 @@ Methods: - client.ai.knowledge.collections.retrieve_documents(slug, \*\*params) -> CollectionRetrieveDocumentsResponse +## Typesafe + +### V1 + +Types: + +```python +from telnyx.types.ai.typesafe import V1SystemoneResponse +``` + +Methods: + +- client.ai.typesafe.v1.systemone(\*\*params) -> V1SystemoneResponse + # AuditEvents Types: @@ -1823,7 +1838,12 @@ Methods: Types: ```python -from telnyx.types import Connection, ConnectionRetrieveResponse, ConnectionListActiveCallsResponse +from telnyx.types import ( + Connection, + ConnectionRetrieveResponse, + ConnectionListActiveCallsResponse, + ConnectionRetrieveCountResponse, +) ``` Methods: @@ -1831,6 +1851,7 @@ Methods: - client.connections.retrieve(id) -> ConnectionRetrieveResponse - client.connections.list(\*\*params) -> SyncDefaultFlatPagination[Connection] - client.connections.list_active_calls(connection_id, \*\*params) -> SyncDefaultFlatPagination[ConnectionListActiveCallsResponse] +- client.connections.retrieve_count() -> ConnectionRetrieveCountResponse # CountryCoverage @@ -4773,6 +4794,18 @@ Methods: - client.texml.initiate_ai_call(connection_id, \*\*params) -> TexmlInitiateAICallResponse - client.texml.secrets(\*\*params) -> TexmlSecretsResponse +## Calls + +Types: + +```python +from telnyx.types.texml import CallCreateResponse +``` + +Methods: + +- client.texml.calls.create(connection_id, \*\*params) -> CallCreateResponse + ## Accounts Types: @@ -6826,7 +6859,82 @@ from telnyx.types.compute import ( Methods: -- client.compute.funcs.retrieve_logs(id, \*\*params) -> FuncRetrieveLogsResponse -- client.compute.funcs.retrieve_metric_aggregates(id, \*\*params) -> FuncRetrieveMetricAggregatesResponse -- client.compute.funcs.retrieve_revisions(id, \*\*params) -> FuncRetrieveRevisionsResponse -- client.compute.funcs.retrieve_ship_inspection(id) -> FuncRetrieveShipInspectionResponse +- client.compute.funcs.retrieve_logs(id, \*\*params) -> FuncRetrieveLogsResponse +- client.compute.funcs.retrieve_metric_aggregates(id, \*\*params) -> FuncRetrieveMetricAggregatesResponse +- client.compute.funcs.retrieve_revisions(id, \*\*params) -> FuncRetrieveRevisionsResponse +- client.compute.funcs.retrieve_ship_inspection(id) -> FuncRetrieveShipInspectionResponse + +### Export + +Types: + +```python +from telnyx.types.compute.funcs import FuncLogExportConfigResponse +``` + +Methods: + +- client.compute.funcs.export.create(id, \*\*params) -> FuncLogExportConfigResponse +- client.compute.funcs.export.list(id) -> FuncLogExportConfigResponse +- client.compute.funcs.export.delete_all(id) -> None + +# NoiseSuppressionEngines + +Types: + +```python +from telnyx.types import NoiseSuppressionEngineListResponse +``` + +Methods: + +- client.noise_suppression_engines.list() -> NoiseSuppressionEngineListResponse + +# BotChallenge + +Types: + +```python +from telnyx.types import BotChallengeCreateResponse +``` + +Methods: + +- client.bot_challenge.create(\*\*params) -> BotChallengeCreateResponse + +# BotSessions + +Types: + +```python +from telnyx.types import BotSessionListResponse +``` + +Methods: + +- client.bot_sessions.list(\*\*params) -> BotSessionListResponse + +# BotSignup + +Types: + +```python +from telnyx.types import SuccessResponse +``` + +Methods: + +- client.bot_signup.create(\*\*params) -> SuccessResponse +- client.bot_signup.resend_magic_link(\*\*params) -> SuccessResponse + +# MachinePayments + +Types: + +```python +from telnyx.types import MachinePaymentAccountCreditResponse +``` + +Methods: + +- client.machine_payments.account_credit(\*\*params) -> MachinePaymentAccountCreditResponse diff --git a/pyproject.toml b/pyproject.toml index ab8d35410..9f250f1e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "telnyx" -version = "4.180.0" +version = "4.181.0" description = "The official Python library for the telnyx API" dynamic = ["readme"] license = "MIT" diff --git a/src/telnyx/_client.py b/src/telnyx/_client.py index 11c29ae54..8a9e789f8 100644 --- a/src/telnyx/_client.py +++ b/src/telnyx/_client.py @@ -74,6 +74,7 @@ messaging, sim_cards, user_tags, + bot_signup, global_ips, recordings, reputation, @@ -86,12 +87,14 @@ ota_updates, short_codes, audit_events, + bot_sessions, call_reasons, email_blocks, email_events, oauth_grants, requirements, voice_clones, + bot_challenge, channel_zones, email_domains, email_inboxes, @@ -130,6 +133,7 @@ fax_applications, fqdn_connections, inbound_channels, + machine_payments, managed_accounts, meeting_sessions, network_coverage, @@ -201,6 +205,7 @@ sub_number_orders_report, call_control_applications, messaging_profile_metrics, + noise_suppression_engines, private_wireless_gateways, wireless_blocklist_values, custom_storage_credentials, @@ -237,6 +242,7 @@ from .resources.documents import DocumentsResource, AsyncDocumentsResource from .resources.user_tags import UserTagsResource, AsyncUserTagsResource from .resources.x402.x402 import X402Resource, AsyncX402Resource + from .resources.bot_signup import BotSignupResource, AsyncBotSignupResource from .resources.global_ips import GlobalIPsResource, AsyncGlobalIPsResource from .resources.well_known import WellKnownResource, AsyncWellKnownResource from .resources.call_events import CallEventsResource, AsyncCallEventsResource @@ -248,11 +254,13 @@ from .resources.short_codes import ShortCodesResource, AsyncShortCodesResource from .resources.texml.texml import TexmlResource, AsyncTexmlResource from .resources.audit_events import AuditEventsResource, AsyncAuditEventsResource + from .resources.bot_sessions import BotSessionsResource, AsyncBotSessionsResource from .resources.call_reasons import CallReasonsResource, AsyncCallReasonsResource from .resources.email_events import EmailEventsResource, AsyncEmailEventsResource from .resources.oauth_grants import OAuthGrantsResource, AsyncOAuthGrantsResource from .resources.requirements import RequirementsResource, AsyncRequirementsResource from .resources.voice_clones import VoiceClonesResource, AsyncVoiceClonesResource + from .resources.bot_challenge import BotChallengeResource, AsyncBotChallengeResource from .resources.channel_zones import ChannelZonesResource, AsyncChannelZonesResource from .resources.email_threads import EmailThreadsResource, AsyncEmailThreadsResource from .resources.legacy.legacy import LegacyResource, AsyncLegacyResource @@ -288,6 +296,7 @@ from .resources.country_coverage import CountryCoverageResource, AsyncCountryCoverageResource from .resources.fax_applications import FaxApplicationsResource, AsyncFaxApplicationsResource from .resources.inbound_channels import InboundChannelsResource, AsyncInboundChannelsResource + from .resources.machine_payments import MachinePaymentsResource, AsyncMachinePaymentsResource from .resources.network_coverage import NetworkCoverageResource, AsyncNetworkCoverageResource from .resources.numbers_features import NumbersFeaturesResource, AsyncNumbersFeaturesResource from .resources.access_ip_address import AccessIPAddressResource, AsyncAccessIPAddressResource @@ -369,6 +378,10 @@ MessagingProfileMetricsResource, AsyncMessagingProfileMetricsResource, ) + from .resources.noise_suppression_engines import ( + NoiseSuppressionEnginesResource, + AsyncNoiseSuppressionEnginesResource, + ) from .resources.private_wireless_gateways import ( PrivateWirelessGatewaysResource, AsyncPrivateWirelessGatewaysResource, @@ -1858,6 +1871,55 @@ def compute(self) -> ComputeResource: return ComputeResource(self) + @cached_property + def noise_suppression_engines(self) -> NoiseSuppressionEnginesResource: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import NoiseSuppressionEnginesResource + + return NoiseSuppressionEnginesResource(self) + + @cached_property + def bot_challenge(self) -> BotChallengeResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import BotChallengeResource + + return BotChallengeResource(self) + + @cached_property + def bot_sessions(self) -> BotSessionsResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import BotSessionsResource + + return BotSessionsResource(self) + + @cached_property + def bot_signup(self) -> BotSignupResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import BotSignupResource + + return BotSignupResource(self) + + @cached_property + def machine_payments(self) -> MachinePaymentsResource: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import MachinePaymentsResource + + return MachinePaymentsResource(self) + @cached_property def with_raw_response(self) -> TelnyxWithRawResponse: return TelnyxWithRawResponse(self) @@ -3362,6 +3424,55 @@ def compute(self) -> AsyncComputeResource: return AsyncComputeResource(self) + @cached_property + def noise_suppression_engines(self) -> AsyncNoiseSuppressionEnginesResource: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import AsyncNoiseSuppressionEnginesResource + + return AsyncNoiseSuppressionEnginesResource(self) + + @cached_property + def bot_challenge(self) -> AsyncBotChallengeResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import AsyncBotChallengeResource + + return AsyncBotChallengeResource(self) + + @cached_property + def bot_sessions(self) -> AsyncBotSessionsResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import AsyncBotSessionsResource + + return AsyncBotSessionsResource(self) + + @cached_property + def bot_signup(self) -> AsyncBotSignupResource: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import AsyncBotSignupResource + + return AsyncBotSignupResource(self) + + @cached_property + def machine_payments(self) -> AsyncMachinePaymentsResource: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import AsyncMachinePaymentsResource + + return AsyncMachinePaymentsResource(self) + @cached_property def with_raw_response(self) -> AsyncTelnyxWithRawResponse: return AsyncTelnyxWithRawResponse(self) @@ -4802,6 +4913,55 @@ def compute(self) -> compute.ComputeResourceWithRawResponse: return ComputeResourceWithRawResponse(self._client.compute) + @cached_property + def noise_suppression_engines(self) -> noise_suppression_engines.NoiseSuppressionEnginesResourceWithRawResponse: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import NoiseSuppressionEnginesResourceWithRawResponse + + return NoiseSuppressionEnginesResourceWithRawResponse(self._client.noise_suppression_engines) + + @cached_property + def bot_challenge(self) -> bot_challenge.BotChallengeResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import BotChallengeResourceWithRawResponse + + return BotChallengeResourceWithRawResponse(self._client.bot_challenge) + + @cached_property + def bot_sessions(self) -> bot_sessions.BotSessionsResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import BotSessionsResourceWithRawResponse + + return BotSessionsResourceWithRawResponse(self._client.bot_sessions) + + @cached_property + def bot_signup(self) -> bot_signup.BotSignupResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import BotSignupResourceWithRawResponse + + return BotSignupResourceWithRawResponse(self._client.bot_signup) + + @cached_property + def machine_payments(self) -> machine_payments.MachinePaymentsResourceWithRawResponse: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import MachinePaymentsResourceWithRawResponse + + return MachinePaymentsResourceWithRawResponse(self._client.machine_payments) + class AsyncTelnyxWithRawResponse: _client: AsyncTelnyx @@ -6113,6 +6273,57 @@ def compute(self) -> compute.AsyncComputeResourceWithRawResponse: return AsyncComputeResourceWithRawResponse(self._client.compute) + @cached_property + def noise_suppression_engines( + self, + ) -> noise_suppression_engines.AsyncNoiseSuppressionEnginesResourceWithRawResponse: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import AsyncNoiseSuppressionEnginesResourceWithRawResponse + + return AsyncNoiseSuppressionEnginesResourceWithRawResponse(self._client.noise_suppression_engines) + + @cached_property + def bot_challenge(self) -> bot_challenge.AsyncBotChallengeResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import AsyncBotChallengeResourceWithRawResponse + + return AsyncBotChallengeResourceWithRawResponse(self._client.bot_challenge) + + @cached_property + def bot_sessions(self) -> bot_sessions.AsyncBotSessionsResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import AsyncBotSessionsResourceWithRawResponse + + return AsyncBotSessionsResourceWithRawResponse(self._client.bot_sessions) + + @cached_property + def bot_signup(self) -> bot_signup.AsyncBotSignupResourceWithRawResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import AsyncBotSignupResourceWithRawResponse + + return AsyncBotSignupResourceWithRawResponse(self._client.bot_signup) + + @cached_property + def machine_payments(self) -> machine_payments.AsyncMachinePaymentsResourceWithRawResponse: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import AsyncMachinePaymentsResourceWithRawResponse + + return AsyncMachinePaymentsResourceWithRawResponse(self._client.machine_payments) + class TelnyxWithStreamedResponse: _client: Telnyx @@ -7426,6 +7637,57 @@ def compute(self) -> compute.ComputeResourceWithStreamingResponse: return ComputeResourceWithStreamingResponse(self._client.compute) + @cached_property + def noise_suppression_engines( + self, + ) -> noise_suppression_engines.NoiseSuppressionEnginesResourceWithStreamingResponse: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import NoiseSuppressionEnginesResourceWithStreamingResponse + + return NoiseSuppressionEnginesResourceWithStreamingResponse(self._client.noise_suppression_engines) + + @cached_property + def bot_challenge(self) -> bot_challenge.BotChallengeResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import BotChallengeResourceWithStreamingResponse + + return BotChallengeResourceWithStreamingResponse(self._client.bot_challenge) + + @cached_property + def bot_sessions(self) -> bot_sessions.BotSessionsResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import BotSessionsResourceWithStreamingResponse + + return BotSessionsResourceWithStreamingResponse(self._client.bot_sessions) + + @cached_property + def bot_signup(self) -> bot_signup.BotSignupResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import BotSignupResourceWithStreamingResponse + + return BotSignupResourceWithStreamingResponse(self._client.bot_signup) + + @cached_property + def machine_payments(self) -> machine_payments.MachinePaymentsResourceWithStreamingResponse: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import MachinePaymentsResourceWithStreamingResponse + + return MachinePaymentsResourceWithStreamingResponse(self._client.machine_payments) + class AsyncTelnyxWithStreamedResponse: _client: AsyncTelnyx @@ -8787,6 +9049,57 @@ def compute(self) -> compute.AsyncComputeResourceWithStreamingResponse: return AsyncComputeResourceWithStreamingResponse(self._client.compute) + @cached_property + def noise_suppression_engines( + self, + ) -> noise_suppression_engines.AsyncNoiseSuppressionEnginesResourceWithStreamingResponse: + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + from .resources.noise_suppression_engines import AsyncNoiseSuppressionEnginesResourceWithStreamingResponse + + return AsyncNoiseSuppressionEnginesResourceWithStreamingResponse(self._client.noise_suppression_engines) + + @cached_property + def bot_challenge(self) -> bot_challenge.AsyncBotChallengeResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_challenge import AsyncBotChallengeResourceWithStreamingResponse + + return AsyncBotChallengeResourceWithStreamingResponse(self._client.bot_challenge) + + @cached_property + def bot_sessions(self) -> bot_sessions.AsyncBotSessionsResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_sessions import AsyncBotSessionsResourceWithStreamingResponse + + return AsyncBotSessionsResourceWithStreamingResponse(self._client.bot_sessions) + + @cached_property + def bot_signup(self) -> bot_signup.AsyncBotSignupResourceWithStreamingResponse: + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + from .resources.bot_signup import AsyncBotSignupResourceWithStreamingResponse + + return AsyncBotSignupResourceWithStreamingResponse(self._client.bot_signup) + + @cached_property + def machine_payments(self) -> machine_payments.AsyncMachinePaymentsResourceWithStreamingResponse: + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + from .resources.machine_payments import AsyncMachinePaymentsResourceWithStreamingResponse + + return AsyncMachinePaymentsResourceWithStreamingResponse(self._client.machine_payments) + Client = Telnyx diff --git a/src/telnyx/_version.py b/src/telnyx/_version.py index 2c5801666..000f5dc32 100644 --- a/src/telnyx/_version.py +++ b/src/telnyx/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "telnyx" -__version__ = "4.180.0" # x-release-please-version +__version__ = "4.181.0" # x-release-please-version diff --git a/src/telnyx/resources/__init__.py b/src/telnyx/resources/__init__.py index 7595ed0ba..a07625f89 100644 --- a/src/telnyx/resources/__init__.py +++ b/src/telnyx/resources/__init__.py @@ -297,6 +297,14 @@ UserTagsResourceWithStreamingResponse, AsyncUserTagsResourceWithStreamingResponse, ) +from .bot_signup import ( + BotSignupResource, + AsyncBotSignupResource, + BotSignupResourceWithRawResponse, + AsyncBotSignupResourceWithRawResponse, + BotSignupResourceWithStreamingResponse, + AsyncBotSignupResourceWithStreamingResponse, +) from .global_ips import ( GlobalIPsResource, AsyncGlobalIPsResource, @@ -393,6 +401,14 @@ AuditEventsResourceWithStreamingResponse, AsyncAuditEventsResourceWithStreamingResponse, ) +from .bot_sessions import ( + BotSessionsResource, + AsyncBotSessionsResource, + BotSessionsResourceWithRawResponse, + AsyncBotSessionsResourceWithRawResponse, + BotSessionsResourceWithStreamingResponse, + AsyncBotSessionsResourceWithStreamingResponse, +) from .call_reasons import ( CallReasonsResource, AsyncCallReasonsResource, @@ -441,6 +457,14 @@ VoiceClonesResourceWithStreamingResponse, AsyncVoiceClonesResourceWithStreamingResponse, ) +from .bot_challenge import ( + BotChallengeResource, + AsyncBotChallengeResource, + BotChallengeResourceWithRawResponse, + AsyncBotChallengeResourceWithRawResponse, + BotChallengeResourceWithStreamingResponse, + AsyncBotChallengeResourceWithStreamingResponse, +) from .channel_zones import ( ChannelZonesResource, AsyncChannelZonesResource, @@ -745,6 +769,14 @@ InboundChannelsResourceWithStreamingResponse, AsyncInboundChannelsResourceWithStreamingResponse, ) +from .machine_payments import ( + MachinePaymentsResource, + AsyncMachinePaymentsResource, + MachinePaymentsResourceWithRawResponse, + AsyncMachinePaymentsResourceWithRawResponse, + MachinePaymentsResourceWithStreamingResponse, + AsyncMachinePaymentsResourceWithStreamingResponse, +) from .managed_accounts import ( ManagedAccountsResource, AsyncManagedAccountsResource, @@ -1313,6 +1345,14 @@ MessagingProfileMetricsResourceWithStreamingResponse, AsyncMessagingProfileMetricsResourceWithStreamingResponse, ) +from .noise_suppression_engines import ( + NoiseSuppressionEnginesResource, + AsyncNoiseSuppressionEnginesResource, + NoiseSuppressionEnginesResourceWithRawResponse, + AsyncNoiseSuppressionEnginesResourceWithRawResponse, + NoiseSuppressionEnginesResourceWithStreamingResponse, + AsyncNoiseSuppressionEnginesResourceWithStreamingResponse, +) from .private_wireless_gateways import ( PrivateWirelessGatewaysResource, AsyncPrivateWirelessGatewaysResource, @@ -2553,4 +2593,34 @@ "AsyncComputeResourceWithRawResponse", "ComputeResourceWithStreamingResponse", "AsyncComputeResourceWithStreamingResponse", + "NoiseSuppressionEnginesResource", + "AsyncNoiseSuppressionEnginesResource", + "NoiseSuppressionEnginesResourceWithRawResponse", + "AsyncNoiseSuppressionEnginesResourceWithRawResponse", + "NoiseSuppressionEnginesResourceWithStreamingResponse", + "AsyncNoiseSuppressionEnginesResourceWithStreamingResponse", + "BotChallengeResource", + "AsyncBotChallengeResource", + "BotChallengeResourceWithRawResponse", + "AsyncBotChallengeResourceWithRawResponse", + "BotChallengeResourceWithStreamingResponse", + "AsyncBotChallengeResourceWithStreamingResponse", + "BotSessionsResource", + "AsyncBotSessionsResource", + "BotSessionsResourceWithRawResponse", + "AsyncBotSessionsResourceWithRawResponse", + "BotSessionsResourceWithStreamingResponse", + "AsyncBotSessionsResourceWithStreamingResponse", + "BotSignupResource", + "AsyncBotSignupResource", + "BotSignupResourceWithRawResponse", + "AsyncBotSignupResourceWithRawResponse", + "BotSignupResourceWithStreamingResponse", + "AsyncBotSignupResourceWithStreamingResponse", + "MachinePaymentsResource", + "AsyncMachinePaymentsResource", + "MachinePaymentsResourceWithRawResponse", + "AsyncMachinePaymentsResourceWithRawResponse", + "MachinePaymentsResourceWithStreamingResponse", + "AsyncMachinePaymentsResourceWithStreamingResponse", ] diff --git a/src/telnyx/resources/ai/__init__.py b/src/telnyx/resources/ai/__init__.py index 8aff9743b..eeb3e681a 100644 --- a/src/telnyx/resources/ai/__init__.py +++ b/src/telnyx/resources/ai/__init__.py @@ -48,6 +48,14 @@ MissionsResourceWithStreamingResponse, AsyncMissionsResourceWithStreamingResponse, ) +from .typesafe import ( + TypesafeResource, + AsyncTypesafeResource, + TypesafeResourceWithRawResponse, + AsyncTypesafeResourceWithRawResponse, + TypesafeResourceWithStreamingResponse, + AsyncTypesafeResourceWithStreamingResponse, +) from .anthropic import ( AnthropicResource, AsyncAnthropicResource, @@ -206,6 +214,12 @@ "AsyncKnowledgeResourceWithRawResponse", "KnowledgeResourceWithStreamingResponse", "AsyncKnowledgeResourceWithStreamingResponse", + "TypesafeResource", + "AsyncTypesafeResource", + "TypesafeResourceWithRawResponse", + "AsyncTypesafeResourceWithRawResponse", + "TypesafeResourceWithStreamingResponse", + "AsyncTypesafeResourceWithStreamingResponse", "AIResource", "AsyncAIResource", "AIResourceWithRawResponse", diff --git a/src/telnyx/resources/ai/ai.py b/src/telnyx/resources/ai/ai.py index 2d4f72a1b..3c5b076a7 100644 --- a/src/telnyx/resources/ai/ai.py +++ b/src/telnyx/resources/ai/ai.py @@ -69,6 +69,14 @@ MissionsResourceWithStreamingResponse, AsyncMissionsResourceWithStreamingResponse, ) +from .typesafe.typesafe import ( + TypesafeResource, + AsyncTypesafeResource, + TypesafeResourceWithRawResponse, + AsyncTypesafeResourceWithRawResponse, + TypesafeResourceWithStreamingResponse, + AsyncTypesafeResourceWithStreamingResponse, +) from .anthropic.anthropic import ( AnthropicResource, AsyncAnthropicResource, @@ -204,6 +212,10 @@ def anthropic(self) -> AnthropicResource: def knowledge(self) -> KnowledgeResource: return KnowledgeResource(self._client) + @cached_property + def typesafe(self) -> TypesafeResource: + return TypesafeResource(self._client) + @cached_property def with_raw_response(self) -> AIResourceWithRawResponse: """ @@ -497,6 +509,10 @@ def anthropic(self) -> AsyncAnthropicResource: def knowledge(self) -> AsyncKnowledgeResource: return AsyncKnowledgeResource(self._client) + @cached_property + def typesafe(self) -> AsyncTypesafeResource: + return AsyncTypesafeResource(self._client) + @cached_property def with_raw_response(self) -> AsyncAIResourceWithRawResponse: """ @@ -802,6 +818,10 @@ def anthropic(self) -> AnthropicResourceWithRawResponse: def knowledge(self) -> KnowledgeResourceWithRawResponse: return KnowledgeResourceWithRawResponse(self._ai.knowledge) + @cached_property + def typesafe(self) -> TypesafeResourceWithRawResponse: + return TypesafeResourceWithRawResponse(self._ai.typesafe) + class AsyncAIResourceWithRawResponse: def __init__(self, ai: AsyncAIResource) -> None: @@ -878,6 +898,10 @@ def anthropic(self) -> AsyncAnthropicResourceWithRawResponse: def knowledge(self) -> AsyncKnowledgeResourceWithRawResponse: return AsyncKnowledgeResourceWithRawResponse(self._ai.knowledge) + @cached_property + def typesafe(self) -> AsyncTypesafeResourceWithRawResponse: + return AsyncTypesafeResourceWithRawResponse(self._ai.typesafe) + class AIResourceWithStreamingResponse: def __init__(self, ai: AIResource) -> None: @@ -954,6 +978,10 @@ def anthropic(self) -> AnthropicResourceWithStreamingResponse: def knowledge(self) -> KnowledgeResourceWithStreamingResponse: return KnowledgeResourceWithStreamingResponse(self._ai.knowledge) + @cached_property + def typesafe(self) -> TypesafeResourceWithStreamingResponse: + return TypesafeResourceWithStreamingResponse(self._ai.typesafe) + class AsyncAIResourceWithStreamingResponse: def __init__(self, ai: AsyncAIResource) -> None: @@ -1029,3 +1057,7 @@ def anthropic(self) -> AsyncAnthropicResourceWithStreamingResponse: @cached_property def knowledge(self) -> AsyncKnowledgeResourceWithStreamingResponse: return AsyncKnowledgeResourceWithStreamingResponse(self._ai.knowledge) + + @cached_property + def typesafe(self) -> AsyncTypesafeResourceWithStreamingResponse: + return AsyncTypesafeResourceWithStreamingResponse(self._ai.typesafe) diff --git a/src/telnyx/resources/ai/assistants/assistants.py b/src/telnyx/resources/ai/assistants/assistants.py index 62e44f416..6fca0cf0b 100644 --- a/src/telnyx/resources/ai/assistants/assistants.py +++ b/src/telnyx/resources/ai/assistants/assistants.py @@ -282,10 +282,10 @@ def create( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. tags: Tags associated with the assistant. Tags can also be managed with the assistant tag endpoints. @@ -527,10 +527,10 @@ def update( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. promote_to_main: Indicates whether the assistant should be promoted to the main version. Defaults to true. @@ -539,11 +539,22 @@ def update( tag endpoints. tool_ids: IDs of shared tools to attach to the assistant. New integrations should prefer - `tool_ids` over inline `tools`. + `tool_ids` over inline `tools`. On update, a sent `tool_ids` array fully + replaces the assistant's attached shared tools; omit the field to leave them + unchanged. Single-instance tool types are counted across inline `tools` and + `tool_ids` combined, so attaching a shared tool of such a type when an instance + already exists returns HTTP 400 with error code 10015. tools: Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach shared tools created with the AI Tools - endpoints. + endpoints. On update, a sent `tools` array fully replaces the assistant's inline + tools; omit the field to leave the inline tools unchanged. Each tool type except + `function`, `webhook`, and `client_side_tool` allows at most one instance per + assistant, counted across inline `tools` and shared `tool_ids` combined — + sending a duplicate of such a type returns HTTP 400 with error code 10015. + Responses merge shared tools into `tools` with `shared: true`; when updating, + omit those tools from the `tools` array and manage them through `tool_ids` + instead. version_name: Human-readable name for the assistant version. @@ -1079,10 +1090,10 @@ async def create( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. tags: Tags associated with the assistant. Tags can also be managed with the assistant tag endpoints. @@ -1324,10 +1335,10 @@ async def update( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. promote_to_main: Indicates whether the assistant should be promoted to the main version. Defaults to true. @@ -1336,11 +1347,22 @@ async def update( tag endpoints. tool_ids: IDs of shared tools to attach to the assistant. New integrations should prefer - `tool_ids` over inline `tools`. + `tool_ids` over inline `tools`. On update, a sent `tool_ids` array fully + replaces the assistant's attached shared tools; omit the field to leave them + unchanged. Single-instance tool types are counted across inline `tools` and + `tool_ids` combined, so attaching a shared tool of such a type when an instance + already exists returns HTTP 400 with error code 10015. tools: Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach shared tools created with the AI Tools - endpoints. + endpoints. On update, a sent `tools` array fully replaces the assistant's inline + tools; omit the field to leave the inline tools unchanged. Each tool type except + `function`, `webhook`, and `client_side_tool` allows at most one instance per + assistant, counted across inline `tools` and shared `tool_ids` combined — + sending a duplicate of such a type returns HTTP 400 with error code 10015. + Responses merge shared tools into `tools` with `shared: true`; when updating, + omit those tools from the `tools` array and manage them through `tool_ids` + instead. version_name: Human-readable name for the assistant version. diff --git a/src/telnyx/resources/ai/assistants/versions.py b/src/telnyx/resources/ai/assistants/versions.py index 33af21060..3d6b53050 100644 --- a/src/telnyx/resources/ai/assistants/versions.py +++ b/src/telnyx/resources/ai/assistants/versions.py @@ -231,20 +231,31 @@ def update( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. tags: Tags associated with the assistant. Tags can also be managed with the assistant tag endpoints. tool_ids: IDs of shared tools to attach to the assistant. New integrations should prefer - `tool_ids` over inline `tools`. + `tool_ids` over inline `tools`. On update, a sent `tool_ids` array fully + replaces the assistant's attached shared tools; omit the field to leave them + unchanged. Single-instance tool types are counted across inline `tools` and + `tool_ids` combined, so attaching a shared tool of such a type when an instance + already exists returns HTTP 400 with error code 10015. tools: Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach shared tools created with the AI Tools - endpoints. + endpoints. On update, a sent `tools` array fully replaces the assistant's inline + tools; omit the field to leave the inline tools unchanged. Each tool type except + `function`, `webhook`, and `client_side_tool` allows at most one instance per + assistant, counted across inline `tools` and shared `tool_ids` combined — + sending a duplicate of such a type returns HTTP 400 with error code 10015. + Responses merge shared tools into `tools` with `shared: true`; when updating, + omit those tools from the `tools` array and manage them through `tool_ids` + instead. version_name: Human-readable name for the assistant version. @@ -614,20 +625,31 @@ async def update( post_conversation_settings: Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to - execute tool calls such as logging to a CRM or sending a summary. The assistant - can execute multiple parallel or sequential tools during this phase. - Telephony-control tools (e.g. hangup, transfer) are unavailable - post-conversation. Beta feature. + execute final tool calls such as sending a summary or updating a record via + webhook or function tools. Integration and MCP server tools are not available + post-conversation; call-control tools (e.g. hangup, transfer) are also + unavailable. Beta feature. tags: Tags associated with the assistant. Tags can also be managed with the assistant tag endpoints. tool_ids: IDs of shared tools to attach to the assistant. New integrations should prefer - `tool_ids` over inline `tools`. + `tool_ids` over inline `tools`. On update, a sent `tool_ids` array fully + replaces the assistant's attached shared tools; omit the field to leave them + unchanged. Single-instance tool types are counted across inline `tools` and + `tool_ids` combined, so attaching a shared tool of such a type when an instance + already exists returns HTTP 400 with error code 10015. tools: Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach shared tools created with the AI Tools - endpoints. + endpoints. On update, a sent `tools` array fully replaces the assistant's inline + tools; omit the field to leave the inline tools unchanged. Each tool type except + `function`, `webhook`, and `client_side_tool` allows at most one instance per + assistant, counted across inline `tools` and shared `tool_ids` combined — + sending a duplicate of such a type returns HTTP 400 with error code 10015. + Responses merge shared tools into `tools` with `shared: true`; when updating, + omit those tools from the `tools` array and manage them through `tool_ids` + instead. version_name: Human-readable name for the assistant version. diff --git a/src/telnyx/resources/ai/audio.py b/src/telnyx/resources/ai/audio.py index 3f1f53bb5..1325aec42 100644 --- a/src/telnyx/resources/ai/audio.py +++ b/src/telnyx/resources/ai/audio.py @@ -48,7 +48,16 @@ def with_streaming_response(self) -> AudioResourceWithStreamingResponse: def transcribe( self, *, - model: Literal["distil-whisper/distil-large-v2", "openai/whisper-large-v3-turbo", "deepgram/nova-3"], + model: Literal[ + "distil-whisper/distil-large-v2", + "openai/whisper-large-v3-turbo", + "deepgram/nova-2", + "deepgram/nova-2-medical", + "deepgram/nova-3", + "deepgram/nova-3-medical", + "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", + ], file: FileTypes | Omit = omit, file_url: str | Omit = omit, language: str | Omit = omit, @@ -71,25 +80,36 @@ def transcribe( Args: model: ID of the model to use. `distil-whisper/distil-large-v2` is lower latency but English-only. `openai/whisper-large-v3-turbo` is multi-lingual but slightly - higher latency. `deepgram/nova-3` supports English variants (en, en-US, en-GB, - en-AU, en-NZ, en-IN) and only accepts mp3/wav files. + higher latency. The `deepgram/*` models only accept mp3/wav files: + `deepgram/nova-3` covers ~49 languages plus `multi` and `deepgram/nova-2` covers + ~33, while the `-medical` variants are tuned for clinical vocabulary and accept + English only (`en` and its regional variants, e.g. `en-US`, `en-GB`). + `nvidia/parakeet-v3` is multilingual with automatic language detection; + `omi-health/omi-med-stt-v1` is a medical model, English only. file: The audio file object to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. File uploads are limited to 100 MB. Cannot - be used together with `file_url`. Note: `deepgram/nova-3` only supports mp3 and - wav formats. + be used together with `file_url`. Note: the `deepgram/*` models only support mp3 + and wav formats. file_url: Link to audio file in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. Support for hosted files is limited to 100MB. Cannot be used - together with `file`. Note: `deepgram/nova-3` only supports mp3 and wav formats. - - language: The language of the audio to be transcribed. For `deepgram/nova-3`, only English - variants are supported: `en`, `en-US`, `en-GB`, `en-AU`, `en-NZ`, `en-IN`. For + together with `file`. Note: the `deepgram/*` models only support mp3 and wav + formats. + + language: The language of the audio to be transcribed. `deepgram/nova-3` supports ~49 + languages plus `multi`, and `deepgram/nova-2` supports ~33 plus `multi`; the + `-medical` variants are English only (`en` and its regional variants, e.g. + `en-US`, `en-GB`). Deepgram models validate on the base language and forward the + full tag, so regional variants such as `de-CH` and `pt-BR` are accepted where + the base language is supported; an unsupported language returns a 400. For `openai/whisper-large-v3-turbo`, supports multiple languages. `distil-whisper/distil-large-v2` does not support language parameter. + `nvidia/parakeet-v3` detects the language automatically; + `omi-health/omi-med-stt-v1` is English only. - model_config: Additional model-specific configuration parameters. Only allowed with - `deepgram/nova-3` model. Can include Deepgram-specific options such as + model_config: Additional model-specific configuration parameters. Only allowed with the + `deepgram/*` models. Can include Deepgram-specific options such as `smart_format`, `punctuate`, `diarize`, `utterance`, `numerals`, and `language`. If `language` is provided both as a top-level parameter and in `model_config`, the top-level parameter takes precedence. @@ -160,7 +180,16 @@ def with_streaming_response(self) -> AsyncAudioResourceWithStreamingResponse: async def transcribe( self, *, - model: Literal["distil-whisper/distil-large-v2", "openai/whisper-large-v3-turbo", "deepgram/nova-3"], + model: Literal[ + "distil-whisper/distil-large-v2", + "openai/whisper-large-v3-turbo", + "deepgram/nova-2", + "deepgram/nova-2-medical", + "deepgram/nova-3", + "deepgram/nova-3-medical", + "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", + ], file: FileTypes | Omit = omit, file_url: str | Omit = omit, language: str | Omit = omit, @@ -183,25 +212,36 @@ async def transcribe( Args: model: ID of the model to use. `distil-whisper/distil-large-v2` is lower latency but English-only. `openai/whisper-large-v3-turbo` is multi-lingual but slightly - higher latency. `deepgram/nova-3` supports English variants (en, en-US, en-GB, - en-AU, en-NZ, en-IN) and only accepts mp3/wav files. + higher latency. The `deepgram/*` models only accept mp3/wav files: + `deepgram/nova-3` covers ~49 languages plus `multi` and `deepgram/nova-2` covers + ~33, while the `-medical` variants are tuned for clinical vocabulary and accept + English only (`en` and its regional variants, e.g. `en-US`, `en-GB`). + `nvidia/parakeet-v3` is multilingual with automatic language detection; + `omi-health/omi-med-stt-v1` is a medical model, English only. file: The audio file object to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. File uploads are limited to 100 MB. Cannot - be used together with `file_url`. Note: `deepgram/nova-3` only supports mp3 and - wav formats. + be used together with `file_url`. Note: the `deepgram/*` models only support mp3 + and wav formats. file_url: Link to audio file in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. Support for hosted files is limited to 100MB. Cannot be used - together with `file`. Note: `deepgram/nova-3` only supports mp3 and wav formats. - - language: The language of the audio to be transcribed. For `deepgram/nova-3`, only English - variants are supported: `en`, `en-US`, `en-GB`, `en-AU`, `en-NZ`, `en-IN`. For + together with `file`. Note: the `deepgram/*` models only support mp3 and wav + formats. + + language: The language of the audio to be transcribed. `deepgram/nova-3` supports ~49 + languages plus `multi`, and `deepgram/nova-2` supports ~33 plus `multi`; the + `-medical` variants are English only (`en` and its regional variants, e.g. + `en-US`, `en-GB`). Deepgram models validate on the base language and forward the + full tag, so regional variants such as `de-CH` and `pt-BR` are accepted where + the base language is supported; an unsupported language returns a 400. For `openai/whisper-large-v3-turbo`, supports multiple languages. `distil-whisper/distil-large-v2` does not support language parameter. + `nvidia/parakeet-v3` detects the language automatically; + `omi-health/omi-med-stt-v1` is English only. - model_config: Additional model-specific configuration parameters. Only allowed with - `deepgram/nova-3` model. Can include Deepgram-specific options such as + model_config: Additional model-specific configuration parameters. Only allowed with the + `deepgram/*` models. Can include Deepgram-specific options such as `smart_format`, `punctuate`, `diarize`, `utterance`, `numerals`, and `language`. If `language` is provided both as a top-level parameter and in `model_config`, the top-level parameter takes precedence. diff --git a/src/telnyx/resources/ai/typesafe/__init__.py b/src/telnyx/resources/ai/typesafe/__init__.py new file mode 100644 index 000000000..330efe519 --- /dev/null +++ b/src/telnyx/resources/ai/typesafe/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .v1 import ( + V1Resource, + AsyncV1Resource, + V1ResourceWithRawResponse, + AsyncV1ResourceWithRawResponse, + V1ResourceWithStreamingResponse, + AsyncV1ResourceWithStreamingResponse, +) +from .typesafe import ( + TypesafeResource, + AsyncTypesafeResource, + TypesafeResourceWithRawResponse, + AsyncTypesafeResourceWithRawResponse, + TypesafeResourceWithStreamingResponse, + AsyncTypesafeResourceWithStreamingResponse, +) + +__all__ = [ + "V1Resource", + "AsyncV1Resource", + "V1ResourceWithRawResponse", + "AsyncV1ResourceWithRawResponse", + "V1ResourceWithStreamingResponse", + "AsyncV1ResourceWithStreamingResponse", + "TypesafeResource", + "AsyncTypesafeResource", + "TypesafeResourceWithRawResponse", + "AsyncTypesafeResourceWithRawResponse", + "TypesafeResourceWithStreamingResponse", + "AsyncTypesafeResourceWithStreamingResponse", +] diff --git a/src/telnyx/resources/ai/typesafe/typesafe.py b/src/telnyx/resources/ai/typesafe/typesafe.py new file mode 100644 index 000000000..a91b38c44 --- /dev/null +++ b/src/telnyx/resources/ai/typesafe/typesafe.py @@ -0,0 +1,120 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .v1 import ( + V1Resource, + AsyncV1Resource, + V1ResourceWithRawResponse, + AsyncV1ResourceWithRawResponse, + V1ResourceWithStreamingResponse, + AsyncV1ResourceWithStreamingResponse, +) +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["TypesafeResource", "AsyncTypesafeResource"] + + +class TypesafeResource(SyncAPIResource): + @cached_property + def v1(self) -> V1Resource: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return V1Resource(self._client) + + @cached_property + def with_raw_response(self) -> TypesafeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return TypesafeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TypesafeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return TypesafeResourceWithStreamingResponse(self) + + +class AsyncTypesafeResource(AsyncAPIResource): + @cached_property + def v1(self) -> AsyncV1Resource: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return AsyncV1Resource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncTypesafeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncTypesafeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTypesafeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncTypesafeResourceWithStreamingResponse(self) + + +class TypesafeResourceWithRawResponse: + def __init__(self, typesafe: TypesafeResource) -> None: + self._typesafe = typesafe + + @cached_property + def v1(self) -> V1ResourceWithRawResponse: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return V1ResourceWithRawResponse(self._typesafe.v1) + + +class AsyncTypesafeResourceWithRawResponse: + def __init__(self, typesafe: AsyncTypesafeResource) -> None: + self._typesafe = typesafe + + @cached_property + def v1(self) -> AsyncV1ResourceWithRawResponse: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return AsyncV1ResourceWithRawResponse(self._typesafe.v1) + + +class TypesafeResourceWithStreamingResponse: + def __init__(self, typesafe: TypesafeResource) -> None: + self._typesafe = typesafe + + @cached_property + def v1(self) -> V1ResourceWithStreamingResponse: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return V1ResourceWithStreamingResponse(self._typesafe.v1) + + +class AsyncTypesafeResourceWithStreamingResponse: + def __init__(self, typesafe: AsyncTypesafeResource) -> None: + self._typesafe = typesafe + + @cached_property + def v1(self) -> AsyncV1ResourceWithStreamingResponse: + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + return AsyncV1ResourceWithStreamingResponse(self._typesafe.v1) diff --git a/src/telnyx/resources/ai/typesafe/v1.py b/src/telnyx/resources/ai/typesafe/v1.py new file mode 100644 index 000000000..f08ba8dfb --- /dev/null +++ b/src/telnyx/resources/ai/typesafe/v1.py @@ -0,0 +1,231 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.ai.typesafe import v1_systemone_params +from ....types.ai.typesafe.v1_systemone_response import V1SystemoneResponse + +__all__ = ["V1Resource", "AsyncV1Resource"] + + +class V1Resource(SyncAPIResource): + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + + @cached_property + def with_raw_response(self) -> V1ResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return V1ResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> V1ResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return V1ResourceWithStreamingResponse(self) + + def systemone( + self, + *, + questions: Dict[str, v1_systemone_params.Questions], + state: Union[str, Dict[str, object], Iterable[object]], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> V1SystemoneResponse: + """ + **Beta API.** Telnyx controls model selection. + + Evaluate shared context using named choice, noul (yes/no), and score questions. + Returns TypeSafe System One-compatible answer shapes, an opaque compatibility + identifier, and token usage. See the + [decision model guide](https://developers.telnyx.com/docs/inference/decision-models) + for examples and compatibility limits. + + The supported request subset requires instructions for every question, string + descriptions for criteria (or null for choice descriptions), 1–64 questions, and + 2–64 options for choice and score questions. The SDK-supplied model value is + ignored and cannot select a model. Other unknown fields are rejected. The + endpoint is synchronous and does not stream. + + Use the TypeSafe Python SDK with base_url set to + https://api.telnyx.com/v2/ai/typesafe and a Telnyx API key. The SDK appends + /v1/systemone. Compatibility covers this operation and the documented request + subset; it does not include TypeSafe model listing. Scores describe relative + preference, not calibrated correctness. + + Args: + questions: Between 1 and 64 named questions. Each key identifies the corresponding answer. + + state: Shared context evaluated by every question. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/ai/typesafe/v1/systemone", + body=maybe_transform( + { + "questions": questions, + "state": state, + }, + v1_systemone_params.V1SystemoneParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1SystemoneResponse, + ) + + +class AsyncV1Resource(AsyncAPIResource): + """ + Beta API for evaluating shared context with typed questions and structured answers. Telnyx manages model selection. + """ + + @cached_property + def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncV1ResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncV1ResourceWithStreamingResponse(self) + + async def systemone( + self, + *, + questions: Dict[str, v1_systemone_params.Questions], + state: Union[str, Dict[str, object], Iterable[object]], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> V1SystemoneResponse: + """ + **Beta API.** Telnyx controls model selection. + + Evaluate shared context using named choice, noul (yes/no), and score questions. + Returns TypeSafe System One-compatible answer shapes, an opaque compatibility + identifier, and token usage. See the + [decision model guide](https://developers.telnyx.com/docs/inference/decision-models) + for examples and compatibility limits. + + The supported request subset requires instructions for every question, string + descriptions for criteria (or null for choice descriptions), 1–64 questions, and + 2–64 options for choice and score questions. The SDK-supplied model value is + ignored and cannot select a model. Other unknown fields are rejected. The + endpoint is synchronous and does not stream. + + Use the TypeSafe Python SDK with base_url set to + https://api.telnyx.com/v2/ai/typesafe and a Telnyx API key. The SDK appends + /v1/systemone. Compatibility covers this operation and the documented request + subset; it does not include TypeSafe model listing. Scores describe relative + preference, not calibrated correctness. + + Args: + questions: Between 1 and 64 named questions. Each key identifies the corresponding answer. + + state: Shared context evaluated by every question. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/ai/typesafe/v1/systemone", + body=await async_maybe_transform( + { + "questions": questions, + "state": state, + }, + v1_systemone_params.V1SystemoneParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1SystemoneResponse, + ) + + +class V1ResourceWithRawResponse: + def __init__(self, v1: V1Resource) -> None: + self._v1 = v1 + + self.systemone = to_raw_response_wrapper( + v1.systemone, + ) + + +class AsyncV1ResourceWithRawResponse: + def __init__(self, v1: AsyncV1Resource) -> None: + self._v1 = v1 + + self.systemone = async_to_raw_response_wrapper( + v1.systemone, + ) + + +class V1ResourceWithStreamingResponse: + def __init__(self, v1: V1Resource) -> None: + self._v1 = v1 + + self.systemone = to_streamed_response_wrapper( + v1.systemone, + ) + + +class AsyncV1ResourceWithStreamingResponse: + def __init__(self, v1: AsyncV1Resource) -> None: + self._v1 = v1 + + self.systemone = async_to_streamed_response_wrapper( + v1.systemone, + ) diff --git a/src/telnyx/resources/bot_challenge.py b/src/telnyx/resources/bot_challenge.py new file mode 100644 index 000000000..de263a354 --- /dev/null +++ b/src/telnyx/resources/bot_challenge.py @@ -0,0 +1,221 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import bot_challenge_create_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.bot_challenge_create_response import BotChallengeCreateResponse + +__all__ = ["BotChallengeResource", "AsyncBotChallengeResource"] + + +class BotChallengeResource(SyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> BotChallengeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return BotChallengeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BotChallengeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return BotChallengeResourceWithStreamingResponse(self) + + def create( + self, + *, + llm_model_name: str | Omit = omit, + llm_parameter_count: str | Omit = omit, + llm_quantization: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BotChallengeCreateResponse: + """Generates a reverse-CAPTCHA challenge used to gate the bot signup flow. + + A random + active problem is selected from the pool; math problems are returned obfuscated + (case randomization, symbol injection, spacing noise) with an unobfuscated + rounding instruction appended, while string and binary problems are returned + as-is. The response contains a single-use nonce, the problem text, and the + current terms-and-conditions and privacy-policy URLs, which must be echoed back + on the signup request. Challenges expire after a short window (10 minutes by + default) and can only be answered once. This endpoint is public and + unauthenticated. + + Args: + llm_model_name: Name of the LLM the client is using. + + llm_parameter_count: Parameter count of the client LLM. + + llm_quantization: Quantization of the client LLM. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v2/bot_challenge", + body=maybe_transform( + { + "llm_model_name": llm_model_name, + "llm_parameter_count": llm_parameter_count, + "llm_quantization": llm_quantization, + }, + bot_challenge_create_params.BotChallengeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BotChallengeCreateResponse, + ) + + +class AsyncBotChallengeResource(AsyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> AsyncBotChallengeResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncBotChallengeResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBotChallengeResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncBotChallengeResourceWithStreamingResponse(self) + + async def create( + self, + *, + llm_model_name: str | Omit = omit, + llm_parameter_count: str | Omit = omit, + llm_quantization: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BotChallengeCreateResponse: + """Generates a reverse-CAPTCHA challenge used to gate the bot signup flow. + + A random + active problem is selected from the pool; math problems are returned obfuscated + (case randomization, symbol injection, spacing noise) with an unobfuscated + rounding instruction appended, while string and binary problems are returned + as-is. The response contains a single-use nonce, the problem text, and the + current terms-and-conditions and privacy-policy URLs, which must be echoed back + on the signup request. Challenges expire after a short window (10 minutes by + default) and can only be answered once. This endpoint is public and + unauthenticated. + + Args: + llm_model_name: Name of the LLM the client is using. + + llm_parameter_count: Parameter count of the client LLM. + + llm_quantization: Quantization of the client LLM. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v2/bot_challenge", + body=await async_maybe_transform( + { + "llm_model_name": llm_model_name, + "llm_parameter_count": llm_parameter_count, + "llm_quantization": llm_quantization, + }, + bot_challenge_create_params.BotChallengeCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BotChallengeCreateResponse, + ) + + +class BotChallengeResourceWithRawResponse: + def __init__(self, bot_challenge: BotChallengeResource) -> None: + self._bot_challenge = bot_challenge + + self.create = to_raw_response_wrapper( + bot_challenge.create, + ) + + +class AsyncBotChallengeResourceWithRawResponse: + def __init__(self, bot_challenge: AsyncBotChallengeResource) -> None: + self._bot_challenge = bot_challenge + + self.create = async_to_raw_response_wrapper( + bot_challenge.create, + ) + + +class BotChallengeResourceWithStreamingResponse: + def __init__(self, bot_challenge: BotChallengeResource) -> None: + self._bot_challenge = bot_challenge + + self.create = to_streamed_response_wrapper( + bot_challenge.create, + ) + + +class AsyncBotChallengeResourceWithStreamingResponse: + def __init__(self, bot_challenge: AsyncBotChallengeResource) -> None: + self._bot_challenge = bot_challenge + + self.create = async_to_streamed_response_wrapper( + bot_challenge.create, + ) diff --git a/src/telnyx/resources/bot_sessions.py b/src/telnyx/resources/bot_sessions.py new file mode 100644 index 000000000..702ac307f --- /dev/null +++ b/src/telnyx/resources/bot_sessions.py @@ -0,0 +1,223 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import bot_session_list_params +from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.bot_session_list_response import BotSessionListResponse + +__all__ = ["BotSessionsResource", "AsyncBotSessionsResource"] + + +class BotSessionsResource(SyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> BotSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return BotSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BotSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return BotSessionsResourceWithStreamingResponse(self) + + def list( + self, + *, + email: str, + portal_redirect_token: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BotSessionListResponse: + """ + Consumes the one-time portal redirect (magic link) token emailed during bot + signup and returns an API session. The token is a UUIDv7 that encodes its + creation time; it expires after a configurable validity window (15 minutes by + default) and is cleared on first use. Although the action creates a session, the + route uses the GET verb because it is opened from an email link. On first use + the account is also initialized. For bot signup (freemium) accounts the response + is a minimal envelope containing only the `api_v2_token`; accounts that are + permitted to use magic links but are not freemium accounts may instead receive + an extended session payload when additional steps (such as two-factor + authentication or identity verification) are required. This endpoint is public; + the magic link token in the query string is the credential. + + Args: + email: Email address associated with the magic link token. + + portal_redirect_token: Single-use portal redirect (magic link) token, a UUIDv7 sent to the account + owner's email. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/v2/bot_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "email": email, + "portal_redirect_token": portal_redirect_token, + }, + bot_session_list_params.BotSessionListParams, + ), + ), + cast_to=BotSessionListResponse, + ) + + +class AsyncBotSessionsResource(AsyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> AsyncBotSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncBotSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBotSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncBotSessionsResourceWithStreamingResponse(self) + + async def list( + self, + *, + email: str, + portal_redirect_token: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BotSessionListResponse: + """ + Consumes the one-time portal redirect (magic link) token emailed during bot + signup and returns an API session. The token is a UUIDv7 that encodes its + creation time; it expires after a configurable validity window (15 minutes by + default) and is cleared on first use. Although the action creates a session, the + route uses the GET verb because it is opened from an email link. On first use + the account is also initialized. For bot signup (freemium) accounts the response + is a minimal envelope containing only the `api_v2_token`; accounts that are + permitted to use magic links but are not freemium accounts may instead receive + an extended session payload when additional steps (such as two-factor + authentication or identity verification) are required. This endpoint is public; + the magic link token in the query string is the credential. + + Args: + email: Email address associated with the magic link token. + + portal_redirect_token: Single-use portal redirect (magic link) token, a UUIDv7 sent to the account + owner's email. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/v2/bot_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "email": email, + "portal_redirect_token": portal_redirect_token, + }, + bot_session_list_params.BotSessionListParams, + ), + ), + cast_to=BotSessionListResponse, + ) + + +class BotSessionsResourceWithRawResponse: + def __init__(self, bot_sessions: BotSessionsResource) -> None: + self._bot_sessions = bot_sessions + + self.list = to_raw_response_wrapper( + bot_sessions.list, + ) + + +class AsyncBotSessionsResourceWithRawResponse: + def __init__(self, bot_sessions: AsyncBotSessionsResource) -> None: + self._bot_sessions = bot_sessions + + self.list = async_to_raw_response_wrapper( + bot_sessions.list, + ) + + +class BotSessionsResourceWithStreamingResponse: + def __init__(self, bot_sessions: BotSessionsResource) -> None: + self._bot_sessions = bot_sessions + + self.list = to_streamed_response_wrapper( + bot_sessions.list, + ) + + +class AsyncBotSessionsResourceWithStreamingResponse: + def __init__(self, bot_sessions: AsyncBotSessionsResource) -> None: + self._bot_sessions = bot_sessions + + self.list = async_to_streamed_response_wrapper( + bot_sessions.list, + ) diff --git a/src/telnyx/resources/bot_signup.py b/src/telnyx/resources/bot_signup.py new file mode 100644 index 000000000..6492d523b --- /dev/null +++ b/src/telnyx/resources/bot_signup.py @@ -0,0 +1,367 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..types import bot_signup_create_params, bot_signup_resend_magic_link_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.success_response import SuccessResponse + +__all__ = ["BotSignupResource", "AsyncBotSignupResource"] + + +class BotSignupResource(SyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> BotSignupResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return BotSignupResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BotSignupResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return BotSignupResourceWithStreamingResponse(self) + + def create( + self, + *, + bot_challenge_answer: str, + bot_challenge_nonce: str, + privacy_policy_url: str, + terms_and_conditions_url: str, + terms_of_service: Literal[True], + email: str | Omit = omit, + terms_and_conditions_eu_url: str | Omit = omit, + terms_of_service_eu: Literal[True] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SuccessResponse: + """Creates a freemium Telnyx account through the agentic signup flow. + + The request + must carry a valid answer to a previously issued bot challenge + (`bot_challenge_nonce` and `bot_challenge_answer`), accept the terms of service, + and echo the exact terms-and-conditions and privacy-policy URLs returned by the + challenge endpoint. When EU consent enforcement is enabled, + `terms_of_service_eu` and `terms_and_conditions_eu_url` are also required. On + success a one-time sign-in (magic) link is emailed to the address provided; if + the email address belongs to an existing account, a sign-in link is sent instead + of creating a duplicate account. `email` may only be omitted when + placeholder-email registration is enabled server-side. This endpoint is public + and unauthenticated, gated by the freemium feature flags and per-country + availability, and subject to per-IP and per-domain registration limits. + + Args: + bot_challenge_answer: Answer to the issued bot challenge. + + bot_challenge_nonce: Nonce from a previously issued bot challenge. + + privacy_policy_url: Must exactly match the privacy-policy URL returned by the challenge endpoint. + + terms_and_conditions_url: Must exactly match the terms-and-conditions URL returned by the challenge + endpoint. + + terms_of_service: Must be true to accept the terms of service. + + email: Email address for the new account. The magic link is sent here. May only be + omitted when placeholder-email registration is enabled server-side. + + terms_and_conditions_eu_url: EU terms-and-conditions URL. Required when EU consent enforcement is enabled. + + terms_of_service_eu: EU terms-of-service acceptance. Required when EU consent enforcement is enabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v2/bot_signup", + body=maybe_transform( + { + "bot_challenge_answer": bot_challenge_answer, + "bot_challenge_nonce": bot_challenge_nonce, + "privacy_policy_url": privacy_policy_url, + "terms_and_conditions_url": terms_and_conditions_url, + "terms_of_service": terms_of_service, + "email": email, + "terms_and_conditions_eu_url": terms_and_conditions_eu_url, + "terms_of_service_eu": terms_of_service_eu, + }, + bot_signup_create_params.BotSignupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SuccessResponse, + ) + + def resend_magic_link( + self, + *, + email: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SuccessResponse: + """ + Resends the one-time sign-in (magic) link for an eligible bot signup account. + Eligibility (account exists, was registered through bot signup, is active, and + has not exceeded the resend limit or rate window) is evaluated server-side; the + response is intentionally uniform and does not reveal whether the account exists + or whether a link was actually sent. This endpoint is public and + unauthenticated, gated by the freemium feature flags and per-country + availability. + + Args: + email: Email address of the bot signup account to resend the magic link to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/v2/bot_signup/resend_magic_link", + body=maybe_transform({"email": email}, bot_signup_resend_magic_link_params.BotSignupResendMagicLinkParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SuccessResponse, + ) + + +class AsyncBotSignupResource(AsyncAPIResource): + """Agentic (bot) signup for Telnyx accounts. + + An AI agent solves a reverse-CAPTCHA challenge designed to be easy for LLMs and hard for humans, registers an account, and signs in by consuming a magic link emailed to the account owner. All endpoints are public and unauthenticated; signup endpoints are additionally gated by the freemium feature flags and per-country availability. + """ + + @cached_property + def with_raw_response(self) -> AsyncBotSignupResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncBotSignupResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBotSignupResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncBotSignupResourceWithStreamingResponse(self) + + async def create( + self, + *, + bot_challenge_answer: str, + bot_challenge_nonce: str, + privacy_policy_url: str, + terms_and_conditions_url: str, + terms_of_service: Literal[True], + email: str | Omit = omit, + terms_and_conditions_eu_url: str | Omit = omit, + terms_of_service_eu: Literal[True] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SuccessResponse: + """Creates a freemium Telnyx account through the agentic signup flow. + + The request + must carry a valid answer to a previously issued bot challenge + (`bot_challenge_nonce` and `bot_challenge_answer`), accept the terms of service, + and echo the exact terms-and-conditions and privacy-policy URLs returned by the + challenge endpoint. When EU consent enforcement is enabled, + `terms_of_service_eu` and `terms_and_conditions_eu_url` are also required. On + success a one-time sign-in (magic) link is emailed to the address provided; if + the email address belongs to an existing account, a sign-in link is sent instead + of creating a duplicate account. `email` may only be omitted when + placeholder-email registration is enabled server-side. This endpoint is public + and unauthenticated, gated by the freemium feature flags and per-country + availability, and subject to per-IP and per-domain registration limits. + + Args: + bot_challenge_answer: Answer to the issued bot challenge. + + bot_challenge_nonce: Nonce from a previously issued bot challenge. + + privacy_policy_url: Must exactly match the privacy-policy URL returned by the challenge endpoint. + + terms_and_conditions_url: Must exactly match the terms-and-conditions URL returned by the challenge + endpoint. + + terms_of_service: Must be true to accept the terms of service. + + email: Email address for the new account. The magic link is sent here. May only be + omitted when placeholder-email registration is enabled server-side. + + terms_and_conditions_eu_url: EU terms-and-conditions URL. Required when EU consent enforcement is enabled. + + terms_of_service_eu: EU terms-of-service acceptance. Required when EU consent enforcement is enabled. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v2/bot_signup", + body=await async_maybe_transform( + { + "bot_challenge_answer": bot_challenge_answer, + "bot_challenge_nonce": bot_challenge_nonce, + "privacy_policy_url": privacy_policy_url, + "terms_and_conditions_url": terms_and_conditions_url, + "terms_of_service": terms_of_service, + "email": email, + "terms_and_conditions_eu_url": terms_and_conditions_eu_url, + "terms_of_service_eu": terms_of_service_eu, + }, + bot_signup_create_params.BotSignupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SuccessResponse, + ) + + async def resend_magic_link( + self, + *, + email: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SuccessResponse: + """ + Resends the one-time sign-in (magic) link for an eligible bot signup account. + Eligibility (account exists, was registered through bot signup, is active, and + has not exceeded the resend limit or rate window) is evaluated server-side; the + response is intentionally uniform and does not reveal whether the account exists + or whether a link was actually sent. This endpoint is public and + unauthenticated, gated by the freemium feature flags and per-country + availability. + + Args: + email: Email address of the bot signup account to resend the magic link to. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/v2/bot_signup/resend_magic_link", + body=await async_maybe_transform( + {"email": email}, bot_signup_resend_magic_link_params.BotSignupResendMagicLinkParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SuccessResponse, + ) + + +class BotSignupResourceWithRawResponse: + def __init__(self, bot_signup: BotSignupResource) -> None: + self._bot_signup = bot_signup + + self.create = to_raw_response_wrapper( + bot_signup.create, + ) + self.resend_magic_link = to_raw_response_wrapper( + bot_signup.resend_magic_link, + ) + + +class AsyncBotSignupResourceWithRawResponse: + def __init__(self, bot_signup: AsyncBotSignupResource) -> None: + self._bot_signup = bot_signup + + self.create = async_to_raw_response_wrapper( + bot_signup.create, + ) + self.resend_magic_link = async_to_raw_response_wrapper( + bot_signup.resend_magic_link, + ) + + +class BotSignupResourceWithStreamingResponse: + def __init__(self, bot_signup: BotSignupResource) -> None: + self._bot_signup = bot_signup + + self.create = to_streamed_response_wrapper( + bot_signup.create, + ) + self.resend_magic_link = to_streamed_response_wrapper( + bot_signup.resend_magic_link, + ) + + +class AsyncBotSignupResourceWithStreamingResponse: + def __init__(self, bot_signup: AsyncBotSignupResource) -> None: + self._bot_signup = bot_signup + + self.create = async_to_streamed_response_wrapper( + bot_signup.create, + ) + self.resend_magic_link = async_to_streamed_response_wrapper( + bot_signup.resend_magic_link, + ) diff --git a/src/telnyx/resources/calls/actions.py b/src/telnyx/resources/calls/actions.py index fb47700f6..c6c8c5eb2 100644 --- a/src/telnyx/resources/calls/actions.py +++ b/src/telnyx/resources/calls/actions.py @@ -4019,11 +4019,12 @@ def transfer( custom_headers: Custom headers to be added to the SIP INVITE. - diversion: The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + diversion: The `to` number of an active inbound call, in +E164 format. Telnyx checks + whether there is currently an active inbound call where `to` matches this + `diversion` value and `from` matches the `from` number supplied for this + request. If such a call exists, the `from` number is treated as verified (since + it is already on an active inbound call to you) and can be used as the caller id + for this outbound call. early_media: If set to false, early media will not be passed to the originating leg. @@ -8143,11 +8144,12 @@ async def transfer( custom_headers: Custom headers to be added to the SIP INVITE. - diversion: The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + diversion: The `to` number of an active inbound call, in +E164 format. Telnyx checks + whether there is currently an active inbound call where `to` matches this + `diversion` value and `from` matches the `from` number supplied for this + request. If such a call exists, the `from` number is treated as verified (since + it is already on an active inbound call to you) and can be used as the caller id + for this outbound call. early_media: If set to false, early media will not be passed to the originating leg. diff --git a/src/telnyx/resources/calls/calls.py b/src/telnyx/resources/calls/calls.py index 1b14cf68e..d12e0b6d5 100644 --- a/src/telnyx/resources/calls/calls.py +++ b/src/telnyx/resources/calls/calls.py @@ -264,11 +264,12 @@ def dial( AI-generated. Results are delivered via the `call.deepfake_detection.result` webhook. - diversion: The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + diversion: The `to` number of an active inbound call, in +E164 format. Telnyx checks + whether there is currently an active inbound call where `to` matches this + `diversion` value and `from` matches the `from` number supplied for this + request. If such a call exists, the `from` number is treated as verified (since + it is already on an active inbound call to you) and can be used as the caller id + for this outbound call. enable_dialogflow: Enables Dialogflow for the current call. The default value is false. @@ -761,11 +762,12 @@ async def dial( AI-generated. Results are delivered via the `call.deepfake_detection.result` webhook. - diversion: The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + diversion: The `to` number of an active inbound call, in +E164 format. Telnyx checks + whether there is currently an active inbound call where `to` matches this + `diversion` value and `from` matches the `from` number supplied for this + request. If such a call exists, the `from` number is treated as verified (since + it is already on an active inbound call to you) and can be used as the caller id + for this outbound call. enable_dialogflow: Enables Dialogflow for the current call. The default value is false. diff --git a/src/telnyx/resources/compute/compute.py b/src/telnyx/resources/compute/compute.py index 5a77c3552..819bc2039 100644 --- a/src/telnyx/resources/compute/compute.py +++ b/src/telnyx/resources/compute/compute.py @@ -2,7 +2,9 @@ from __future__ import annotations -from .funcs import ( +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from .funcs.funcs import ( FuncsResource, AsyncFuncsResource, FuncsResourceWithRawResponse, @@ -10,8 +12,6 @@ FuncsResourceWithStreamingResponse, AsyncFuncsResourceWithStreamingResponse, ) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource __all__ = ["ComputeResource", "AsyncComputeResource"] diff --git a/src/telnyx/resources/compute/funcs/__init__.py b/src/telnyx/resources/compute/funcs/__init__.py new file mode 100644 index 000000000..6c19a73cf --- /dev/null +++ b/src/telnyx/resources/compute/funcs/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .funcs import ( + FuncsResource, + AsyncFuncsResource, + FuncsResourceWithRawResponse, + AsyncFuncsResourceWithRawResponse, + FuncsResourceWithStreamingResponse, + AsyncFuncsResourceWithStreamingResponse, +) +from .export import ( + ExportResource, + AsyncExportResource, + ExportResourceWithRawResponse, + AsyncExportResourceWithRawResponse, + ExportResourceWithStreamingResponse, + AsyncExportResourceWithStreamingResponse, +) + +__all__ = [ + "ExportResource", + "AsyncExportResource", + "ExportResourceWithRawResponse", + "AsyncExportResourceWithRawResponse", + "ExportResourceWithStreamingResponse", + "AsyncExportResourceWithStreamingResponse", + "FuncsResource", + "AsyncFuncsResource", + "FuncsResourceWithRawResponse", + "AsyncFuncsResourceWithRawResponse", + "FuncsResourceWithStreamingResponse", + "AsyncFuncsResourceWithStreamingResponse", +] diff --git a/src/telnyx/resources/compute/funcs/export.py b/src/telnyx/resources/compute/funcs/export.py new file mode 100644 index 000000000..269bfaa9b --- /dev/null +++ b/src/telnyx/resources/compute/funcs/export.py @@ -0,0 +1,399 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict + +import httpx + +from ...._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.compute.funcs import export_create_params +from ....types.compute.funcs.func_log_export_config_response import FuncLogExportConfigResponse + +__all__ = ["ExportResource", "AsyncExportResource"] + + +class ExportResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExportResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return ExportResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExportResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return ExportResourceWithStreamingResponse(self) + + def create( + self, + id: str, + *, + endpoint: str, + headers: Dict[str, str], + invocation_export_enabled: bool, + runtime_export_enabled: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FuncLogExportConfigResponse: + """ + Configures the external OTLP endpoint a function's runtime and/or invocation + logs are pushed to as they happen. This operation is a **full replace, not a + patch**: `endpoint`, `headers`, `runtime_export_enabled`, and + `invocation_export_enabled` are all required on every call — omitting any of + them is a 422, not "keep the current value". Headers are encrypted at rest and + never returned in any response. + + The endpoint must be an HTTPS URL. When export is configured, new log records + are converted to OTLP log records and delivered continuously; export never + bypasses platform log storage, and delivery retries with a bounded policy while + the destination is unreachable. Only logs generated after configuration are + exported — there is no historical replay. + + Args: + endpoint: HTTPS URL to push logs to + + headers: Headers attached to every export push, as key-value pairs (e.g. an auth token + the collector expects). Required even when empty — {} means "no headers". + Encrypted at rest; never returned. + + invocation_export_enabled: Export invocation records (one per HTTP request) to this destination + + runtime_export_enabled: Export runtime logs (function stdout/stderr) to this destination + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._put( + path_template("/compute/funcs/{id}/logs/export", id=id), + body=maybe_transform( + { + "endpoint": endpoint, + "headers": headers, + "invocation_export_enabled": invocation_export_enabled, + "runtime_export_enabled": runtime_export_enabled, + }, + export_create_params.ExportCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FuncLogExportConfigResponse, + ) + + def list( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FuncLogExportConfigResponse: + """ + Returns the function's configured log export destination and which log types are + exported. Headers are never returned. Returns 404 (error code 10005) when no + destination is configured for the function. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/compute/funcs/{id}/logs/export", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FuncLogExportConfigResponse, + ) + + def delete_all( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Stops exporting a function's logs and removes its destination configuration. + Idempotent: deleting when nothing is configured succeeds. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/compute/funcs/{id}/logs/export", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncExportResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExportResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncExportResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExportResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncExportResourceWithStreamingResponse(self) + + async def create( + self, + id: str, + *, + endpoint: str, + headers: Dict[str, str], + invocation_export_enabled: bool, + runtime_export_enabled: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FuncLogExportConfigResponse: + """ + Configures the external OTLP endpoint a function's runtime and/or invocation + logs are pushed to as they happen. This operation is a **full replace, not a + patch**: `endpoint`, `headers`, `runtime_export_enabled`, and + `invocation_export_enabled` are all required on every call — omitting any of + them is a 422, not "keep the current value". Headers are encrypted at rest and + never returned in any response. + + The endpoint must be an HTTPS URL. When export is configured, new log records + are converted to OTLP log records and delivered continuously; export never + bypasses platform log storage, and delivery retries with a bounded policy while + the destination is unreachable. Only logs generated after configuration are + exported — there is no historical replay. + + Args: + endpoint: HTTPS URL to push logs to + + headers: Headers attached to every export push, as key-value pairs (e.g. an auth token + the collector expects). Required even when empty — {} means "no headers". + Encrypted at rest; never returned. + + invocation_export_enabled: Export invocation records (one per HTTP request) to this destination + + runtime_export_enabled: Export runtime logs (function stdout/stderr) to this destination + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._put( + path_template("/compute/funcs/{id}/logs/export", id=id), + body=await async_maybe_transform( + { + "endpoint": endpoint, + "headers": headers, + "invocation_export_enabled": invocation_export_enabled, + "runtime_export_enabled": runtime_export_enabled, + }, + export_create_params.ExportCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FuncLogExportConfigResponse, + ) + + async def list( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> FuncLogExportConfigResponse: + """ + Returns the function's configured log export destination and which log types are + exported. Headers are never returned. Returns 404 (error code 10005) when no + destination is configured for the function. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/compute/funcs/{id}/logs/export", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FuncLogExportConfigResponse, + ) + + async def delete_all( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Stops exporting a function's logs and removes its destination configuration. + Idempotent: deleting when nothing is configured succeeds. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/compute/funcs/{id}/logs/export", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ExportResourceWithRawResponse: + def __init__(self, export: ExportResource) -> None: + self._export = export + + self.create = to_raw_response_wrapper( + export.create, + ) + self.list = to_raw_response_wrapper( + export.list, + ) + self.delete_all = to_raw_response_wrapper( + export.delete_all, + ) + + +class AsyncExportResourceWithRawResponse: + def __init__(self, export: AsyncExportResource) -> None: + self._export = export + + self.create = async_to_raw_response_wrapper( + export.create, + ) + self.list = async_to_raw_response_wrapper( + export.list, + ) + self.delete_all = async_to_raw_response_wrapper( + export.delete_all, + ) + + +class ExportResourceWithStreamingResponse: + def __init__(self, export: ExportResource) -> None: + self._export = export + + self.create = to_streamed_response_wrapper( + export.create, + ) + self.list = to_streamed_response_wrapper( + export.list, + ) + self.delete_all = to_streamed_response_wrapper( + export.delete_all, + ) + + +class AsyncExportResourceWithStreamingResponse: + def __init__(self, export: AsyncExportResource) -> None: + self._export = export + + self.create = async_to_streamed_response_wrapper( + export.create, + ) + self.list = async_to_streamed_response_wrapper( + export.list, + ) + self.delete_all = async_to_streamed_response_wrapper( + export.delete_all, + ) diff --git a/src/telnyx/resources/compute/funcs.py b/src/telnyx/resources/compute/funcs/funcs.py similarity index 92% rename from src/telnyx/resources/compute/funcs.py rename to src/telnyx/resources/compute/funcs/funcs.py index 512b8839d..3c62edd12 100644 --- a/src/telnyx/resources/compute/funcs.py +++ b/src/telnyx/resources/compute/funcs/funcs.py @@ -8,31 +8,43 @@ import httpx -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( +from .export import ( + ExportResource, + AsyncExportResource, + ExportResourceWithRawResponse, + AsyncExportResourceWithRawResponse, + ExportResourceWithStreamingResponse, + AsyncExportResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( to_raw_response_wrapper, to_streamed_response_wrapper, async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ..._base_client import make_request_options -from ...types.compute import ( +from ...._base_client import make_request_options +from ....types.compute import ( func_retrieve_logs_params, func_retrieve_revisions_params, func_retrieve_metric_aggregates_params, ) -from ...types.compute.func_retrieve_logs_response import FuncRetrieveLogsResponse -from ...types.compute.func_retrieve_revisions_response import FuncRetrieveRevisionsResponse -from ...types.compute.func_retrieve_ship_inspection_response import FuncRetrieveShipInspectionResponse -from ...types.compute.func_retrieve_metric_aggregates_response import FuncRetrieveMetricAggregatesResponse +from ....types.compute.func_retrieve_logs_response import FuncRetrieveLogsResponse +from ....types.compute.func_retrieve_revisions_response import FuncRetrieveRevisionsResponse +from ....types.compute.func_retrieve_ship_inspection_response import FuncRetrieveShipInspectionResponse +from ....types.compute.func_retrieve_metric_aggregates_response import FuncRetrieveMetricAggregatesResponse __all__ = ["FuncsResource", "AsyncFuncsResource"] class FuncsResource(SyncAPIResource): + @cached_property + def export(self) -> ExportResource: + return ExportResource(self._client) + @cached_property def with_raw_response(self) -> FuncsResourceWithRawResponse: """ @@ -264,6 +276,10 @@ def retrieve_ship_inspection( class AsyncFuncsResource(AsyncAPIResource): + @cached_property + def export(self) -> AsyncExportResource: + return AsyncExportResource(self._client) + @cached_property def with_raw_response(self) -> AsyncFuncsResourceWithRawResponse: """ @@ -511,6 +527,10 @@ def __init__(self, funcs: FuncsResource) -> None: funcs.retrieve_ship_inspection, ) + @cached_property + def export(self) -> ExportResourceWithRawResponse: + return ExportResourceWithRawResponse(self._funcs.export) + class AsyncFuncsResourceWithRawResponse: def __init__(self, funcs: AsyncFuncsResource) -> None: @@ -529,6 +549,10 @@ def __init__(self, funcs: AsyncFuncsResource) -> None: funcs.retrieve_ship_inspection, ) + @cached_property + def export(self) -> AsyncExportResourceWithRawResponse: + return AsyncExportResourceWithRawResponse(self._funcs.export) + class FuncsResourceWithStreamingResponse: def __init__(self, funcs: FuncsResource) -> None: @@ -547,6 +571,10 @@ def __init__(self, funcs: FuncsResource) -> None: funcs.retrieve_ship_inspection, ) + @cached_property + def export(self) -> ExportResourceWithStreamingResponse: + return ExportResourceWithStreamingResponse(self._funcs.export) + class AsyncFuncsResourceWithStreamingResponse: def __init__(self, funcs: AsyncFuncsResource) -> None: @@ -564,3 +592,7 @@ def __init__(self, funcs: AsyncFuncsResource) -> None: self.retrieve_ship_inspection = async_to_streamed_response_wrapper( funcs.retrieve_ship_inspection, ) + + @cached_property + def export(self) -> AsyncExportResourceWithStreamingResponse: + return AsyncExportResourceWithStreamingResponse(self._funcs.export) diff --git a/src/telnyx/resources/connections.py b/src/telnyx/resources/connections.py index 91f6fa264..7acb3e9a8 100644 --- a/src/telnyx/resources/connections.py +++ b/src/telnyx/resources/connections.py @@ -21,6 +21,7 @@ from .._base_client import AsyncPaginator, make_request_options from ..types.connection import Connection from ..types.connection_retrieve_response import ConnectionRetrieveResponse +from ..types.connection_retrieve_count_response import ConnectionRetrieveCountResponse from ..types.connection_list_active_calls_response import ConnectionListActiveCallsResponse __all__ = ["ConnectionsResource", "AsyncConnectionsResource"] @@ -197,6 +198,29 @@ def list_active_calls( model=ConnectionListActiveCallsResponse, ) + def retrieve_count( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectionRetrieveCountResponse: + """ + Returns the number of connections associated with the authenticated user, + grouped by connection type, together with the connection limits that apply to + the user. Forward-only connections are excluded from the counts. + """ + return self._get( + "/connections/count", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectionRetrieveCountResponse, + ) + class AsyncConnectionsResource(AsyncAPIResource): @cached_property @@ -371,6 +395,29 @@ def list_active_calls( model=ConnectionListActiveCallsResponse, ) + async def retrieve_count( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConnectionRetrieveCountResponse: + """ + Returns the number of connections associated with the authenticated user, + grouped by connection type, together with the connection limits that apply to + the user. Forward-only connections are excluded from the counts. + """ + return await self._get( + "/connections/count", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectionRetrieveCountResponse, + ) + class ConnectionsResourceWithRawResponse: def __init__(self, connections: ConnectionsResource) -> None: @@ -385,6 +432,9 @@ def __init__(self, connections: ConnectionsResource) -> None: self.list_active_calls = to_raw_response_wrapper( connections.list_active_calls, ) + self.retrieve_count = to_raw_response_wrapper( + connections.retrieve_count, + ) class AsyncConnectionsResourceWithRawResponse: @@ -400,6 +450,9 @@ def __init__(self, connections: AsyncConnectionsResource) -> None: self.list_active_calls = async_to_raw_response_wrapper( connections.list_active_calls, ) + self.retrieve_count = async_to_raw_response_wrapper( + connections.retrieve_count, + ) class ConnectionsResourceWithStreamingResponse: @@ -415,6 +468,9 @@ def __init__(self, connections: ConnectionsResource) -> None: self.list_active_calls = to_streamed_response_wrapper( connections.list_active_calls, ) + self.retrieve_count = to_streamed_response_wrapper( + connections.retrieve_count, + ) class AsyncConnectionsResourceWithStreamingResponse: @@ -430,3 +486,6 @@ def __init__(self, connections: AsyncConnectionsResource) -> None: self.list_active_calls = async_to_streamed_response_wrapper( connections.list_active_calls, ) + self.retrieve_count = async_to_streamed_response_wrapper( + connections.retrieve_count, + ) diff --git a/src/telnyx/resources/detail_records.py b/src/telnyx/resources/detail_records.py index df6bbafaf..f98825951 100644 --- a/src/telnyx/resources/detail_records.py +++ b/src/telnyx/resources/detail_records.py @@ -67,8 +67,19 @@ def list( filter: Filter records on a given record attribute and value.
Example: filter[status]=delivered.
Required: filter[record_type] must be specified. - - sort: Specifies the sort order for results.
Example: sort=-created_at +
The valid filter fields depend on the record_type: filtering by a field + that does not exist for the selected record_type is rejected with a 400 error. + Call-control and sip-trunking records use started_at, finished_at and + answered_at (they have no created_at); messaging records use created_at. To list + the fields available for a record_type, use the /v2/detail_records/options + endpoint. + + sort: Specifies the sort order for results.
Example: sort=-created_at
The + valid sort fields depend on the record_type: sort by a field that does not exist + for the selected record_type is rejected with a 400 error. Call-control and + sip-trunking records use started_at, finished_at and answered_at (they have no + created_at); messaging records use created_at. To list the fields available for + a record_type, use the /v2/detail_records/options endpoint. extra_headers: Send extra headers @@ -145,8 +156,19 @@ def list( filter: Filter records on a given record attribute and value.
Example: filter[status]=delivered.
Required: filter[record_type] must be specified. - - sort: Specifies the sort order for results.
Example: sort=-created_at +
The valid filter fields depend on the record_type: filtering by a field + that does not exist for the selected record_type is rejected with a 400 error. + Call-control and sip-trunking records use started_at, finished_at and + answered_at (they have no created_at); messaging records use created_at. To list + the fields available for a record_type, use the /v2/detail_records/options + endpoint. + + sort: Specifies the sort order for results.
Example: sort=-created_at
The + valid sort fields depend on the record_type: sort by a field that does not exist + for the selected record_type is rejected with a 400 error. Call-control and + sip-trunking records use started_at, finished_at and answered_at (they have no + created_at); messaging records use created_at. To list the fields available for + a record_type, use the /v2/detail_records/options endpoint. extra_headers: Send extra headers diff --git a/src/telnyx/resources/email_messages/email_messages.py b/src/telnyx/resources/email_messages/email_messages.py index c8d444293..574c5efc6 100644 --- a/src/telnyx/resources/email_messages/email_messages.py +++ b/src/telnyx/resources/email_messages/email_messages.py @@ -384,9 +384,11 @@ def batch( ) -> EmailMessageBatchResponse: """Creates up to 1,000 email messages in a single request. - Each message is - validated and sent independently; per-message failures do not affect other - messages in the batch. All responses use 207 Multi-Status. + Request-wide admission + checks run first and can reject the whole batch before message creation. After + those checks pass, each message is validated and sent independently; item-level + failures do not affect other messages, and the processed batch returns 207 + Multi-Status. Args: messages: Array of email messages to send. Up to 1,000 messages per batch request. Each @@ -891,9 +893,11 @@ async def batch( ) -> EmailMessageBatchResponse: """Creates up to 1,000 email messages in a single request. - Each message is - validated and sent independently; per-message failures do not affect other - messages in the batch. All responses use 207 Multi-Status. + Request-wide admission + checks run first and can reject the whole batch before message creation. After + those checks pass, each message is validated and sent independently; item-level + failures do not affect other messages, and the processed batch returns 207 + Multi-Status. Args: messages: Array of email messages to send. Up to 1,000 messages per batch request. Each diff --git a/src/telnyx/resources/machine_payments.py b/src/telnyx/resources/machine_payments.py new file mode 100644 index 000000000..d8abc8c94 --- /dev/null +++ b/src/telnyx/resources/machine_payments.py @@ -0,0 +1,251 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import machine_payment_account_credit_params +from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.machine_payment_account_credit_response import MachinePaymentAccountCreditResponse + +__all__ = ["MachinePaymentsResource", "AsyncMachinePaymentsResource"] + + +class MachinePaymentsResource(SyncAPIResource): + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + + @cached_property + def with_raw_response(self) -> MachinePaymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return MachinePaymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MachinePaymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return MachinePaymentsResourceWithStreamingResponse(self) + + def account_credit( + self, + *, + amount_usd: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MachinePaymentAccountCreditResponse: + """ + Creates an account credit using the Machine Payment Protocol (MPP), an HTTP-402 + payment flow for machines and agents. + + The flow has two steps. First, send an authenticated request with the + `amount_usd` to credit; the response is `402 Payment Required` with one or more + payment challenges (for example separate Tempo and Stripe challenges) in the + `WWW-Authenticate` header. Second, retry the request with an + `Authorization: Payment ...` credential constructed from the challenge; on + success the response includes the credited transaction and a `Payment-Receipt` + header. + + The credited account is never chosen by the request body: the initial request + credits the account of the authenticated user, and a paid retry credits the + account bound to the verified payment credential. The amount must be within the + configured bounds (by default between 5.00 and 500.00 USD). + + Successful paid retries are idempotent — when Rails reaches its + duplicate-transaction lookup for an already-recorded payment, it returns the + existing transaction with `created: false` instead of crediting the account + again. This deduplication applies to successful fulfillment: re-sending the same + Stripe credential may instead be rejected by the upstream provider as an + idempotent replay and return `402 Payment Required` rather than the existing + transaction. + + > **Warning: the payment credential is bound to a specific Telnyx account ID.** + > A payment is captured before the bound account is validated. If the credential + > names an account that is missing, suspended, blocked, cancelled, dormant, or + > ineligible for the tier, the payment is captured but **no account is + > credited**. If the credential names a different but eligible account, that + > account is credited — the service does not compare it against the payer's + > account. There is **no automatic refund**: if the captured payment does not + > credit the intended account, contact Telnyx support for remediation. + + Args: + amount_usd: Amount to credit in USD, as a decimal string with up to two fractional digits + (by default between 5.00 and 500.00). The request body is required on the + initial challenge request and remains required on a paid retry, where you + re-send the identical body plus the payment credential — the credential, not the + body, selects the payment, and the retried body is not re-validated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/machine-payments/account-credit", + body=maybe_transform( + {"amount_usd": amount_usd}, machine_payment_account_credit_params.MachinePaymentAccountCreditParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MachinePaymentAccountCreditResponse, + ) + + +class AsyncMachinePaymentsResource(AsyncAPIResource): + """Machine payment (MPP) account-credit operations. + + Fund your Telnyx account programmatically from a machine or agent using the Machine Payment Protocol, an HTTP-402 flow settled via Stripe or Tempo. + """ + + @cached_property + def with_raw_response(self) -> AsyncMachinePaymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncMachinePaymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMachinePaymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncMachinePaymentsResourceWithStreamingResponse(self) + + async def account_credit( + self, + *, + amount_usd: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MachinePaymentAccountCreditResponse: + """ + Creates an account credit using the Machine Payment Protocol (MPP), an HTTP-402 + payment flow for machines and agents. + + The flow has two steps. First, send an authenticated request with the + `amount_usd` to credit; the response is `402 Payment Required` with one or more + payment challenges (for example separate Tempo and Stripe challenges) in the + `WWW-Authenticate` header. Second, retry the request with an + `Authorization: Payment ...` credential constructed from the challenge; on + success the response includes the credited transaction and a `Payment-Receipt` + header. + + The credited account is never chosen by the request body: the initial request + credits the account of the authenticated user, and a paid retry credits the + account bound to the verified payment credential. The amount must be within the + configured bounds (by default between 5.00 and 500.00 USD). + + Successful paid retries are idempotent — when Rails reaches its + duplicate-transaction lookup for an already-recorded payment, it returns the + existing transaction with `created: false` instead of crediting the account + again. This deduplication applies to successful fulfillment: re-sending the same + Stripe credential may instead be rejected by the upstream provider as an + idempotent replay and return `402 Payment Required` rather than the existing + transaction. + + > **Warning: the payment credential is bound to a specific Telnyx account ID.** + > A payment is captured before the bound account is validated. If the credential + > names an account that is missing, suspended, blocked, cancelled, dormant, or + > ineligible for the tier, the payment is captured but **no account is + > credited**. If the credential names a different but eligible account, that + > account is credited — the service does not compare it against the payer's + > account. There is **no automatic refund**: if the captured payment does not + > credit the intended account, contact Telnyx support for remediation. + + Args: + amount_usd: Amount to credit in USD, as a decimal string with up to two fractional digits + (by default between 5.00 and 500.00). The request body is required on the + initial challenge request and remains required on a paid retry, where you + re-send the identical body plus the payment credential — the credential, not the + body, selects the payment, and the retried body is not re-validated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/machine-payments/account-credit", + body=await async_maybe_transform( + {"amount_usd": amount_usd}, machine_payment_account_credit_params.MachinePaymentAccountCreditParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MachinePaymentAccountCreditResponse, + ) + + +class MachinePaymentsResourceWithRawResponse: + def __init__(self, machine_payments: MachinePaymentsResource) -> None: + self._machine_payments = machine_payments + + self.account_credit = to_raw_response_wrapper( + machine_payments.account_credit, + ) + + +class AsyncMachinePaymentsResourceWithRawResponse: + def __init__(self, machine_payments: AsyncMachinePaymentsResource) -> None: + self._machine_payments = machine_payments + + self.account_credit = async_to_raw_response_wrapper( + machine_payments.account_credit, + ) + + +class MachinePaymentsResourceWithStreamingResponse: + def __init__(self, machine_payments: MachinePaymentsResource) -> None: + self._machine_payments = machine_payments + + self.account_credit = to_streamed_response_wrapper( + machine_payments.account_credit, + ) + + +class AsyncMachinePaymentsResourceWithStreamingResponse: + def __init__(self, machine_payments: AsyncMachinePaymentsResource) -> None: + self._machine_payments = machine_payments + + self.account_credit = async_to_streamed_response_wrapper( + machine_payments.account_credit, + ) diff --git a/src/telnyx/resources/noise_suppression_engines.py b/src/telnyx/resources/noise_suppression_engines.py new file mode 100644 index 000000000..331e6e61f --- /dev/null +++ b/src/telnyx/resources/noise_suppression_engines.py @@ -0,0 +1,153 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Query, Headers, NotGiven, not_given +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.noise_suppression_engine_list_response import NoiseSuppressionEngineListResponse + +__all__ = ["NoiseSuppressionEnginesResource", "AsyncNoiseSuppressionEnginesResource"] + + +class NoiseSuppressionEnginesResource(SyncAPIResource): + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + + @cached_property + def with_raw_response(self) -> NoiseSuppressionEnginesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return NoiseSuppressionEnginesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NoiseSuppressionEnginesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return NoiseSuppressionEnginesResourceWithStreamingResponse(self) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NoiseSuppressionEngineListResponse: + """ + Returns all noise suppression engines available to the authenticated user. + Engines gated behind a feature flag are included only when the flag is enabled + for the user's account. Results are not paginated; the number of engines is + expected to remain small. + """ + return self._get( + "/noise_suppression_engines", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoiseSuppressionEngineListResponse, + ) + + +class AsyncNoiseSuppressionEnginesResource(AsyncAPIResource): + """ + Noise suppression engines that can be selected when configuring noise suppression on voice connections. + """ + + @cached_property + def with_raw_response(self) -> AsyncNoiseSuppressionEnginesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncNoiseSuppressionEnginesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNoiseSuppressionEnginesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncNoiseSuppressionEnginesResourceWithStreamingResponse(self) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NoiseSuppressionEngineListResponse: + """ + Returns all noise suppression engines available to the authenticated user. + Engines gated behind a feature flag are included only when the flag is enabled + for the user's account. Results are not paginated; the number of engines is + expected to remain small. + """ + return await self._get( + "/noise_suppression_engines", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoiseSuppressionEngineListResponse, + ) + + +class NoiseSuppressionEnginesResourceWithRawResponse: + def __init__(self, noise_suppression_engines: NoiseSuppressionEnginesResource) -> None: + self._noise_suppression_engines = noise_suppression_engines + + self.list = to_raw_response_wrapper( + noise_suppression_engines.list, + ) + + +class AsyncNoiseSuppressionEnginesResourceWithRawResponse: + def __init__(self, noise_suppression_engines: AsyncNoiseSuppressionEnginesResource) -> None: + self._noise_suppression_engines = noise_suppression_engines + + self.list = async_to_raw_response_wrapper( + noise_suppression_engines.list, + ) + + +class NoiseSuppressionEnginesResourceWithStreamingResponse: + def __init__(self, noise_suppression_engines: NoiseSuppressionEnginesResource) -> None: + self._noise_suppression_engines = noise_suppression_engines + + self.list = to_streamed_response_wrapper( + noise_suppression_engines.list, + ) + + +class AsyncNoiseSuppressionEnginesResourceWithStreamingResponse: + def __init__(self, noise_suppression_engines: AsyncNoiseSuppressionEnginesResource) -> None: + self._noise_suppression_engines = noise_suppression_engines + + self.list = async_to_streamed_response_wrapper( + noise_suppression_engines.list, + ) diff --git a/src/telnyx/resources/speech_to_text.py b/src/telnyx/resources/speech_to_text.py index cbad154af..222dd39d1 100644 --- a/src/telnyx/resources/speech_to_text.py +++ b/src/telnyx/resources/speech_to_text.py @@ -193,6 +193,7 @@ def retrieve_transcription( "speechmatics/standard", "soniox/stt-rt-v4", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", @@ -465,6 +466,7 @@ async def retrieve_transcription( "speechmatics/standard", "soniox/stt-rt-v4", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", diff --git a/src/telnyx/resources/texml/__init__.py b/src/telnyx/resources/texml/__init__.py index e5cfbfc32..20315ac4f 100644 --- a/src/telnyx/resources/texml/__init__.py +++ b/src/telnyx/resources/texml/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .calls import ( + CallsResource, + AsyncCallsResource, + CallsResourceWithRawResponse, + AsyncCallsResourceWithRawResponse, + CallsResourceWithStreamingResponse, + AsyncCallsResourceWithStreamingResponse, +) from .texml import ( TexmlResource, AsyncTexmlResource, @@ -18,6 +26,12 @@ ) __all__ = [ + "CallsResource", + "AsyncCallsResource", + "CallsResourceWithRawResponse", + "AsyncCallsResourceWithRawResponse", + "CallsResourceWithStreamingResponse", + "AsyncCallsResourceWithStreamingResponse", "AccountsResource", "AsyncAccountsResource", "AccountsResourceWithRawResponse", diff --git a/src/telnyx/resources/texml/accounts/conferences/participants.py b/src/telnyx/resources/texml/accounts/conferences/participants.py index bd05c3979..4834d3ccb 100644 --- a/src/telnyx/resources/texml/accounts/conferences/participants.py +++ b/src/telnyx/resources/texml/accounts/conferences/participants.py @@ -278,7 +278,14 @@ def participants( from_: str | Omit = omit, label: str | Omit = omit, machine_detection: Literal["Enable", "DetectMessageEnd"] | Omit = omit, + machine_detection_beep_max_frequency: int | Omit = omit, + machine_detection_beep_min_frequency: int | Omit = omit, + machine_detection_beep_min_tone_duration: int | Omit = omit, machine_detection_beep_profile: Literal["both", "freq_only"] | Omit = omit, + machine_detection_beep_spectral_confirmation: bool | Omit = omit, + machine_detection_beep_spectral_min_purity: float | Omit = omit, + machine_detection_beep_spectral_reject_fax_cng: bool | Omit = omit, + machine_detection_beep_spectral_window: int | Omit = omit, machine_detection_silence_timeout: int | Omit = omit, machine_detection_speech_end_threshold: int | Omit = omit, machine_detection_speech_threshold: int | Omit = omit, @@ -391,11 +398,36 @@ def participants( identified. Use `DetectMessageEnd`, if you would like to leave a message on an answering machine. + machine_detection_beep_max_frequency: Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + Only used when MachineDetection is enabled. + + machine_detection_beep_min_frequency: Lowest frequency, in Hz, that a tone must reach to be treated as a beep. Raising + it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + + machine_detection_beep_min_tone_duration: Shortest tone, in milliseconds, that can be treated as a beep. Raising it + rejects brief tones such as call-progress blips. Only used when MachineDetection + is enabled. + machine_detection_beep_profile: Selects which detectors must validate a beep. `both` requires the amplitude and frequency detectors to agree. `freq_only` uses the frequency detector alone, for beeps whose volume is too unsteady for the default profile. Only used when MachineDetection is enabled. + machine_detection_beep_spectral_confirmation: When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_min_purity: Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_reject_fax_cng: When enabled, the fax CNG tone is rejected rather than reported as a beep. Only + used when MachineDetection is enabled. + + machine_detection_beep_spectral_window: Length of the spectral confirmation window, in milliseconds. Only used when + MachineDetection is enabled. + machine_detection_silence_timeout: If initial silence duration is greater than this value, consider it a machine. Ignored when `premium` detection is used. @@ -502,7 +534,14 @@ def participants( "from_": from_, "label": label, "machine_detection": machine_detection, + "machine_detection_beep_max_frequency": machine_detection_beep_max_frequency, + "machine_detection_beep_min_frequency": machine_detection_beep_min_frequency, + "machine_detection_beep_min_tone_duration": machine_detection_beep_min_tone_duration, "machine_detection_beep_profile": machine_detection_beep_profile, + "machine_detection_beep_spectral_confirmation": machine_detection_beep_spectral_confirmation, + "machine_detection_beep_spectral_min_purity": machine_detection_beep_spectral_min_purity, + "machine_detection_beep_spectral_reject_fax_cng": machine_detection_beep_spectral_reject_fax_cng, + "machine_detection_beep_spectral_window": machine_detection_beep_spectral_window, "machine_detection_silence_timeout": machine_detection_silence_timeout, "machine_detection_speech_end_threshold": machine_detection_speech_end_threshold, "machine_detection_speech_threshold": machine_detection_speech_threshold, @@ -827,7 +866,14 @@ async def participants( from_: str | Omit = omit, label: str | Omit = omit, machine_detection: Literal["Enable", "DetectMessageEnd"] | Omit = omit, + machine_detection_beep_max_frequency: int | Omit = omit, + machine_detection_beep_min_frequency: int | Omit = omit, + machine_detection_beep_min_tone_duration: int | Omit = omit, machine_detection_beep_profile: Literal["both", "freq_only"] | Omit = omit, + machine_detection_beep_spectral_confirmation: bool | Omit = omit, + machine_detection_beep_spectral_min_purity: float | Omit = omit, + machine_detection_beep_spectral_reject_fax_cng: bool | Omit = omit, + machine_detection_beep_spectral_window: int | Omit = omit, machine_detection_silence_timeout: int | Omit = omit, machine_detection_speech_end_threshold: int | Omit = omit, machine_detection_speech_threshold: int | Omit = omit, @@ -940,11 +986,36 @@ async def participants( identified. Use `DetectMessageEnd`, if you would like to leave a message on an answering machine. + machine_detection_beep_max_frequency: Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + Only used when MachineDetection is enabled. + + machine_detection_beep_min_frequency: Lowest frequency, in Hz, that a tone must reach to be treated as a beep. Raising + it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + + machine_detection_beep_min_tone_duration: Shortest tone, in milliseconds, that can be treated as a beep. Raising it + rejects brief tones such as call-progress blips. Only used when MachineDetection + is enabled. + machine_detection_beep_profile: Selects which detectors must validate a beep. `both` requires the amplitude and frequency detectors to agree. `freq_only` uses the frequency detector alone, for beeps whose volume is too unsteady for the default profile. Only used when MachineDetection is enabled. + machine_detection_beep_spectral_confirmation: When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_min_purity: Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_reject_fax_cng: When enabled, the fax CNG tone is rejected rather than reported as a beep. Only + used when MachineDetection is enabled. + + machine_detection_beep_spectral_window: Length of the spectral confirmation window, in milliseconds. Only used when + MachineDetection is enabled. + machine_detection_silence_timeout: If initial silence duration is greater than this value, consider it a machine. Ignored when `premium` detection is used. @@ -1051,7 +1122,14 @@ async def participants( "from_": from_, "label": label, "machine_detection": machine_detection, + "machine_detection_beep_max_frequency": machine_detection_beep_max_frequency, + "machine_detection_beep_min_frequency": machine_detection_beep_min_frequency, + "machine_detection_beep_min_tone_duration": machine_detection_beep_min_tone_duration, "machine_detection_beep_profile": machine_detection_beep_profile, + "machine_detection_beep_spectral_confirmation": machine_detection_beep_spectral_confirmation, + "machine_detection_beep_spectral_min_purity": machine_detection_beep_spectral_min_purity, + "machine_detection_beep_spectral_reject_fax_cng": machine_detection_beep_spectral_reject_fax_cng, + "machine_detection_beep_spectral_window": machine_detection_beep_spectral_window, "machine_detection_silence_timeout": machine_detection_silence_timeout, "machine_detection_speech_end_threshold": machine_detection_speech_end_threshold, "machine_detection_speech_threshold": machine_detection_speech_threshold, diff --git a/src/telnyx/resources/texml/calls.py b/src/telnyx/resources/texml/calls.py new file mode 100644 index 000000000..c6ff7c9df --- /dev/null +++ b/src/telnyx/resources/texml/calls.py @@ -0,0 +1,233 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...types.texml import call_create_params +from ..._base_client import make_request_options +from ...types.texml.call_create_response import CallCreateResponse + +__all__ = ["CallsResource", "AsyncCallsResource"] + + +class CallsResource(SyncAPIResource): + """TeXML REST Commands""" + + @cached_property + def with_raw_response(self) -> CallsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return CallsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CallsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return CallsResourceWithStreamingResponse(self) + + def create( + self, + connection_id: str, + *, + from_: str, + to: str, + method: Literal["GET", "POST"] | Omit = omit, + texml: str | Omit = omit, + url: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CallCreateResponse: + """ + Initiate an outbound TeXML call using a TeXML application connection ID, not an + account SID. Request parameter names are case-sensitive. From and To are + required; Texml supplies inline instructions and Url overrides the application + XML request URL. When neither is supplied, the application configuration + supplies the instructions. The response is a flat call object without a data + wrapper. + + Args: + from_: The E.164-formatted phone number or SIP URI to present as the caller. + + to: The E.164-formatted phone number or SIP URI to call. + + method: HTTP method used to retrieve TeXML instructions from Url. + + texml: Inline TeXML instructions to execute when the call is answered. + + url: The URL from which to retrieve TeXML instructions. Overrides the TeXML + application XML request URL. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not connection_id: + raise ValueError(f"Expected a non-empty value for `connection_id` but received {connection_id!r}") + return self._post( + path_template("/texml/calls/{connection_id}", connection_id=connection_id), + body=maybe_transform( + { + "from_": from_, + "to": to, + "method": method, + "texml": texml, + "url": url, + }, + call_create_params.CallCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CallCreateResponse, + ) + + +class AsyncCallsResource(AsyncAPIResource): + """TeXML REST Commands""" + + @cached_property + def with_raw_response(self) -> AsyncCallsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncCallsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCallsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncCallsResourceWithStreamingResponse(self) + + async def create( + self, + connection_id: str, + *, + from_: str, + to: str, + method: Literal["GET", "POST"] | Omit = omit, + texml: str | Omit = omit, + url: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> CallCreateResponse: + """ + Initiate an outbound TeXML call using a TeXML application connection ID, not an + account SID. Request parameter names are case-sensitive. From and To are + required; Texml supplies inline instructions and Url overrides the application + XML request URL. When neither is supplied, the application configuration + supplies the instructions. The response is a flat call object without a data + wrapper. + + Args: + from_: The E.164-formatted phone number or SIP URI to present as the caller. + + to: The E.164-formatted phone number or SIP URI to call. + + method: HTTP method used to retrieve TeXML instructions from Url. + + texml: Inline TeXML instructions to execute when the call is answered. + + url: The URL from which to retrieve TeXML instructions. Overrides the TeXML + application XML request URL. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not connection_id: + raise ValueError(f"Expected a non-empty value for `connection_id` but received {connection_id!r}") + return await self._post( + path_template("/texml/calls/{connection_id}", connection_id=connection_id), + body=await async_maybe_transform( + { + "from_": from_, + "to": to, + "method": method, + "texml": texml, + "url": url, + }, + call_create_params.CallCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CallCreateResponse, + ) + + +class CallsResourceWithRawResponse: + def __init__(self, calls: CallsResource) -> None: + self._calls = calls + + self.create = to_raw_response_wrapper( + calls.create, + ) + + +class AsyncCallsResourceWithRawResponse: + def __init__(self, calls: AsyncCallsResource) -> None: + self._calls = calls + + self.create = async_to_raw_response_wrapper( + calls.create, + ) + + +class CallsResourceWithStreamingResponse: + def __init__(self, calls: CallsResource) -> None: + self._calls = calls + + self.create = to_streamed_response_wrapper( + calls.create, + ) + + +class AsyncCallsResourceWithStreamingResponse: + def __init__(self, calls: AsyncCallsResource) -> None: + self._calls = calls + + self.create = async_to_streamed_response_wrapper( + calls.create, + ) diff --git a/src/telnyx/resources/texml/texml.py b/src/telnyx/resources/texml/texml.py index bbb107605..3364bf4f2 100644 --- a/src/telnyx/resources/texml/texml.py +++ b/src/telnyx/resources/texml/texml.py @@ -7,6 +7,14 @@ import httpx +from .calls import ( + CallsResource, + AsyncCallsResource, + CallsResourceWithRawResponse, + AsyncCallsResourceWithRawResponse, + CallsResourceWithStreamingResponse, + AsyncCallsResourceWithStreamingResponse, +) from ...types import texml_secrets_params, texml_initiate_ai_call_params from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform @@ -36,6 +44,11 @@ class TexmlResource(SyncAPIResource): """TeXML REST Commands""" + @cached_property + def calls(self) -> CallsResource: + """TeXML REST Commands""" + return CallsResource(self._client) + @cached_property def accounts(self) -> AccountsResource: """TeXML REST Commands""" @@ -79,7 +92,14 @@ def initiate_ai_call( custom_headers: Iterable[texml_initiate_ai_call_params.CustomHeader] | Omit = omit, detection_mode: Literal["Premium", "Regular", "PremiumCallScreening"] | Omit = omit, machine_detection: Literal["Enable", "Disable", "DetectMessageEnd"] | Omit = omit, + machine_detection_beep_max_frequency: int | Omit = omit, + machine_detection_beep_min_frequency: int | Omit = omit, + machine_detection_beep_min_tone_duration: int | Omit = omit, machine_detection_beep_profile: Literal["both", "freq_only"] | Omit = omit, + machine_detection_beep_spectral_confirmation: bool | Omit = omit, + machine_detection_beep_spectral_min_purity: float | Omit = omit, + machine_detection_beep_spectral_reject_fax_cng: bool | Omit = omit, + machine_detection_beep_spectral_window: int | Omit = omit, machine_detection_prompt_end_timeout: int | Omit = omit, machine_detection_silence_timeout: int | Omit = omit, machine_detection_speech_end_threshold: int | Omit = omit, @@ -172,11 +192,36 @@ def initiate_ai_call( machine_detection: Enables Answering Machine Detection. + machine_detection_beep_max_frequency: Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + Only used when MachineDetection is enabled. + + machine_detection_beep_min_frequency: Lowest frequency, in Hz, that a tone must reach to be treated as a beep. Raising + it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + + machine_detection_beep_min_tone_duration: Shortest tone, in milliseconds, that can be treated as a beep. Raising it + rejects brief tones such as call-progress blips. Only used when MachineDetection + is enabled. + machine_detection_beep_profile: Selects which detectors must validate a beep. `both` requires the amplitude and frequency detectors to agree. `freq_only` uses the frequency detector alone, for beeps whose volume is too unsteady for the default profile. Only used when MachineDetection is enabled. + machine_detection_beep_spectral_confirmation: When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_min_purity: Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_reject_fax_cng: When enabled, the fax CNG tone is rejected rather than reported as a beep. Only + used when MachineDetection is enabled. + + machine_detection_beep_spectral_window: Length of the spectral confirmation window, in milliseconds. Only used when + MachineDetection is enabled. + machine_detection_prompt_end_timeout: Silence duration threshold after a call screening prompt before ending prompt detection, in milliseconds. Used when `DetectionMode` is `PremiumCallScreening`. @@ -278,7 +323,14 @@ def initiate_ai_call( "custom_headers": custom_headers, "detection_mode": detection_mode, "machine_detection": machine_detection, + "machine_detection_beep_max_frequency": machine_detection_beep_max_frequency, + "machine_detection_beep_min_frequency": machine_detection_beep_min_frequency, + "machine_detection_beep_min_tone_duration": machine_detection_beep_min_tone_duration, "machine_detection_beep_profile": machine_detection_beep_profile, + "machine_detection_beep_spectral_confirmation": machine_detection_beep_spectral_confirmation, + "machine_detection_beep_spectral_min_purity": machine_detection_beep_spectral_min_purity, + "machine_detection_beep_spectral_reject_fax_cng": machine_detection_beep_spectral_reject_fax_cng, + "machine_detection_beep_spectral_window": machine_detection_beep_spectral_window, "machine_detection_prompt_end_timeout": machine_detection_prompt_end_timeout, "machine_detection_silence_timeout": machine_detection_silence_timeout, "machine_detection_speech_end_threshold": machine_detection_speech_end_threshold, @@ -365,6 +417,11 @@ def secrets( class AsyncTexmlResource(AsyncAPIResource): """TeXML REST Commands""" + @cached_property + def calls(self) -> AsyncCallsResource: + """TeXML REST Commands""" + return AsyncCallsResource(self._client) + @cached_property def accounts(self) -> AsyncAccountsResource: """TeXML REST Commands""" @@ -408,7 +465,14 @@ async def initiate_ai_call( custom_headers: Iterable[texml_initiate_ai_call_params.CustomHeader] | Omit = omit, detection_mode: Literal["Premium", "Regular", "PremiumCallScreening"] | Omit = omit, machine_detection: Literal["Enable", "Disable", "DetectMessageEnd"] | Omit = omit, + machine_detection_beep_max_frequency: int | Omit = omit, + machine_detection_beep_min_frequency: int | Omit = omit, + machine_detection_beep_min_tone_duration: int | Omit = omit, machine_detection_beep_profile: Literal["both", "freq_only"] | Omit = omit, + machine_detection_beep_spectral_confirmation: bool | Omit = omit, + machine_detection_beep_spectral_min_purity: float | Omit = omit, + machine_detection_beep_spectral_reject_fax_cng: bool | Omit = omit, + machine_detection_beep_spectral_window: int | Omit = omit, machine_detection_prompt_end_timeout: int | Omit = omit, machine_detection_silence_timeout: int | Omit = omit, machine_detection_speech_end_threshold: int | Omit = omit, @@ -501,11 +565,36 @@ async def initiate_ai_call( machine_detection: Enables Answering Machine Detection. + machine_detection_beep_max_frequency: Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + Only used when MachineDetection is enabled. + + machine_detection_beep_min_frequency: Lowest frequency, in Hz, that a tone must reach to be treated as a beep. Raising + it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + + machine_detection_beep_min_tone_duration: Shortest tone, in milliseconds, that can be treated as a beep. Raising it + rejects brief tones such as call-progress blips. Only used when MachineDetection + is enabled. + machine_detection_beep_profile: Selects which detectors must validate a beep. `both` requires the amplitude and frequency detectors to agree. `freq_only` uses the frequency detector alone, for beeps whose volume is too unsteady for the default profile. Only used when MachineDetection is enabled. + machine_detection_beep_spectral_confirmation: When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_min_purity: Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + + machine_detection_beep_spectral_reject_fax_cng: When enabled, the fax CNG tone is rejected rather than reported as a beep. Only + used when MachineDetection is enabled. + + machine_detection_beep_spectral_window: Length of the spectral confirmation window, in milliseconds. Only used when + MachineDetection is enabled. + machine_detection_prompt_end_timeout: Silence duration threshold after a call screening prompt before ending prompt detection, in milliseconds. Used when `DetectionMode` is `PremiumCallScreening`. @@ -607,7 +696,14 @@ async def initiate_ai_call( "custom_headers": custom_headers, "detection_mode": detection_mode, "machine_detection": machine_detection, + "machine_detection_beep_max_frequency": machine_detection_beep_max_frequency, + "machine_detection_beep_min_frequency": machine_detection_beep_min_frequency, + "machine_detection_beep_min_tone_duration": machine_detection_beep_min_tone_duration, "machine_detection_beep_profile": machine_detection_beep_profile, + "machine_detection_beep_spectral_confirmation": machine_detection_beep_spectral_confirmation, + "machine_detection_beep_spectral_min_purity": machine_detection_beep_spectral_min_purity, + "machine_detection_beep_spectral_reject_fax_cng": machine_detection_beep_spectral_reject_fax_cng, + "machine_detection_beep_spectral_window": machine_detection_beep_spectral_window, "machine_detection_prompt_end_timeout": machine_detection_prompt_end_timeout, "machine_detection_silence_timeout": machine_detection_silence_timeout, "machine_detection_speech_end_threshold": machine_detection_speech_end_threshold, @@ -702,6 +798,11 @@ def __init__(self, texml: TexmlResource) -> None: texml.secrets, ) + @cached_property + def calls(self) -> CallsResourceWithRawResponse: + """TeXML REST Commands""" + return CallsResourceWithRawResponse(self._texml.calls) + @cached_property def accounts(self) -> AccountsResourceWithRawResponse: """TeXML REST Commands""" @@ -719,6 +820,11 @@ def __init__(self, texml: AsyncTexmlResource) -> None: texml.secrets, ) + @cached_property + def calls(self) -> AsyncCallsResourceWithRawResponse: + """TeXML REST Commands""" + return AsyncCallsResourceWithRawResponse(self._texml.calls) + @cached_property def accounts(self) -> AsyncAccountsResourceWithRawResponse: """TeXML REST Commands""" @@ -736,6 +842,11 @@ def __init__(self, texml: TexmlResource) -> None: texml.secrets, ) + @cached_property + def calls(self) -> CallsResourceWithStreamingResponse: + """TeXML REST Commands""" + return CallsResourceWithStreamingResponse(self._texml.calls) + @cached_property def accounts(self) -> AccountsResourceWithStreamingResponse: """TeXML REST Commands""" @@ -753,6 +864,11 @@ def __init__(self, texml: AsyncTexmlResource) -> None: texml.secrets, ) + @cached_property + def calls(self) -> AsyncCallsResourceWithStreamingResponse: + """TeXML REST Commands""" + return AsyncCallsResourceWithStreamingResponse(self._texml.calls) + @cached_property def accounts(self) -> AsyncAccountsResourceWithStreamingResponse: """TeXML REST Commands""" diff --git a/src/telnyx/resources/voice_clones.py b/src/telnyx/resources/voice_clones.py index b8fd5aabf..a686b5bbc 100644 --- a/src/telnyx/resources/voice_clones.py +++ b/src/telnyx/resources/voice_clones.py @@ -257,8 +257,10 @@ def create_from_upload( """Creates a new voice clone by uploading an audio file directly. Supported - formats: WAV, MP3, FLAC, OGG, M4A. For best results, provide 5–10 seconds of - clear speech. Maximum file size: 5MB for Telnyx, 20MB for Minimax. + formats: WAV, MP3, FLAC, OGG, M4A. For best results, provide 5–60 seconds of + clear speech (Ultra accepts up to 60 seconds; Qwen3TTS auto-trims to 10 seconds; + Minimax accepts up to 5 minutes). Maximum file size: 5MB for Telnyx, 20MB for + Minimax. Args: voice_clone_upload_request: Multipart form data for creating a voice clone from a direct audio upload. @@ -540,8 +542,10 @@ async def create_from_upload( """Creates a new voice clone by uploading an audio file directly. Supported - formats: WAV, MP3, FLAC, OGG, M4A. For best results, provide 5–10 seconds of - clear speech. Maximum file size: 5MB for Telnyx, 20MB for Minimax. + formats: WAV, MP3, FLAC, OGG, M4A. For best results, provide 5–60 seconds of + clear speech (Ultra accepts up to 60 seconds; Qwen3TTS auto-trims to 10 seconds; + Minimax accepts up to 5 minutes). Maximum file size: 5MB for Telnyx, 20MB for + Minimax. Args: voice_clone_upload_request: Multipart form data for creating a voice clone from a direct audio upload. diff --git a/src/telnyx/types/__init__.py b/src/telnyx/types/__init__.py index 8b22e9ea8..3a40e6fdb 100644 --- a/src/telnyx/types/__init__.py +++ b/src/telnyx/types/__init__.py @@ -161,6 +161,7 @@ from .room_list_params import RoomListParams as RoomListParams from .sip_header_param import SipHeaderParam as SipHeaderParam from .stt_service_type import SttServiceType as SttServiceType +from .success_response import SuccessResponse as SuccessResponse from .user_requirement import UserRequirement as UserRequirement from .voice_clone_data import VoiceCloneData as VoiceCloneData from .webhook_delivery import WebhookDelivery as WebhookDelivery @@ -354,6 +355,7 @@ from .address_delete_response import AddressDeleteResponse as AddressDeleteResponse from .audit_event_list_params import AuditEventListParams as AuditEventListParams from .authentication_provider import AuthenticationProvider as AuthenticationProvider +from .bot_session_list_params import BotSessionListParams as BotSessionListParams from .call_conversation_ended import CallConversationEnded as CallConversationEnded from .call_cost_webhook_event import CallCostWebhookEvent as CallCostWebhookEvent from .call_hold_webhook_event import CallHoldWebhookEvent as CallHoldWebhookEvent @@ -403,6 +405,7 @@ from .whatsapp_reaction_param import WhatsappReactionParam as WhatsappReactionParam from .attachment_request_param import AttachmentRequestParam as AttachmentRequestParam from .azure_configuration_data import AzureConfigurationData as AzureConfigurationData +from .bot_signup_create_params import BotSignupCreateParams as BotSignupCreateParams from .call_control_application import CallControlApplication as CallControlApplication from .call_event_list_response import CallEventListResponse as CallEventListResponse from .channel_zone_list_params import ChannelZoneListParams as ChannelZoneListParams @@ -445,6 +448,7 @@ from .audit_event_list_response import AuditEventListResponse as AuditEventListResponse from .balance_retrieve_response import BalanceRetrieveResponse as BalanceRetrieveResponse from .billing_group_list_params import BillingGroupListParams as BillingGroupListParams +from .bot_session_list_response import BotSessionListResponse as BotSessionListResponse from .call_hangup_webhook_event import CallHangupWebhookEvent as CallHangupWebhookEvent from .call_reason_list_response import CallReasonListResponse as CallReasonListResponse from .call_unhold_webhook_event import CallUnholdWebhookEvent as CallUnholdWebhookEvent @@ -469,6 +473,7 @@ from .message_retrieve_response import MessageRetrieveResponse as MessageRetrieveResponse from .message_schedule_response import MessageScheduleResponse as MessageScheduleResponse from .message_whatsapp_response import MessageWhatsappResponse as MessageWhatsappResponse +from .messaging_inbound_message import MessagingInboundMessage as MessagingInboundMessage from .network_retrieve_response import NetworkRetrieveResponse as NetworkRetrieveResponse from .number_order_phone_number import NumberOrderPhoneNumber as NumberOrderPhoneNumber from .oauth_introspect_response import OAuthIntrospectResponse as OAuthIntrospectResponse @@ -532,6 +537,7 @@ from .access_ip_range_list_params import AccessIPRangeListParams as AccessIPRangeListParams from .billing_group_create_params import BillingGroupCreateParams as BillingGroupCreateParams from .billing_group_update_params import BillingGroupUpdateParams as BillingGroupUpdateParams +from .bot_challenge_create_params import BotChallengeCreateParams as BotChallengeCreateParams from .call_answered_webhook_event import CallAnsweredWebhookEvent as CallAnsweredWebhookEvent from .call_enqueued_webhook_event import CallEnqueuedWebhookEvent as CallEnqueuedWebhookEvent from .call_machine_greeting_ended import CallMachineGreetingEnded as CallMachineGreetingEnded @@ -629,6 +635,7 @@ from .billing_group_create_response import BillingGroupCreateResponse as BillingGroupCreateResponse from .billing_group_delete_response import BillingGroupDeleteResponse as BillingGroupDeleteResponse from .billing_group_update_response import BillingGroupUpdateResponse as BillingGroupUpdateResponse +from .bot_challenge_create_response import BotChallengeCreateResponse as BotChallengeCreateResponse from .bulk_sim_card_action_detailed import BulkSimCardActionDetailed as BulkSimCardActionDetailed from .call_left_queue_webhook_event import CallLeftQueueWebhookEvent as CallLeftQueueWebhookEvent from .call_reason_validate_response import CallReasonValidateResponse as CallReasonValidateResponse @@ -873,13 +880,13 @@ from .call_recording_transcription_saved import CallRecordingTranscriptionSaved as CallRecordingTranscriptionSaved from .call_refer_completed_webhook_event import CallReferCompletedWebhookEvent as CallReferCompletedWebhookEvent from .conference_participant_speak_ended import ConferenceParticipantSpeakEnded as ConferenceParticipantSpeakEnded +from .connection_retrieve_count_response import ConnectionRetrieveCountResponse as ConnectionRetrieveCountResponse from .country_coverage_retrieve_response import CountryCoverageRetrieveResponse as CountryCoverageRetrieveResponse from .email_block_retrieve_events_params import EmailBlockRetrieveEventsParams as EmailBlockRetrieveEventsParams from .email_block_retrieve_export_params import EmailBlockRetrieveExportParams as EmailBlockRetrieveExportParams from .global_ip_assignment_update_params import GlobalIPAssignmentUpdateParams as GlobalIPAssignmentUpdateParams from .global_ip_health_check_list_params import GlobalIPHealthCheckListParams as GlobalIPHealthCheckListParams from .integration_secret_create_response import IntegrationSecretCreateResponse as IntegrationSecretCreateResponse -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload as MessagingOutboundMessagePayload from .messaging_url_domain_list_response import MessagingURLDomainListResponse as MessagingURLDomainListResponse from .mobile_push_credential_list_params import MobilePushCredentialListParams as MobilePushCredentialListParams from .notification_channel_create_params import NotificationChannelCreateParams as NotificationChannelCreateParams @@ -906,6 +913,7 @@ from .wireless_blocklist_update_response import WirelessBlocklistUpdateResponse as WirelessBlocklistUpdateResponse from .wireless_retrieve_regions_response import WirelessRetrieveRegionsResponse as WirelessRetrieveRegionsResponse from .authentication_provider_list_params import AuthenticationProviderListParams as AuthenticationProviderListParams +from .bot_signup_resend_magic_link_params import BotSignupResendMagicLinkParams as BotSignupResendMagicLinkParams from .call_machine_premium_greeting_ended import CallMachinePremiumGreetingEnded as CallMachinePremiumGreetingEnded from .call_payment_progress_webhook_event import CallPaymentProgressWebhookEvent as CallPaymentProgressWebhookEvent from .call_playback_started_webhook_event import CallPlaybackStartedWebhookEvent as CallPlaybackStartedWebhookEvent @@ -1041,6 +1049,9 @@ from .inexplicit_number_order_create_params import ( InexplicitNumberOrderCreateParams as InexplicitNumberOrderCreateParams, ) +from .machine_payment_account_credit_params import ( + MachinePaymentAccountCreditParams as MachinePaymentAccountCreditParams, +) from .messaging_hosted_number_update_params import ( MessagingHostedNumberUpdateParams as MessagingHostedNumberUpdateParams, ) @@ -1136,6 +1147,9 @@ from .messaging_profile_metric_list_response import ( MessagingProfileMetricListResponse as MessagingProfileMetricListResponse, ) +from .noise_suppression_engine_list_response import ( + NoiseSuppressionEngineListResponse as NoiseSuppressionEngineListResponse, +) from .notification_channel_retrieve_response import ( NotificationChannelRetrieveResponse as NotificationChannelRetrieveResponse, ) @@ -1220,6 +1234,9 @@ from .inexplicit_number_order_create_response import ( InexplicitNumberOrderCreateResponse as InexplicitNumberOrderCreateResponse, ) +from .machine_payment_account_credit_response import ( + MachinePaymentAccountCreditResponse as MachinePaymentAccountCreditResponse, +) from .messaging_hosted_number_delete_response import ( MessagingHostedNumberDeleteResponse as MessagingHostedNumberDeleteResponse, ) diff --git a/src/telnyx/types/ai/__init__.py b/src/telnyx/types/ai/__init__.py index bbd64274b..76a0e26eb 100644 --- a/src/telnyx/types/ai/__init__.py +++ b/src/telnyx/types/ai/__init__.py @@ -97,7 +97,6 @@ from .collection import Collection as Collection from .mcp_server import McpServer as McpServer from .speak_node import SpeakNode as SpeakNode - from .hangup_tool import HangupTool as HangupTool from .integration import Integration as Integration from .conversation import Conversation as Conversation from .external_llm import ExternalLlm as ExternalLlm @@ -146,6 +145,7 @@ from .transcription_settings_config import TranscriptionSettingsConfig as TranscriptionSettingsConfig from .conversation_retrieve_response import ConversationRetrieveResponse as ConversationRetrieveResponse from .transcription_endpointing_plan import TranscriptionEndpointingPlan as TranscriptionEndpointingPlan + from .audio_transcription_response_word import AudioTranscriptionResponseWord as AudioTranscriptionResponseWord from .embedding_similarity_search_response import ( EmbeddingSimilaritySearchResponse as EmbeddingSimilaritySearchResponse, ) @@ -204,10 +204,6 @@ def __getattr__(name: str) -> Any: from .flow_node import FlowNode return FlowNode - if name == "HangupTool": - from .hangup_tool import HangupTool - - return HangupTool if name == "HangupToolParams": from .hangup_tool_params import HangupToolParams @@ -304,6 +300,10 @@ def __getattr__(name: str) -> Any: from .assistant_send_sms_response import AssistantSendSMSResponse return AssistantSendSMSResponse + if name == "AudioTranscriptionResponseWord": + from .audio_transcription_response_word import AudioTranscriptionResponseWord + + return AudioTranscriptionResponseWord if name == "AudioTranscribeResponse": from .audio_transcribe_response import AudioTranscribeResponse diff --git a/src/telnyx/types/ai/assistant_create_params.py b/src/telnyx/types/ai/assistant_create_params.py index e579df2d1..16f2788bf 100644 --- a/src/telnyx/types/ai/assistant_create_params.py +++ b/src/telnyx/types/ai/assistant_create_params.py @@ -155,10 +155,10 @@ class AssistantCreateParams(TypedDict, total=False): """Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the - conversation ends, allowing it to execute tool calls such as logging to a CRM or - sending a summary. The assistant can execute multiple parallel or sequential - tools during this phase. Telephony-control tools (e.g. hangup, transfer) are - unavailable post-conversation. Beta feature. + conversation ends, allowing it to execute final tool calls such as sending a + summary or updating a record via webhook or function tools. Integration and MCP + server tools are not available post-conversation; call-control tools (e.g. + hangup, transfer) are also unavailable. Beta feature. """ privacy_settings: PrivacySettingsParam diff --git a/src/telnyx/types/ai/assistant_tool.py b/src/telnyx/types/ai/assistant_tool.py index f3079b625..44e036d40 100644 --- a/src/telnyx/types/ai/assistant_tool.py +++ b/src/telnyx/types/ai/assistant_tool.py @@ -9,20 +9,23 @@ from ..._utils import PropertyInfo from ..._models import BaseModel -from .hangup_tool import HangupTool from .retrieval_tool import RetrievalTool from .pay_tool_params import PayToolParams +from .hangup_tool_params import HangupToolParams +from .openai.function_definition import FunctionDefinition from .update_dynamic_variables_tool_params import UpdateDynamicVariablesToolParams from .inference_embedding_webhook_tool_params import InferenceEmbeddingWebhookToolParams __all__ = [ "AssistantTool", + "Function", "ClientSideTool", "ClientSideToolClientSideTool", "ClientSideToolClientSideToolParameters", "Handoff", "HandoffHandoff", "HandoffHandoffAIAssistant", + "Hangup", "Transfer", "TransferTransfer", "TransferTransferTargetsTargetsList", @@ -53,6 +56,23 @@ ] +class Function(BaseModel): + function: FunctionDefinition + + type: Literal["function"] + + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + + class ClientSideToolClientSideToolParameters(BaseModel): """The parameters the tool accepts, described as a JSON Schema object. @@ -89,6 +109,17 @@ class ClientSideTool(BaseModel): type: Literal["client_side_tool"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class HandoffHandoffAIAssistant(BaseModel): id: str @@ -120,6 +151,34 @@ class Handoff(BaseModel): type: Literal["handoff"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + + +class Hangup(BaseModel): + hangup: HangupToolParams + + type: Literal["hangup"] + + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class TransferTransferTargetsTargetsList(BaseModel): to: str @@ -345,6 +404,17 @@ class Transfer(BaseModel): type: Literal["transfer"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class InviteInviteCustomHeader(BaseModel): name: Optional[str] = None @@ -418,6 +488,17 @@ class Invite(BaseModel): type: Literal["invite"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class ReferReferTarget(BaseModel): name: str @@ -479,12 +560,34 @@ class Refer(BaseModel): type: Literal["refer"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class SendDtmf(BaseModel): send_dtmf: Dict[str, object] type: Literal["send_dtmf"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class SendMessageSendMessage(BaseModel): message_template: Optional[str] = None @@ -518,6 +621,17 @@ class SendMessage(BaseModel): type: Literal["send_message"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class SkipTurnSkipTurn(BaseModel): description: Optional[str] = None @@ -529,6 +643,17 @@ class SkipTurn(BaseModel): type: Literal["skip_turn"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class Pay(BaseModel): """ @@ -539,6 +664,17 @@ class Pay(BaseModel): type: Literal["pay"] + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + class UpdateDynamicVariables(BaseModel): """ @@ -550,14 +686,26 @@ class UpdateDynamicVariables(BaseModel): update_dynamic_variables: UpdateDynamicVariablesToolParams """Configuration for an update_dynamic_variables tool.""" + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ + AssistantTool: TypeAlias = Annotated[ Union[ + Function, InferenceEmbeddingWebhookToolParams, ClientSideTool, RetrievalTool, Handoff, - HangupTool, + Hangup, Transfer, Invite, Refer, diff --git a/src/telnyx/types/ai/assistant_tool_param.py b/src/telnyx/types/ai/assistant_tool_param.py index 753c15155..c0a52352d 100644 --- a/src/telnyx/types/ai/assistant_tool_param.py +++ b/src/telnyx/types/ai/assistant_tool_param.py @@ -6,20 +6,23 @@ from typing_extensions import Literal, Required, TypeAlias, TypedDict from ..._types import SequenceNotStr -from .hangup_tool_param import HangupToolParam from .retrieval_tool_param import RetrievalToolParam from .pay_tool_params_param import PayToolParamsParam +from .hangup_tool_params_param import HangupToolParamsParam +from .openai.function_definition_param import FunctionDefinitionParam from .update_dynamic_variables_tool_params_param import UpdateDynamicVariablesToolParamsParam from .inference_embedding_webhook_tool_params_param import InferenceEmbeddingWebhookToolParamsParam __all__ = [ "AssistantToolParam", + "Function", "ClientSideTool", "ClientSideToolClientSideTool", "ClientSideToolClientSideToolParameters", "Handoff", "HandoffHandoff", "HandoffHandoffAIAssistant", + "Hangup", "Transfer", "TransferTransfer", "TransferTransferTargetsTargetsList", @@ -50,6 +53,12 @@ ] +class Function(TypedDict, total=False): + function: Required[FunctionDefinitionParam] + + type: Required[Literal["function"]] + + class ClientSideToolClientSideToolParameters(TypedDict, total=False): """The parameters the tool accepts, described as a JSON Schema object. @@ -118,6 +127,12 @@ class Handoff(TypedDict, total=False): type: Required[Literal["handoff"]] +class Hangup(TypedDict, total=False): + hangup: Required[HangupToolParamsParam] + + type: Required[Literal["hangup"]] + + class TransferTransferTargetsTargetsList(TypedDict, total=False): to: Required[str] """The destination number or SIP URI of the call.""" @@ -549,11 +564,12 @@ class UpdateDynamicVariables(TypedDict, total=False): AssistantToolParam: TypeAlias = Union[ + Function, InferenceEmbeddingWebhookToolParamsParam, ClientSideTool, RetrievalToolParam, Handoff, - HangupToolParam, + Hangup, Transfer, Invite, Refer, diff --git a/src/telnyx/types/ai/assistant_update_params.py b/src/telnyx/types/ai/assistant_update_params.py index 0ea5158a4..962ac6a57 100644 --- a/src/telnyx/types/ai/assistant_update_params.py +++ b/src/telnyx/types/ai/assistant_update_params.py @@ -155,10 +155,10 @@ class AssistantUpdateParams(TypedDict, total=False): """Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the - conversation ends, allowing it to execute tool calls such as logging to a CRM or - sending a summary. The assistant can execute multiple parallel or sequential - tools during this phase. Telephony-control tools (e.g. hangup, transfer) are - unavailable post-conversation. Beta feature. + conversation ends, allowing it to execute final tool calls such as sending a + summary or updating a record via webhook or function tools. Integration and MCP + server tools are not available post-conversation; call-control tools (e.g. + hangup, transfer) are also unavailable. Beta feature. """ privacy_settings: PrivacySettingsParam @@ -180,14 +180,25 @@ class AssistantUpdateParams(TypedDict, total=False): tool_ids: SequenceNotStr[str] """IDs of shared tools to attach to the assistant. - New integrations should prefer `tool_ids` over inline `tools`. + New integrations should prefer `tool_ids` over inline `tools`. On update, a sent + `tool_ids` array fully replaces the assistant's attached shared tools; omit the + field to leave them unchanged. Single-instance tool types are counted across + inline `tools` and `tool_ids` combined, so attaching a shared tool of such a + type when an instance already exists returns HTTP 400 with error code 10015. """ tools: Iterable[AssistantToolParam] """Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach - shared tools created with the AI Tools endpoints. + shared tools created with the AI Tools endpoints. On update, a sent `tools` + array fully replaces the assistant's inline tools; omit the field to leave the + inline tools unchanged. Each tool type except `function`, `webhook`, and + `client_side_tool` allows at most one instance per assistant, counted across + inline `tools` and shared `tool_ids` combined — sending a duplicate of such a + type returns HTTP 400 with error code 10015. Responses merge shared tools into + `tools` with `shared: true`; when updating, omit those tools from the `tools` + array and manage them through `tool_ids` instead. """ transcription: TranscriptionSettingsParam diff --git a/src/telnyx/types/ai/assistants/version_update_params.py b/src/telnyx/types/ai/assistants/version_update_params.py index 66a52f5b6..cf2f14132 100644 --- a/src/telnyx/types/ai/assistants/version_update_params.py +++ b/src/telnyx/types/ai/assistants/version_update_params.py @@ -157,10 +157,10 @@ class VersionUpdateParams(TypedDict, total=False): """Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the - conversation ends, allowing it to execute tool calls such as logging to a CRM or - sending a summary. The assistant can execute multiple parallel or sequential - tools during this phase. Telephony-control tools (e.g. hangup, transfer) are - unavailable post-conversation. Beta feature. + conversation ends, allowing it to execute final tool calls such as sending a + summary or updating a record via webhook or function tools. Integration and MCP + server tools are not available post-conversation; call-control tools (e.g. + hangup, transfer) are also unavailable. Beta feature. """ privacy_settings: PrivacySettingsParam @@ -176,14 +176,25 @@ class VersionUpdateParams(TypedDict, total=False): tool_ids: SequenceNotStr[str] """IDs of shared tools to attach to the assistant. - New integrations should prefer `tool_ids` over inline `tools`. + New integrations should prefer `tool_ids` over inline `tools`. On update, a sent + `tool_ids` array fully replaces the assistant's attached shared tools; omit the + field to leave them unchanged. Single-instance tool types are counted across + inline `tools` and `tool_ids` combined, so attaching a shared tool of such a + type when an instance already exists returns HTTP 400 with error code 10015. """ tools: Iterable[AssistantToolParam] """Deprecated for new integrations. Inline tool definitions available to the assistant. Prefer `tool_ids` to attach - shared tools created with the AI Tools endpoints. + shared tools created with the AI Tools endpoints. On update, a sent `tools` + array fully replaces the assistant's inline tools; omit the field to leave the + inline tools unchanged. Each tool type except `function`, `webhook`, and + `client_side_tool` allows at most one instance per assistant, counted across + inline `tools` and shared `tool_ids` combined — sending a duplicate of such a + type returns HTTP 400 with error code 10015. Responses merge shared tools into + `tools` with `shared: true`; when updating, omit those tools from the `tools` + array and manage them through `tool_ids` instead. """ transcription: TranscriptionSettingsParam diff --git a/src/telnyx/types/ai/audio_transcribe_params.py b/src/telnyx/types/ai/audio_transcribe_params.py index 15264e9b3..f21406ed5 100644 --- a/src/telnyx/types/ai/audio_transcribe_params.py +++ b/src/telnyx/types/ai/audio_transcribe_params.py @@ -12,43 +12,64 @@ class AudioTranscribeParams(TypedDict, total=False): - model: Required[Literal["distil-whisper/distil-large-v2", "openai/whisper-large-v3-turbo", "deepgram/nova-3"]] + model: Required[ + Literal[ + "distil-whisper/distil-large-v2", + "openai/whisper-large-v3-turbo", + "deepgram/nova-2", + "deepgram/nova-2-medical", + "deepgram/nova-3", + "deepgram/nova-3-medical", + "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", + ] + ] """ID of the model to use. `distil-whisper/distil-large-v2` is lower latency but English-only. `openai/whisper-large-v3-turbo` is multi-lingual but slightly higher latency. - `deepgram/nova-3` supports English variants (en, en-US, en-GB, en-AU, en-NZ, - en-IN) and only accepts mp3/wav files. + The `deepgram/*` models only accept mp3/wav files: `deepgram/nova-3` covers ~49 + languages plus `multi` and `deepgram/nova-2` covers ~33, while the `-medical` + variants are tuned for clinical vocabulary and accept English only (`en` and its + regional variants, e.g. `en-US`, `en-GB`). `nvidia/parakeet-v3` is multilingual + with automatic language detection; `omi-health/omi-med-stt-v1` is a medical + model, English only. """ file: FileTypes """ The audio file object to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. File uploads are limited to 100 MB. Cannot - be used together with `file_url`. Note: `deepgram/nova-3` only supports mp3 and - wav formats. + be used together with `file_url`. Note: the `deepgram/*` models only support mp3 + and wav formats. """ file_url: str """ Link to audio file in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. Support for hosted files is limited to 100MB. Cannot be used - together with `file`. Note: `deepgram/nova-3` only supports mp3 and wav formats. + together with `file`. Note: the `deepgram/*` models only support mp3 and wav + formats. """ language: str """The language of the audio to be transcribed. - For `deepgram/nova-3`, only English variants are supported: `en`, `en-US`, - `en-GB`, `en-AU`, `en-NZ`, `en-IN`. For `openai/whisper-large-v3-turbo`, - supports multiple languages. `distil-whisper/distil-large-v2` does not support - language parameter. + `deepgram/nova-3` supports ~49 languages plus `multi`, and `deepgram/nova-2` + supports ~33 plus `multi`; the `-medical` variants are English only (`en` and + its regional variants, e.g. `en-US`, `en-GB`). Deepgram models validate on the + base language and forward the full tag, so regional variants such as `de-CH` and + `pt-BR` are accepted where the base language is supported; an unsupported + language returns a 400. For `openai/whisper-large-v3-turbo`, supports multiple + languages. `distil-whisper/distil-large-v2` does not support language parameter. + `nvidia/parakeet-v3` detects the language automatically; + `omi-health/omi-med-stt-v1` is English only. """ model_config: Dict[str, object] """Additional model-specific configuration parameters. - Only allowed with `deepgram/nova-3` model. Can include Deepgram-specific options + Only allowed with the `deepgram/*` models. Can include Deepgram-specific options such as `smart_format`, `punctuate`, `diarize`, `utterance`, `numerals`, and `language`. If `language` is provided both as a top-level parameter and in `model_config`, the top-level parameter takes precedence. diff --git a/src/telnyx/types/ai/audio_transcribe_response.py b/src/telnyx/types/ai/audio_transcribe_response.py index fcc5007ab..05ac29854 100644 --- a/src/telnyx/types/ai/audio_transcribe_response.py +++ b/src/telnyx/types/ai/audio_transcribe_response.py @@ -5,8 +5,9 @@ from typing import List, Optional from ..._models import BaseModel +from .audio_transcription_response_word import AudioTranscriptionResponseWord -__all__ = ["AudioTranscribeResponse", "Segment", "Word"] +__all__ = ["AudioTranscribeResponse", "Segment"] class Segment(BaseModel): @@ -22,33 +23,25 @@ class Segment(BaseModel): text: str """Text content of the segment.""" + speakers: Optional[List[int]] = None + """Speaker indices heard in this segment. -class Word(BaseModel): - """Word-level timing detail. - - Only present when using `deepgram/nova-3` with `model_config` options that enable word timestamps. + Returned by the `deepgram/*` models when `diarize` is enabled via + `model_config`. """ - end: float - """End time of the word in seconds.""" - - start: float - """Start time of the word in seconds.""" + words: Optional[List[AudioTranscriptionResponseWord]] = None + """Word-level timing detail for this segment. - word: str - """The transcribed word.""" - - confidence: Optional[float] = None - """Confidence score for the word (0.0 to 1.0).""" - - speaker: Optional[int] = None - """Speaker index. Only present when diarization is enabled via `model_config`.""" + Returned by the `deepgram/*` models when word-level output is enabled via + `model_config`. + """ class AudioTranscribeResponse(BaseModel): """Response fields vary by model. - `distil-whisper/distil-large-v2` returns `text`, `duration`, and `segments` in `verbose_json` mode. `openai/whisper-large-v3-turbo` returns `text` only. `deepgram/nova-3` returns `text` and, depending on `model_config`, may include `words` with per-word timestamps and speaker labels. + `distil-whisper/distil-large-v2` returns `text`, `duration`, and `segments` in `verbose_json` mode. `openai/whisper-large-v3-turbo` returns `text` only. The `deepgram/*` models return `text` and, depending on `model_config`, may include `words` with per-word timestamps and speaker labels. The Parakeet models (`nvidia/parakeet-v3`, `omi-health/omi-med-stt-v1`) return `text` only. """ text: str @@ -57,7 +50,7 @@ class AudioTranscribeResponse(BaseModel): duration: Optional[float] = None """The duration of the audio file in seconds. - Returned by `distil-whisper/distil-large-v2` and `deepgram/nova-3` when + Returned by `distil-whisper/distil-large-v2` and the `deepgram/*` models when `response_format` is `verbose_json`. Not returned by `openai/whisper-large-v3-turbo`. """ @@ -65,13 +58,14 @@ class AudioTranscribeResponse(BaseModel): segments: Optional[List[Segment]] = None """Segments of the transcribed text and their corresponding details. - Returned by `distil-whisper/distil-large-v2` when `response_format` is - `verbose_json`. Not returned by `openai/whisper-large-v3-turbo`. + Returned by `distil-whisper/distil-large-v2` and the `deepgram/*` models when + `response_format` is `verbose_json`; Deepgram segments also carry nested `words` + and `speakers`. Not returned by `openai/whisper-large-v3-turbo`. """ - words: Optional[List[Word]] = None + words: Optional[List[AudioTranscriptionResponseWord]] = None """Word-level timestamps and optional speaker labels. - Only returned by `deepgram/nova-3` when word-level output is enabled via + Only returned by the `deepgram/*` models when word-level output is enabled via `model_config`. """ diff --git a/src/telnyx/types/ai/audio_transcription_response_word.py b/src/telnyx/types/ai/audio_transcription_response_word.py new file mode 100644 index 000000000..5062e74fd --- /dev/null +++ b/src/telnyx/types/ai/audio_transcription_response_word.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["AudioTranscriptionResponseWord"] + + +class AudioTranscriptionResponseWord(BaseModel): + """Word-level timing detail. + + Only present when using a `deepgram/*` model with `model_config` options that enable word timestamps. + """ + + end: float + """End time of the word in seconds.""" + + start: float + """Start time of the word in seconds.""" + + word: str + """The transcribed word.""" + + confidence: Optional[float] = None + """Confidence score for the word (0.0 to 1.0).""" + + punctuated_word: Optional[str] = None + """The transcribed word with punctuation and capitalisation applied. + + Only present when `punctuate` or `smart_format` is enabled via `model_config`. + """ + + speaker: Optional[int] = None + """Speaker index. Only present when diarization is enabled via `model_config`.""" + + speaker_confidence: Optional[float] = None + """Confidence score for the speaker assignment (0.0 to 1.0). + + Only present when diarization is enabled via `model_config`. + """ diff --git a/src/telnyx/types/ai/hangup_tool.py b/src/telnyx/types/ai/hangup_tool.py deleted file mode 100644 index 45be91d2e..000000000 --- a/src/telnyx/types/ai/hangup_tool.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -from ..._models import BaseModel -from .hangup_tool_params import HangupToolParams - -__all__ = ["HangupTool"] - - -class HangupTool(BaseModel): - hangup: HangupToolParams - - type: Literal["hangup"] diff --git a/src/telnyx/types/ai/inference_embedding.py b/src/telnyx/types/ai/inference_embedding.py index 373c03b9e..e03d12d0a 100644 --- a/src/telnyx/types/ai/inference_embedding.py +++ b/src/telnyx/types/ai/inference_embedding.py @@ -156,10 +156,10 @@ class InferenceEmbedding(BaseModel): """Configuration for post-conversation processing. When enabled, the assistant receives one additional LLM turn after the - conversation ends, allowing it to execute tool calls such as logging to a CRM or - sending a summary. The assistant can execute multiple parallel or sequential - tools during this phase. Telephony-control tools (e.g. hangup, transfer) are - unavailable post-conversation. Beta feature. + conversation ends, allowing it to execute final tool calls such as sending a + summary or updating a record via webhook or function tools. Integration and MCP + server tools are not available post-conversation; call-control tools (e.g. + hangup, transfer) are also unavailable. Beta feature. """ privacy_settings: Optional[PrivacySettings] = None @@ -176,10 +176,14 @@ class InferenceEmbedding(BaseModel): telephony_settings: Optional[TelephonySettings] = None tools: Optional[List[AssistantTool]] = None - """Deprecated for new integrations. - - Inline tool definitions available to the assistant. Prefer `tool_ids` to attach - shared tools created with the AI Tools endpoints. + """The assistant's tools. + + Responses merge the assistant's shared Tools Library tools into this array + alongside inline tools, each flagged `shared: true`; inline tools carry + `shared: false`. On update, a sent `tools` array fully replaces the inline tools + only — shared tools stay attached unless `tool_ids` changes. Each tool type + except `function`, `webhook`, and `client_side_tool` allows at most one instance + per assistant across both sources. """ transcription: Optional[TranscriptionSettings] = None diff --git a/src/telnyx/types/ai/inference_embedding_interruption_settings.py b/src/telnyx/types/ai/inference_embedding_interruption_settings.py index 501c7b3ee..b08c6d478 100644 --- a/src/telnyx/types/ai/inference_embedding_interruption_settings.py +++ b/src/telnyx/types/ai/inference_embedding_interruption_settings.py @@ -21,6 +21,12 @@ class InferenceEmbeddingInterruptionSettings(BaseModel): enable: Optional[bool] = None """Whether users can interrupt the assistant while it is speaking.""" + interrupt_prediction_threshold: Optional[float] = None + """Interrupt-prediction sensitivity, from 0.0 to 1.0. + + Set to null or 0.0 to disable interrupt prediction. + """ + start_speaking_plan: Optional[StartSpeakingPlan] = None """Controls when the assistant starts speaking after the user stops. diff --git a/src/telnyx/types/ai/inference_embedding_interruption_settings_param.py b/src/telnyx/types/ai/inference_embedding_interruption_settings_param.py index 25a9c7678..31917d7f4 100644 --- a/src/telnyx/types/ai/inference_embedding_interruption_settings_param.py +++ b/src/telnyx/types/ai/inference_embedding_interruption_settings_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import TypedDict from .start_speaking_plan_param import StartSpeakingPlanParam @@ -20,6 +21,12 @@ class InferenceEmbeddingInterruptionSettingsParam(TypedDict, total=False): enable: bool """Whether users can interrupt the assistant while it is speaking.""" + interrupt_prediction_threshold: Optional[float] + """Interrupt-prediction sensitivity, from 0.0 to 1.0. + + Set to null or 0.0 to disable interrupt prediction. + """ + start_speaking_plan: StartSpeakingPlanParam """Controls when the assistant starts speaking after the user stops. diff --git a/src/telnyx/types/ai/inference_embedding_webhook_tool_params.py b/src/telnyx/types/ai/inference_embedding_webhook_tool_params.py index 1b2058268..6a4f28a0c 100644 --- a/src/telnyx/types/ai/inference_embedding_webhook_tool_params.py +++ b/src/telnyx/types/ai/inference_embedding_webhook_tool_params.py @@ -234,3 +234,14 @@ class InferenceEmbeddingWebhookToolParams(BaseModel): type: Literal["webhook"] webhook: Webhook + + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ diff --git a/src/telnyx/types/ai/openai/__init__.py b/src/telnyx/types/ai/openai/__init__.py index 80295a1de..56bec554a 100644 --- a/src/telnyx/types/ai/openai/__init__.py +++ b/src/telnyx/types/ai/openai/__init__.py @@ -4,11 +4,13 @@ from typing import TYPE_CHECKING, Any +from .function_definition_param import FunctionDefinitionParam as FunctionDefinitionParam from .chat_create_completion_params import ChatCreateCompletionParams as ChatCreateCompletionParams from .chat_create_completion_response import ChatCreateCompletionResponse as ChatCreateCompletionResponse from .embedding_create_embeddings_params import EmbeddingCreateEmbeddingsParams as EmbeddingCreateEmbeddingsParams if TYPE_CHECKING: + from .function_definition import FunctionDefinition as FunctionDefinition from .embedding_create_embeddings_response import ( EmbeddingCreateEmbeddingsResponse as EmbeddingCreateEmbeddingsResponse, ) @@ -26,4 +28,8 @@ def __getattr__(name: str) -> Any: from .embedding_list_embedding_models_response import EmbeddingListEmbeddingModelsResponse return EmbeddingListEmbeddingModelsResponse + if name == "FunctionDefinition": + from .function_definition import FunctionDefinition + + return FunctionDefinition raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/ai/openai/chat_create_completion_params.py b/src/telnyx/types/ai/openai/chat_create_completion_params.py index 4570e5a4d..8595202f5 100644 --- a/src/telnyx/types/ai/openai/chat_create_completion_params.py +++ b/src/telnyx/types/ai/openai/chat_create_completion_params.py @@ -7,6 +7,7 @@ from ...._types import SequenceNotStr from ..bucket_ids_param import BucketIDsParam +from .function_definition_param import FunctionDefinitionParam __all__ = [ "ChatCreateCompletionParams", @@ -19,7 +20,6 @@ "ResponseFormatResponseFormatJsonSchemaParamJsonSchema", "Tool", "ToolFunction", - "ToolFunctionFunction", "ToolRetrieval", ] @@ -267,16 +267,8 @@ class ResponseFormatResponseFormatJsonSchemaParam(TypedDict, total=False): ] -class ToolFunctionFunction(TypedDict, total=False): - name: Required[str] - - description: str - - parameters: Dict[str, object] - - class ToolFunction(TypedDict, total=False): - function: Required[ToolFunctionFunction] + function: Required[FunctionDefinitionParam] type: Required[Literal["function"]] diff --git a/src/telnyx/types/ai/openai/function_definition.py b/src/telnyx/types/ai/openai/function_definition.py new file mode 100644 index 000000000..9bf12a6b3 --- /dev/null +++ b/src/telnyx/types/ai/openai/function_definition.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional + +from ...._models import BaseModel + +__all__ = ["FunctionDefinition"] + + +class FunctionDefinition(BaseModel): + name: str + + description: Optional[str] = None + + parameters: Optional[Dict[str, object]] = None diff --git a/src/telnyx/types/ai/openai/function_definition_param.py b/src/telnyx/types/ai/openai/function_definition_param.py new file mode 100644 index 000000000..24ed5fafe --- /dev/null +++ b/src/telnyx/types/ai/openai/function_definition_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["FunctionDefinitionParam"] + + +class FunctionDefinitionParam(TypedDict, total=False): + name: Required[str] + + description: str + + parameters: Dict[str, object] diff --git a/src/telnyx/types/ai/post_conversation_settings.py b/src/telnyx/types/ai/post_conversation_settings.py index b94996352..efeb64840 100644 --- a/src/telnyx/types/ai/post_conversation_settings.py +++ b/src/telnyx/types/ai/post_conversation_settings.py @@ -12,7 +12,7 @@ class PostConversationSettings(BaseModel): """Configuration for post-conversation processing. - When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to execute tool calls such as logging to a CRM or sending a summary. The assistant can execute multiple parallel or sequential tools during this phase. Telephony-control tools (e.g. hangup, transfer) are unavailable post-conversation. Beta feature. + When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to execute final tool calls such as sending a summary or updating a record via webhook or function tools. Integration and MCP server tools are not available post-conversation; call-control tools (e.g. hangup, transfer) are also unavailable. Beta feature. """ enabled: Optional[bool] = None diff --git a/src/telnyx/types/ai/post_conversation_settings_req_param.py b/src/telnyx/types/ai/post_conversation_settings_req_param.py index 1198ac715..db59ab67b 100644 --- a/src/telnyx/types/ai/post_conversation_settings_req_param.py +++ b/src/telnyx/types/ai/post_conversation_settings_req_param.py @@ -10,7 +10,7 @@ class PostConversationSettingsReqParam(TypedDict, total=False): """Configuration for post-conversation processing. - When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to execute tool calls such as logging to a CRM or sending a summary. The assistant can execute multiple parallel or sequential tools during this phase. Telephony-control tools (e.g. hangup, transfer) are unavailable post-conversation. Beta feature. + When enabled, the assistant receives one additional LLM turn after the conversation ends, allowing it to execute final tool calls such as sending a summary or updating a record via webhook or function tools. Integration and MCP server tools are not available post-conversation; call-control tools (e.g. hangup, transfer) are also unavailable. Beta feature. """ enabled: bool diff --git a/src/telnyx/types/ai/privacy_settings.py b/src/telnyx/types/ai/privacy_settings.py index e950304f0..976d29356 100644 --- a/src/telnyx/types/ai/privacy_settings.py +++ b/src/telnyx/types/ai/privacy_settings.py @@ -19,3 +19,19 @@ class PrivacySettings(BaseModel): you have set at the account, number, or application level. All such external settings remain in force regardless of your selection here. """ + + in_transit_data_locality: Optional[bool] = None + """ + Requires every model call made for a web chat turn to be received and served + inside your organization's data-locality region, rather than only stored there. + Applies to web chat only — voice and messaging assistants are unaffected. + Enabling it requires a data-locality region with in-region inference (USA, EU, + AUS, UAE; see + [Inference regions](https://developers.telnyx.com/docs/inference/models/regions)) + and Telnyx-hosted models for the assistant, its fallback, and any + conversation-flow node that overrides the model; the request is rejected + otherwise. Once enabled, send chat requests to your region's API hostname: a + request entering the platform in another region is rejected rather than + forwarded, because forwarding it would already have moved the content across the + border. Defaults to false. + """ diff --git a/src/telnyx/types/ai/privacy_settings_param.py b/src/telnyx/types/ai/privacy_settings_param.py index a9b492577..b22c41547 100644 --- a/src/telnyx/types/ai/privacy_settings_param.py +++ b/src/telnyx/types/ai/privacy_settings_param.py @@ -17,3 +17,19 @@ class PrivacySettingsParam(TypedDict, total=False): you have set at the account, number, or application level. All such external settings remain in force regardless of your selection here. """ + + in_transit_data_locality: bool + """ + Requires every model call made for a web chat turn to be received and served + inside your organization's data-locality region, rather than only stored there. + Applies to web chat only — voice and messaging assistants are unaffected. + Enabling it requires a data-locality region with in-region inference (USA, EU, + AUS, UAE; see + [Inference regions](https://developers.telnyx.com/docs/inference/models/regions)) + and Telnyx-hosted models for the assistant, its fallback, and any + conversation-flow node that overrides the model; the request is rejected + otherwise. Once enabled, send chat requests to your region's API hostname: a + request entering the platform in another region is rejected rather than + forwarded, because forwarding it would already have moved the content across the + border. Defaults to false. + """ diff --git a/src/telnyx/types/ai/retrieval_tool.py b/src/telnyx/types/ai/retrieval_tool.py index f07729e26..f4e36911b 100644 --- a/src/telnyx/types/ai/retrieval_tool.py +++ b/src/telnyx/types/ai/retrieval_tool.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import Literal from ..._models import BaseModel @@ -14,3 +15,14 @@ class RetrievalTool(BaseModel): retrieval: BucketIDs type: Literal["retrieval"] + + shared: Optional[bool] = None + """Whether this tool comes from the shared Tools Library. + + Responses merge shared tools into `tools` with `shared: true`; inline tools + carry `shared: false`. Read-only: set by the server, not accepted in requests. + When updating an assistant, omit `shared: true` tools from the request `tools` + array and manage them through `tool_ids` instead — re-sending their definitions + creates an inline duplicate (rejected with error code 10015 when the type allows + only one instance per assistant). + """ diff --git a/src/telnyx/types/ai/telephony_settings.py b/src/telnyx/types/ai/telephony_settings.py index 5e64f5302..98128bc92 100644 --- a/src/telnyx/types/ai/telephony_settings.py +++ b/src/telnyx/types/ai/telephony_settings.py @@ -20,14 +20,40 @@ class NoiseSuppressionConfig(BaseModel): """Configuration for noise suppression. - Only applicable when noise_suppression is 'deepfilternet'. + Applicable fields depend on the engine: 'attenuation_limit' and 'mode' only when noise_suppression is 'deepfilternet'; 'family', 'size' and 'enhancement_level' only when noise_suppression is 'aicoustics'. """ attenuation_limit: Optional[int] = None - """Attenuation limit for noise suppression. Range: 0-100.""" + """Attenuation limit for noise suppression. + + Range: 0-100. Only applicable when noise_suppression is 'deepfilternet'. + """ + + enhancement_level: Optional[float] = None + """AiCoustics enhancement intensity. + + Range: 0-1. Only applicable when noise_suppression is 'aicoustics'. + """ + + family: Optional[Literal["quail"]] = None + """AiCoustics model family optimized for Voice AI and STT. + + Only applicable when noise_suppression is 'aicoustics'. + """ mode: Optional[Literal["advanced"]] = None - """Mode for noise suppression configuration.""" + """Mode for noise suppression configuration. + + Only applicable when noise_suppression is 'deepfilternet'. + """ + + size: Optional[Literal["vf", "vf_2_0_l"]] = None + """AiCoustics model size. + + 'vf' tracks the latest model release; 'vf_2_0_l' is pinned to version 2.0 for + consistent, predictable behavior. Only applicable when noise_suppression is + 'aicoustics'. + """ class RecordingSettings(BaseModel): @@ -127,16 +153,19 @@ class TelephonySettings(BaseModel): bridged the call. """ - noise_suppression: Optional[Literal["krisp", "deepfilternet", "disabled"]] = None + noise_suppression: Optional[Literal["aicoustics", "krisp", "deepfilternet", "disabled"]] = None """The noise suppression engine to use. - Use 'disabled' to turn off noise suppression. + 'aicoustics' is STT-optimized and recommended for AI assistants (configure + through noise_suppression_config). Use 'disabled' to turn off noise suppression. """ noise_suppression_config: Optional[NoiseSuppressionConfig] = None """Configuration for noise suppression. - Only applicable when noise_suppression is 'deepfilternet'. + Applicable fields depend on the engine: 'attenuation_limit' and 'mode' only when + noise_suppression is 'deepfilternet'; 'family', 'size' and 'enhancement_level' + only when noise_suppression is 'aicoustics'. """ recording_settings: Optional[RecordingSettings] = None diff --git a/src/telnyx/types/ai/telephony_settings_param.py b/src/telnyx/types/ai/telephony_settings_param.py index 24348ded3..6c9091b87 100644 --- a/src/telnyx/types/ai/telephony_settings_param.py +++ b/src/telnyx/types/ai/telephony_settings_param.py @@ -17,14 +17,40 @@ class NoiseSuppressionConfig(TypedDict, total=False): """Configuration for noise suppression. - Only applicable when noise_suppression is 'deepfilternet'. + Applicable fields depend on the engine: 'attenuation_limit' and 'mode' only when noise_suppression is 'deepfilternet'; 'family', 'size' and 'enhancement_level' only when noise_suppression is 'aicoustics'. """ attenuation_limit: int - """Attenuation limit for noise suppression. Range: 0-100.""" + """Attenuation limit for noise suppression. + + Range: 0-100. Only applicable when noise_suppression is 'deepfilternet'. + """ + + enhancement_level: float + """AiCoustics enhancement intensity. + + Range: 0-1. Only applicable when noise_suppression is 'aicoustics'. + """ + + family: Literal["quail"] + """AiCoustics model family optimized for Voice AI and STT. + + Only applicable when noise_suppression is 'aicoustics'. + """ mode: Literal["advanced"] - """Mode for noise suppression configuration.""" + """Mode for noise suppression configuration. + + Only applicable when noise_suppression is 'deepfilternet'. + """ + + size: Literal["vf", "vf_2_0_l"] + """AiCoustics model size. + + 'vf' tracks the latest model release; 'vf_2_0_l' is pinned to version 2.0 for + consistent, predictable behavior. Only applicable when noise_suppression is + 'aicoustics'. + """ class RecordingSettings(TypedDict, total=False): @@ -124,16 +150,19 @@ class TelephonySettingsParam(TypedDict, total=False): bridged the call. """ - noise_suppression: Literal["krisp", "deepfilternet", "disabled"] + noise_suppression: Literal["aicoustics", "krisp", "deepfilternet", "disabled"] """The noise suppression engine to use. - Use 'disabled' to turn off noise suppression. + 'aicoustics' is STT-optimized and recommended for AI assistants (configure + through noise_suppression_config). Use 'disabled' to turn off noise suppression. """ noise_suppression_config: NoiseSuppressionConfig """Configuration for noise suppression. - Only applicable when noise_suppression is 'deepfilternet'. + Applicable fields depend on the engine: 'attenuation_limit' and 'mode' only when + noise_suppression is 'deepfilternet'; 'family', 'size' and 'enhancement_level' + only when noise_suppression is 'aicoustics'. """ recording_settings: RecordingSettings diff --git a/src/telnyx/types/ai/transcription_settings.py b/src/telnyx/types/ai/transcription_settings.py index 961e55888..62a458d9e 100644 --- a/src/telnyx/types/ai/transcription_settings.py +++ b/src/telnyx/types/ai/transcription_settings.py @@ -46,11 +46,13 @@ class TranscriptionSettings(BaseModel): "deepgram/nova-3", "deepgram/nova-2", "azure/fast", + "assemblyai/universal-3-5-pro", "assemblyai/universal-streaming", "xai/grok-stt", "soniox/stt-rt-v4", "soniox/stt-rt-v5", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", @@ -66,14 +68,17 @@ class TranscriptionSettings(BaseModel): - `deepgram/nova-3` is multilingual with automatic language detection. - `deepgram/nova-2` is Deepgram's previous-generation multilingual model. - `azure/fast` is a multilingual Azure transcription model. - - `assemblyai/universal-streaming` is a multilingual streaming model with - configurable turn detection. + - `assemblyai/universal-3-5-pro` is a multilingual streaming model with + configurable turn detection. The legacy alias `assemblyai/universal-streaming` + is still accepted and resolves to the same model. - `xai/grok-stt` is a multilingual Grok STT model. - `soniox/stt-rt-v4` and `soniox/stt-rt-v5` are multilingual streaming models with automatic language detection, configurable endpointing, term biasing (`context`), and `language_hints`. - `nvidia/parakeet-v3` is a multilingual transcription model with automatic language detection. + - `omi-health/omi-med-stt-v1` is an English-only medical transcription model + (Parakeet-based). - `humain/realtime` is a streaming model with native Arabic and Arabic/English code-switching support. - `reson8/turns` is a turn-based streaming model covering 10 European languages diff --git a/src/telnyx/types/ai/transcription_settings_config.py b/src/telnyx/types/ai/transcription_settings_config.py index e404ef4fc..e613da93b 100644 --- a/src/telnyx/types/ai/transcription_settings_config.py +++ b/src/telnyx/types/ai/transcription_settings_config.py @@ -37,10 +37,10 @@ class TranscriptionSettingsConfig(BaseModel): """ end_of_turn_confidence_threshold: Optional[float] = None - """Available only for assemblyai/universal-streaming. - - Confidence level required to trigger an end of turn. Higher values require more - certainty before ending a turn. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Confidence level required to trigger an end of + turn. Higher values require more certainty before ending a turn. """ eot_threshold: Optional[float] = None @@ -90,16 +90,17 @@ class TranscriptionSettingsConfig(BaseModel): """ max_turn_silence: Optional[int] = None - """Available only for assemblyai/universal-streaming. - - Maximum duration of silence in milliseconds before forcing an end of turn. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Maximum duration of silence in milliseconds + before forcing an end of turn. """ min_turn_silence: Optional[int] = None - """Available only for assemblyai/universal-streaming. - - Minimum duration of silence in milliseconds before a turn can end. Must be less - than or equal to max_turn_silence. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Minimum duration of silence in milliseconds + before a turn can end. Must be less than or equal to max_turn_silence. """ numerals: Optional[bool] = None diff --git a/src/telnyx/types/ai/transcription_settings_config_param.py b/src/telnyx/types/ai/transcription_settings_config_param.py index b6300fed0..6ebe64270 100644 --- a/src/telnyx/types/ai/transcription_settings_config_param.py +++ b/src/telnyx/types/ai/transcription_settings_config_param.py @@ -37,10 +37,10 @@ class TranscriptionSettingsConfigParam(TypedDict, total=False): """ end_of_turn_confidence_threshold: float - """Available only for assemblyai/universal-streaming. - - Confidence level required to trigger an end of turn. Higher values require more - certainty before ending a turn. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Confidence level required to trigger an end of + turn. Higher values require more certainty before ending a turn. """ eot_threshold: float @@ -90,16 +90,17 @@ class TranscriptionSettingsConfigParam(TypedDict, total=False): """ max_turn_silence: int - """Available only for assemblyai/universal-streaming. - - Maximum duration of silence in milliseconds before forcing an end of turn. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Maximum duration of silence in milliseconds + before forcing an end of turn. """ min_turn_silence: int - """Available only for assemblyai/universal-streaming. - - Minimum duration of silence in milliseconds before a turn can end. Must be less - than or equal to max_turn_silence. + """ + Available only for assemblyai/universal-3-5-pro (and its legacy alias + assemblyai/universal-streaming). Minimum duration of silence in milliseconds + before a turn can end. Must be less than or equal to max_turn_silence. """ numerals: bool diff --git a/src/telnyx/types/ai/transcription_settings_param.py b/src/telnyx/types/ai/transcription_settings_param.py index 59b9b92e6..6635850e4 100644 --- a/src/telnyx/types/ai/transcription_settings_param.py +++ b/src/telnyx/types/ai/transcription_settings_param.py @@ -43,11 +43,13 @@ class TranscriptionSettingsParam(TypedDict, total=False): "deepgram/nova-3", "deepgram/nova-2", "azure/fast", + "assemblyai/universal-3-5-pro", "assemblyai/universal-streaming", "xai/grok-stt", "soniox/stt-rt-v4", "soniox/stt-rt-v5", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", @@ -62,14 +64,17 @@ class TranscriptionSettingsParam(TypedDict, total=False): - `deepgram/nova-3` is multilingual with automatic language detection. - `deepgram/nova-2` is Deepgram's previous-generation multilingual model. - `azure/fast` is a multilingual Azure transcription model. - - `assemblyai/universal-streaming` is a multilingual streaming model with - configurable turn detection. + - `assemblyai/universal-3-5-pro` is a multilingual streaming model with + configurable turn detection. The legacy alias `assemblyai/universal-streaming` + is still accepted and resolves to the same model. - `xai/grok-stt` is a multilingual Grok STT model. - `soniox/stt-rt-v4` and `soniox/stt-rt-v5` are multilingual streaming models with automatic language detection, configurable endpointing, term biasing (`context`), and `language_hints`. - `nvidia/parakeet-v3` is a multilingual transcription model with automatic language detection. + - `omi-health/omi-med-stt-v1` is an English-only medical transcription model + (Parakeet-based). - `humain/realtime` is a streaming model with native Arabic and Arabic/English code-switching support. - `reson8/turns` is a turn-based streaming model covering 10 European languages diff --git a/src/telnyx/types/ai/typesafe/__init__.py b/src/telnyx/types/ai/typesafe/__init__.py new file mode 100644 index 000000000..490bc05e9 --- /dev/null +++ b/src/telnyx/types/ai/typesafe/__init__.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from .v1_systemone_params import V1SystemoneParams as V1SystemoneParams + +if TYPE_CHECKING: + from .v1_systemone_response import V1SystemoneResponse as V1SystemoneResponse + + +def __getattr__(name: str) -> Any: + if name == "V1SystemoneResponse": + from .v1_systemone_response import V1SystemoneResponse + + return V1SystemoneResponse + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/ai/typesafe/v1_systemone_params.py b/src/telnyx/types/ai/typesafe/v1_systemone_params.py new file mode 100644 index 000000000..4c54d1636 --- /dev/null +++ b/src/telnyx/types/ai/typesafe/v1_systemone_params.py @@ -0,0 +1,91 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from ...._types import SequenceNotStr + +__all__ = [ + "V1SystemoneParams", + "Questions", + "QuestionsDecisionModelChoiceQuestion", + "QuestionsDecisionModelNoulQuestion", + "QuestionsDecisionModelNoulQuestionCriteria", + "QuestionsDecisionModelScoreQuestion", +] + + +class V1SystemoneParams(TypedDict, total=False): + questions: Required[Dict[str, Questions]] + """Between 1 and 64 named questions. Each key identifies the corresponding answer.""" + + state: Required[Union[str, Dict[str, object], Iterable[object]]] + """Shared context evaluated by every question.""" + + +class QuestionsDecisionModelChoiceQuestion(TypedDict, total=False): + """Select one of the supplied options.""" + + criteria: Required[Dict[str, Optional[str]]] + """Between 2 and 64 option keys mapped to description strings or null. + + A null description uses the option key as its text. + """ + + instructions: Required[Union[str, Dict[str, object], Iterable[object]]] + """Required instructions describing what to decide about the shared state.""" + + type: Required[Literal["choice"]] + """Question type.""" + + +class QuestionsDecisionModelNoulQuestionCriteria(TypedDict, total=False): + """Optional descriptions for the positive and negative outcomes. + + Descriptions must be strings. + """ + + false: str + """Description of the negative outcome.""" + + true: str + """Description of the positive outcome.""" + + +class QuestionsDecisionModelNoulQuestion(TypedDict, total=False): + """Evaluate a yes/no question. Omit criteria to use Yes and No descriptions.""" + + instructions: Required[Union[str, Dict[str, object], Iterable[object]]] + """Required instructions describing what to decide about the shared state.""" + + type: Required[Literal["noul"]] + """Question type.""" + + criteria: QuestionsDecisionModelNoulQuestionCriteria + """Optional descriptions for the positive and negative outcomes. + + Descriptions must be strings. + """ + + +class QuestionsDecisionModelScoreQuestion(TypedDict, total=False): + """Rate the state against an ordered rubric.""" + + criteria: Required[SequenceNotStr[str]] + """Between 2 and 64 description strings in ascending score order. + + Indices start at zero. + """ + + instructions: Required[Union[str, Dict[str, object], Iterable[object]]] + """Required instructions describing what to decide about the shared state.""" + + type: Required[Literal["score"]] + """Question type.""" + + +Questions: TypeAlias = Union[ + QuestionsDecisionModelChoiceQuestion, QuestionsDecisionModelNoulQuestion, QuestionsDecisionModelScoreQuestion +] diff --git a/src/telnyx/types/ai/typesafe/v1_systemone_response.py b/src/telnyx/types/ai/typesafe/v1_systemone_response.py new file mode 100644 index 000000000..3af00de36 --- /dev/null +++ b/src/telnyx/types/ai/typesafe/v1_systemone_response.py @@ -0,0 +1,131 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ...._utils import PropertyInfo +from ...._models import BaseModel + +__all__ = [ + "V1SystemoneResponse", + "Answers", + "AnswersDecisionModelChoiceAnswer", + "AnswersDecisionModelNoulAnswer", + "AnswersDecisionModelScoreAnswer", + "Usage", +] + + +class AnswersDecisionModelChoiceAnswer(BaseModel): + """A selected option and the distribution across all supplied option keys.""" + + choice: str + """The option key with the highest relative score. + + Ties favor the first option in request order. + """ + + confidence: float + """ + Normalized entropy confidence: 1 - H(p) / ln(N), where H(p) = -sum(p \\** ln(p)) + and N is the number of options. Zero indicates a uniform distribution; one + indicates concentration on one option. This is neither the winning probability + nor calibrated correctness. + """ + + probabilities: Dict[str, float] + """ + Relative scores normalized across the supplied options, summing approximately + to 1. These are not calibrated probabilities of correctness. + """ + + type: Literal["choice"] + """Answer type.""" + + +class AnswersDecisionModelNoulAnswer(BaseModel): + """A yes/no score with no separate confidence or probabilities fields.""" + + noul: float + """Score of the positive outcome. + + Values near 1 favor yes; values near 0 favor no. This is a number, not a + Boolean, and is not calibrated correctness. + """ + + type: Literal["noul"] + """Answer type.""" + + +class AnswersDecisionModelScoreAnswer(BaseModel): + """An expected rating over the ordered criteria.""" + + confidence: float + """ + Normalized entropy confidence: 1 - H(p) / ln(N), where H(p) = -sum(p \\** ln(p)) + and N is the number of options. Zero indicates a uniform distribution; one + indicates concentration on one option. This is neither the winning probability + nor calibrated correctness. + """ + + legend: Dict[str, str] + """ + Criterion descriptions keyed by stringified zero-based indices, such as "0", + "1", and "2". + """ + + probabilities: Dict[str, float] + """Relative scores keyed by the same stringified indices as legend.""" + + score: float + """Expected zero-based criterion index: sum(index \\** probability). + + Ranges from 0 to N-1 for N criteria; fractional values are valid. + """ + + type: Literal["score"] + """Answer type.""" + + +Answers: TypeAlias = Annotated[ + Union[AnswersDecisionModelChoiceAnswer, AnswersDecisionModelNoulAnswer, AnswersDecisionModelScoreAnswer], + PropertyInfo(discriminator="type"), +] + + +class Usage(BaseModel): + """Token usage for the completed evaluation.""" + + input_tokens: int + """ + Input tokens processed, including shared-context preparation and question + evaluation. This can exceed the token count of the unique input text. + """ + + output_tokens: int + """Output tokens used for the evaluation, including shared-context preparation.""" + + +class V1SystemoneResponse(BaseModel): + """A complete synchronous evaluation. + + Answers are returned directly without a data wrapper. + """ + + answers: Dict[str, Answers] + """Answers keyed by exactly the question IDs in the request. + + Each answer type matches its question. + """ + + model: str + """ + Opaque Telnyx-controlled identifier retained for TypeSafe SDK response + compatibility. It is not a selectable model name or a guarantee of a particular + underlying model. + """ + + usage: Usage + """Token usage for the completed evaluation.""" diff --git a/src/telnyx/types/bot_challenge_create_params.py b/src/telnyx/types/bot_challenge_create_params.py new file mode 100644 index 000000000..da769d5aa --- /dev/null +++ b/src/telnyx/types/bot_challenge_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BotChallengeCreateParams"] + + +class BotChallengeCreateParams(TypedDict, total=False): + llm_model_name: str + """Name of the LLM the client is using.""" + + llm_parameter_count: str + """Parameter count of the client LLM.""" + + llm_quantization: str + """Quantization of the client LLM.""" diff --git a/src/telnyx/types/bot_challenge_create_response.py b/src/telnyx/types/bot_challenge_create_response.py new file mode 100644 index 000000000..463bf4572 --- /dev/null +++ b/src/telnyx/types/bot_challenge_create_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["BotChallengeCreateResponse", "Data"] + + +class Data(BaseModel): + challenge_type: Literal["math", "string", "binary"] + """Type of challenge.""" + + nonce: str + """Single-use challenge identifier. + + Submit it as `bot_challenge_nonce` on the signup request. + """ + + privacy_policy_url: str + """Current privacy-policy URL. Echo this back on the signup request.""" + + problem: str + """Problem text to solve. + + Math problems are obfuscated and end with an unobfuscated rounding instruction; + string and binary problems are returned as-is. + """ + + terms_and_conditions_url: str + """Current terms-and-conditions URL. Echo this back on the signup request.""" + + precision: Optional[int] = None + """Decimal places expected in the answer. Present only for math challenges.""" + + +class BotChallengeCreateResponse(BaseModel): + data: Data diff --git a/src/telnyx/types/bot_session_list_params.py b/src/telnyx/types/bot_session_list_params.py new file mode 100644 index 000000000..2c97820a4 --- /dev/null +++ b/src/telnyx/types/bot_session_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BotSessionListParams"] + + +class BotSessionListParams(TypedDict, total=False): + email: Required[str] + """Email address associated with the magic link token.""" + + portal_redirect_token: Required[str] + """ + Single-use portal redirect (magic link) token, a UUIDv7 sent to the account + owner's email. + """ diff --git a/src/telnyx/types/bot_session_list_response.py b/src/telnyx/types/bot_session_list_response.py new file mode 100644 index 000000000..185b5e607 --- /dev/null +++ b/src/telnyx/types/bot_session_list_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["BotSessionListResponse", "Data"] + + +class Data(BaseModel): + api_v2_token: str + """API v2 session token for the signed-in user. + + Use it as a bearer token on authenticated endpoints. + """ + + +class BotSessionListResponse(BaseModel): + data: Data diff --git a/src/telnyx/types/bot_signup_create_params.py b/src/telnyx/types/bot_signup_create_params.py new file mode 100644 index 000000000..0a93f7e71 --- /dev/null +++ b/src/telnyx/types/bot_signup_create_params.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["BotSignupCreateParams"] + + +class BotSignupCreateParams(TypedDict, total=False): + bot_challenge_answer: Required[str] + """Answer to the issued bot challenge.""" + + bot_challenge_nonce: Required[str] + """Nonce from a previously issued bot challenge.""" + + privacy_policy_url: Required[str] + """Must exactly match the privacy-policy URL returned by the challenge endpoint.""" + + terms_and_conditions_url: Required[str] + """ + Must exactly match the terms-and-conditions URL returned by the challenge + endpoint. + """ + + terms_of_service: Required[Literal[True]] + """Must be true to accept the terms of service.""" + + email: str + """Email address for the new account. + + The magic link is sent here. May only be omitted when placeholder-email + registration is enabled server-side. + """ + + terms_and_conditions_eu_url: str + """EU terms-and-conditions URL. Required when EU consent enforcement is enabled.""" + + terms_of_service_eu: Literal[True] + """EU terms-of-service acceptance. + + Required when EU consent enforcement is enabled. + """ diff --git a/src/telnyx/types/bot_signup_resend_magic_link_params.py b/src/telnyx/types/bot_signup_resend_magic_link_params.py new file mode 100644 index 000000000..a549170c3 --- /dev/null +++ b/src/telnyx/types/bot_signup_resend_magic_link_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BotSignupResendMagicLinkParams"] + + +class BotSignupResendMagicLinkParams(TypedDict, total=False): + email: Required[str] + """Email address of the bot signup account to resend the magic link to.""" diff --git a/src/telnyx/types/call_dial_params.py b/src/telnyx/types/call_dial_params.py index 00e5bafb4..713fe8ea6 100644 --- a/src/telnyx/types/call_dial_params.py +++ b/src/telnyx/types/call_dial_params.py @@ -159,12 +159,13 @@ class CallDialParams(TypedDict, total=False): dialogflow_config: DialogflowConfigParam diversion: str - """ - The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + """The `to` number of an active inbound call, in +E164 format. + + Telnyx checks whether there is currently an active inbound call where `to` + matches this `diversion` value and `from` matches the `from` number supplied for + this request. If such a call exists, the `from` number is treated as verified + (since it is already on an active inbound call to you) and can be used as the + caller id for this outbound call. """ enable_dialogflow: bool @@ -456,6 +457,52 @@ class AnsweringMachineDetectionConfig(TypedDict, total=False): default profile. """ + beep_max_frequency_hz: int + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when beep detection is active. + """ + + beep_min_frequency_hz: int + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when beep detection is active. + """ + + beep_min_tone_duration_millis: int + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when beep + detection is active. + """ + + beep_spectral_confirmation: bool + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when beep detection is active. + """ + + beep_spectral_min_purity: float + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when beep detection is active. + """ + + beep_spectral_reject_fax_cng: bool + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when beep detection is active. + """ + + beep_spectral_window_millis: int + """Length of the spectral confirmation window, in milliseconds. + + Only used when beep detection is active. + """ + between_words_silence_millis: int """Maximum threshold for silence between words.""" diff --git a/src/telnyx/types/calls/action_transfer_params.py b/src/telnyx/types/calls/action_transfer_params.py index 68e8f2495..33634f182 100644 --- a/src/telnyx/types/calls/action_transfer_params.py +++ b/src/telnyx/types/calls/action_transfer_params.py @@ -72,12 +72,13 @@ class ActionTransferParams(TypedDict, total=False): """Custom headers to be added to the SIP INVITE.""" diversion: str - """ - The number the inbound call being transferred was originally received on, in - +E164 format. Supplying it lets an unverified non-Telnyx `from` be used as the - caller id, provided that number is still on an active inbound call to this - `diversion` number for your account. The `diversion` number itself must be one - you own or have verified. + """The `to` number of an active inbound call, in +E164 format. + + Telnyx checks whether there is currently an active inbound call where `to` + matches this `diversion` value and `from` matches the `from` number supplied for + this request. If such a call exists, the `from` number is treated as verified + (since it is already on an active inbound call to you) and can be used as the + caller id for this outbound call. """ early_media: bool @@ -310,6 +311,52 @@ class AnsweringMachineDetectionConfig(TypedDict, total=False): default profile. """ + beep_max_frequency_hz: int + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when beep detection is active. + """ + + beep_min_frequency_hz: int + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when beep detection is active. + """ + + beep_min_tone_duration_millis: int + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when beep + detection is active. + """ + + beep_spectral_confirmation: bool + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when beep detection is active. + """ + + beep_spectral_min_purity: float + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when beep detection is active. + """ + + beep_spectral_reject_fax_cng: bool + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when beep detection is active. + """ + + beep_spectral_window_millis: int + """Length of the spectral confirmation window, in milliseconds. + + Only used when beep detection is active. + """ + between_words_silence_millis: int """Maximum threshold for silence between words.""" diff --git a/src/telnyx/types/calls/transcription_config_param.py b/src/telnyx/types/calls/transcription_config_param.py index 23276c809..bc30d2f30 100644 --- a/src/telnyx/types/calls/transcription_config_param.py +++ b/src/telnyx/types/calls/transcription_config_param.py @@ -23,18 +23,19 @@ class TranscriptionConfigParam(TypedDict, total=False): language-specific hints `en`, `es`, `fr`, `de`, `hi`, `ru`, `pt`, `ja`, `it`, and `nl`. For `soniox/stt-rt-v4`, `auto` omits the language hint and lets Soniox auto-detect; ISO 639-1 codes (e.g. `en`, `es`) bias detection toward that - language. For `assemblyai/universal-streaming`, `auto` (or unset) enables native - multilingual code-switching; ISO 639-1 codes (`en`, `es`, `de`, `fr`, `pt`, - `it`, `tr`, `nl`, `sv`, `no`, `da`, `fi`, `hi`, `vi`, `ar`, `he`, `ja`, `zh`) - bias the session to that language. For `humain/realtime`, supported values are - `ar`, `en`, `codeswitch` (Arabic/English code-switching), and `auto` (resolves - server-side to code-switching). Unlike other models, `humain/realtime` does not - fall back to `auto` when `language` is omitted — omitting it applies `en` - instead. For `reson8/turns`, supported values are `auto` (or unset) for - automatic language detection, and the language codes `nl`, `en`, `fr`, `fy`, - `de`, `it`, `pl`, `pt`, `es`, and `sv` to fix the transcription language. For - `cohere/ar-stt`, supported values are `ar` and `en`; unlike other models, this - model does not auto-detect and defaults to `ar` when `language` is omitted. + language. For `assemblyai/universal-3-5-pro` (and its legacy alias + `assemblyai/universal-streaming`), `auto` (or unset) enables native multilingual + code-switching; ISO 639-1 codes (`en`, `es`, `de`, `fr`, `pt`, `it`, `tr`, `nl`, + `sv`, `no`, `da`, `fi`, `hi`, `vi`, `ar`, `he`, `ja`, `zh`) bias the session to + that language. For `humain/realtime`, supported values are `ar`, `en`, + `codeswitch` (Arabic/English code-switching), and `auto` (resolves server-side + to code-switching). Unlike other models, `humain/realtime` does not fall back to + `auto` when `language` is omitted — omitting it applies `en` instead. For + `reson8/turns`, supported values are `auto` (or unset) for automatic language + detection, and the language codes `nl`, `en`, `fr`, `fy`, `de`, `it`, `pl`, + `pt`, `es`, and `sv` to fix the transcription language. For `cohere/ar-stt`, + supported values are `ar` and `en`; unlike other models, this model does not + auto-detect and defaults to `ar` when `language` is omitted. """ model: Literal[ @@ -44,10 +45,12 @@ class TranscriptionConfigParam(TypedDict, total=False): "deepgram/nova-2", "speechmatics/standard", "speechmatics/enhanced", + "assemblyai/universal-3-5-pro", "assemblyai/universal-streaming", "xai/grok-stt", "soniox/stt-rt-v4", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", @@ -65,12 +68,16 @@ class TranscriptionConfigParam(TypedDict, total=False): - `deepgram/nova-3` and `deepgram/nova-2` for live streaming transcription. - `speechmatics/standard` and `speechmatics/enhanced` for live streaming transcription. - - `assemblyai/universal-streaming` for live streaming transcription. + - `assemblyai/universal-3-5-pro` for live streaming transcription. The legacy + alias `assemblyai/universal-streaming` is still accepted and resolves to the + same model. - `xai/grok-stt` for live streaming transcription. - `soniox/stt-rt-v4` for live streaming multilingual transcription with automatic language detection. - `nvidia/parakeet-v3` for multilingual transcription with automatic language detection. + - `omi-health/omi-med-stt-v1` for English-only medical transcription + (Parakeet-based). - `humain/realtime` for live streaming transcription with native Arabic and Arabic/English code-switching support. - `reson8/turns` for live streaming turn-based transcription of 10 European diff --git a/src/telnyx/types/calls/transcription_engine_assemblyai_config_param.py b/src/telnyx/types/calls/transcription_engine_assemblyai_config_param.py index b5f62f193..ab6ba0fcd 100644 --- a/src/telnyx/types/calls/transcription_engine_assemblyai_config_param.py +++ b/src/telnyx/types/calls/transcription_engine_assemblyai_config_param.py @@ -17,5 +17,9 @@ class TranscriptionEngineAssemblyaiConfigParam(TypedDict, total=False): transcription_engine: Literal["AssemblyAI"] """Engine identifier for AssemblyAI transcription service""" - transcription_model: Literal["assemblyai/universal-streaming"] - """The model to use for transcription.""" + transcription_model: Literal["assemblyai/universal-3-5-pro", "assemblyai/universal-streaming"] + """The model to use for transcription. + + `assemblyai/universal-streaming` is a legacy alias of + `assemblyai/universal-3-5-pro` and resolves to the same model. + """ diff --git a/src/telnyx/types/calls/transcription_engine_parakeet_config_param.py b/src/telnyx/types/calls/transcription_engine_parakeet_config_param.py index b15bce9b7..58b99a7f6 100644 --- a/src/telnyx/types/calls/transcription_engine_parakeet_config_param.py +++ b/src/telnyx/types/calls/transcription_engine_parakeet_config_param.py @@ -17,5 +17,5 @@ class TranscriptionEngineParakeetConfigParam(TypedDict, total=False): transcription_engine: Literal["Parakeet"] """Engine identifier for Parakeet transcription service""" - transcription_model: Literal["nvidia/parakeet-v3"] + transcription_model: Literal["nvidia/parakeet-v3", "omi-health/omi-med-stt-v1"] """The model to use for transcription.""" diff --git a/src/telnyx/types/compute/funcs/__init__.py b/src/telnyx/types/compute/funcs/__init__.py new file mode 100644 index 000000000..25b036650 --- /dev/null +++ b/src/telnyx/types/compute/funcs/__init__.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from .export_create_params import ExportCreateParams as ExportCreateParams + +if TYPE_CHECKING: + from .func_log_export_config_response import FuncLogExportConfigResponse as FuncLogExportConfigResponse + + +def __getattr__(name: str) -> Any: + if name == "FuncLogExportConfigResponse": + from .func_log_export_config_response import FuncLogExportConfigResponse + + return FuncLogExportConfigResponse + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/compute/funcs/export_create_params.py b/src/telnyx/types/compute/funcs/export_create_params.py new file mode 100644 index 000000000..3ead0ec86 --- /dev/null +++ b/src/telnyx/types/compute/funcs/export_create_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["ExportCreateParams"] + + +class ExportCreateParams(TypedDict, total=False): + endpoint: Required[str] + """HTTPS URL to push logs to""" + + headers: Required[Dict[str, str]] + """Headers attached to every export push, as key-value pairs (e.g. + + an auth token the collector expects). Required even when empty — {} means "no + headers". Encrypted at rest; never returned. + """ + + invocation_export_enabled: Required[bool] + """Export invocation records (one per HTTP request) to this destination""" + + runtime_export_enabled: Required[bool] + """Export runtime logs (function stdout/stderr) to this destination""" diff --git a/src/telnyx/types/compute/funcs/func_log_export_config_response.py b/src/telnyx/types/compute/funcs/func_log_export_config_response.py new file mode 100644 index 000000000..6f766f3a6 --- /dev/null +++ b/src/telnyx/types/compute/funcs/func_log_export_config_response.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["FuncLogExportConfigResponse", "Data"] + + +class Data(BaseModel): + """Metadata-only view of a function's log export destination. + + Header values are write-only (encrypted server-side) and never appear in any response. + """ + + id: Optional[str] = None + """Configuration record ID""" + + created_at: Optional[datetime] = None + + enabled: Optional[bool] = None + """Whether export is enabled for this function""" + + endpoint: Optional[str] = None + """HTTPS OTLP endpoint URL logs are pushed to""" + + func_id: Optional[str] = None + """Function ID this configuration belongs to""" + + invocation_export_enabled: Optional[bool] = None + """Whether invocation records (one per HTTP request) are exported""" + + record_type: Optional[Literal["compute_func_log_export_config"]] = None + + runtime_export_enabled: Optional[bool] = None + """Whether runtime logs (function stdout/stderr) are exported""" + + updated_at: Optional[datetime] = None + + +class FuncLogExportConfigResponse(BaseModel): + data: Optional[Data] = None + """Metadata-only view of a function's log export destination. + + Header values are write-only (encrypted server-side) and never appear in any + response. + """ diff --git a/src/telnyx/types/connection_retrieve_count_response.py b/src/telnyx/types/connection_retrieve_count_response.py new file mode 100644 index 000000000..0af1a1de6 --- /dev/null +++ b/src/telnyx/types/connection_retrieve_count_response.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import TypeAlias + +from .._models import BaseModel + +__all__ = [ + "ConnectionRetrieveCountResponse", + "Data", + "DataCounts", + "DataLimits", + "DataLimitsGlobalConnectionLimit", + "DataLimitsPerTypeConnectionLimits", +] + + +class DataCounts(BaseModel): + """Counts of the authenticated user's connections, grouped by connection type. + + Forward-only connections are excluded. + """ + + call_control_applications: int + """Number of Call Control applications.""" + + credential_connections: int + """Number of credential connections.""" + + external_connections: int + """Number of external connections.""" + + fax_connections: int + """Number of Fax applications.""" + + fqdn_connections: int + """Number of FQDN connections.""" + + ip_connections: int + """Number of IP connections.""" + + microsoft_teams_sbc_connections: int + """Number of Microsoft Teams SBC (direct routing) connections.""" + + mobile_voice_connections: int + """Number of mobile voice (IMS) connections.""" + + operator_connect_connections: int + """Number of Microsoft Operator Connect connections.""" + + texml_applications: int + """Number of TeXML applications.""" + + third_party_provider_connections: int + """Number of third-party provider connections.""" + + uac_connections: int + """Number of UAC connections.""" + + zoom_sbc_connections: int + """Number of Zoom SBC connections.""" + + +class DataLimitsGlobalConnectionLimit(BaseModel): + global_limit: int + """Maximum total number of connections allowed, when a global limit applies.""" + + +class DataLimitsPerTypeConnectionLimits(BaseModel): + standard_limit: int + """Maximum number of standard connections allowed, when per-type limits apply.""" + + texml_limit: int + """Maximum number of TeXML applications allowed, when per-type limits apply.""" + + uac_limit: int + """Maximum number of UAC connections allowed, when per-type limits apply.""" + + +DataLimits: TypeAlias = Union[DataLimitsGlobalConnectionLimit, DataLimitsPerTypeConnectionLimits] + + +class Data(BaseModel): + counts: DataCounts + """Counts of the authenticated user's connections, grouped by connection type. + + Forward-only connections are excluded. + """ + + limits: DataLimits + """Connection limits that apply to the user. + + Contains a single global_limit when a global connection limit applies, or + per-type limits (standard_limit, texml_limit and uac_limit) when the user has + per-type connection count capabilities. + """ + + record_type: str + """Identifies the type of the resource.""" + + +class ConnectionRetrieveCountResponse(BaseModel): + data: Data diff --git a/src/telnyx/types/detail_record_list_params.py b/src/telnyx/types/detail_record_list_params.py index 7e2f7092a..c6db15fbf 100644 --- a/src/telnyx/types/detail_record_list_params.py +++ b/src/telnyx/types/detail_record_list_params.py @@ -15,7 +15,12 @@ class DetailRecordListParams(TypedDict, total=False): """Filter records on a given record attribute and value.
Example: filter[status]=delivered.
Required: filter[record_type] must - be specified. + be specified.
The valid filter fields depend on the record_type: filtering + by a field that does not exist for the selected record_type is rejected with a + 400 error. Call-control and sip-trunking records use started_at, finished_at and + answered_at (they have no created_at); messaging records use created_at. To list + the fields available for a record_type, use the /v2/detail_records/options + endpoint. """ page_number: Annotated[int, PropertyInfo(alias="page[number]")] @@ -23,13 +28,21 @@ class DetailRecordListParams(TypedDict, total=False): page_size: Annotated[int, PropertyInfo(alias="page[size]")] sort: SequenceNotStr[str] - """Specifies the sort order for results.
Example: sort=-created_at""" + """Specifies the sort order for results. + +
Example: sort=-created_at
The valid sort fields depend on the + record_type: sort by a field that does not exist for the selected record_type is + rejected with a 400 error. Call-control and sip-trunking records use started_at, + finished_at and answered_at (they have no created_at); messaging records use + created_at. To list the fields available for a record_type, use the + /v2/detail_records/options endpoint. + """ class Filter(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] """Filter records on a given record attribute and value. -
Example: filter[status]=delivered.
Required: filter[record_type] must be specified. +
Example: filter[status]=delivered.
Required: filter[record_type] must be specified.
The valid filter fields depend on the record_type: filtering by a field that does not exist for the selected record_type is rejected with a 400 error. Call-control and sip-trunking records use started_at, finished_at and answered_at (they have no created_at); messaging records use created_at. To list the fields available for a record_type, use the /v2/detail_records/options endpoint. """ record_type: Required[ diff --git a/src/telnyx/types/inbound_message_webhook_event.py b/src/telnyx/types/inbound_message_webhook_event.py index bb52b55b6..97116b7f6 100644 --- a/src/telnyx/types/inbound_message_webhook_event.py +++ b/src/telnyx/types/inbound_message_webhook_event.py @@ -3,30 +3,12 @@ from __future__ import annotations from typing import Optional -from datetime import datetime -from typing_extensions import Literal from .._models import BaseModel -from .messaging_inbound_message_payload import MessagingInboundMessagePayload +from .messaging_inbound_message import MessagingInboundMessage -__all__ = ["InboundMessageWebhookEvent", "Data"] - - -class Data(BaseModel): - id: Optional[str] = None - """Identifies the type of resource.""" - - event_type: Optional[Literal["message.received"]] = None - """The type of event being delivered.""" - - occurred_at: Optional[datetime] = None - """ISO 8601 formatted date indicating when the resource was created.""" - - payload: Optional[MessagingInboundMessagePayload] = None - - record_type: Optional[Literal["event"]] = None - """Identifies the type of the resource.""" +__all__ = ["InboundMessageWebhookEvent"] class InboundMessageWebhookEvent(BaseModel): - data: Optional[Data] = None + data: Optional[MessagingInboundMessage] = None diff --git a/src/telnyx/types/inbound_message_webhook_event1.py b/src/telnyx/types/inbound_message_webhook_event1.py index bb52b55b6..97116b7f6 100644 --- a/src/telnyx/types/inbound_message_webhook_event1.py +++ b/src/telnyx/types/inbound_message_webhook_event1.py @@ -3,30 +3,12 @@ from __future__ import annotations from typing import Optional -from datetime import datetime -from typing_extensions import Literal from .._models import BaseModel -from .messaging_inbound_message_payload import MessagingInboundMessagePayload +from .messaging_inbound_message import MessagingInboundMessage -__all__ = ["InboundMessageWebhookEvent", "Data"] - - -class Data(BaseModel): - id: Optional[str] = None - """Identifies the type of resource.""" - - event_type: Optional[Literal["message.received"]] = None - """The type of event being delivered.""" - - occurred_at: Optional[datetime] = None - """ISO 8601 formatted date indicating when the resource was created.""" - - payload: Optional[MessagingInboundMessagePayload] = None - - record_type: Optional[Literal["event"]] = None - """Identifies the type of the resource.""" +__all__ = ["InboundMessageWebhookEvent"] class InboundMessageWebhookEvent(BaseModel): - data: Optional[Data] = None + data: Optional[MessagingInboundMessage] = None diff --git a/src/telnyx/types/machine_payment_account_credit_params.py b/src/telnyx/types/machine_payment_account_credit_params.py new file mode 100644 index 000000000..cb1b922f2 --- /dev/null +++ b/src/telnyx/types/machine_payment_account_credit_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["MachinePaymentAccountCreditParams"] + + +class MachinePaymentAccountCreditParams(TypedDict, total=False): + amount_usd: Required[str] + """ + Amount to credit in USD, as a decimal string with up to two fractional digits + (by default between 5.00 and 500.00). The request body is required on the + initial challenge request and remains required on a paid retry, where you + re-send the identical body plus the payment credential — the credential, not the + body, selects the payment, and the retried body is not re-validated. + """ diff --git a/src/telnyx/types/machine_payment_account_credit_response.py b/src/telnyx/types/machine_payment_account_credit_response.py new file mode 100644 index 000000000..8ff9de0d2 --- /dev/null +++ b/src/telnyx/types/machine_payment_account_credit_response.py @@ -0,0 +1,87 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["MachinePaymentAccountCreditResponse", "Data"] + + +class Data(BaseModel): + """An account-credit transaction settled through the Machine Payment Protocol.""" + + id: str + """Unique identifier of the account-credit transaction.""" + + account_id: str + """Identifier of the credited Telnyx account. + + Derived from the authenticated user on the initial request and from the verified + payment credential on a paid retry — never from the request body. + """ + + amount: str + """Credited amount as a decimal string with two fractional digits.""" + + currency: str + """ISO 4217 currency code of the credited amount (currently always USD).""" + + payment_source: Literal["machine_payment"] + """ + Payment source identifier distinguishing machine payments from other + account-credit sources. + """ + + record_type: Literal["machine_payment_account_credit"] + """Record type identifier.""" + + created: Optional[bool] = None + """ + True when this response created a new account credit, false when an existing + transaction was returned for a duplicate paid retry. + """ + + created_at: Optional[datetime] = None + """ISO 8601 timestamp when the transaction was created.""" + + mpp_resource: Optional[str] = None + """ + Machine Payment Protocol resource identifier the payment credential was bound + to. + """ + + payment_intent_id: Optional[str] = None + """Stripe PaymentIntent identifier for Stripe settlements. + + Absent for Tempo settlements. + """ + + payment_method: Optional[Literal["stripe_spt", "tempo_usdc"]] = None + """ + Payment method used by the provider: `stripe_spt` for Stripe Shared Payment + Token payments, `tempo_usdc` for Tempo USDC payments. + """ + + provider: Optional[Literal["stripe", "tempo"]] = None + """Upstream payment provider that settled the payment.""" + + receipt_reference: Optional[str] = None + """ + Provider receipt reference: the Stripe PaymentIntent identifier for Stripe + settlements, or the on-chain transaction hash for Tempo settlements. + """ + + status: Optional[Literal["new", "processing", "settled", "expired", "invalid"]] = None + """Status of the transaction. + + Successful machine payment credits are recorded as `settled`. + """ + + +class MachinePaymentAccountCreditResponse(BaseModel): + data: Optional[Data] = None + """An account-credit transaction settled through the Machine Payment Protocol.""" diff --git a/src/telnyx/types/message_retrieve_group_messages_response.py b/src/telnyx/types/message_retrieve_group_messages_response.py index 93bec037a..a18163d7a 100644 --- a/src/telnyx/types/message_retrieve_group_messages_response.py +++ b/src/telnyx/types/message_retrieve_group_messages_response.py @@ -5,10 +5,10 @@ from typing import List, Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageRetrieveGroupMessagesResponse"] class MessageRetrieveGroupMessagesResponse(BaseModel): - data: Optional[List[MessagingOutboundMessagePayload]] = None + data: Optional[List[OutboundMessagePayload]] = None diff --git a/src/telnyx/types/message_retrieve_response.py b/src/telnyx/types/message_retrieve_response.py index d916e98a7..4e02bab4c 100644 --- a/src/telnyx/types/message_retrieve_response.py +++ b/src/telnyx/types/message_retrieve_response.py @@ -7,13 +7,13 @@ from .._utils import PropertyInfo from .._models import BaseModel +from .outbound_message_payload import OutboundMessagePayload from .messaging_inbound_message_payload import MessagingInboundMessagePayload -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload __all__ = ["MessageRetrieveResponse", "Data"] Data: TypeAlias = Annotated[ - Union[MessagingOutboundMessagePayload, MessagingInboundMessagePayload], PropertyInfo(discriminator="direction") + Union[OutboundMessagePayload, MessagingInboundMessagePayload], PropertyInfo(discriminator="direction") ] diff --git a/src/telnyx/types/message_schedule_response.py b/src/telnyx/types/message_schedule_response.py index 97f415575..40168708d 100644 --- a/src/telnyx/types/message_schedule_response.py +++ b/src/telnyx/types/message_schedule_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageScheduleResponse"] class MessageScheduleResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/message_send_group_mms_response.py b/src/telnyx/types/message_send_group_mms_response.py index a3d805ba6..c7f539daa 100644 --- a/src/telnyx/types/message_send_group_mms_response.py +++ b/src/telnyx/types/message_send_group_mms_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageSendGroupMmsResponse"] class MessageSendGroupMmsResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/message_send_long_code_response.py b/src/telnyx/types/message_send_long_code_response.py index 3e3f0e629..e9ffdf7eb 100644 --- a/src/telnyx/types/message_send_long_code_response.py +++ b/src/telnyx/types/message_send_long_code_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageSendLongCodeResponse"] class MessageSendLongCodeResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/message_send_number_pool_response.py b/src/telnyx/types/message_send_number_pool_response.py index 17a80bc7d..3a8c9163d 100644 --- a/src/telnyx/types/message_send_number_pool_response.py +++ b/src/telnyx/types/message_send_number_pool_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageSendNumberPoolResponse"] class MessageSendNumberPoolResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/message_send_response.py b/src/telnyx/types/message_send_response.py index 1f38879f6..c1f006614 100644 --- a/src/telnyx/types/message_send_response.py +++ b/src/telnyx/types/message_send_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageSendResponse"] class MessageSendResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/message_send_short_code_response.py b/src/telnyx/types/message_send_short_code_response.py index 950e4ca8a..3b02b298e 100644 --- a/src/telnyx/types/message_send_short_code_response.py +++ b/src/telnyx/types/message_send_short_code_response.py @@ -5,10 +5,10 @@ from typing import Optional from .._models import BaseModel -from .messaging_outbound_message_payload import MessagingOutboundMessagePayload +from .outbound_message_payload import OutboundMessagePayload __all__ = ["MessageSendShortCodeResponse"] class MessageSendShortCodeResponse(BaseModel): - data: Optional[MessagingOutboundMessagePayload] = None + data: Optional[OutboundMessagePayload] = None diff --git a/src/telnyx/types/messaging_inbound_message.py b/src/telnyx/types/messaging_inbound_message.py new file mode 100644 index 000000000..762880bb0 --- /dev/null +++ b/src/telnyx/types/messaging_inbound_message.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .messaging_inbound_message_payload import MessagingInboundMessagePayload + +__all__ = ["MessagingInboundMessage"] + + +class MessagingInboundMessage(BaseModel): + id: Optional[str] = None + """Identifies the type of resource.""" + + event_type: Optional[Literal["message.received"]] = None + """The type of event being delivered.""" + + occurred_at: Optional[datetime] = None + """ISO 8601 formatted date indicating when the resource was created.""" + + payload: Optional[MessagingInboundMessagePayload] = None + + record_type: Optional[Literal["event"]] = None + """Identifies the type of the resource.""" diff --git a/src/telnyx/types/messaging_inbound_message_payload.py b/src/telnyx/types/messaging_inbound_message_payload.py index 0cdf0c60e..9452ceb83 100644 --- a/src/telnyx/types/messaging_inbound_message_payload.py +++ b/src/telnyx/types/messaging_inbound_message_payload.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Dict, List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo @@ -15,7 +15,14 @@ "MessagingInboundMessagePayload", "Body", "BodyEdit", + "BodyLocation", "BodyRevoke", + "BodySuggestionResponse", + "BodyText", + "BodyTextBody", + "BodyUserFile", + "BodyUserFilePayload", + "BodyUserFileThumbnail", "Cc", "Cost", "CostBreakdown", @@ -40,6 +47,14 @@ class BodyEdit(BaseModel): """ +class BodyLocation(BaseModel): + """Location shared in an RCS message.""" + + latitude: Optional[float] = None + + longitude: Optional[float] = None + + class BodyRevoke(BaseModel): """Details for a revoked WhatsApp message.""" @@ -50,10 +65,65 @@ class BodyRevoke(BaseModel): """ +class BodySuggestionResponse(BaseModel): + """Selected RCS suggestion.""" + + postback_data: Optional[str] = None + + text: Optional[str] = None + + +class BodyTextBody(BaseModel): + body: Optional[str] = None + + if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> object: ... + else: + __pydantic_extra__: Dict[str, object] + + +BodyText: TypeAlias = Union[str, BodyTextBody] + + +class BodyUserFilePayload(BaseModel): + file_name: Optional[str] = None + + file_size_bytes: Optional[int] = None + + file_uri: Optional[str] = None + + mime_type: Optional[str] = None + + +class BodyUserFileThumbnail(BaseModel): + file_name: Optional[str] = None + + file_size_bytes: Optional[int] = None + + file_uri: Optional[str] = None + + mime_type: Optional[str] = None + + +class BodyUserFile(BaseModel): + """RCS file attachment and optional thumbnail.""" + + payload: Optional[BodyUserFilePayload] = None + + thumbnail: Optional[BodyUserFileThumbnail] = None + + class Body(BaseModel): - """WhatsApp message body. + """Message body for RCS and WhatsApp. - For message edits and revocations, inspect `type` and the corresponding `edit` or `revoke` object. + RCS messages contain text, user_file, location, or suggestion_response. For WhatsApp edits and revocations, inspect type and the corresponding edit or revoke object. """ id: Optional[str] = None @@ -68,9 +138,18 @@ class Body(BaseModel): from_: Optional[str] = FieldInfo(alias="from", default=None) """WhatsApp sender in E.164 format.""" + location: Optional[BodyLocation] = None + """Location shared in an RCS message.""" + revoke: Optional[BodyRevoke] = None """Details for a revoked WhatsApp message.""" + suggestion_response: Optional[BodySuggestionResponse] = None + """Selected RCS suggestion.""" + + text: Optional[BodyText] = None + """RCS text string or WhatsApp text object.""" + timestamp: Optional[str] = None """Unix timestamp supplied by Meta.""" @@ -80,6 +159,9 @@ class Body(BaseModel): Edit and revoke events use `edit` and `revoke`, respectively. """ + user_file: Optional[BodyUserFile] = None + """RCS file attachment and optional thumbnail.""" + if TYPE_CHECKING: # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a # value to this field, so for compatibility we avoid doing it at runtime. @@ -144,7 +226,7 @@ class From(BaseModel): carrier: Optional[str] = None """The carrier of the sender.""" - line_type: Optional[Literal["Wireline", "Wireless", "VoWiFi", "VoIP", "Pre-Paid Wireless", ""]] = None + line_type: Optional[Literal["Wireline", "Wireless", "VoWiFi", "VoIP", "Pre-Paid Wireless", "", "long_code"]] = None """The line-type of the sender.""" phone_number: Optional[str] = None @@ -153,7 +235,7 @@ class From(BaseModel): code). """ - status: Optional[Literal["received", "delivered"]] = None + status: Optional[Literal["received", "delivered", "webhook_delivered"]] = None class Media(BaseModel): @@ -171,6 +253,12 @@ class Media(BaseModel): class ToUnionMember0(BaseModel): + agent_id: Optional[str] = None + """RCS agent identifier.""" + + agent_name: Optional[str] = None + """RCS agent name.""" + carrier: Optional[str] = None """The carrier of the receiver.""" @@ -198,11 +286,19 @@ class MessagingInboundMessagePayload(BaseModel): id: Optional[str] = None """Identifies the type of resource.""" + autoresponse_type: Optional[str] = None + """Automatic response type triggered by an inbound opt-in, opt-out, or help + keyword. + + Examples include START, STOP, and HELP. + """ + body: Optional[Body] = None - """WhatsApp message body. + """Message body for RCS and WhatsApp. - For message edits and revocations, inspect `type` and the corresponding `edit` - or `revoke` object. + RCS messages contain text, user_file, location, or suggestion_response. For + WhatsApp edits and revocations, inspect type and the corresponding edit or + revoke object. """ cc: Optional[List[Cc]] = None @@ -279,11 +375,12 @@ class MessagingInboundMessagePayload(BaseModel): to: Union[List[ToUnionMember0], str, None] = None """Receiving address. - SMS and MMS webhooks use an array of recipients. WhatsApp webhooks use one E.164 - phone number. + SMS, MMS and RCS webhooks use an array of recipients. RCS recipients are + identified by agent_id and agent_name. WhatsApp webhooks use one E.164 phone + number. """ - type: Optional[Literal["SMS", "MMS", "WHATSAPP"]] = None + type: Optional[Literal["SMS", "MMS", "WHATSAPP", "RCS"]] = None """The messaging channel used for the message.""" valid_until: Optional[datetime] = None diff --git a/src/telnyx/types/messaging_outbound_message_payload.py b/src/telnyx/types/messaging_outbound_message_payload.py deleted file mode 100644 index c022e0692..000000000 --- a/src/telnyx/types/messaging_outbound_message_payload.py +++ /dev/null @@ -1,236 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .messaging_error_0b38e7044b import MessagingError0b38e7044b - -__all__ = [ - "MessagingOutboundMessagePayload", - "Cc", - "Cost", - "CostBreakdown", - "CostBreakdownCarrierFee", - "CostBreakdownRate", - "From", - "Media", - "To", -] - - -class Cc(BaseModel): - carrier: Optional[str] = None - """The carrier of the receiver.""" - - line_type: Optional[Literal["Wireline", "Wireless", "VoWiFi", "VoIP", "Pre-Paid Wireless", ""]] = None - """The line-type of the receiver.""" - - phone_number: Optional[str] = None - """Receiving address (+E.164 formatted phone number or short code).""" - - status: Optional[ - Literal["queued", "sending", "sent", "delivered", "sending_failed", "delivery_failed", "delivery_unconfirmed"] - ] = None - - -class Cost(BaseModel): - amount: Optional[str] = None - """The amount deducted from your account.""" - - currency: Optional[str] = None - """The ISO 4217 currency identifier.""" - - -class CostBreakdownCarrierFee(BaseModel): - amount: Optional[str] = None - """The carrier fee amount.""" - - currency: Optional[str] = None - """The ISO 4217 currency identifier.""" - - -class CostBreakdownRate(BaseModel): - amount: Optional[str] = None - """The rate amount applied.""" - - currency: Optional[str] = None - """The ISO 4217 currency identifier.""" - - -class CostBreakdown(BaseModel): - """Detailed breakdown of the message cost components.""" - - carrier_fee: Optional[CostBreakdownCarrierFee] = None - - rate: Optional[CostBreakdownRate] = None - - -class From(BaseModel): - carrier: Optional[str] = None - """The carrier of the receiver.""" - - line_type: Optional[Literal["Wireline", "Wireless", "VoWiFi", "VoIP", "Pre-Paid Wireless", ""]] = None - """The line-type of the receiver.""" - - phone_number: Optional[str] = None - """ - Sending address (+E.164 formatted phone number, alphanumeric sender ID, or short - code). - """ - - -class Media(BaseModel): - content_type: Optional[str] = None - """The MIME type of the requested media.""" - - sha256: Optional[str] = None - """The SHA256 hash of the requested media.""" - - size: Optional[int] = None - """The size of the requested media.""" - - url: Optional[str] = None - """The url of the media requested to be sent.""" - - -class To(BaseModel): - carrier: Optional[str] = None - """The carrier of the receiver.""" - - line_type: Optional[Literal["Wireline", "Wireless", "VoWiFi", "VoIP", "Pre-Paid Wireless", ""]] = None - """The line-type of the receiver.""" - - phone_number: Optional[str] = None - """Receiving address (+E.164 formatted phone number or short code).""" - - status: Optional[ - Literal[ - "queued", - "sending", - "sent", - "expired", - "sending_failed", - "delivery_unconfirmed", - "delivered", - "delivery_failed", - ] - ] = None - """The delivery status of the message.""" - - -class MessagingOutboundMessagePayload(BaseModel): - id: Optional[str] = None - """Identifies the type of resource.""" - - cc: Optional[List[Cc]] = None - - completed_at: Optional[datetime] = None - """ISO 8601 formatted date indicating when the message was finalized.""" - - cost: Optional[Cost] = None - - cost_breakdown: Optional[CostBreakdown] = None - """Detailed breakdown of the message cost components.""" - - direction: Optional[Literal["outbound"]] = None - """The direction of the message. - - Inbound messages are sent to you whereas outbound messages are sent from you. - """ - - encoding: Optional[str] = None - """Encoding scheme used for the message body.""" - - errors: Optional[List[MessagingError0b38e7044b]] = None - """ - These errors may point at addressees when referring to unsuccessful/unconfirmed - delivery statuses. - """ - - from_: Optional[From] = FieldInfo(alias="from", default=None) - - media: Optional[List[Media]] = None - - messaging_profile_id: Optional[str] = None - """Unique identifier for a messaging profile.""" - - num_chars: Optional[int] = None - """The number of characters in the message text""" - - organization_id: Optional[str] = None - """The id of the organization the messaging profile belongs to.""" - - parts: Optional[int] = None - """Number of parts into which the message's body must be split.""" - - received_at: Optional[datetime] = None - """ISO 8601 formatted date indicating when the message request was received.""" - - record_type: Optional[Literal["message"]] = None - """Identifies the type of the resource.""" - - sent_at: Optional[datetime] = None - """ISO 8601 formatted date indicating when the message was sent.""" - - smart_encoding_applied: Optional[bool] = None - """Indicates whether smart encoding was applied to this message. - - When `true`, one or more Unicode characters were automatically replaced with - GSM-7 equivalents to reduce segment count and cost. The original message text is - preserved in webhooks. - """ - - subject: Optional[str] = None - """Subject of multimedia message""" - - tags: Optional[List[str]] = None - """Tags associated with the resource.""" - - tcr_campaign_billable: Optional[bool] = None - """Indicates whether the TCR campaign is billable.""" - - tcr_campaign_id: Optional[str] = None - """The Campaign Registry (TCR) campaign ID associated with the message.""" - - tcr_campaign_registered: Optional[str] = None - """The registration status of the TCR campaign.""" - - text: Optional[str] = None - """Message body (i.e., content) as a non-empty string. - - **Required for SMS** - """ - - to: Optional[List[To]] = None - - type: Optional[Literal["SMS", "MMS"]] = None - """The type of message.""" - - valid_until: Optional[datetime] = None - """ - Message must be out of the queue by this time or else it will be discarded and - marked as 'sending_failed'. Once the message moves out of the queue, this field - will be nulled - """ - - wait_seconds: Optional[float] = None - """ - Seconds the message is queued due to rate limiting before being sent to the - carrier. Represents the maximum wait across all applicable rate limits (account, - carrier, campaign). 0.0 = no queuing delay. - """ - - webhook_failover_url: Optional[str] = None - """ - The failover URL where webhooks related to this message will be sent if sending - to the primary URL fails. - """ - - webhook_url: Optional[str] = None - """The URL where webhooks related to this message will be sent.""" diff --git a/src/telnyx/types/noise_suppression_engine_list_response.py b/src/telnyx/types/noise_suppression_engine_list_response.py new file mode 100644 index 000000000..851ac843e --- /dev/null +++ b/src/telnyx/types/noise_suppression_engine_list_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List + +from .._models import BaseModel + +__all__ = ["NoiseSuppressionEngineListResponse", "Data"] + + +class Data(BaseModel): + """A noise suppression engine available to the authenticated user.""" + + default_attenuation_level: int + """Default attenuation level of the engine (0-100, in multiples of ten).""" + + label: str + """Human-readable name of the engine.""" + + value: str + """ + Machine-readable identifier of the engine, used when configuring noise + suppression. + """ + + +class NoiseSuppressionEngineListResponse(BaseModel): + data: List[Data] diff --git a/src/telnyx/types/number_order_status_update_webhook_event.py b/src/telnyx/types/number_order_status_update_webhook_event.py index 788c90b6c..376d7f3fc 100644 --- a/src/telnyx/types/number_order_status_update_webhook_event.py +++ b/src/telnyx/types/number_order_status_update_webhook_event.py @@ -123,7 +123,7 @@ class Data(BaseModel): id: str """Unique identifier for the event""" - event_type: str + event_type: Literal["number_order.complete"] """The type of event being sent""" occurred_at: datetime diff --git a/src/telnyx/types/number_order_status_update_webhook_event1.py b/src/telnyx/types/number_order_status_update_webhook_event1.py index 788c90b6c..376d7f3fc 100644 --- a/src/telnyx/types/number_order_status_update_webhook_event1.py +++ b/src/telnyx/types/number_order_status_update_webhook_event1.py @@ -123,7 +123,7 @@ class Data(BaseModel): id: str """Unique identifier for the event""" - event_type: str + event_type: Literal["number_order.complete"] """The type of event being sent""" occurred_at: datetime diff --git a/src/telnyx/types/outbound_message.py b/src/telnyx/types/outbound_message.py index cb929ffa0..92c4118ad 100644 --- a/src/telnyx/types/outbound_message.py +++ b/src/telnyx/types/outbound_message.py @@ -16,7 +16,7 @@ class OutboundMessage(BaseModel): id: Optional[str] = None """Identifies the type of resource.""" - event_type: Optional[Literal["message.sent", "message.finalized"]] = None + event_type: Optional[Literal["message.sent", "message.finalized", "message.read"]] = None """The type of event being delivered.""" occurred_at: Optional[datetime] = None diff --git a/src/telnyx/types/outbound_message_payload.py b/src/telnyx/types/outbound_message_payload.py index d402968d3..9f4147845 100644 --- a/src/telnyx/types/outbound_message_payload.py +++ b/src/telnyx/types/outbound_message_payload.py @@ -9,10 +9,11 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .shared.messaging_error import MessagingError +from .messaging_error_0b38e7044b import MessagingError0b38e7044b __all__ = [ "OutboundMessagePayload", + "Body", "Cc", "Cost", "CostBreakdown", @@ -24,6 +25,13 @@ ] +class Body(BaseModel): + """RCS webhook message body. Text messages use the text property.""" + + text: Optional[str] = None + """RCS text message.""" + + class Cc(BaseModel): carrier: Optional[str] = None """The carrier of the receiver.""" @@ -72,6 +80,12 @@ class CostBreakdown(BaseModel): class From(BaseModel): + agent_id: Optional[str] = None + """RCS agent identifier.""" + + agent_name: Optional[str] = None + """RCS agent name.""" + carrier: Optional[str] = None """The carrier of the receiver.""" @@ -119,6 +133,7 @@ class To(BaseModel): "delivery_unconfirmed", "delivered", "delivery_failed", + "read", ] ] = None """The delivery status of the message.""" @@ -128,6 +143,9 @@ class OutboundMessagePayload(BaseModel): id: Optional[str] = None """Identifies the type of resource.""" + body: Optional[Body] = None + """RCS webhook message body. Text messages use the text property.""" + cc: Optional[List[Cc]] = None completed_at: Optional[datetime] = None @@ -147,7 +165,7 @@ class OutboundMessagePayload(BaseModel): encoding: Optional[str] = None """Encoding scheme used for the message body.""" - errors: Optional[List[MessagingError]] = None + errors: Optional[List[MessagingError0b38e7044b]] = None """ These errors may point at addressees when referring to unsuccessful/unconfirmed delivery statuses. @@ -209,7 +227,7 @@ class OutboundMessagePayload(BaseModel): to: Optional[List[To]] = None - type: Optional[Literal["SMS", "MMS"]] = None + type: Optional[Literal["SMS", "MMS", "RCS"]] = None """The type of message.""" valid_until: Optional[datetime] = None diff --git a/src/telnyx/types/speech_to_text_retrieve_transcription_params.py b/src/telnyx/types/speech_to_text_retrieve_transcription_params.py index a56aea9c3..6bf0603f6 100644 --- a/src/telnyx/types/speech_to_text_retrieve_transcription_params.py +++ b/src/telnyx/types/speech_to_text_retrieve_transcription_params.py @@ -79,6 +79,7 @@ class SpeechToTextRetrieveTranscriptionParams(TypedDict, total=False): "speechmatics/standard", "soniox/stt-rt-v4", "nvidia/parakeet-v3", + "omi-health/omi-med-stt-v1", "humain/realtime", "reson8/turns", "cohere/ar-stt", diff --git a/src/telnyx/types/success_response.py b/src/telnyx/types/success_response.py new file mode 100644 index 000000000..47eaf5782 --- /dev/null +++ b/src/telnyx/types/success_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["SuccessResponse"] + + +class SuccessResponse(BaseModel): + """Status envelope used by the signup and magic-link flows.""" + + message: str + """Human-readable status message.""" + + success: bool + """Whether the request was accepted.""" diff --git a/src/telnyx/types/texml/__init__.py b/src/telnyx/types/texml/__init__.py index 50619e3c1..cbc98a191 100644 --- a/src/telnyx/types/texml/__init__.py +++ b/src/telnyx/types/texml/__init__.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any +from .call_create_params import CallCreateParams as CallCreateParams from .account_retrieve_recordings_json_params import ( AccountRetrieveRecordingsJsonParams as AccountRetrieveRecordingsJsonParams, ) @@ -12,6 +13,7 @@ ) if TYPE_CHECKING: + from .call_create_response import CallCreateResponse as CallCreateResponse from .texml_recording_subresources_uris import TexmlRecordingSubresourcesUris as TexmlRecordingSubresourcesUris from .texml_get_call_recording_response_body import ( TexmlGetCallRecordingResponseBody as TexmlGetCallRecordingResponseBody, @@ -22,6 +24,10 @@ def __getattr__(name: str) -> Any: + if name == "CallCreateResponse": + from .call_create_response import CallCreateResponse + + return CallCreateResponse if name == "TexmlGetCallRecordingResponseBody": from .texml_get_call_recording_response_body import TexmlGetCallRecordingResponseBody diff --git a/src/telnyx/types/texml/accounts/call_calls_params.py b/src/telnyx/types/texml/accounts/call_calls_params.py index f1d2babc9..81ee3009f 100644 --- a/src/telnyx/types/texml/accounts/call_calls_params.py +++ b/src/telnyx/types/texml/accounts/call_calls_params.py @@ -122,6 +122,27 @@ class BodyWithURL(TypedDict, total=False): ] """Enables Answering Machine Detection.""" + machine_detection_beep_max_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMaxFrequency")] + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_min_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinFrequency")] + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + """ + + machine_detection_beep_min_tone_duration: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinToneDuration")] + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when + MachineDetection is enabled. + """ + machine_detection_beep_profile: Annotated[ Literal["both", "freq_only"], PropertyInfo(alias="MachineDetectionBeepProfile") ] @@ -132,6 +153,37 @@ class BodyWithURL(TypedDict, total=False): default profile. Only used when MachineDetection is enabled. """ + machine_detection_beep_spectral_confirmation: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralConfirmation") + ] + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_min_purity: Annotated[ + float, PropertyInfo(alias="MachineDetectionBeepSpectralMinPurity") + ] + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_reject_fax_cng: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralRejectFaxCng") + ] + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_window: Annotated[int, PropertyInfo(alias="MachineDetectionBeepSpectralWindow")] + """Length of the spectral confirmation window, in milliseconds. + + Only used when MachineDetection is enabled. + """ + machine_detection_prompt_end_timeout: Annotated[int, PropertyInfo(alias="MachineDetectionPromptEndTimeout")] """ Silence duration threshold after a call screening prompt before ending prompt @@ -382,6 +434,27 @@ class BodyWithTeXml(TypedDict, total=False): ] """Enables Answering Machine Detection.""" + machine_detection_beep_max_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMaxFrequency")] + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_min_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinFrequency")] + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + """ + + machine_detection_beep_min_tone_duration: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinToneDuration")] + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when + MachineDetection is enabled. + """ + machine_detection_beep_profile: Annotated[ Literal["both", "freq_only"], PropertyInfo(alias="MachineDetectionBeepProfile") ] @@ -392,6 +465,37 @@ class BodyWithTeXml(TypedDict, total=False): default profile. Only used when MachineDetection is enabled. """ + machine_detection_beep_spectral_confirmation: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralConfirmation") + ] + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_min_purity: Annotated[ + float, PropertyInfo(alias="MachineDetectionBeepSpectralMinPurity") + ] + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_reject_fax_cng: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralRejectFaxCng") + ] + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_window: Annotated[int, PropertyInfo(alias="MachineDetectionBeepSpectralWindow")] + """Length of the spectral confirmation window, in milliseconds. + + Only used when MachineDetection is enabled. + """ + machine_detection_prompt_end_timeout: Annotated[int, PropertyInfo(alias="MachineDetectionPromptEndTimeout")] """ Silence duration threshold after a call screening prompt before ending prompt @@ -635,6 +739,27 @@ class BodyApplicationDefault(TypedDict, total=False): ] """Enables Answering Machine Detection.""" + machine_detection_beep_max_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMaxFrequency")] + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_min_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinFrequency")] + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + """ + + machine_detection_beep_min_tone_duration: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinToneDuration")] + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when + MachineDetection is enabled. + """ + machine_detection_beep_profile: Annotated[ Literal["both", "freq_only"], PropertyInfo(alias="MachineDetectionBeepProfile") ] @@ -645,6 +770,37 @@ class BodyApplicationDefault(TypedDict, total=False): default profile. Only used when MachineDetection is enabled. """ + machine_detection_beep_spectral_confirmation: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralConfirmation") + ] + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_min_purity: Annotated[ + float, PropertyInfo(alias="MachineDetectionBeepSpectralMinPurity") + ] + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_reject_fax_cng: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralRejectFaxCng") + ] + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_window: Annotated[int, PropertyInfo(alias="MachineDetectionBeepSpectralWindow")] + """Length of the spectral confirmation window, in milliseconds. + + Only used when MachineDetection is enabled. + """ + machine_detection_prompt_end_timeout: Annotated[int, PropertyInfo(alias="MachineDetectionPromptEndTimeout")] """ Silence duration threshold after a call screening prompt before ending prompt diff --git a/src/telnyx/types/texml/accounts/conferences/participant_participants_params.py b/src/telnyx/types/texml/accounts/conferences/participant_participants_params.py index 41a22a782..139f5137b 100644 --- a/src/telnyx/types/texml/accounts/conferences/participant_participants_params.py +++ b/src/telnyx/types/texml/accounts/conferences/participant_participants_params.py @@ -156,6 +156,27 @@ class ParticipantParticipantsParams(TypedDict, total=False): answering machine. """ + machine_detection_beep_max_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMaxFrequency")] + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_min_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinFrequency")] + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + """ + + machine_detection_beep_min_tone_duration: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinToneDuration")] + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when + MachineDetection is enabled. + """ + machine_detection_beep_profile: Annotated[ Literal["both", "freq_only"], PropertyInfo(alias="MachineDetectionBeepProfile") ] @@ -166,6 +187,37 @@ class ParticipantParticipantsParams(TypedDict, total=False): default profile. Only used when MachineDetection is enabled. """ + machine_detection_beep_spectral_confirmation: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralConfirmation") + ] + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_min_purity: Annotated[ + float, PropertyInfo(alias="MachineDetectionBeepSpectralMinPurity") + ] + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_reject_fax_cng: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralRejectFaxCng") + ] + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_window: Annotated[int, PropertyInfo(alias="MachineDetectionBeepSpectralWindow")] + """Length of the spectral confirmation window, in milliseconds. + + Only used when MachineDetection is enabled. + """ + machine_detection_silence_timeout: Annotated[int, PropertyInfo(alias="MachineDetectionSilenceTimeout")] """If initial silence duration is greater than this value, consider it a machine. diff --git a/src/telnyx/types/texml/call_create_params.py b/src/telnyx/types/texml/call_create_params.py new file mode 100644 index 000000000..1411f6a99 --- /dev/null +++ b/src/telnyx/types/texml/call_create_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["CallCreateParams"] + + +class CallCreateParams(TypedDict, total=False): + from_: Required[Annotated[str, PropertyInfo(alias="From")]] + """The E.164-formatted phone number or SIP URI to present as the caller.""" + + to: Required[Annotated[str, PropertyInfo(alias="To")]] + """The E.164-formatted phone number or SIP URI to call.""" + + method: Annotated[Literal["GET", "POST"], PropertyInfo(alias="Method")] + """HTTP method used to retrieve TeXML instructions from Url.""" + + texml: Annotated[str, PropertyInfo(alias="Texml")] + """Inline TeXML instructions to execute when the call is answered.""" + + url: Annotated[str, PropertyInfo(alias="Url")] + """The URL from which to retrieve TeXML instructions. + + Overrides the TeXML application XML request URL. + """ diff --git a/src/telnyx/types/texml/call_create_response.py b/src/telnyx/types/texml/call_create_response.py new file mode 100644 index 000000000..91034cdbd --- /dev/null +++ b/src/telnyx/types/texml/call_create_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["CallCreateResponse"] + + +class CallCreateResponse(BaseModel): + call_sid: str + """The call control ID of the created call.""" + + from_: str = FieldInfo(alias="from") + """The caller address.""" + + status: Literal["queued"] + """The initial status of the outbound call.""" + + to: str + """The called address.""" diff --git a/src/telnyx/types/texml_initiate_ai_call_params.py b/src/telnyx/types/texml_initiate_ai_call_params.py index 3adfaa199..a58b03d0e 100644 --- a/src/telnyx/types/texml_initiate_ai_call_params.py +++ b/src/telnyx/types/texml_initiate_ai_call_params.py @@ -91,6 +91,27 @@ class TexmlInitiateAICallParams(TypedDict, total=False): ] """Enables Answering Machine Detection.""" + machine_detection_beep_max_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMaxFrequency")] + """Highest frequency, in Hz, that a tone can reach and still be treated as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_min_frequency: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinFrequency")] + """Lowest frequency, in Hz, that a tone must reach to be treated as a beep. + + Raising it above 480 excludes North American ringback (440 + 480 Hz), which can + otherwise be reported as a beep when the `freq_only` profile is in use. Only + used when MachineDetection is enabled. + """ + + machine_detection_beep_min_tone_duration: Annotated[int, PropertyInfo(alias="MachineDetectionBeepMinToneDuration")] + """Shortest tone, in milliseconds, that can be treated as a beep. + + Raising it rejects brief tones such as call-progress blips. Only used when + MachineDetection is enabled. + """ + machine_detection_beep_profile: Annotated[ Literal["both", "freq_only"], PropertyInfo(alias="MachineDetectionBeepProfile") ] @@ -101,6 +122,37 @@ class TexmlInitiateAICallParams(TypedDict, total=False): default profile. Only used when MachineDetection is enabled. """ + machine_detection_beep_spectral_confirmation: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralConfirmation") + ] + """ + When enabled, a candidate beep must pass an additional spectral check before it + is reported. Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_min_purity: Annotated[ + float, PropertyInfo(alias="MachineDetectionBeepSpectralMinPurity") + ] + """Minimum spectral purity, from 0 to 1, for a tone to be treated as a beep. + + Raising it rejects mixed tones such as ringback, which combines two frequencies. + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_reject_fax_cng: Annotated[ + bool, PropertyInfo(alias="MachineDetectionBeepSpectralRejectFaxCng") + ] + """When enabled, the fax CNG tone is rejected rather than reported as a beep. + + Only used when MachineDetection is enabled. + """ + + machine_detection_beep_spectral_window: Annotated[int, PropertyInfo(alias="MachineDetectionBeepSpectralWindow")] + """Length of the spectral confirmation window, in milliseconds. + + Only used when MachineDetection is enabled. + """ + machine_detection_prompt_end_timeout: Annotated[int, PropertyInfo(alias="MachineDetectionPromptEndTimeout")] """ Silence duration threshold after a call screening prompt before ending prompt diff --git a/src/telnyx/types/voice_clone_create_from_upload_params.py b/src/telnyx/types/voice_clone_create_from_upload_params.py index 4b89a8cff..b7643422b 100644 --- a/src/telnyx/types/voice_clone_create_from_upload_params.py +++ b/src/telnyx/types/voice_clone_create_from_upload_params.py @@ -62,7 +62,7 @@ class VoiceCloneUploadRequestTelnyxUltraClone(TypedDict, total=False): audio_file: Required[FileTypes] """Audio file to clone the voice from. - Supported formats: WAV, MP3, FLAC, OGG, M4A. For best quality, provide 5–10 + Supported formats: WAV, MP3, FLAC, OGG, M4A. For best quality, provide up to 60 seconds of clear, uninterrupted speech. Maximum size: 5MB. """ diff --git a/tests/api_resources/ai/assistants/test_versions.py b/tests/api_resources/ai/assistants/test_versions.py index 76f1f978b..a101b32ee 100644 --- a/tests/api_resources/ai/assistants/test_versions.py +++ b/tests/api_resources/ai/assistants/test_versions.py @@ -320,6 +320,7 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -354,16 +355,22 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -390,66 +397,12 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ @@ -1006,6 +959,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -1040,16 +994,22 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -1076,66 +1036,12 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ diff --git a/tests/api_resources/ai/test_assistants.py b/tests/api_resources/ai/test_assistants.py index 4a7420ec0..025c2fc27 100644 --- a/tests/api_resources/ai/test_assistants.py +++ b/tests/api_resources/ai/test_assistants.py @@ -260,6 +260,7 @@ def test_method_create_with_all_params(self, client: Telnyx) -> None: interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -293,16 +294,22 @@ def test_method_create_with_all_params(self, client: Telnyx) -> None: "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -329,66 +336,12 @@ def test_method_create_with_all_params(self, client: Telnyx) -> None: tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ @@ -768,6 +721,7 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -802,17 +756,23 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, promote_to_main=True, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -839,66 +799,12 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ @@ -1574,6 +1480,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -1607,16 +1514,22 @@ async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -1643,66 +1556,12 @@ async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ @@ -2082,6 +1941,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> interruption_settings={ "disable_greeting_interruption": True, "enable": True, + "interrupt_prediction_threshold": 0, "start_speaking_plan": { "transcription_endpointing_plan": { "on_no_punctuation_seconds": 0, @@ -2116,17 +1976,23 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> "status": "enabled", }, post_conversation_settings={"enabled": True}, - privacy_settings={"data_retention": True}, + privacy_settings={ + "data_retention": True, + "in_transit_data_locality": True, + }, promote_to_main=True, tags=["string"], telephony_settings={ "default_texml_app_id": "default_texml_app_id", "disable_dtmf": True, "fallback_destination": "fallback_destination", - "noise_suppression": "krisp", + "noise_suppression": "aicoustics", "noise_suppression_config": { "attenuation_limit": 0, + "enhancement_level": 0, + "family": "quail", "mode": "advanced", + "size": "vf", }, "recording_settings": { "channels": "single", @@ -2153,66 +2019,12 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> tool_ids=["string"], tools=[ { - "type": "webhook", - "webhook": { - "description": "description", + "function": { "name": "name", - "url": "https://example.com/api/v1/function", - "async": True, - "async_timeout_ms": 1, - "body_parameters": { - "properties": { - "age": "bar", - "location": "bar", - }, - "required": ["age", "location"], - "type": "object", - }, - "headers": [ - { - "name": "name", - "value": "value", - } - ], - "messages": [ - { - "content": "Let me look that up for you.", - "type": "request_start", - "timing_ms": 100, - }, - { - "content": "Still working on that.", - "timing_ms": 5000, - "type": "request_response_delayed", - }, - ], - "method": "GET", - "path_parameters": { - "properties": {"id": "bar"}, - "required": ["id"], - "type": "object", - }, - "preset_body_fields": { - "account_id": "bar", - "source": "bar", - }, - "preset_query_params": { - "caller": "bar", - "channel": "bar", - }, - "query_parameters": { - "properties": {"page": "bar"}, - "required": ["page"], - "type": "object", - }, - "store_fields_as_variables": [ - { - "name": "x", - "value_path": "x", - } - ], - "timeout_ms": 500, + "description": "description", + "parameters": {"foo": "bar"}, }, + "type": "function", } ], transcription={ diff --git a/tests/api_resources/ai/typesafe/__init__.py b/tests/api_resources/ai/typesafe/__init__.py new file mode 100644 index 000000000..fd8019a9a --- /dev/null +++ b/tests/api_resources/ai/typesafe/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/ai/typesafe/test_v1.py b/tests/api_resources/ai/typesafe/test_v1.py new file mode 100644 index 000000000..45c5d81b0 --- /dev/null +++ b/tests/api_resources/ai/typesafe/test_v1.py @@ -0,0 +1,212 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.ai.typesafe import V1SystemoneResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestV1: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_systemone(self, client: Telnyx) -> None: + v1 = client.ai.typesafe.v1.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_systemone(self, client: Telnyx) -> None: + response = client.ai.typesafe.v1.with_raw_response.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = response.parse() + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_systemone(self, client: Telnyx) -> None: + with client.ai.typesafe.v1.with_streaming_response.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = response.parse() + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncV1: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_systemone(self, async_client: AsyncTelnyx) -> None: + v1 = await async_client.ai.typesafe.v1.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_systemone(self, async_client: AsyncTelnyx) -> None: + response = await async_client.ai.typesafe.v1.with_raw_response.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = await response.parse() + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_systemone(self, async_client: AsyncTelnyx) -> None: + async with async_client.ai.typesafe.v1.with_streaming_response.systemone( + questions={ + "team": { + "criteria": { + "billing": "Payments and refunds", + "technical_support": "Service faults and technical problems", + "sales": "New purchases", + }, + "instructions": "Choose the team that should handle this incident.", + "type": "choice", + }, + "production_incident": { + "instructions": "Does the message describe an active production incident?", + "type": "noul", + }, + "urgency": { + "criteria": ["Low", "Normal", "High", "Critical"], + "instructions": "Rate operational urgency.", + "type": "score", + }, + }, + state="Our production calls are failing. Every customer is affected.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = await response.parse() + assert_matches_type(V1SystemoneResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/calls/test_actions.py b/tests/api_resources/calls/test_actions.py index 1c6953009..238271476 100644 --- a/tests/api_resources/calls/test_actions.py +++ b/tests/api_resources/calls/test_actions.py @@ -2837,6 +2837,13 @@ def test_method_transfer_with_all_params(self, client: Telnyx) -> None: answering_machine_detection_config={ "after_greeting_silence_millis": 1000, "beep_detection_profile": "freq_only", + "beep_max_frequency_hz": 2000, + "beep_min_frequency_hz": 550, + "beep_min_tone_duration_millis": 300, + "beep_spectral_confirmation": True, + "beep_spectral_min_purity": 0.8, + "beep_spectral_reject_fax_cng": True, + "beep_spectral_window_millis": 100, "between_words_silence_millis": 1000, "greeting_duration_millis": 1000, "greeting_silence_duration_millis": 2000, @@ -5777,6 +5784,13 @@ async def test_method_transfer_with_all_params(self, async_client: AsyncTelnyx) answering_machine_detection_config={ "after_greeting_silence_millis": 1000, "beep_detection_profile": "freq_only", + "beep_max_frequency_hz": 2000, + "beep_min_frequency_hz": 550, + "beep_min_tone_duration_millis": 300, + "beep_spectral_confirmation": True, + "beep_spectral_min_purity": 0.8, + "beep_spectral_reject_fax_cng": True, + "beep_spectral_window_millis": 100, "between_words_silence_millis": 1000, "greeting_duration_millis": 1000, "greeting_silence_duration_millis": 2000, diff --git a/tests/api_resources/compute/funcs/__init__.py b/tests/api_resources/compute/funcs/__init__.py new file mode 100644 index 000000000..fd8019a9a --- /dev/null +++ b/tests/api_resources/compute/funcs/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/compute/funcs/test_export.py b/tests/api_resources/compute/funcs/test_export.py new file mode 100644 index 000000000..132a218a7 --- /dev/null +++ b/tests/api_resources/compute/funcs/test_export.py @@ -0,0 +1,308 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.compute.funcs import FuncLogExportConfigResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExport: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + export = client.compute.funcs.export.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.compute.funcs.export.with_raw_response.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.compute.funcs.export.with_streaming_response.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.compute.funcs.export.with_raw_response.create( + id="", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + export = client.compute.funcs.export.list( + "id", + ) + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.compute.funcs.export.with_raw_response.list( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.compute.funcs.export.with_streaming_response.list( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.compute.funcs.export.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete_all(self, client: Telnyx) -> None: + export = client.compute.funcs.export.delete_all( + "id", + ) + assert export is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete_all(self, client: Telnyx) -> None: + response = client.compute.funcs.export.with_raw_response.delete_all( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = response.parse() + assert export is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete_all(self, client: Telnyx) -> None: + with client.compute.funcs.export.with_streaming_response.delete_all( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = response.parse() + assert export is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete_all(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.compute.funcs.export.with_raw_response.delete_all( + "", + ) + + +class TestAsyncExport: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + export = await async_client.compute.funcs.export.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.compute.funcs.export.with_raw_response.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = await response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.compute.funcs.export.with_streaming_response.create( + id="id", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = await response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.compute.funcs.export.with_raw_response.create( + id="", + endpoint="https://api.honeycomb.io/v1/logs", + headers={"x-honeycomb-team": "abc123"}, + invocation_export_enabled=True, + runtime_export_enabled=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + export = await async_client.compute.funcs.export.list( + "id", + ) + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.compute.funcs.export.with_raw_response.list( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = await response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.compute.funcs.export.with_streaming_response.list( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = await response.parse() + assert_matches_type(FuncLogExportConfigResponse, export, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.compute.funcs.export.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete_all(self, async_client: AsyncTelnyx) -> None: + export = await async_client.compute.funcs.export.delete_all( + "id", + ) + assert export is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete_all(self, async_client: AsyncTelnyx) -> None: + response = await async_client.compute.funcs.export.with_raw_response.delete_all( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + export = await response.parse() + assert export is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete_all(self, async_client: AsyncTelnyx) -> None: + async with async_client.compute.funcs.export.with_streaming_response.delete_all( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + export = await response.parse() + assert export is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete_all(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.compute.funcs.export.with_raw_response.delete_all( + "", + ) diff --git a/tests/api_resources/test_bot_challenge.py b/tests/api_resources/test_bot_challenge.py new file mode 100644 index 000000000..0f3f7c5e4 --- /dev/null +++ b/tests/api_resources/test_bot_challenge.py @@ -0,0 +1,100 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import BotChallengeCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBotChallenge: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + bot_challenge = client.bot_challenge.create() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + bot_challenge = client.bot_challenge.create( + llm_model_name="claude-opus-4", + llm_parameter_count="175B", + llm_quantization="int8", + ) + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.bot_challenge.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_challenge = response.parse() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.bot_challenge.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_challenge = response.parse() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBotChallenge: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + bot_challenge = await async_client.bot_challenge.create() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + bot_challenge = await async_client.bot_challenge.create( + llm_model_name="claude-opus-4", + llm_parameter_count="175B", + llm_quantization="int8", + ) + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.bot_challenge.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_challenge = await response.parse() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.bot_challenge.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_challenge = await response.parse() + assert_matches_type(BotChallengeCreateResponse, bot_challenge, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_bot_sessions.py b/tests/api_resources/test_bot_sessions.py new file mode 100644 index 000000000..61c4e03d5 --- /dev/null +++ b/tests/api_resources/test_bot_sessions.py @@ -0,0 +1,98 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import BotSessionListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBotSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + bot_session = client.bot_sessions.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.bot_sessions.with_raw_response.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_session = response.parse() + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.bot_sessions.with_streaming_response.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_session = response.parse() + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBotSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + bot_session = await async_client.bot_sessions.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.bot_sessions.with_raw_response.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_session = await response.parse() + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.bot_sessions.with_streaming_response.list( + email="agent-owner@example.com", + portal_redirect_token="01890a7e-e2f7-7c3d-8dbb-9a2c5f3d1e0b", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_session = await response.parse() + assert_matches_type(BotSessionListResponse, bot_session, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_bot_signup.py b/tests/api_resources/test_bot_signup.py new file mode 100644 index 000000000..5009c1d4b --- /dev/null +++ b/tests/api_resources/test_bot_signup.py @@ -0,0 +1,214 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import SuccessResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBotSignup: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + bot_signup = client.bot_signup.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + bot_signup = client.bot_signup.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + email="agent-owner@example.com", + terms_and_conditions_eu_url="https://telnyx.com/terms-and-conditions-of-service-eu", + terms_of_service_eu=True, + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.bot_signup.with_raw_response.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_signup = response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.bot_signup.with_streaming_response.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_signup = response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_resend_magic_link(self, client: Telnyx) -> None: + bot_signup = client.bot_signup.resend_magic_link( + email="agent-owner@example.com", + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_resend_magic_link(self, client: Telnyx) -> None: + response = client.bot_signup.with_raw_response.resend_magic_link( + email="agent-owner@example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_signup = response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_resend_magic_link(self, client: Telnyx) -> None: + with client.bot_signup.with_streaming_response.resend_magic_link( + email="agent-owner@example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_signup = response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncBotSignup: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + bot_signup = await async_client.bot_signup.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + bot_signup = await async_client.bot_signup.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + email="agent-owner@example.com", + terms_and_conditions_eu_url="https://telnyx.com/terms-and-conditions-of-service-eu", + terms_of_service_eu=True, + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.bot_signup.with_raw_response.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_signup = await response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.bot_signup.with_streaming_response.create( + bot_challenge_answer="35", + bot_challenge_nonce="c6feda4e-6501-4db9-a21f-665e5b4ce2ba", + privacy_policy_url="https://telnyx.com/privacy-policy", + terms_and_conditions_url="https://telnyx.com/terms-and-conditions-of-service", + terms_of_service=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_signup = await response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_resend_magic_link(self, async_client: AsyncTelnyx) -> None: + bot_signup = await async_client.bot_signup.resend_magic_link( + email="agent-owner@example.com", + ) + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_resend_magic_link(self, async_client: AsyncTelnyx) -> None: + response = await async_client.bot_signup.with_raw_response.resend_magic_link( + email="agent-owner@example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + bot_signup = await response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_resend_magic_link(self, async_client: AsyncTelnyx) -> None: + async with async_client.bot_signup.with_streaming_response.resend_magic_link( + email="agent-owner@example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + bot_signup = await response.parse() + assert_matches_type(SuccessResponse, bot_signup, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_calls.py b/tests/api_resources/test_calls.py index d490b3e43..644dbdb3c 100644 --- a/tests/api_resources/test_calls.py +++ b/tests/api_resources/test_calls.py @@ -41,6 +41,13 @@ def test_method_dial_with_all_params(self, client: Telnyx) -> None: answering_machine_detection_config={ "after_greeting_silence_millis": 1000, "beep_detection_profile": "freq_only", + "beep_max_frequency_hz": 2000, + "beep_min_frequency_hz": 550, + "beep_min_tone_duration_millis": 300, + "beep_spectral_confirmation": True, + "beep_spectral_min_purity": 0.8, + "beep_spectral_reject_fax_cng": True, + "beep_spectral_window_millis": 100, "between_words_silence_millis": 1000, "greeting_duration_millis": 1000, "greeting_silence_duration_millis": 2000, @@ -393,6 +400,13 @@ async def test_method_dial_with_all_params(self, async_client: AsyncTelnyx) -> N answering_machine_detection_config={ "after_greeting_silence_millis": 1000, "beep_detection_profile": "freq_only", + "beep_max_frequency_hz": 2000, + "beep_min_frequency_hz": 550, + "beep_min_tone_duration_millis": 300, + "beep_spectral_confirmation": True, + "beep_spectral_min_purity": 0.8, + "beep_spectral_reject_fax_cng": True, + "beep_spectral_window_millis": 100, "between_words_silence_millis": 1000, "greeting_duration_millis": 1000, "greeting_silence_duration_millis": 2000, diff --git a/tests/api_resources/test_connections.py b/tests/api_resources/test_connections.py index 48d3d90b1..f05402b27 100644 --- a/tests/api_resources/test_connections.py +++ b/tests/api_resources/test_connections.py @@ -12,6 +12,7 @@ from telnyx.types import ( Connection, ConnectionRetrieveResponse, + ConnectionRetrieveCountResponse, ConnectionListActiveCallsResponse, ) from telnyx.pagination import SyncDefaultFlatPagination, AsyncDefaultFlatPagination @@ -161,6 +162,34 @@ def test_path_params_list_active_calls(self, client: Telnyx) -> None: connection_id="", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_count(self, client: Telnyx) -> None: + connection = client.connections.retrieve_count() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_count(self, client: Telnyx) -> None: + response = client.connections.with_raw_response.retrieve_count() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_count(self, client: Telnyx) -> None: + with client.connections.with_streaming_response.retrieve_count() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncConnections: parametrize = pytest.mark.parametrize( @@ -311,3 +340,31 @@ async def test_path_params_list_active_calls(self, async_client: AsyncTelnyx) -> await async_client.connections.with_raw_response.list_active_calls( connection_id="", ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_count(self, async_client: AsyncTelnyx) -> None: + connection = await async_client.connections.retrieve_count() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_count(self, async_client: AsyncTelnyx) -> None: + response = await async_client.connections.with_raw_response.retrieve_count() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_count(self, async_client: AsyncTelnyx) -> None: + async with async_client.connections.with_streaming_response.retrieve_count() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert_matches_type(ConnectionRetrieveCountResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_machine_payments.py b/tests/api_resources/test_machine_payments.py new file mode 100644 index 000000000..3d5f7c2eb --- /dev/null +++ b/tests/api_resources/test_machine_payments.py @@ -0,0 +1,92 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import MachinePaymentAccountCreditResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMachinePayments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_account_credit(self, client: Telnyx) -> None: + machine_payment = client.machine_payments.account_credit( + amount_usd="10.00", + ) + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_account_credit(self, client: Telnyx) -> None: + response = client.machine_payments.with_raw_response.account_credit( + amount_usd="10.00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + machine_payment = response.parse() + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_account_credit(self, client: Telnyx) -> None: + with client.machine_payments.with_streaming_response.account_credit( + amount_usd="10.00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + machine_payment = response.parse() + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncMachinePayments: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_account_credit(self, async_client: AsyncTelnyx) -> None: + machine_payment = await async_client.machine_payments.account_credit( + amount_usd="10.00", + ) + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_account_credit(self, async_client: AsyncTelnyx) -> None: + response = await async_client.machine_payments.with_raw_response.account_credit( + amount_usd="10.00", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + machine_payment = await response.parse() + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_account_credit(self, async_client: AsyncTelnyx) -> None: + async with async_client.machine_payments.with_streaming_response.account_credit( + amount_usd="10.00", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + machine_payment = await response.parse() + assert_matches_type(MachinePaymentAccountCreditResponse, machine_payment, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_noise_suppression_engines.py b/tests/api_resources/test_noise_suppression_engines.py new file mode 100644 index 000000000..3beea017f --- /dev/null +++ b/tests/api_resources/test_noise_suppression_engines.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import NoiseSuppressionEngineListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNoiseSuppressionEngines: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + noise_suppression_engine = client.noise_suppression_engines.list() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.noise_suppression_engines.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + noise_suppression_engine = response.parse() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.noise_suppression_engines.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + noise_suppression_engine = response.parse() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncNoiseSuppressionEngines: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + noise_suppression_engine = await async_client.noise_suppression_engines.list() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.noise_suppression_engines.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + noise_suppression_engine = await response.parse() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.noise_suppression_engines.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + noise_suppression_engine = await response.parse() + assert_matches_type(NoiseSuppressionEngineListResponse, noise_suppression_engine, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_texml.py b/tests/api_resources/test_texml.py index 50eace414..89533a6e2 100644 --- a/tests/api_resources/test_texml.py +++ b/tests/api_resources/test_texml.py @@ -62,7 +62,14 @@ def test_method_initiate_ai_call_with_all_params(self, client: Telnyx) -> None: ], detection_mode="Premium", machine_detection="Enable", + machine_detection_beep_max_frequency=2000, + machine_detection_beep_min_frequency=550, + machine_detection_beep_min_tone_duration=300, machine_detection_beep_profile="freq_only", + machine_detection_beep_spectral_confirmation=True, + machine_detection_beep_spectral_min_purity=0.8, + machine_detection_beep_spectral_reject_fax_cng=True, + machine_detection_beep_spectral_window=100, machine_detection_prompt_end_timeout=5000, machine_detection_silence_timeout=2000, machine_detection_speech_end_threshold=2000, @@ -219,7 +226,14 @@ async def test_method_initiate_ai_call_with_all_params(self, async_client: Async ], detection_mode="Premium", machine_detection="Enable", + machine_detection_beep_max_frequency=2000, + machine_detection_beep_min_frequency=550, + machine_detection_beep_min_tone_duration=300, machine_detection_beep_profile="freq_only", + machine_detection_beep_spectral_confirmation=True, + machine_detection_beep_spectral_min_purity=0.8, + machine_detection_beep_spectral_reject_fax_cng=True, + machine_detection_beep_spectral_window=100, machine_detection_prompt_end_timeout=5000, machine_detection_silence_timeout=2000, machine_detection_speech_end_threshold=2000, diff --git a/tests/api_resources/texml/accounts/conferences/test_participants.py b/tests/api_resources/texml/accounts/conferences/test_participants.py index 6f315d6d8..d30375d97 100644 --- a/tests/api_resources/texml/accounts/conferences/test_participants.py +++ b/tests/api_resources/texml/accounts/conferences/test_participants.py @@ -284,7 +284,14 @@ def test_method_participants_with_all_params(self, client: Telnyx) -> None: from_="+12065550200", label="customer", machine_detection="Enable", + machine_detection_beep_max_frequency=2000, + machine_detection_beep_min_frequency=550, + machine_detection_beep_min_tone_duration=300, machine_detection_beep_profile="freq_only", + machine_detection_beep_spectral_confirmation=True, + machine_detection_beep_spectral_min_purity=0.8, + machine_detection_beep_spectral_reject_fax_cng=True, + machine_detection_beep_spectral_window=100, machine_detection_silence_timeout=2000, machine_detection_speech_end_threshold=2000, machine_detection_speech_threshold=2000, @@ -676,7 +683,14 @@ async def test_method_participants_with_all_params(self, async_client: AsyncTeln from_="+12065550200", label="customer", machine_detection="Enable", + machine_detection_beep_max_frequency=2000, + machine_detection_beep_min_frequency=550, + machine_detection_beep_min_tone_duration=300, machine_detection_beep_profile="freq_only", + machine_detection_beep_spectral_confirmation=True, + machine_detection_beep_spectral_min_purity=0.8, + machine_detection_beep_spectral_reject_fax_cng=True, + machine_detection_beep_spectral_window=100, machine_detection_silence_timeout=2000, machine_detection_speech_end_threshold=2000, machine_detection_speech_threshold=2000, diff --git a/tests/api_resources/texml/accounts/test_calls.py b/tests/api_resources/texml/accounts/test_calls.py index 34bc82c11..3d526d83a 100644 --- a/tests/api_resources/texml/accounts/test_calls.py +++ b/tests/api_resources/texml/accounts/test_calls.py @@ -180,7 +180,14 @@ def test_method_calls_with_all_params(self, client: Telnyx) -> None: "fallback_url": "https://www.example.com/instructions-fallback.xml", "from_": "+13120001234", "machine_detection": "Enable", + "machine_detection_beep_max_frequency": 2000, + "machine_detection_beep_min_frequency": 550, + "machine_detection_beep_min_tone_duration": 300, "machine_detection_beep_profile": "freq_only", + "machine_detection_beep_spectral_confirmation": True, + "machine_detection_beep_spectral_min_purity": 0.8, + "machine_detection_beep_spectral_reject_fax_cng": True, + "machine_detection_beep_spectral_window": 100, "machine_detection_prompt_end_timeout": 5000, "machine_detection_silence_timeout": 2000, "machine_detection_speech_end_threshold": 2000, @@ -614,7 +621,14 @@ async def test_method_calls_with_all_params(self, async_client: AsyncTelnyx) -> "fallback_url": "https://www.example.com/instructions-fallback.xml", "from_": "+13120001234", "machine_detection": "Enable", + "machine_detection_beep_max_frequency": 2000, + "machine_detection_beep_min_frequency": 550, + "machine_detection_beep_min_tone_duration": 300, "machine_detection_beep_profile": "freq_only", + "machine_detection_beep_spectral_confirmation": True, + "machine_detection_beep_spectral_min_purity": 0.8, + "machine_detection_beep_spectral_reject_fax_cng": True, + "machine_detection_beep_spectral_window": 100, "machine_detection_prompt_end_timeout": 5000, "machine_detection_silence_timeout": 2000, "machine_detection_speech_end_threshold": 2000, diff --git a/tests/api_resources/texml/test_calls.py b/tests/api_resources/texml/test_calls.py new file mode 100644 index 000000000..c5688c59f --- /dev/null +++ b/tests/api_resources/texml/test_calls.py @@ -0,0 +1,150 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.texml import CallCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCalls: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + call = client.texml.calls.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + call = client.texml.calls.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + method="POST", + texml="Hello", + url="https://example.com/instructions.xml", + ) + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.texml.calls.with_raw_response.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = response.parse() + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.texml.calls.with_streaming_response.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = response.parse() + assert_matches_type(CallCreateResponse, call, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"): + client.texml.calls.with_raw_response.create( + connection_id="", + from_="+13120001234", + to="+13121230000", + ) + + +class TestAsyncCalls: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + call = await async_client.texml.calls.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + call = await async_client.texml.calls.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + method="POST", + texml="Hello", + url="https://example.com/instructions.xml", + ) + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.texml.calls.with_raw_response.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + call = await response.parse() + assert_matches_type(CallCreateResponse, call, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.texml.calls.with_streaming_response.create( + connection_id="1234567890", + from_="+13120001234", + to="+13121230000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + call = await response.parse() + assert_matches_type(CallCreateResponse, call, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connection_id` but received ''"): + await async_client.texml.calls.with_raw_response.create( + connection_id="", + from_="+13120001234", + to="+13121230000", + )