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

import typing
from json.decoder import JSONDecodeError

from ...core.api_error import ApiError
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ...core.http_response import AsyncHttpResponse, HttpResponse
from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import parse_obj_as
from ...core.request_options import RequestOptions
from ...core.serialization import convert_and_respect_annotation_metadata
from ...errors.bad_request_error import BadRequestError
from ...errors.internal_server_error import InternalServerError
from ...errors.not_found_error import NotFoundError
from ...errors.unauthorized_error import UnauthorizedError
from ...types.campaign_submission_result import CampaignSubmissionResult
from ...types.campaign_validation_result import CampaignValidationResult
from ...types.error import Error
from ...types.message_volume_enum import MessageVolumeEnum
from ...types.toll_free_campaign_with_extended_brand_and_status import TollFreeCampaignWithExtendedBrandAndStatus
from .types.toll_free_autofill_response import TollFreeAutofillResponse
from .types.toll_free_campaign_keywords import TollFreeCampaignKeywords
from .types.toll_free_campaign_links import TollFreeCampaignLinks
from .types.toll_free_campaign_opt_in import TollFreeCampaignOptIn
from .types.toll_free_campaign_options import TollFreeCampaignOptions
from .types.toll_free_campaign_use_case import TollFreeCampaignUseCase

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


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

    def autofill(
        self,
        *,
        additional_info: typing.Optional[str] = OMIT,
        campaign_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TollFreeAutofillResponse]:
        """
        Generate campaign details based off existing campaign and the brand it's connected to.

        Parameters
        ----------
        additional_info : typing.Optional[str]
            Any additional information you want to provide.

        campaign_id : typing.Optional[str]
            Unique identifier for the campaign.
            - When autofilling 10DLC campaigns, it must begin with the prefix `dlc_` (e.g., `dlc_1234567890`)
            - When autofilling Toll-Free campaigns, it must begin with the prefix `tf_` (e.g., `tf_1234567890`)
            - When autofilling RCS campaigns, it must begin with the prefix `rcs_` (e.g., `rcs_1234567890`)

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

        Returns
        -------
        HttpResponse[TollFreeAutofillResponse]
            Returns autofilled toll-free information.
        """
        _response = self._client_wrapper.httpx_client.request(
            "campaigns/toll-free/autofill",
            method="POST",
            json={
                "additionalInfo": additional_info,
                "campaignId": campaign_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeAutofillResponse,
                    parse_obj_as(
                        type_=TollFreeAutofillResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get(
        self, campaign_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]:
        """
        Retrieve Toll-Free campaign.

        Parameters
        ----------
        campaign_id : str
            Unique identifier of toll-free campaign. Must begin with the prefix `tf_`.

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

        Returns
        -------
        HttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]
            Successfully retrieved.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"campaigns/toll-free/{jsonable_encoder(campaign_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeCampaignWithExtendedBrandAndStatus,
                    parse_obj_as(
                        type_=TollFreeCampaignWithExtendedBrandAndStatus,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def submit(
        self, campaign_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[CampaignSubmissionResult]:
        """
        Submit your toll-free campaign for approval and activation with carriers.

        Parameters
        ----------
        campaign_id : str
            Unique identifier of the toll-free campaign to submit. Must begin with the prefix `tf_`.

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

        Returns
        -------
        HttpResponse[CampaignSubmissionResult]
            Successfully submitted toll-free campaign for approval.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"campaigns/toll-free/submit/{jsonable_encoder(campaign_id)}",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CampaignSubmissionResult,
                    parse_obj_as(
                        type_=CampaignSubmissionResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def upsert(
        self,
        *,
        brand: typing.Optional[str] = OMIT,
        campaign_id: typing.Optional[str] = OMIT,
        keywords: typing.Optional[TollFreeCampaignKeywords] = OMIT,
        links: typing.Optional[TollFreeCampaignLinks] = OMIT,
        monthly_volume: typing.Optional[MessageVolumeEnum] = OMIT,
        name: typing.Optional[str] = OMIT,
        opt_in: typing.Optional[TollFreeCampaignOptIn] = OMIT,
        options: typing.Optional[TollFreeCampaignOptions] = OMIT,
        production_message_content: typing.Optional[str] = OMIT,
        use_case: typing.Optional[TollFreeCampaignUseCase] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]:
        """
        Create a new toll-free campaign or update an existing one.

        <Note>
        **To create a new campaign:** Omit `campaignId` — one will be generated automatically.

        **Before you start:** Create a [brand](/api-reference/brands/upsert) first — you'll need its `id` for the [`brand`](#request.body.brand) field.

        All fields are **required** unless specified otherwise, and will be validated when [submitted](/api-reference/campaigns/toll-free/submit).

        **See the response for example values for each field.**
        </Note>

        Parameters
        ----------
        brand : typing.Optional[str]
            Brand id. This identifier is a string that always begins with the prefix `b_`, for example: `b_1234567890`.

        campaign_id : typing.Optional[str]
            Unique identifier for the campaign. This identifier is a string that always begins with the prefix `tf_`, for example: `tf_1234567890`.

        keywords : typing.Optional[TollFreeCampaignKeywords]
            Keyword response configuration.

        links : typing.Optional[TollFreeCampaignLinks]
            Legal documentation links.

        monthly_volume : typing.Optional[MessageVolumeEnum]

        name : typing.Optional[str]
            Display name of the campaign. This is not sent to carriers for approval and is only used for your reference on the Pinnacle dashboard.

        opt_in : typing.Optional[TollFreeCampaignOptIn]
            Opt-in method and workflow.

        options : typing.Optional[TollFreeCampaignOptions]
            Campaign configuration options.

        production_message_content : typing.Optional[str]
            Example message(s) that would be sent in production. Should reflect the actual content users will receive, including HELP/STOP disclosures. See the [Production Message Content](/guides/campaigns/opt-in-compliance#production-message-content) section for requirements.

        use_case : typing.Optional[TollFreeCampaignUseCase]
            Use case classification for the campaign.

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

        Returns
        -------
        HttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]
            Successfully created or updated toll-free campaign.
        """
        _response = self._client_wrapper.httpx_client.request(
            "campaigns/toll-free",
            method="POST",
            json={
                "brand": brand,
                "campaignId": campaign_id,
                "keywords": convert_and_respect_annotation_metadata(
                    object_=keywords, annotation=TollFreeCampaignKeywords, direction="write"
                ),
                "links": convert_and_respect_annotation_metadata(
                    object_=links, annotation=TollFreeCampaignLinks, direction="write"
                ),
                "monthlyVolume": monthly_volume,
                "name": name,
                "optIn": convert_and_respect_annotation_metadata(
                    object_=opt_in, annotation=TollFreeCampaignOptIn, direction="write"
                ),
                "options": convert_and_respect_annotation_metadata(
                    object_=options, annotation=TollFreeCampaignOptions, direction="write"
                ),
                "productionMessageContent": production_message_content,
                "useCase": convert_and_respect_annotation_metadata(
                    object_=use_case, annotation=TollFreeCampaignUseCase, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeCampaignWithExtendedBrandAndStatus,
                    parse_obj_as(
                        type_=TollFreeCampaignWithExtendedBrandAndStatus,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def validate(
        self,
        *,
        campaign_id: str,
        additional_info: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[CampaignValidationResult]:
        """
        Validate your toll-free campaign configuration against carrier requirements and compliance rules.

        Parameters
        ----------
        campaign_id : str
            Unique identifier for the campaign.
            - When validating 10DLC campaigns, it must begin with the prefix `dlc_` (e.g., `dlc_1234567890`)
            - When validating toll-free campaigns, it must begin with the prefix `tf_` (e.g., `tf_1234567890`)
            - When validating RCS campaigns, it must begin with the prefix `rcs_` (e.g., `rcs_1234567890`)

        additional_info : typing.Optional[str]
            Any additional information you want to provide.

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

        Returns
        -------
        HttpResponse[CampaignValidationResult]
            Returns validation results.
        """
        _response = self._client_wrapper.httpx_client.request(
            "campaigns/toll-free/validate",
            method="POST",
            json={
                "additionalInfo": additional_info,
                "campaignId": campaign_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CampaignValidationResult,
                    parse_obj_as(
                        type_=CampaignValidationResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


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

    async def autofill(
        self,
        *,
        additional_info: typing.Optional[str] = OMIT,
        campaign_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TollFreeAutofillResponse]:
        """
        Generate campaign details based off existing campaign and the brand it's connected to.

        Parameters
        ----------
        additional_info : typing.Optional[str]
            Any additional information you want to provide.

        campaign_id : typing.Optional[str]
            Unique identifier for the campaign.
            - When autofilling 10DLC campaigns, it must begin with the prefix `dlc_` (e.g., `dlc_1234567890`)
            - When autofilling Toll-Free campaigns, it must begin with the prefix `tf_` (e.g., `tf_1234567890`)
            - When autofilling RCS campaigns, it must begin with the prefix `rcs_` (e.g., `rcs_1234567890`)

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

        Returns
        -------
        AsyncHttpResponse[TollFreeAutofillResponse]
            Returns autofilled toll-free information.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "campaigns/toll-free/autofill",
            method="POST",
            json={
                "additionalInfo": additional_info,
                "campaignId": campaign_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeAutofillResponse,
                    parse_obj_as(
                        type_=TollFreeAutofillResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get(
        self, campaign_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]:
        """
        Retrieve Toll-Free campaign.

        Parameters
        ----------
        campaign_id : str
            Unique identifier of toll-free campaign. Must begin with the prefix `tf_`.

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

        Returns
        -------
        AsyncHttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]
            Successfully retrieved.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"campaigns/toll-free/{jsonable_encoder(campaign_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeCampaignWithExtendedBrandAndStatus,
                    parse_obj_as(
                        type_=TollFreeCampaignWithExtendedBrandAndStatus,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def submit(
        self, campaign_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[CampaignSubmissionResult]:
        """
        Submit your toll-free campaign for approval and activation with carriers.

        Parameters
        ----------
        campaign_id : str
            Unique identifier of the toll-free campaign to submit. Must begin with the prefix `tf_`.

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

        Returns
        -------
        AsyncHttpResponse[CampaignSubmissionResult]
            Successfully submitted toll-free campaign for approval.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"campaigns/toll-free/submit/{jsonable_encoder(campaign_id)}",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CampaignSubmissionResult,
                    parse_obj_as(
                        type_=CampaignSubmissionResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def upsert(
        self,
        *,
        brand: typing.Optional[str] = OMIT,
        campaign_id: typing.Optional[str] = OMIT,
        keywords: typing.Optional[TollFreeCampaignKeywords] = OMIT,
        links: typing.Optional[TollFreeCampaignLinks] = OMIT,
        monthly_volume: typing.Optional[MessageVolumeEnum] = OMIT,
        name: typing.Optional[str] = OMIT,
        opt_in: typing.Optional[TollFreeCampaignOptIn] = OMIT,
        options: typing.Optional[TollFreeCampaignOptions] = OMIT,
        production_message_content: typing.Optional[str] = OMIT,
        use_case: typing.Optional[TollFreeCampaignUseCase] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]:
        """
        Create a new toll-free campaign or update an existing one.

        <Note>
        **To create a new campaign:** Omit `campaignId` — one will be generated automatically.

        **Before you start:** Create a [brand](/api-reference/brands/upsert) first — you'll need its `id` for the [`brand`](#request.body.brand) field.

        All fields are **required** unless specified otherwise, and will be validated when [submitted](/api-reference/campaigns/toll-free/submit).

        **See the response for example values for each field.**
        </Note>

        Parameters
        ----------
        brand : typing.Optional[str]
            Brand id. This identifier is a string that always begins with the prefix `b_`, for example: `b_1234567890`.

        campaign_id : typing.Optional[str]
            Unique identifier for the campaign. This identifier is a string that always begins with the prefix `tf_`, for example: `tf_1234567890`.

        keywords : typing.Optional[TollFreeCampaignKeywords]
            Keyword response configuration.

        links : typing.Optional[TollFreeCampaignLinks]
            Legal documentation links.

        monthly_volume : typing.Optional[MessageVolumeEnum]

        name : typing.Optional[str]
            Display name of the campaign. This is not sent to carriers for approval and is only used for your reference on the Pinnacle dashboard.

        opt_in : typing.Optional[TollFreeCampaignOptIn]
            Opt-in method and workflow.

        options : typing.Optional[TollFreeCampaignOptions]
            Campaign configuration options.

        production_message_content : typing.Optional[str]
            Example message(s) that would be sent in production. Should reflect the actual content users will receive, including HELP/STOP disclosures. See the [Production Message Content](/guides/campaigns/opt-in-compliance#production-message-content) section for requirements.

        use_case : typing.Optional[TollFreeCampaignUseCase]
            Use case classification for the campaign.

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

        Returns
        -------
        AsyncHttpResponse[TollFreeCampaignWithExtendedBrandAndStatus]
            Successfully created or updated toll-free campaign.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "campaigns/toll-free",
            method="POST",
            json={
                "brand": brand,
                "campaignId": campaign_id,
                "keywords": convert_and_respect_annotation_metadata(
                    object_=keywords, annotation=TollFreeCampaignKeywords, direction="write"
                ),
                "links": convert_and_respect_annotation_metadata(
                    object_=links, annotation=TollFreeCampaignLinks, direction="write"
                ),
                "monthlyVolume": monthly_volume,
                "name": name,
                "optIn": convert_and_respect_annotation_metadata(
                    object_=opt_in, annotation=TollFreeCampaignOptIn, direction="write"
                ),
                "options": convert_and_respect_annotation_metadata(
                    object_=options, annotation=TollFreeCampaignOptions, direction="write"
                ),
                "productionMessageContent": production_message_content,
                "useCase": convert_and_respect_annotation_metadata(
                    object_=use_case, annotation=TollFreeCampaignUseCase, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TollFreeCampaignWithExtendedBrandAndStatus,
                    parse_obj_as(
                        type_=TollFreeCampaignWithExtendedBrandAndStatus,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def validate(
        self,
        *,
        campaign_id: str,
        additional_info: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[CampaignValidationResult]:
        """
        Validate your toll-free campaign configuration against carrier requirements and compliance rules.

        Parameters
        ----------
        campaign_id : str
            Unique identifier for the campaign.
            - When validating 10DLC campaigns, it must begin with the prefix `dlc_` (e.g., `dlc_1234567890`)
            - When validating toll-free campaigns, it must begin with the prefix `tf_` (e.g., `tf_1234567890`)
            - When validating RCS campaigns, it must begin with the prefix `rcs_` (e.g., `rcs_1234567890`)

        additional_info : typing.Optional[str]
            Any additional information you want to provide.

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

        Returns
        -------
        AsyncHttpResponse[CampaignValidationResult]
            Returns validation results.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "campaigns/toll-free/validate",
            method="POST",
            json={
                "additionalInfo": additional_info,
                "campaignId": campaign_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CampaignValidationResult,
                    parse_obj_as(
                        type_=CampaignValidationResult,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        parse_obj_as(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
