# 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.pagination import AsyncPager, BaseHttpResponse, SyncPager
from ...core.request_options import RequestOptions
from ...core.serialization import convert_and_respect_annotation_metadata
from ...core.unchecked_base_model import construct_type
from ...requests.booking_custom_attribute_delete_request import BookingCustomAttributeDeleteRequestParams
from ...requests.booking_custom_attribute_upsert_request import BookingCustomAttributeUpsertRequestParams
from ...requests.custom_attribute import CustomAttributeParams
from ...types.bulk_delete_booking_custom_attributes_response import BulkDeleteBookingCustomAttributesResponse
from ...types.bulk_upsert_booking_custom_attributes_response import BulkUpsertBookingCustomAttributesResponse
from ...types.custom_attribute import CustomAttribute
from ...types.delete_booking_custom_attribute_response import DeleteBookingCustomAttributeResponse
from ...types.list_booking_custom_attributes_response import ListBookingCustomAttributesResponse
from ...types.retrieve_booking_custom_attribute_response import RetrieveBookingCustomAttributeResponse
from ...types.upsert_booking_custom_attribute_response import UpsertBookingCustomAttributeResponse

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


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

    def batch_delete(
        self,
        *,
        values: typing.Dict[str, BookingCustomAttributeDeleteRequestParams],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BulkDeleteBookingCustomAttributesResponse]:
        """
        Bulk deletes bookings custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        values : typing.Dict[str, BookingCustomAttributeDeleteRequestParams]
            A map containing 1 to 25 individual Delete requests. For each request, provide an
            arbitrary ID that is unique for this `BulkDeleteBookingCustomAttributes` request and the
            information needed to delete a custom attribute.

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

        Returns
        -------
        HttpResponse[BulkDeleteBookingCustomAttributesResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/bookings/custom-attributes/bulk-delete",
            method="POST",
            json={
                "values": convert_and_respect_annotation_metadata(
                    object_=values,
                    annotation=typing.Dict[str, BookingCustomAttributeDeleteRequestParams],
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkDeleteBookingCustomAttributesResponse,
                    construct_type(
                        type_=BulkDeleteBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 batch_upsert(
        self,
        *,
        values: typing.Dict[str, BookingCustomAttributeUpsertRequestParams],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BulkUpsertBookingCustomAttributesResponse]:
        """
        Bulk upserts bookings custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        values : typing.Dict[str, BookingCustomAttributeUpsertRequestParams]
            A map containing 1 to 25 individual upsert requests. For each request, provide an
            arbitrary ID that is unique for this `BulkUpsertBookingCustomAttributes` request and the
            information needed to create or update a custom attribute.

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

        Returns
        -------
        HttpResponse[BulkUpsertBookingCustomAttributesResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/bookings/custom-attributes/bulk-upsert",
            method="POST",
            json={
                "values": convert_and_respect_annotation_metadata(
                    object_=values,
                    annotation=typing.Dict[str, BookingCustomAttributeUpsertRequestParams],
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkUpsertBookingCustomAttributesResponse,
                    construct_type(
                        type_=BulkUpsertBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 list(
        self,
        booking_id: str,
        *,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        with_definitions: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[CustomAttribute]:
        """
        Lists a booking's custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_READ` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_READ` and `APPOINTMENTS_READ` for the OAuth scope.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        limit : typing.Optional[int]
            The maximum number of results to return in a single paged response. This limit is advisory.
            The response might contain more or fewer results. The minimum value is 1 and the maximum value is 100.
            The default value is 20. For more information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        cursor : typing.Optional[str]
            The cursor returned in the paged response from the previous call to this endpoint.
            Provide this cursor to retrieve the next page of results for your original request. For more
            information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        with_definitions : typing.Optional[bool]
            Indicates whether to return the [custom attribute definition](entity:CustomAttributeDefinition) in the `definition` field of each
            custom attribute. Set this parameter to `true` to get the name and description of each custom
            attribute, information about the data type, or other definition details. The default value is `false`.

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

        Returns
        -------
        SyncPager[CustomAttribute]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes",
            method="GET",
            params={
                "limit": limit,
                "cursor": cursor,
                "with_definitions": with_definitions,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListBookingCustomAttributesResponse,
                    construct_type(
                        type_=ListBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.custom_attributes
                _parsed_next = _parsed_response.cursor
                _has_next = _parsed_next is not None and _parsed_next != ""
                _get_next = lambda: self.list(
                    booking_id,
                    limit=limit,
                    cursor=_parsed_next,
                    with_definitions=with_definitions,
                    request_options=request_options,
                )
                return SyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            _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,
        booking_id: str,
        key: str,
        *,
        with_definition: typing.Optional[bool] = None,
        version: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[RetrieveBookingCustomAttributeResponse]:
        """
        Retrieves a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_READ` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_READ` and `APPOINTMENTS_READ` for the OAuth scope.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to retrieve. This key must match the `key` of a custom
            attribute definition in the Square seller account. If the requesting application is not the
            definition owner, you must use the qualified key.

        with_definition : typing.Optional[bool]
            Indicates whether to return the [custom attribute definition](entity:CustomAttributeDefinition) in the `definition` field of
            the custom attribute. Set this parameter to `true` to get the name and description of the custom
            attribute, information about the data type, or other definition details. The default value is `false`.

        version : typing.Optional[int]
            The current version of the custom attribute, which is used for strongly consistent reads to
            guarantee that you receive the most up-to-date data. When included in the request, Square
            returns the specified version or a higher version if one exists. If the specified version is
            higher than the current version, Square returns a `BAD_REQUEST` error.

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

        Returns
        -------
        HttpResponse[RetrieveBookingCustomAttributeResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="GET",
            params={
                "with_definition": with_definition,
                "version": version,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveBookingCustomAttributeResponse,
                    construct_type(
                        type_=RetrieveBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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,
        booking_id: str,
        key: str,
        *,
        custom_attribute: CustomAttributeParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[UpsertBookingCustomAttributeResponse]:
        """
        Upserts a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to create or update. This key must match the `key` of a
            custom attribute definition in the Square seller account. If the requesting application is not
            the definition owner, you must use the qualified key.

        custom_attribute : CustomAttributeParams
            The custom attribute to create or update, with the following fields:

            - `value`. This value must conform to the `schema` specified by the definition.
            For more information, see [Value data types](https://developer.squareup.com/docs/booking-custom-attributes-api/custom-attributes#value-data-types).

            - `version`. To enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control for an update operation, include this optional field and specify the current version
            of the custom attribute.

        idempotency_key : typing.Optional[str]
            A unique identifier for this request, used to ensure idempotency. For more information,
            see [Idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency).

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

        Returns
        -------
        HttpResponse[UpsertBookingCustomAttributeResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="PUT",
            json={
                "custom_attribute": convert_and_respect_annotation_metadata(
                    object_=custom_attribute, annotation=CustomAttributeParams, direction="write"
                ),
                "idempotency_key": idempotency_key,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpsertBookingCustomAttributeResponse,
                    construct_type(
                        type_=UpsertBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 delete(
        self, booking_id: str, key: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[DeleteBookingCustomAttributeResponse]:
        """
        Deletes a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to delete. This key must match the `key` of a custom
            attribute definition in the Square seller account. If the requesting application is not the
            definition owner, you must use the qualified key.

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

        Returns
        -------
        HttpResponse[DeleteBookingCustomAttributeResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteBookingCustomAttributeResponse,
                    construct_type(
                        type_=DeleteBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 AsyncRawCustomAttributesClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def batch_delete(
        self,
        *,
        values: typing.Dict[str, BookingCustomAttributeDeleteRequestParams],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BulkDeleteBookingCustomAttributesResponse]:
        """
        Bulk deletes bookings custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        values : typing.Dict[str, BookingCustomAttributeDeleteRequestParams]
            A map containing 1 to 25 individual Delete requests. For each request, provide an
            arbitrary ID that is unique for this `BulkDeleteBookingCustomAttributes` request and the
            information needed to delete a custom attribute.

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

        Returns
        -------
        AsyncHttpResponse[BulkDeleteBookingCustomAttributesResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/bookings/custom-attributes/bulk-delete",
            method="POST",
            json={
                "values": convert_and_respect_annotation_metadata(
                    object_=values,
                    annotation=typing.Dict[str, BookingCustomAttributeDeleteRequestParams],
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkDeleteBookingCustomAttributesResponse,
                    construct_type(
                        type_=BulkDeleteBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 batch_upsert(
        self,
        *,
        values: typing.Dict[str, BookingCustomAttributeUpsertRequestParams],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BulkUpsertBookingCustomAttributesResponse]:
        """
        Bulk upserts bookings custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        values : typing.Dict[str, BookingCustomAttributeUpsertRequestParams]
            A map containing 1 to 25 individual upsert requests. For each request, provide an
            arbitrary ID that is unique for this `BulkUpsertBookingCustomAttributes` request and the
            information needed to create or update a custom attribute.

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

        Returns
        -------
        AsyncHttpResponse[BulkUpsertBookingCustomAttributesResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/bookings/custom-attributes/bulk-upsert",
            method="POST",
            json={
                "values": convert_and_respect_annotation_metadata(
                    object_=values,
                    annotation=typing.Dict[str, BookingCustomAttributeUpsertRequestParams],
                    direction="write",
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkUpsertBookingCustomAttributesResponse,
                    construct_type(
                        type_=BulkUpsertBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 list(
        self,
        booking_id: str,
        *,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        with_definitions: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[CustomAttribute]:
        """
        Lists a booking's custom attributes.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_READ` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_READ` and `APPOINTMENTS_READ` for the OAuth scope.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        limit : typing.Optional[int]
            The maximum number of results to return in a single paged response. This limit is advisory.
            The response might contain more or fewer results. The minimum value is 1 and the maximum value is 100.
            The default value is 20. For more information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        cursor : typing.Optional[str]
            The cursor returned in the paged response from the previous call to this endpoint.
            Provide this cursor to retrieve the next page of results for your original request. For more
            information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        with_definitions : typing.Optional[bool]
            Indicates whether to return the [custom attribute definition](entity:CustomAttributeDefinition) in the `definition` field of each
            custom attribute. Set this parameter to `true` to get the name and description of each custom
            attribute, information about the data type, or other definition details. The default value is `false`.

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

        Returns
        -------
        AsyncPager[CustomAttribute]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes",
            method="GET",
            params={
                "limit": limit,
                "cursor": cursor,
                "with_definitions": with_definitions,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListBookingCustomAttributesResponse,
                    construct_type(
                        type_=ListBookingCustomAttributesResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.custom_attributes
                _parsed_next = _parsed_response.cursor
                _has_next = _parsed_next is not None and _parsed_next != ""

                async def _get_next():
                    return await self.list(
                        booking_id,
                        limit=limit,
                        cursor=_parsed_next,
                        with_definitions=with_definitions,
                        request_options=request_options,
                    )

                return AsyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            _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,
        booking_id: str,
        key: str,
        *,
        with_definition: typing.Optional[bool] = None,
        version: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[RetrieveBookingCustomAttributeResponse]:
        """
        Retrieves a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_READ` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_READ` and `APPOINTMENTS_READ` for the OAuth scope.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to retrieve. This key must match the `key` of a custom
            attribute definition in the Square seller account. If the requesting application is not the
            definition owner, you must use the qualified key.

        with_definition : typing.Optional[bool]
            Indicates whether to return the [custom attribute definition](entity:CustomAttributeDefinition) in the `definition` field of
            the custom attribute. Set this parameter to `true` to get the name and description of the custom
            attribute, information about the data type, or other definition details. The default value is `false`.

        version : typing.Optional[int]
            The current version of the custom attribute, which is used for strongly consistent reads to
            guarantee that you receive the most up-to-date data. When included in the request, Square
            returns the specified version or a higher version if one exists. If the specified version is
            higher than the current version, Square returns a `BAD_REQUEST` error.

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

        Returns
        -------
        AsyncHttpResponse[RetrieveBookingCustomAttributeResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="GET",
            params={
                "with_definition": with_definition,
                "version": version,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveBookingCustomAttributeResponse,
                    construct_type(
                        type_=RetrieveBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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,
        booking_id: str,
        key: str,
        *,
        custom_attribute: CustomAttributeParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[UpsertBookingCustomAttributeResponse]:
        """
        Upserts a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to create or update. This key must match the `key` of a
            custom attribute definition in the Square seller account. If the requesting application is not
            the definition owner, you must use the qualified key.

        custom_attribute : CustomAttributeParams
            The custom attribute to create or update, with the following fields:

            - `value`. This value must conform to the `schema` specified by the definition.
            For more information, see [Value data types](https://developer.squareup.com/docs/booking-custom-attributes-api/custom-attributes#value-data-types).

            - `version`. To enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control for an update operation, include this optional field and specify the current version
            of the custom attribute.

        idempotency_key : typing.Optional[str]
            A unique identifier for this request, used to ensure idempotency. For more information,
            see [Idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency).

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

        Returns
        -------
        AsyncHttpResponse[UpsertBookingCustomAttributeResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="PUT",
            json={
                "custom_attribute": convert_and_respect_annotation_metadata(
                    object_=custom_attribute, annotation=CustomAttributeParams, direction="write"
                ),
                "idempotency_key": idempotency_key,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpsertBookingCustomAttributeResponse,
                    construct_type(
                        type_=UpsertBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 delete(
        self, booking_id: str, key: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[DeleteBookingCustomAttributeResponse]:
        """
        Deletes a bookings custom attribute.

        To call this endpoint with buyer-level permissions, set `APPOINTMENTS_WRITE` for the OAuth scope.
        To call this endpoint with seller-level permissions, set `APPOINTMENTS_ALL_WRITE` and `APPOINTMENTS_WRITE` for the OAuth scope.

        For calls to this endpoint with seller-level permissions to succeed, the seller must have subscribed to *Appointments Plus*
        or *Appointments Premium*.

        Parameters
        ----------
        booking_id : str
            The ID of the target [booking](entity:Booking).

        key : str
            The key of the custom attribute to delete. This key must match the `key` of a custom
            attribute definition in the Square seller account. If the requesting application is not the
            definition owner, you must use the qualified key.

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

        Returns
        -------
        AsyncHttpResponse[DeleteBookingCustomAttributeResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/bookings/{jsonable_encoder(booking_id)}/custom-attributes/{jsonable_encoder(key)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteBookingCustomAttributeResponse,
                    construct_type(
                        type_=DeleteBookingCustomAttributeResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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)
