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

import typing
from json.decoder import JSONDecodeError

from ..commons.errors.bad_request import BadRequest
from ..commons.errors.conflict import Conflict
from ..commons.errors.forbidden import Forbidden
from ..commons.errors.internal_server_error import InternalServerError
from ..commons.errors.not_found import NotFound
from ..commons.errors.unauthorized import Unauthorized
from ..commons.errors.unimplemented import Unimplemented
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.request_options import RequestOptions
from ..entity_types.types.account_type import AccountType
from ..entity_types.types.entity_id import EntityId
from ..entity_types.types.entity_onboarding_link_type import EntityOnboardingLinkType
from ..entity_types.types.entity_response import EntityResponse
from ..entity_types.types.entity_status import EntityStatus
from ..entity_types.types.find_entity_response import FindEntityResponse
from ..entity_types.types.profile_request import ProfileRequest
from ..entity_types.types.token_generation_entity_options import TokenGenerationEntityOptions
from ..entity_types.types.token_generation_invoice_options import TokenGenerationInvoiceOptions
from ..entity_types.types.token_generation_pages_options import TokenGenerationPagesOptions
from ..entity_types.types.token_generation_style_options import TokenGenerationStyleOptions
from ..entity_types.types.token_generation_vendor_options import TokenGenerationVendorOptions
from ..payment_method_types.types.payment_method_id import PaymentMethodId
from .approval_policy.client import ApprovalPolicyClient, AsyncApprovalPolicyClient
from .counterparty.client import AsyncCounterpartyClient, CounterpartyClient
from .customization.client import AsyncCustomizationClient, CustomizationClient
from .email_log.client import AsyncEmailLogClient, EmailLogClient
from .external_accounting_system.client import AsyncExternalAccountingSystemClient, ExternalAccountingSystemClient
from .invoice.client import AsyncInvoiceClient, InvoiceClient
from .metadata.client import AsyncMetadataClient, MetadataClient
from .notification_policy.client import AsyncNotificationPolicyClient, NotificationPolicyClient
from .payment_method.client import AsyncPaymentMethodClient, PaymentMethodClient
from .representative.client import AsyncRepresentativeClient, RepresentativeClient
from .user.client import AsyncUserClient, UserClient

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


class EntityClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper
        self.email_log = EmailLogClient(client_wrapper=self._client_wrapper)
        self.user = UserClient(client_wrapper=self._client_wrapper)
        self.approval_policy = ApprovalPolicyClient(client_wrapper=self._client_wrapper)
        self.counterparty = CounterpartyClient(client_wrapper=self._client_wrapper)
        self.customization = CustomizationClient(client_wrapper=self._client_wrapper)
        self.external_accounting_system = ExternalAccountingSystemClient(client_wrapper=self._client_wrapper)
        self.invoice = InvoiceClient(client_wrapper=self._client_wrapper)
        self.metadata = MetadataClient(client_wrapper=self._client_wrapper)
        self.notification_policy = NotificationPolicyClient(client_wrapper=self._client_wrapper)
        self.payment_method = PaymentMethodClient(client_wrapper=self._client_wrapper)
        self.representative = RepresentativeClient(client_wrapper=self._client_wrapper)

    def find(
        self,
        *,
        payment_methods: typing.Optional[bool] = None,
        is_customer: typing.Optional[bool] = None,
        foreign_id: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
        status: typing.Optional[typing.Union[EntityStatus, typing.Sequence[EntityStatus]]] = None,
        is_payee: typing.Optional[bool] = None,
        is_payor: typing.Optional[bool] = None,
        name: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        starting_after: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> FindEntityResponse:
        """
        Search all entities with the given filters. If no filters are provided, all entities will be returned.

        Parameters
        ----------
        payment_methods : typing.Optional[bool]
            If true, will include entity payment methods as part of the response

        is_customer : typing.Optional[bool]
            If true, only entities with a direct relationship to the requesting organization will be returned. If false or not provided, all entities will be returned.

        foreign_id : typing.Optional[typing.Union[str, typing.Sequence[str]]]
            ID used to identify this entity in your system

        status : typing.Optional[typing.Union[EntityStatus, typing.Sequence[EntityStatus]]]

        is_payee : typing.Optional[bool]
            If true, entities that are marked as payees will be returned.
            If false or not provided, entities that are marked as payees will not be returned.

        is_payor : typing.Optional[bool]
            If true or not provided, entities that are marked as payors will be returned.
            If false, entities that are marked as payors will not be returned.

        name : typing.Optional[str]
            Filter entities by name. Partial matches are supported.

        limit : typing.Optional[int]
            Number of entities to return. Limit can range between 1 and 100, and the default is 10.

        starting_after : typing.Optional[EntityId]
            The ID of the entity to start after. If not provided, the first page of entities will be returned.

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

        Returns
        -------
        FindEntityResponse

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.find(
            is_customer=True,
            foreign_id="MY-DB-ID-12345",
            payment_methods=True,
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            "entity",
            method="GET",
            params={
                "paymentMethods": payment_methods,
                "isCustomer": is_customer,
                "foreignId": foreign_id,
                "status": status,
                "isPayee": is_payee,
                "isPayor": is_payor,
                "name": name,
                "limit": limit,
                "startingAfter": starting_after,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(FindEntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def create(
        self,
        *,
        is_customer: bool,
        account_type: AccountType,
        profile: ProfileRequest,
        is_payor: bool,
        is_payee: bool,
        foreign_id: typing.Optional[str] = OMIT,
        email_to: typing.Optional[str] = OMIT,
        email_to_alias: typing.Optional[typing.Sequence[str]] = OMIT,
        is_network_payor: typing.Optional[bool] = OMIT,
        is_network_payee: typing.Optional[bool] = OMIT,
        logo: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> EntityResponse:
        """
        Parameters
        ----------
        is_customer : bool
            If this entity has a direct relationship with your organization (e.g your direct customer or client), set this to true. Otherwise, set to false (e.g your customer's vendors).

        account_type : AccountType

        profile : ProfileRequest

        is_payor : bool
            If this entity will be paying invoices, set this to true.

        is_payee : bool
            If this entity will be receiving payments, set this to true.

        foreign_id : typing.Optional[str]
            The ID used to identify this entity in your system. This ID must be unique across all entities in your system.

        email_to : typing.Optional[str]
            Sets the email address to which to send invoices to be added to the Invoice Inbox. Only provide the local-part/username of the email address, do not include the @domain.com

        email_to_alias : typing.Optional[typing.Sequence[str]]
            Email inbox alias addresses. Used when forwarding emails to the emailTo address from an alias. Include the full email address.

        is_network_payor : typing.Optional[bool]
            Control if this entity should be available as a payor to any entity on your platform. If set to false, this entity will only be available as a payor to entities that have a direct relationship with this entity. Defaults to false.

        is_network_payee : typing.Optional[bool]
            Control if this entity should be available as a payee to any entity on your platform. If set to false, this entity will only be available as a payee to entities that have a direct relationship with this entity. Defaults to false.

        logo : typing.Optional[str]
            Base64 encoded PNG image data for the entity logo.

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa import (
            Address,
            BusinessProfileRequest,
            Ein,
            PhoneNumber,
            ProfileRequest,
            TaxId,
        )
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.create(
            is_customer=True,
            is_payor=True,
            is_payee=False,
            account_type="business",
            foreign_id="MY-DB-ID-12345",
            profile=ProfileRequest(
                business=BusinessProfileRequest(
                    email="customer@acme.com",
                    legal_business_name="Acme Inc.",
                    website="http://www.acme.com",
                    business_type="llc",
                    phone=PhoneNumber(
                        country_code="1",
                        number="4155551234",
                    ),
                    address=Address(
                        address_line_1="123 Main St",
                        address_line_2="Unit 1",
                        city="San Francisco",
                        state_or_province="CA",
                        postal_code="94105",
                        country="US",
                    ),
                    tax_id=TaxId(
                        ein=Ein(
                            number="12-3456789",
                        ),
                    ),
                ),
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            "entity",
            method="POST",
            json={
                "foreignId": foreign_id,
                "emailTo": email_to,
                "emailToAlias": email_to_alias,
                "isCustomer": is_customer,
                "accountType": account_type,
                "profile": profile,
                "isPayor": is_payor,
                "isPayee": is_payee,
                "isNetworkPayor": is_network_payor,
                "isNetworkPayee": is_network_payee,
                "logo": logo,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get(self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None) -> EntityResponse:
        """
        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.get(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}", method="GET", request_options=request_options
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update(
        self,
        entity_id: EntityId,
        *,
        foreign_id: typing.Optional[str] = OMIT,
        email_to: typing.Optional[str] = OMIT,
        email_to_alias: typing.Optional[typing.Sequence[str]] = OMIT,
        is_customer: typing.Optional[bool] = OMIT,
        account_type: typing.Optional[AccountType] = OMIT,
        profile: typing.Optional[ProfileRequest] = OMIT,
        is_payor: typing.Optional[bool] = OMIT,
        is_payee: typing.Optional[bool] = OMIT,
        is_network_payor: typing.Optional[bool] = OMIT,
        is_network_payee: typing.Optional[bool] = OMIT,
        logo: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> EntityResponse:
        """
        Parameters
        ----------
        entity_id : EntityId

        foreign_id : typing.Optional[str]
            The ID used to identify this entity in your system. This ID must be unique across all entities in your system.

        email_to : typing.Optional[str]
            Sets the email address to which to send invoices to be added to the Invoice Inbox. Only provide the local-part/username of the email address, do not include the @domain.com

        email_to_alias : typing.Optional[typing.Sequence[str]]
            Email inbox alias addresses. Used when forwarding emails to the emailTo address from an alias. Include the full email address.

        is_customer : typing.Optional[bool]
            If this entity has a direct relationship with your organization (e.g your direct customer or client), set this to true. Otherwise, set to false (e.g your customer's vendors).

        account_type : typing.Optional[AccountType]

        profile : typing.Optional[ProfileRequest]

        is_payor : typing.Optional[bool]
            If this entity will be paying invoices, set this to true.

        is_payee : typing.Optional[bool]
            If this entity will be receiving payments, set this to true.

        is_network_payor : typing.Optional[bool]
            Control if this entity should be available as a payor to any entity on your platform. If set to false, this entity will only be available as a payor to entities that have a direct relationship with this entity. Defaults to false.

        is_network_payee : typing.Optional[bool]
            Control if this entity should be available as a payee to any entity on your platform. If set to false, this entity will only be available as a payee to entities that have a direct relationship with this entity. Defaults to false.

        logo : typing.Optional[str]
            Base64 encoded PNG image data for the entity logo.

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa import (
            Address,
            BusinessProfileRequest,
            Ein,
            PhoneNumber,
            ProfileRequest,
            TaxId,
        )
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.update(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            is_customer=True,
            is_payor=True,
            is_payee=False,
            account_type="business",
            foreign_id="MY-DB-ID-12345",
            profile=ProfileRequest(
                business=BusinessProfileRequest(
                    email="customer@acme.com",
                    legal_business_name="Acme Inc.",
                    website="http://www.acme.com",
                    business_type="llc",
                    phone=PhoneNumber(
                        country_code="1",
                        number="4155551234",
                    ),
                    address=Address(
                        address_line_1="123 Main St",
                        address_line_2="Unit 1",
                        city="San Francisco",
                        state_or_province="CA",
                        postal_code="94105",
                        country="US",
                    ),
                    tax_id=TaxId(
                        ein=Ein(
                            number="12-3456789",
                        ),
                    ),
                ),
            ),
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}",
            method="POST",
            json={
                "foreignId": foreign_id,
                "emailTo": email_to,
                "emailToAlias": email_to_alias,
                "isCustomer": is_customer,
                "accountType": account_type,
                "profile": profile,
                "isPayor": is_payor,
                "isPayee": is_payee,
                "isNetworkPayor": is_network_payor,
                "isNetworkPayee": is_network_payee,
                "logo": logo,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete(self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None) -> None:
        """
        Will archive the entity. This action cannot be undone, and the entity will no longer be available for use. The foreignId on the entity will be cleared as well.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.delete(
            entity_id="string",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}", method="DELETE", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def accept_terms_of_service(
        self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        This endpoint is used to indicate acceptance of Mercoa's terms of service for an entity. Send a request to this endpoint only after the entity has accepted the Mercoa ToS. Entities must accept Mercoa ToS before they can be send or pay invoices using Mercoa's payment rails.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.accept_terms_of_service(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/accept-tos", method="POST", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def initiate_kyb(self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None) -> None:
        """
        This endpoint is used to initiate KYB for an entity.
        Send a request to this endpoint only after the entity has accepted the Mercoa ToS,
        all representatives have been added, and all required fields have been filled out.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.initiate_kyb(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/request-kyb", method="POST", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_token(
        self,
        entity_id: EntityId,
        *,
        expires_in: typing.Optional[str] = OMIT,
        invoice: typing.Optional[TokenGenerationInvoiceOptions] = OMIT,
        pages: typing.Optional[TokenGenerationPagesOptions] = OMIT,
        style: typing.Optional[TokenGenerationStyleOptions] = OMIT,
        vendors: typing.Optional[TokenGenerationVendorOptions] = OMIT,
        entity: typing.Optional[TokenGenerationEntityOptions] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Generate a JWT token for an entity with the given options. This token can be used to authenticate the entity in the Mercoa API and iFrame.

        <Warning>We recommend using [this endpoint](/api-reference/entity/user/get-token). This will enable features such as approvals and comments.</Warning>

        Parameters
        ----------
        entity_id : EntityId

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 1h.

        invoice : typing.Optional[TokenGenerationInvoiceOptions]

        pages : typing.Optional[TokenGenerationPagesOptions]

        style : typing.Optional[TokenGenerationStyleOptions]

        vendors : typing.Optional[TokenGenerationVendorOptions]

        entity : typing.Optional[TokenGenerationEntityOptions]

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.get_token(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            expires_in="1h",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/token",
            method="POST",
            json={
                "expiresIn": expires_in,
                "invoice": invoice,
                "pages": pages,
                "style": style,
                "vendors": vendors,
                "entity": entity,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def plaid_link_token(
        self,
        entity_id: EntityId,
        *,
        payment_method_id: typing.Optional[PaymentMethodId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Get a Plaid link token for an entity. This token can be used to add or update a bank account to the entity using Plaid Link.

        Parameters
        ----------
        entity_id : EntityId

        payment_method_id : typing.Optional[PaymentMethodId]
            ID of Bank Account to update

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.plaid_link_token(
            entity_id="string",
            payment_method_id="string",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/plaidLinkToken",
            method="GET",
            params={"paymentMethodId": payment_method_id},
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get_onboarding_link(
        self,
        entity_id: EntityId,
        *,
        type: EntityOnboardingLinkType,
        expires_in: typing.Optional[str] = None,
        connected_entity_id: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Generate an onboarding link for the entity.

        Parameters
        ----------
        entity_id : EntityId

        type : EntityOnboardingLinkType
            The type of onboarding link to generate. If not provided, the default is payee. The onboarding options are determined by your organization's onboarding configuration.

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 24h.

        connected_entity_id : typing.Optional[EntityId]
            The ID of the entity to connect to. If onboarding a payee, this should be the payor entity ID. If onboarding a payor, this should be the payee entity ID. If no connected entity ID is provided, the onboarding link will be for a standalone entity.

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.get_onboarding_link(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            type="PAYOR",
            expires_in="1h",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/onboarding",
            method="GET",
            params={"type": type, "expiresIn": expires_in, "connectedEntityId": connected_entity_id},
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def send_onboarding_link(
        self,
        entity_id: EntityId,
        *,
        type: EntityOnboardingLinkType,
        expires_in: typing.Optional[str] = None,
        connected_entity_id: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        Send an email with a onboarding link to the entity. The email will be sent to the email address associated with the entity.

        Parameters
        ----------
        entity_id : EntityId

        type : EntityOnboardingLinkType
            The type of onboarding link to generate. If not provided, the default is payee. The onboarding options are determined by your organization's onboarding configuration.

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 7 days.

        connected_entity_id : typing.Optional[EntityId]
            The ID of the entity to connect to. If onboarding a payee, this should be the payor entity ID. If onboarding a payor, this should be the payee entity ID. If no connected entity ID is provided, the onboarding link will be for a standalone entity.

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import Mercoa

        client = Mercoa(
            token="YOUR_TOKEN",
        )
        client.entity.send_onboarding_link(
            entity_id="string",
            type="PAYEE",
            expires_in="string",
            connected_entity_id="string",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/onboarding",
            method="POST",
            params={"type": type, "expiresIn": expires_in, "connectedEntityId": connected_entity_id},
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)


class AsyncEntityClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper
        self.email_log = AsyncEmailLogClient(client_wrapper=self._client_wrapper)
        self.user = AsyncUserClient(client_wrapper=self._client_wrapper)
        self.approval_policy = AsyncApprovalPolicyClient(client_wrapper=self._client_wrapper)
        self.counterparty = AsyncCounterpartyClient(client_wrapper=self._client_wrapper)
        self.customization = AsyncCustomizationClient(client_wrapper=self._client_wrapper)
        self.external_accounting_system = AsyncExternalAccountingSystemClient(client_wrapper=self._client_wrapper)
        self.invoice = AsyncInvoiceClient(client_wrapper=self._client_wrapper)
        self.metadata = AsyncMetadataClient(client_wrapper=self._client_wrapper)
        self.notification_policy = AsyncNotificationPolicyClient(client_wrapper=self._client_wrapper)
        self.payment_method = AsyncPaymentMethodClient(client_wrapper=self._client_wrapper)
        self.representative = AsyncRepresentativeClient(client_wrapper=self._client_wrapper)

    async def find(
        self,
        *,
        payment_methods: typing.Optional[bool] = None,
        is_customer: typing.Optional[bool] = None,
        foreign_id: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
        status: typing.Optional[typing.Union[EntityStatus, typing.Sequence[EntityStatus]]] = None,
        is_payee: typing.Optional[bool] = None,
        is_payor: typing.Optional[bool] = None,
        name: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        starting_after: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> FindEntityResponse:
        """
        Search all entities with the given filters. If no filters are provided, all entities will be returned.

        Parameters
        ----------
        payment_methods : typing.Optional[bool]
            If true, will include entity payment methods as part of the response

        is_customer : typing.Optional[bool]
            If true, only entities with a direct relationship to the requesting organization will be returned. If false or not provided, all entities will be returned.

        foreign_id : typing.Optional[typing.Union[str, typing.Sequence[str]]]
            ID used to identify this entity in your system

        status : typing.Optional[typing.Union[EntityStatus, typing.Sequence[EntityStatus]]]

        is_payee : typing.Optional[bool]
            If true, entities that are marked as payees will be returned.
            If false or not provided, entities that are marked as payees will not be returned.

        is_payor : typing.Optional[bool]
            If true or not provided, entities that are marked as payors will be returned.
            If false, entities that are marked as payors will not be returned.

        name : typing.Optional[str]
            Filter entities by name. Partial matches are supported.

        limit : typing.Optional[int]
            Number of entities to return. Limit can range between 1 and 100, and the default is 10.

        starting_after : typing.Optional[EntityId]
            The ID of the entity to start after. If not provided, the first page of entities will be returned.

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

        Returns
        -------
        FindEntityResponse

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.find(
            is_customer=True,
            foreign_id="MY-DB-ID-12345",
            payment_methods=True,
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            "entity",
            method="GET",
            params={
                "paymentMethods": payment_methods,
                "isCustomer": is_customer,
                "foreignId": foreign_id,
                "status": status,
                "isPayee": is_payee,
                "isPayor": is_payor,
                "name": name,
                "limit": limit,
                "startingAfter": starting_after,
            },
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(FindEntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def create(
        self,
        *,
        is_customer: bool,
        account_type: AccountType,
        profile: ProfileRequest,
        is_payor: bool,
        is_payee: bool,
        foreign_id: typing.Optional[str] = OMIT,
        email_to: typing.Optional[str] = OMIT,
        email_to_alias: typing.Optional[typing.Sequence[str]] = OMIT,
        is_network_payor: typing.Optional[bool] = OMIT,
        is_network_payee: typing.Optional[bool] = OMIT,
        logo: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> EntityResponse:
        """
        Parameters
        ----------
        is_customer : bool
            If this entity has a direct relationship with your organization (e.g your direct customer or client), set this to true. Otherwise, set to false (e.g your customer's vendors).

        account_type : AccountType

        profile : ProfileRequest

        is_payor : bool
            If this entity will be paying invoices, set this to true.

        is_payee : bool
            If this entity will be receiving payments, set this to true.

        foreign_id : typing.Optional[str]
            The ID used to identify this entity in your system. This ID must be unique across all entities in your system.

        email_to : typing.Optional[str]
            Sets the email address to which to send invoices to be added to the Invoice Inbox. Only provide the local-part/username of the email address, do not include the @domain.com

        email_to_alias : typing.Optional[typing.Sequence[str]]
            Email inbox alias addresses. Used when forwarding emails to the emailTo address from an alias. Include the full email address.

        is_network_payor : typing.Optional[bool]
            Control if this entity should be available as a payor to any entity on your platform. If set to false, this entity will only be available as a payor to entities that have a direct relationship with this entity. Defaults to false.

        is_network_payee : typing.Optional[bool]
            Control if this entity should be available as a payee to any entity on your platform. If set to false, this entity will only be available as a payee to entities that have a direct relationship with this entity. Defaults to false.

        logo : typing.Optional[str]
            Base64 encoded PNG image data for the entity logo.

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa import (
            Address,
            BusinessProfileRequest,
            Ein,
            PhoneNumber,
            ProfileRequest,
            TaxId,
        )
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.create(
            is_customer=True,
            is_payor=True,
            is_payee=False,
            account_type="business",
            foreign_id="MY-DB-ID-12345",
            profile=ProfileRequest(
                business=BusinessProfileRequest(
                    email="customer@acme.com",
                    legal_business_name="Acme Inc.",
                    website="http://www.acme.com",
                    business_type="llc",
                    phone=PhoneNumber(
                        country_code="1",
                        number="4155551234",
                    ),
                    address=Address(
                        address_line_1="123 Main St",
                        address_line_2="Unit 1",
                        city="San Francisco",
                        state_or_province="CA",
                        postal_code="94105",
                        country="US",
                    ),
                    tax_id=TaxId(
                        ein=Ein(
                            number="12-3456789",
                        ),
                    ),
                ),
            ),
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            "entity",
            method="POST",
            json={
                "foreignId": foreign_id,
                "emailTo": email_to,
                "emailToAlias": email_to_alias,
                "isCustomer": is_customer,
                "accountType": account_type,
                "profile": profile,
                "isPayor": is_payor,
                "isPayee": is_payee,
                "isNetworkPayor": is_network_payor,
                "isNetworkPayee": is_network_payee,
                "logo": logo,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get(
        self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> EntityResponse:
        """
        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.get(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}", method="GET", request_options=request_options
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update(
        self,
        entity_id: EntityId,
        *,
        foreign_id: typing.Optional[str] = OMIT,
        email_to: typing.Optional[str] = OMIT,
        email_to_alias: typing.Optional[typing.Sequence[str]] = OMIT,
        is_customer: typing.Optional[bool] = OMIT,
        account_type: typing.Optional[AccountType] = OMIT,
        profile: typing.Optional[ProfileRequest] = OMIT,
        is_payor: typing.Optional[bool] = OMIT,
        is_payee: typing.Optional[bool] = OMIT,
        is_network_payor: typing.Optional[bool] = OMIT,
        is_network_payee: typing.Optional[bool] = OMIT,
        logo: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> EntityResponse:
        """
        Parameters
        ----------
        entity_id : EntityId

        foreign_id : typing.Optional[str]
            The ID used to identify this entity in your system. This ID must be unique across all entities in your system.

        email_to : typing.Optional[str]
            Sets the email address to which to send invoices to be added to the Invoice Inbox. Only provide the local-part/username of the email address, do not include the @domain.com

        email_to_alias : typing.Optional[typing.Sequence[str]]
            Email inbox alias addresses. Used when forwarding emails to the emailTo address from an alias. Include the full email address.

        is_customer : typing.Optional[bool]
            If this entity has a direct relationship with your organization (e.g your direct customer or client), set this to true. Otherwise, set to false (e.g your customer's vendors).

        account_type : typing.Optional[AccountType]

        profile : typing.Optional[ProfileRequest]

        is_payor : typing.Optional[bool]
            If this entity will be paying invoices, set this to true.

        is_payee : typing.Optional[bool]
            If this entity will be receiving payments, set this to true.

        is_network_payor : typing.Optional[bool]
            Control if this entity should be available as a payor to any entity on your platform. If set to false, this entity will only be available as a payor to entities that have a direct relationship with this entity. Defaults to false.

        is_network_payee : typing.Optional[bool]
            Control if this entity should be available as a payee to any entity on your platform. If set to false, this entity will only be available as a payee to entities that have a direct relationship with this entity. Defaults to false.

        logo : typing.Optional[str]
            Base64 encoded PNG image data for the entity logo.

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

        Returns
        -------
        EntityResponse

        Examples
        --------
        from mercoa import (
            Address,
            BusinessProfileRequest,
            Ein,
            PhoneNumber,
            ProfileRequest,
            TaxId,
        )
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.update(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            is_customer=True,
            is_payor=True,
            is_payee=False,
            account_type="business",
            foreign_id="MY-DB-ID-12345",
            profile=ProfileRequest(
                business=BusinessProfileRequest(
                    email="customer@acme.com",
                    legal_business_name="Acme Inc.",
                    website="http://www.acme.com",
                    business_type="llc",
                    phone=PhoneNumber(
                        country_code="1",
                        number="4155551234",
                    ),
                    address=Address(
                        address_line_1="123 Main St",
                        address_line_2="Unit 1",
                        city="San Francisco",
                        state_or_province="CA",
                        postal_code="94105",
                        country="US",
                    ),
                    tax_id=TaxId(
                        ein=Ein(
                            number="12-3456789",
                        ),
                    ),
                ),
            ),
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}",
            method="POST",
            json={
                "foreignId": foreign_id,
                "emailTo": email_to,
                "emailToAlias": email_to_alias,
                "isCustomer": is_customer,
                "accountType": account_type,
                "profile": profile,
                "isPayor": is_payor,
                "isPayee": is_payee,
                "isNetworkPayor": is_network_payor,
                "isNetworkPayee": is_network_payee,
                "logo": logo,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(EntityResponse, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete(self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None) -> None:
        """
        Will archive the entity. This action cannot be undone, and the entity will no longer be available for use. The foreignId on the entity will be cleared as well.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.delete(
            entity_id="string",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}", method="DELETE", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def accept_terms_of_service(
        self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        This endpoint is used to indicate acceptance of Mercoa's terms of service for an entity. Send a request to this endpoint only after the entity has accepted the Mercoa ToS. Entities must accept Mercoa ToS before they can be send or pay invoices using Mercoa's payment rails.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.accept_terms_of_service(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/accept-tos", method="POST", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def initiate_kyb(
        self, entity_id: EntityId, *, request_options: typing.Optional[RequestOptions] = None
    ) -> None:
        """
        This endpoint is used to initiate KYB for an entity.
        Send a request to this endpoint only after the entity has accepted the Mercoa ToS,
        all representatives have been added, and all required fields have been filled out.

        Parameters
        ----------
        entity_id : EntityId

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.initiate_kyb(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/request-kyb", method="POST", request_options=request_options
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_token(
        self,
        entity_id: EntityId,
        *,
        expires_in: typing.Optional[str] = OMIT,
        invoice: typing.Optional[TokenGenerationInvoiceOptions] = OMIT,
        pages: typing.Optional[TokenGenerationPagesOptions] = OMIT,
        style: typing.Optional[TokenGenerationStyleOptions] = OMIT,
        vendors: typing.Optional[TokenGenerationVendorOptions] = OMIT,
        entity: typing.Optional[TokenGenerationEntityOptions] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Generate a JWT token for an entity with the given options. This token can be used to authenticate the entity in the Mercoa API and iFrame.

        <Warning>We recommend using [this endpoint](/api-reference/entity/user/get-token). This will enable features such as approvals and comments.</Warning>

        Parameters
        ----------
        entity_id : EntityId

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 1h.

        invoice : typing.Optional[TokenGenerationInvoiceOptions]

        pages : typing.Optional[TokenGenerationPagesOptions]

        style : typing.Optional[TokenGenerationStyleOptions]

        vendors : typing.Optional[TokenGenerationVendorOptions]

        entity : typing.Optional[TokenGenerationEntityOptions]

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.get_token(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            expires_in="1h",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/token",
            method="POST",
            json={
                "expiresIn": expires_in,
                "invoice": invoice,
                "pages": pages,
                "style": style,
                "vendors": vendors,
                "entity": entity,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def plaid_link_token(
        self,
        entity_id: EntityId,
        *,
        payment_method_id: typing.Optional[PaymentMethodId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Get a Plaid link token for an entity. This token can be used to add or update a bank account to the entity using Plaid Link.

        Parameters
        ----------
        entity_id : EntityId

        payment_method_id : typing.Optional[PaymentMethodId]
            ID of Bank Account to update

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.plaid_link_token(
            entity_id="string",
            payment_method_id="string",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/plaidLinkToken",
            method="GET",
            params={"paymentMethodId": payment_method_id},
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get_onboarding_link(
        self,
        entity_id: EntityId,
        *,
        type: EntityOnboardingLinkType,
        expires_in: typing.Optional[str] = None,
        connected_entity_id: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> str:
        """
        Generate an onboarding link for the entity.

        Parameters
        ----------
        entity_id : EntityId

        type : EntityOnboardingLinkType
            The type of onboarding link to generate. If not provided, the default is payee. The onboarding options are determined by your organization's onboarding configuration.

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 24h.

        connected_entity_id : typing.Optional[EntityId]
            The ID of the entity to connect to. If onboarding a payee, this should be the payor entity ID. If onboarding a payor, this should be the payee entity ID. If no connected entity ID is provided, the onboarding link will be for a standalone entity.

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

        Returns
        -------
        str

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.get_onboarding_link(
            entity_id="ent_a0f6ea94-0761-4a5e-a416-3c453cb7eced",
            type="PAYOR",
            expires_in="1h",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/onboarding",
            method="GET",
            params={"type": type, "expiresIn": expires_in, "connectedEntityId": connected_entity_id},
            request_options=request_options,
        )
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(str, _response_json)  # type: ignore
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def send_onboarding_link(
        self,
        entity_id: EntityId,
        *,
        type: EntityOnboardingLinkType,
        expires_in: typing.Optional[str] = None,
        connected_entity_id: typing.Optional[EntityId] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        Send an email with a onboarding link to the entity. The email will be sent to the email address associated with the entity.

        Parameters
        ----------
        entity_id : EntityId

        type : EntityOnboardingLinkType
            The type of onboarding link to generate. If not provided, the default is payee. The onboarding options are determined by your organization's onboarding configuration.

        expires_in : typing.Optional[str]
            Expressed in seconds or a string describing a time span. The default is 7 days.

        connected_entity_id : typing.Optional[EntityId]
            The ID of the entity to connect to. If onboarding a payee, this should be the payor entity ID. If onboarding a payor, this should be the payee entity ID. If no connected entity ID is provided, the onboarding link will be for a standalone entity.

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

        Returns
        -------
        None

        Examples
        --------
        from mercoa.client import AsyncMercoa

        client = AsyncMercoa(
            token="YOUR_TOKEN",
        )
        await client.entity.send_onboarding_link(
            entity_id="string",
            type="PAYEE",
            expires_in="string",
            connected_entity_id="string",
        )
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"entity/{jsonable_encoder(entity_id)}/onboarding",
            method="POST",
            params={"type": type, "expiresIn": expires_in, "connectedEntityId": connected_entity_id},
            request_options=request_options,
        )
        if 200 <= _response.status_code < 300:
            return
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        if "errorName" in _response_json:
            if _response_json["errorName"] == "BadRequest":
                raise BadRequest(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unauthorized":
                raise Unauthorized(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Forbidden":
                raise Forbidden(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "NotFound":
                raise NotFound(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Conflict":
                raise Conflict(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "InternalServerError":
                raise InternalServerError(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
            if _response_json["errorName"] == "Unimplemented":
                raise Unimplemented(pydantic_v1.parse_obj_as(str, _response_json["content"]))  # type: ignore
        raise ApiError(status_code=_response.status_code, body=_response_json)
