# This file was auto-generated by Fern from our API Definition.

import typing
import urllib.parse
from json.decoder import JSONDecodeError

from ..commons.errors.server_error import ServerError
from ..commons.errors.unauthorized_error import UnauthorizedError
from ..commons.types.error_body import ErrorBody
from ..commons.types.phone_number import PhoneNumber
from ..commons.types.tools import Tools
from ..commons.types.voice_id import VoiceId
from ..commons.types.webhook import Webhook
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pydantic_utilities import pydantic_v1
from ..core.remove_none_from_dict import remove_none_from_dict
from ..core.request_options import RequestOptions
from .types.country_code import CountryCode
from .types.inbound_number_details_response import InboundNumberDetailsResponse
from .types.inbound_number_response import InboundNumberResponse
from .types.list_inbound_response import ListInboundResponse
from .types.model import Model
from .types.update_inbound_response import UpdateInboundResponse
from .types.voice_settings import VoiceSettings

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class InboundNumbersClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def purchase(
        self,
        *,
        phone_number: PhoneNumber,
        area_code: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        country_code: typing.Optional[CountryCode] = OMIT,
        webhook: typing.Optional[Webhook] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> InboundNumberResponse:
        """
        Purchase and configure a new inbound phone number. ($15/mo. subscription using your stored payment method).

        Parameters
        ----------
        phone_number : PhoneNumber

        area_code : typing.Optional[str]
            Choose a three-digit area code for your phone number. If set as a parameter, a number will only be purchased by exact match if available.

            If not provided, the default value `415` will be used.

        prompt : typing.Optional[str]
            This defines how the AI will start the conversation, information available to it, and its behaviors. Matches how the outbound `task` parameter functions.

        country_code : typing.Optional[CountryCode]
            Choose a country code for your phone number.

            If not provided, the default value `US` will be used.

        webhook : typing.Optional[Webhook]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        InboundNumberResponse

        Examples
        --------
        from bland.client import BlandAI

        client = BlandAI(
            api_key="YOUR_API_KEY",
        )
        client.inbound_numbers.purchase(
            area_code="string",
            prompt="string",
            country_code="US",
            webhook="string",
            phone_number="+18582814611",
        )
        """
        _request: typing.Dict[str, typing.Any] = {"phone_number": phone_number}
        if area_code is not OMIT:
            _request["area_code"] = area_code
        if prompt is not OMIT:
            _request["prompt"] = prompt
        if country_code is not OMIT:
            _request["country_code"] = country_code
        if webhook is not OMIT:
            _request["webhook"] = webhook
        _response = self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/inbound/purchase"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(InboundNumberResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update(
        self,
        phone_number: PhoneNumber,
        *,
        prompt: str,
        tools: Tools,
        transfer_list: typing.Optional[typing.Dict[str, str]] = OMIT,
        model: typing.Optional[Model] = OMIT,
        transfer_phone_number: typing.Optional[PhoneNumber] = OMIT,
        voice_id: typing.Optional[VoiceId] = OMIT,
        webhook: typing.Optional[Webhook] = OMIT,
        record: typing.Optional[bool] = OMIT,
        first_sentence: typing.Optional[str] = OMIT,
        voice_settings: typing.Optional[VoiceSettings] = OMIT,
        dynamic_data: typing.Optional[str] = OMIT,
        interruption_threshold: typing.Optional[int] = OMIT,
        max_duration: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> UpdateInboundResponse:
        """
        Update your inbound agent's settings, prompt and other details.

        Parameters
        ----------
        phone_number : PhoneNumber

        prompt : str
            Provide instructions, relevant information, and examples of the ideal conversation flow.

            For inbound numbers, consider including additional context about the purpose of the call, and what types of callers to expect.

            **Best Practices:**

            **Out-of-the-Box Behaviors (Summarized):**

            - Speech pattern: Direct, concise, casual
            - Spells out symbols, acronyms, abbreviations, percentages, etc. ($4,000,000 -> “four million dollars”)
            - Asks clarifying questions

            **Prompting Tips:**

            Want to easily test out exactly how your agent will behave?

            - Try out Agent Testing!
            - Aim for less than 2,000 characters where possible.
            - Simple, direct prompts are the most predictable and reliable.
            - Frame instructions positively:
              - `"Do this"` rather than `"Don't do this"`.
              - Ex. `“Keep the conversation casual”` rather than `“Don't be too formal”`.
              - This gives concrete examples of what to do, instead of leaving expected behavior open to interpretation.

        tools : Tools

        transfer_list : typing.Optional[typing.Dict[str, str]]
            Give your agent the ability to transfer calls to a set of phone numbers.

            Overrides `transfer_phone_number` if a `transfer_list.default` is specified.

            Will default to `transfer_list.default`, or the chosen phone number.

        model : typing.Optional[Model]
            Select a model to use for your call.

            If no model is provided, the default value `enhanced` will be used.

            In nearly all cases, `enhanced` is the best choice for now.

            Model Differences:

            There are three different ways to use Bland:

            - `model: base`

              - The original, follows scripts/procedures most effectively.
              - Supports all features and capabilities.
              - Best for Custom Tools

            - `model: enhanced`

              - Much faster latency and very conversational, works best with objective-based prompts.
              - Supports all features and capabilities.

            - `model: turbo`
              - The absolute fastest latency possible, can be verbose at times
              - Limited capabilities currently (excludes Transferring, IVR navigation, Custom Tools)
              - Extremely realistic conversation capabilities

        transfer_phone_number : typing.Optional[PhoneNumber]
            A phone number that the agent can transfer to under specific conditions - such as being asked to speak to a human or supervisor.

            Set to `null` to remove.

            Prompting Notes:

            - Specify conditions that the agent should transfer to a human under (examples are great!)
            - In the `task`, refer to the action solely as “transfer” or “transferring”.
            - Alternate phrasing such as “swap” or “switch” can mislead the agent, causing the action to be ignored.

        voice_id : typing.Optional[VoiceId]

        webhook : typing.Optional[Webhook]

        record : typing.Optional[bool]
            To record your phone call, set record to `true`. When your call completes, you can access through the `recording_url` field in the call details or your webhook.

            If no value is provided, the default value `false` will be used.

        first_sentence : typing.Optional[str]
            A phrase that your call will start with instead of a generating one on the fly. This works both with and without `wait_for_greeting`. Can be more than one sentence, but must be less than 200 characters.

            To remove, set to `null` or an empty string.

        voice_settings : typing.Optional[VoiceSettings]
            Alter advanced voice settings for your agent.

            To remove, set to `null` or an empty string.

        dynamic_data : typing.Optional[str]
            Integrate data from external APIs into your agent's knowledge.

            Set to `null` or an empty string to clear dynamic data settings.

            Detailed usage in the Send Call endpoint.

        interruption_threshold : typing.Optional[int]
            How long our AI phone agent should wait in milliseconds before responding.

            When you increase the interruption latency, you force the AI phone agent to listen longer before responding. In practice, increasing the threshold results in less interruptions and more latency.

            Try setting the threshold to 500 milliseconds. You'll encounter higher latency, but you'll be interrupted less frequently.

            Set to `null` to reset to default.

            If no value is provided, the default value `50` will be used.

        max_duration : typing.Optional[int]
            The maximum duration in minutes that calls to your agent can last before being automatically terminated.

            Set to `null` to reset to default.

            If no value is provided, the default value `30` will be used.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        UpdateInboundResponse

        Examples
        --------
        from bland.client import BlandAI

        client = BlandAI(
            api_key="YOUR_API_KEY",
        )
        client.inbound_numbers.update(
            phone_number="+18582814611",
            prompt="29382721828",
            transfer_list={
                "default": "+1234567890",
                "sales": "+1234567890",
                "support": "+1234567890",
                "billing": "+1234567890",
            },
            model="enhanced",
        )
        """
        _request: typing.Dict[str, typing.Any] = {"prompt": prompt, "tools": tools}
        if transfer_list is not OMIT:
            _request["transfer_list"] = transfer_list
        if model is not OMIT:
            _request["model"] = model
        if transfer_phone_number is not OMIT:
            _request["transfer_phone_number"] = transfer_phone_number
        if voice_id is not OMIT:
            _request["voice_id"] = voice_id
        if webhook is not OMIT:
            _request["webhook"] = webhook
        if record is not OMIT:
            _request["record"] = record
        if first_sentence is not OMIT:
            _request["first_sentence"] = first_sentence
        if voice_settings is not OMIT:
            _request["voice_settings"] = voice_settings
        if dynamic_data is not OMIT:
            _request["dynamic_data"] = dynamic_data
        if interruption_threshold is not OMIT:
            _request["interruption_threshold"] = interruption_threshold
        if max_duration is not OMIT:
            _request["max_duration"] = max_duration
        _response = self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(
                f"{self._client_wrapper.get_base_url()}/", f"v1/inbound/{jsonable_encoder(phone_number)}"
            ),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(UpdateInboundResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListInboundResponse:
        """
        Retrieves a list of all inbound phone numbers configured for your account, along with their associated settings.

        Parameters
        ----------
        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        ListInboundResponse

        Examples
        --------
        from bland.client import BlandAI

        client = BlandAI(
            api_key="YOUR_API_KEY",
        )
        client.inbound_numbers.list()
        """
        _response = self._client_wrapper.httpx_client.request(
            method="GET",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/inbound"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(ListInboundResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def details(
        self, phone_number: PhoneNumber, *, request_options: typing.Optional[RequestOptions] = None
    ) -> InboundNumberDetailsResponse:
        """
        Retrieve settings for your inbound phone number.

        Parameters
        ----------
        phone_number : PhoneNumber

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        InboundNumberDetailsResponse

        Examples
        --------
        from bland.client import BlandAI

        client = BlandAI(
            api_key="YOUR_API_KEY",
        )
        client.inbound_numbers.details(
            phone_number="+18582814611",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            method="GET",
            url=urllib.parse.urljoin(
                f"{self._client_wrapper.get_base_url()}/", f"v1/inbound/{jsonable_encoder(phone_number)}"
            ),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(InboundNumberDetailsResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


class AsyncInboundNumbersClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def purchase(
        self,
        *,
        phone_number: PhoneNumber,
        area_code: typing.Optional[str] = OMIT,
        prompt: typing.Optional[str] = OMIT,
        country_code: typing.Optional[CountryCode] = OMIT,
        webhook: typing.Optional[Webhook] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> InboundNumberResponse:
        """
        Purchase and configure a new inbound phone number. ($15/mo. subscription using your stored payment method).

        Parameters
        ----------
        phone_number : PhoneNumber

        area_code : typing.Optional[str]
            Choose a three-digit area code for your phone number. If set as a parameter, a number will only be purchased by exact match if available.

            If not provided, the default value `415` will be used.

        prompt : typing.Optional[str]
            This defines how the AI will start the conversation, information available to it, and its behaviors. Matches how the outbound `task` parameter functions.

        country_code : typing.Optional[CountryCode]
            Choose a country code for your phone number.

            If not provided, the default value `US` will be used.

        webhook : typing.Optional[Webhook]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        InboundNumberResponse

        Examples
        --------
        from bland.client import AsyncBlandAI

        client = AsyncBlandAI(
            api_key="YOUR_API_KEY",
        )
        await client.inbound_numbers.purchase(
            area_code="string",
            prompt="string",
            country_code="US",
            webhook="string",
            phone_number="+18582814611",
        )
        """
        _request: typing.Dict[str, typing.Any] = {"phone_number": phone_number}
        if area_code is not OMIT:
            _request["area_code"] = area_code
        if prompt is not OMIT:
            _request["prompt"] = prompt
        if country_code is not OMIT:
            _request["country_code"] = country_code
        if webhook is not OMIT:
            _request["webhook"] = webhook
        _response = await self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/inbound/purchase"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(InboundNumberResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update(
        self,
        phone_number: PhoneNumber,
        *,
        prompt: str,
        tools: Tools,
        transfer_list: typing.Optional[typing.Dict[str, str]] = OMIT,
        model: typing.Optional[Model] = OMIT,
        transfer_phone_number: typing.Optional[PhoneNumber] = OMIT,
        voice_id: typing.Optional[VoiceId] = OMIT,
        webhook: typing.Optional[Webhook] = OMIT,
        record: typing.Optional[bool] = OMIT,
        first_sentence: typing.Optional[str] = OMIT,
        voice_settings: typing.Optional[VoiceSettings] = OMIT,
        dynamic_data: typing.Optional[str] = OMIT,
        interruption_threshold: typing.Optional[int] = OMIT,
        max_duration: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> UpdateInboundResponse:
        """
        Update your inbound agent's settings, prompt and other details.

        Parameters
        ----------
        phone_number : PhoneNumber

        prompt : str
            Provide instructions, relevant information, and examples of the ideal conversation flow.

            For inbound numbers, consider including additional context about the purpose of the call, and what types of callers to expect.

            **Best Practices:**

            **Out-of-the-Box Behaviors (Summarized):**

            - Speech pattern: Direct, concise, casual
            - Spells out symbols, acronyms, abbreviations, percentages, etc. ($4,000,000 -> “four million dollars”)
            - Asks clarifying questions

            **Prompting Tips:**

            Want to easily test out exactly how your agent will behave?

            - Try out Agent Testing!
            - Aim for less than 2,000 characters where possible.
            - Simple, direct prompts are the most predictable and reliable.
            - Frame instructions positively:
              - `"Do this"` rather than `"Don't do this"`.
              - Ex. `“Keep the conversation casual”` rather than `“Don't be too formal”`.
              - This gives concrete examples of what to do, instead of leaving expected behavior open to interpretation.

        tools : Tools

        transfer_list : typing.Optional[typing.Dict[str, str]]
            Give your agent the ability to transfer calls to a set of phone numbers.

            Overrides `transfer_phone_number` if a `transfer_list.default` is specified.

            Will default to `transfer_list.default`, or the chosen phone number.

        model : typing.Optional[Model]
            Select a model to use for your call.

            If no model is provided, the default value `enhanced` will be used.

            In nearly all cases, `enhanced` is the best choice for now.

            Model Differences:

            There are three different ways to use Bland:

            - `model: base`

              - The original, follows scripts/procedures most effectively.
              - Supports all features and capabilities.
              - Best for Custom Tools

            - `model: enhanced`

              - Much faster latency and very conversational, works best with objective-based prompts.
              - Supports all features and capabilities.

            - `model: turbo`
              - The absolute fastest latency possible, can be verbose at times
              - Limited capabilities currently (excludes Transferring, IVR navigation, Custom Tools)
              - Extremely realistic conversation capabilities

        transfer_phone_number : typing.Optional[PhoneNumber]
            A phone number that the agent can transfer to under specific conditions - such as being asked to speak to a human or supervisor.

            Set to `null` to remove.

            Prompting Notes:

            - Specify conditions that the agent should transfer to a human under (examples are great!)
            - In the `task`, refer to the action solely as “transfer” or “transferring”.
            - Alternate phrasing such as “swap” or “switch” can mislead the agent, causing the action to be ignored.

        voice_id : typing.Optional[VoiceId]

        webhook : typing.Optional[Webhook]

        record : typing.Optional[bool]
            To record your phone call, set record to `true`. When your call completes, you can access through the `recording_url` field in the call details or your webhook.

            If no value is provided, the default value `false` will be used.

        first_sentence : typing.Optional[str]
            A phrase that your call will start with instead of a generating one on the fly. This works both with and without `wait_for_greeting`. Can be more than one sentence, but must be less than 200 characters.

            To remove, set to `null` or an empty string.

        voice_settings : typing.Optional[VoiceSettings]
            Alter advanced voice settings for your agent.

            To remove, set to `null` or an empty string.

        dynamic_data : typing.Optional[str]
            Integrate data from external APIs into your agent's knowledge.

            Set to `null` or an empty string to clear dynamic data settings.

            Detailed usage in the Send Call endpoint.

        interruption_threshold : typing.Optional[int]
            How long our AI phone agent should wait in milliseconds before responding.

            When you increase the interruption latency, you force the AI phone agent to listen longer before responding. In practice, increasing the threshold results in less interruptions and more latency.

            Try setting the threshold to 500 milliseconds. You'll encounter higher latency, but you'll be interrupted less frequently.

            Set to `null` to reset to default.

            If no value is provided, the default value `50` will be used.

        max_duration : typing.Optional[int]
            The maximum duration in minutes that calls to your agent can last before being automatically terminated.

            Set to `null` to reset to default.

            If no value is provided, the default value `30` will be used.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        UpdateInboundResponse

        Examples
        --------
        from bland.client import AsyncBlandAI

        client = AsyncBlandAI(
            api_key="YOUR_API_KEY",
        )
        await client.inbound_numbers.update(
            phone_number="+18582814611",
            prompt="29382721828",
            transfer_list={
                "default": "+1234567890",
                "sales": "+1234567890",
                "support": "+1234567890",
                "billing": "+1234567890",
            },
            model="enhanced",
        )
        """
        _request: typing.Dict[str, typing.Any] = {"prompt": prompt, "tools": tools}
        if transfer_list is not OMIT:
            _request["transfer_list"] = transfer_list
        if model is not OMIT:
            _request["model"] = model
        if transfer_phone_number is not OMIT:
            _request["transfer_phone_number"] = transfer_phone_number
        if voice_id is not OMIT:
            _request["voice_id"] = voice_id
        if webhook is not OMIT:
            _request["webhook"] = webhook
        if record is not OMIT:
            _request["record"] = record
        if first_sentence is not OMIT:
            _request["first_sentence"] = first_sentence
        if voice_settings is not OMIT:
            _request["voice_settings"] = voice_settings
        if dynamic_data is not OMIT:
            _request["dynamic_data"] = dynamic_data
        if interruption_threshold is not OMIT:
            _request["interruption_threshold"] = interruption_threshold
        if max_duration is not OMIT:
            _request["max_duration"] = max_duration
        _response = await self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(
                f"{self._client_wrapper.get_base_url()}/", f"v1/inbound/{jsonable_encoder(phone_number)}"
            ),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(UpdateInboundResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListInboundResponse:
        """
        Retrieves a list of all inbound phone numbers configured for your account, along with their associated settings.

        Parameters
        ----------
        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        ListInboundResponse

        Examples
        --------
        from bland.client import AsyncBlandAI

        client = AsyncBlandAI(
            api_key="YOUR_API_KEY",
        )
        await client.inbound_numbers.list()
        """
        _response = await self._client_wrapper.httpx_client.request(
            method="GET",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/inbound"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(ListInboundResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def details(
        self, phone_number: PhoneNumber, *, request_options: typing.Optional[RequestOptions] = None
    ) -> InboundNumberDetailsResponse:
        """
        Retrieve settings for your inbound phone number.

        Parameters
        ----------
        phone_number : PhoneNumber

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        InboundNumberDetailsResponse

        Examples
        --------
        from bland.client import AsyncBlandAI

        client = AsyncBlandAI(
            api_key="YOUR_API_KEY",
        )
        await client.inbound_numbers.details(
            phone_number="+18582814611",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            method="GET",
            url=urllib.parse.urljoin(
                f"{self._client_wrapper.get_base_url()}/", f"v1/inbound/{jsonable_encoder(phone_number)}"
            ),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(InboundNumberDetailsResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
