"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from __future__ import annotations
from dub.models.components import linktagschemaoutput as components_linktagschemaoutput
from dub.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
from dub.utils import FieldMetadata, QueryParamMetadata, get_discriminator
from enum import Enum
import pydantic
from pydantic import Discriminator, Tag, model_serializer
from typing import Any, Dict, List, Optional, Union
from typing_extensions import (
    Annotated,
    NotRequired,
    TypeAliasType,
    TypedDict,
    deprecated,
)


class QueryParamEvent(str, Enum):
    r"""The type of event to retrieve analytics for. Defaults to 'clicks'."""

    CLICKS = "clicks"
    LEADS = "leads"
    SALES = "sales"


class QueryParamInterval(str, Enum):
    r"""The interval to retrieve analytics for. If undefined, defaults to 24h."""

    TWENTY_FOURH = "24h"
    SEVEND = "7d"
    THIRTYD = "30d"
    NINETYD = "90d"
    ONEY = "1y"
    MTD = "mtd"
    QTD = "qtd"
    YTD = "ytd"
    ALL = "all"


class QueryParamContinent(str, Enum):
    r"""The continent to retrieve analytics for."""

    AF = "AF"
    AN = "AN"
    AS = "AS"
    EU = "EU"
    NA = "NA"
    OC = "OC"
    SA = "SA"


class QueryParamTrigger(str, Enum):
    r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""

    QR = "qr"
    LINK = "link"
    PAGEVIEW = "pageview"
    DEEPLINK = "deeplink"


ListEventsQueryParamTagIdsTypedDict = TypeAliasType(
    "ListEventsQueryParamTagIdsTypedDict", Union[str, List[str]]
)
r"""The tag IDs to retrieve analytics for."""


ListEventsQueryParamTagIds = TypeAliasType(
    "ListEventsQueryParamTagIds", Union[str, List[str]]
)
r"""The tag IDs to retrieve analytics for."""


class QueryParamSaleType(str, Enum):
    r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""

    NEW = "new"
    RECURRING = "recurring"


class QueryParamSortOrder(str, Enum):
    r"""The sort order. The default is `desc`."""

    ASC = "asc"
    DESC = "desc"


class QueryParamSortBy(str, Enum):
    r"""The field to sort the events by. The default is `timestamp`."""

    TIMESTAMP = "timestamp"


@deprecated(
    "warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
)
class Order(str, Enum):
    r"""DEPRECATED. Use `sortOrder` instead."""

    ASC = "asc"
    DESC = "desc"


class ListEventsRequestTypedDict(TypedDict):
    event: NotRequired[QueryParamEvent]
    r"""The type of event to retrieve analytics for. Defaults to 'clicks'."""
    domain: NotRequired[str]
    r"""The domain to filter analytics for."""
    key: NotRequired[str]
    r"""The slug of the short link to retrieve analytics for. Must be used along with the corresponding `domain` of the short link to fetch analytics for a specific short link."""
    link_id: NotRequired[str]
    r"""The unique ID of the short link on Dub to retrieve analytics for."""
    external_id: NotRequired[str]
    r"""The ID of the link in the your database. Must be prefixed with 'ext_' when passed as a query parameter."""
    tenant_id: NotRequired[str]
    r"""The ID of the tenant that created the link inside your system."""
    program_id: NotRequired[str]
    r"""The ID of the program to retrieve analytics for."""
    partner_id: NotRequired[str]
    r"""The ID of the partner to retrieve analytics for."""
    customer_id: NotRequired[str]
    r"""The ID of the customer to retrieve analytics for."""
    interval: NotRequired[QueryParamInterval]
    r"""The interval to retrieve analytics for. If undefined, defaults to 24h."""
    start: NotRequired[str]
    r"""The start date and time when to retrieve analytics from. If set, takes precedence over `interval`."""
    end: NotRequired[str]
    r"""The end date and time when to retrieve analytics from. If not provided, defaults to the current date. If set along with `start`, takes precedence over `interval`."""
    timezone: NotRequired[str]
    r"""The IANA time zone code for aligning timeseries granularity (e.g. America/New_York). Defaults to UTC."""
    country: NotRequired[str]
    r"""The country to retrieve analytics for. Must be passed as a 2-letter ISO 3166-1 country code. See https://d.to/geo for more information."""
    city: NotRequired[str]
    r"""The city to retrieve analytics for."""
    region: NotRequired[str]
    r"""The ISO 3166-2 region code to retrieve analytics for."""
    continent: NotRequired[QueryParamContinent]
    r"""The continent to retrieve analytics for."""
    device: NotRequired[str]
    r"""The device to retrieve analytics for."""
    browser: NotRequired[str]
    r"""The browser to retrieve analytics for."""
    os: NotRequired[str]
    r"""The OS to retrieve analytics for."""
    trigger: NotRequired[QueryParamTrigger]
    r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""
    referer: NotRequired[str]
    r"""The referer hostname to retrieve analytics for."""
    referer_url: NotRequired[str]
    r"""The full referer URL to retrieve analytics for."""
    url: NotRequired[str]
    r"""The URL to retrieve analytics for."""
    tag_ids: NotRequired[ListEventsQueryParamTagIdsTypedDict]
    r"""The tag IDs to retrieve analytics for."""
    folder_id: NotRequired[str]
    r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""
    group_id: NotRequired[str]
    r"""The group ID to retrieve analytics for."""
    root: NotRequired[bool]
    r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""
    sale_type: NotRequired[QueryParamSaleType]
    r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""
    query: NotRequired[str]
    r"""Search the events by a custom metadata value. Only available for lead and sale events."""
    tag_id: NotRequired[str]
    r"""Deprecated: Use `tagIds` instead. The tag ID to retrieve analytics for."""
    qr: NotRequired[bool]
    r"""Deprecated: Use the `trigger` field instead. Filter for QR code scans. If true, filter for QR codes only. If false, filter for links only. If undefined, return both."""
    utm_source: NotRequired[Nullable[str]]
    r"""The UTM source of the short link."""
    utm_medium: NotRequired[Nullable[str]]
    r"""The UTM medium of the short link."""
    utm_campaign: NotRequired[Nullable[str]]
    r"""The UTM campaign of the short link."""
    utm_term: NotRequired[Nullable[str]]
    r"""The UTM term of the short link."""
    utm_content: NotRequired[Nullable[str]]
    r"""The UTM content of the short link."""
    ref: NotRequired[Nullable[str]]
    r"""The ref of the short link."""
    page: NotRequired[float]
    limit: NotRequired[float]
    sort_order: NotRequired[QueryParamSortOrder]
    r"""The sort order. The default is `desc`."""
    sort_by: NotRequired[QueryParamSortBy]
    r"""The field to sort the events by. The default is `timestamp`."""
    order: NotRequired[Order]
    r"""DEPRECATED. Use `sortOrder` instead."""


class ListEventsRequest(BaseModel):
    event: Annotated[
        Optional[QueryParamEvent],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = QueryParamEvent.CLICKS
    r"""The type of event to retrieve analytics for. Defaults to 'clicks'."""

    domain: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The domain to filter analytics for."""

    key: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The slug of the short link to retrieve analytics for. Must be used along with the corresponding `domain` of the short link to fetch analytics for a specific short link."""

    link_id: Annotated[
        Optional[str],
        pydantic.Field(alias="linkId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The unique ID of the short link on Dub to retrieve analytics for."""

    external_id: Annotated[
        Optional[str],
        pydantic.Field(alias="externalId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ID of the link in the your database. Must be prefixed with 'ext_' when passed as a query parameter."""

    tenant_id: Annotated[
        Optional[str],
        pydantic.Field(alias="tenantId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ID of the tenant that created the link inside your system."""

    program_id: Annotated[
        Optional[str],
        pydantic.Field(alias="programId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ID of the program to retrieve analytics for."""

    partner_id: Annotated[
        Optional[str],
        pydantic.Field(alias="partnerId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ID of the partner to retrieve analytics for."""

    customer_id: Annotated[
        Optional[str],
        pydantic.Field(alias="customerId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ID of the customer to retrieve analytics for."""

    interval: Annotated[
        Optional[QueryParamInterval],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The interval to retrieve analytics for. If undefined, defaults to 24h."""

    start: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The start date and time when to retrieve analytics from. If set, takes precedence over `interval`."""

    end: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The end date and time when to retrieve analytics from. If not provided, defaults to the current date. If set along with `start`, takes precedence over `interval`."""

    timezone: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = "UTC"
    r"""The IANA time zone code for aligning timeseries granularity (e.g. America/New_York). Defaults to UTC."""

    country: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The country to retrieve analytics for. Must be passed as a 2-letter ISO 3166-1 country code. See https://d.to/geo for more information."""

    city: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The city to retrieve analytics for."""

    region: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The ISO 3166-2 region code to retrieve analytics for."""

    continent: Annotated[
        Optional[QueryParamContinent],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The continent to retrieve analytics for."""

    device: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The device to retrieve analytics for."""

    browser: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The browser to retrieve analytics for."""

    os: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The OS to retrieve analytics for."""

    trigger: Annotated[
        Optional[QueryParamTrigger],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The trigger to retrieve analytics for. If undefined, returns all trigger types."""

    referer: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The referer hostname to retrieve analytics for."""

    referer_url: Annotated[
        Optional[str],
        pydantic.Field(alias="refererUrl"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The full referer URL to retrieve analytics for."""

    url: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The URL to retrieve analytics for."""

    tag_ids: Annotated[
        Optional[ListEventsQueryParamTagIds],
        pydantic.Field(alias="tagIds"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The tag IDs to retrieve analytics for."""

    folder_id: Annotated[
        Optional[str],
        pydantic.Field(alias="folderId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The folder ID to retrieve analytics for. If not provided, return analytics for unsorted links."""

    group_id: Annotated[
        Optional[str],
        pydantic.Field(alias="groupId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""The group ID to retrieve analytics for."""

    root: Annotated[
        Optional[bool],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""Filter for root domains. If true, filter for domains only. If false, filter for links only. If undefined, return both."""

    sale_type: Annotated[
        Optional[QueryParamSaleType],
        pydantic.Field(alias="saleType"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""Filter sales by type: 'new' for first-time purchases, 'recurring' for repeat purchases. If undefined, returns both."""

    query: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""Search the events by a custom metadata value. Only available for lead and sale events."""

    tag_id: Annotated[
        Optional[str],
        pydantic.Field(alias="tagId"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""Deprecated: Use `tagIds` instead. The tag ID to retrieve analytics for."""

    qr: Annotated[
        Optional[bool],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None
    r"""Deprecated: Use the `trigger` field instead. Filter for QR code scans. If true, filter for QR codes only. If false, filter for links only. If undefined, return both."""

    utm_source: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The UTM source of the short link."""

    utm_medium: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The UTM medium of the short link."""

    utm_campaign: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The UTM campaign of the short link."""

    utm_term: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The UTM term of the short link."""

    utm_content: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The UTM content of the short link."""

    ref: Annotated[
        OptionalNullable[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = UNSET
    r"""The ref of the short link."""

    page: Annotated[
        Optional[float],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = 1

    limit: Annotated[
        Optional[float],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = 100

    sort_order: Annotated[
        Optional[QueryParamSortOrder],
        pydantic.Field(alias="sortOrder"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = QueryParamSortOrder.DESC
    r"""The sort order. The default is `desc`."""

    sort_by: Annotated[
        Optional[QueryParamSortBy],
        pydantic.Field(alias="sortBy"),
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = QueryParamSortBy.TIMESTAMP
    r"""The field to sort the events by. The default is `timestamp`."""

    order: Annotated[
        Optional[Order],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = Order.DESC
    r"""DEPRECATED. Use `sortOrder` instead."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "event",
                "domain",
                "key",
                "linkId",
                "externalId",
                "tenantId",
                "programId",
                "partnerId",
                "customerId",
                "interval",
                "start",
                "end",
                "timezone",
                "country",
                "city",
                "region",
                "continent",
                "device",
                "browser",
                "os",
                "trigger",
                "referer",
                "refererUrl",
                "url",
                "tagIds",
                "folderId",
                "groupId",
                "root",
                "saleType",
                "query",
                "tagId",
                "qr",
                "utm_source",
                "utm_medium",
                "utm_campaign",
                "utm_term",
                "utm_content",
                "ref",
                "page",
                "limit",
                "sortOrder",
                "sortBy",
                "order",
            ]
        )
        nullable_fields = set(
            [
                "utm_source",
                "utm_medium",
                "utm_campaign",
                "utm_term",
                "utm_content",
                "ref",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyEventsEvent(str, Enum):
    SALE = "sale"


class ResponseBodyPaymentProcessor(str, Enum):
    r"""The payment processor via which the sale was made."""

    STRIPE = "stripe"
    SHOPIFY = "shopify"
    POLAR = "polar"
    PADDLE = "paddle"
    REVENUECAT = "revenuecat"
    CUSTOM = "custom"


class ResponseBodySaleTypedDict(TypedDict):
    amount: int
    r"""The amount of the sale in cents (for all two-decimal currencies). If the sale is in a zero-decimal currency, pass the full integer value (e.g. `1437` JPY). Learn more: https://d.to/currency"""
    invoice_id: NotRequired[Nullable[str]]
    r"""The invoice ID of the sale. Can be used as a idempotency key – only one sale event can be recorded for a given invoice ID."""
    payment_processor: NotRequired[ResponseBodyPaymentProcessor]
    r"""The payment processor via which the sale was made."""


class ResponseBodySale(BaseModel):
    amount: int
    r"""The amount of the sale in cents (for all two-decimal currencies). If the sale is in a zero-decimal currency, pass the full integer value (e.g. `1437` JPY). Learn more: https://d.to/currency"""

    invoice_id: Annotated[OptionalNullable[str], pydantic.Field(alias="invoiceId")] = (
        None
    )
    r"""The invoice ID of the sale. Can be used as a idempotency key – only one sale event can be recorded for a given invoice ID."""

    payment_processor: Annotated[
        Optional[ResponseBodyPaymentProcessor], pydantic.Field(alias="paymentProcessor")
    ] = ResponseBodyPaymentProcessor.CUSTOM
    r"""The payment processor via which the sale was made."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["invoiceId", "paymentProcessor"])
        nullable_fields = set(["invoiceId"])
        null_default_fields = set(["invoiceId"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (
                    self.__pydantic_fields_set__.intersection({n})
                    or k in null_default_fields
                )  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyEventsTestVariantsTypedDict(TypedDict):
    url: str
    percentage: float


class ListEventsResponseBodyEventsTestVariants(BaseModel):
    url: str

    percentage: float


class ListEventsResponseBodyLinkTypedDict(TypedDict):
    id: str
    r"""The unique ID of the short link."""
    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""
    url: str
    track_conversion: bool
    external_id: Nullable[str]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""
    tenant_id: Nullable[str]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""
    program_id: Nullable[str]
    r"""The ID of the program the short link is associated with."""
    partner_id: Nullable[str]
    r"""The ID of the partner the short link is associated with."""
    archived: bool
    expires_at: str
    expired_url: Nullable[str]
    disabled_at: str
    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""
    proxy: bool
    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""
    rewrite: bool
    do_index: bool
    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""
    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""
    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""
    public_stats: bool
    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutputTypedDict]]
    r"""The tags assigned to the short link."""
    folder_id: Nullable[str]
    r"""The unique ID of the folder assigned to the short link."""
    webhook_ids: List[str]
    r"""The IDs of the webhooks that the short link is associated with."""
    comments: Nullable[str]
    r"""The comments for the short link."""
    short_link: str
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""
    qr_code: str
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""
    utm_source: Nullable[str]
    r"""The UTM source of the short link."""
    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""
    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""
    utm_term: Nullable[str]
    r"""The UTM term of the short link."""
    utm_content: Nullable[str]
    r"""The UTM content of the short link."""
    test_started_at: str
    test_completed_at: str
    user_id: Nullable[str]
    workspace_id: str
    r"""The workspace ID of the short link."""
    last_clicked: str
    created_at: str
    updated_at: str
    tag_id: Nullable[str]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""
    project_id: str
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""
    test_variants: NotRequired[
        Nullable[List[ListEventsResponseBodyEventsTestVariantsTypedDict]]
    ]
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""
    clicks: NotRequired[float]
    r"""The number of clicks on the short link."""
    leads: NotRequired[float]
    r"""The number of leads the short link has generated."""
    conversions: NotRequired[float]
    r"""The number of leads that converted to paying customers."""
    sales: NotRequired[float]
    r"""The total number of sales (includes recurring sales) generated by the short link."""
    sale_amount: NotRequired[float]
    r"""The total dollar value of sales (in cents) generated by the short link."""


class ListEventsResponseBodyLink(BaseModel):
    id: str
    r"""The unique ID of the short link."""

    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""

    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""

    url: str

    track_conversion: Annotated[bool, pydantic.Field(alias="trackConversion")]

    external_id: Annotated[Nullable[str], pydantic.Field(alias="externalId")]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""

    tenant_id: Annotated[Nullable[str], pydantic.Field(alias="tenantId")]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""

    program_id: Annotated[Nullable[str], pydantic.Field(alias="programId")]
    r"""The ID of the program the short link is associated with."""

    partner_id: Annotated[Nullable[str], pydantic.Field(alias="partnerId")]
    r"""The ID of the partner the short link is associated with."""

    archived: bool

    expires_at: Annotated[str, pydantic.Field(alias="expiresAt")]

    expired_url: Annotated[Nullable[str], pydantic.Field(alias="expiredUrl")]

    disabled_at: Annotated[str, pydantic.Field(alias="disabledAt")]

    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""

    proxy: bool

    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""

    rewrite: bool

    do_index: Annotated[bool, pydantic.Field(alias="doIndex")]

    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""

    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""

    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""

    public_stats: Annotated[bool, pydantic.Field(alias="publicStats")]

    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutput]]
    r"""The tags assigned to the short link."""

    folder_id: Annotated[Nullable[str], pydantic.Field(alias="folderId")]
    r"""The unique ID of the folder assigned to the short link."""

    webhook_ids: Annotated[List[str], pydantic.Field(alias="webhookIds")]
    r"""The IDs of the webhooks that the short link is associated with."""

    comments: Nullable[str]
    r"""The comments for the short link."""

    short_link: Annotated[str, pydantic.Field(alias="shortLink")]
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""

    qr_code: Annotated[str, pydantic.Field(alias="qrCode")]
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""

    utm_source: Nullable[str]
    r"""The UTM source of the short link."""

    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""

    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""

    utm_term: Nullable[str]
    r"""The UTM term of the short link."""

    utm_content: Nullable[str]
    r"""The UTM content of the short link."""

    test_started_at: Annotated[str, pydantic.Field(alias="testStartedAt")]

    test_completed_at: Annotated[str, pydantic.Field(alias="testCompletedAt")]

    user_id: Annotated[Nullable[str], pydantic.Field(alias="userId")]

    workspace_id: Annotated[str, pydantic.Field(alias="workspaceId")]
    r"""The workspace ID of the short link."""

    last_clicked: Annotated[str, pydantic.Field(alias="lastClicked")]

    created_at: Annotated[str, pydantic.Field(alias="createdAt")]

    updated_at: Annotated[str, pydantic.Field(alias="updatedAt")]

    tag_id: Annotated[
        Nullable[str],
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="tagId",
        ),
    ]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""

    project_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="projectId",
        ),
    ]
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""

    test_variants: Annotated[
        OptionalNullable[List[ListEventsResponseBodyEventsTestVariants]],
        pydantic.Field(alias="testVariants"),
    ] = UNSET
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""

    clicks: Optional[float] = 0
    r"""The number of clicks on the short link."""

    leads: Optional[float] = 0
    r"""The number of leads the short link has generated."""

    conversions: Optional[float] = 0
    r"""The number of leads that converted to paying customers."""

    sales: Optional[float] = 0
    r"""The total number of sales (includes recurring sales) generated by the short link."""

    sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
    r"""The total dollar value of sales (in cents) generated by the short link."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            ["testVariants", "clicks", "leads", "conversions", "sales", "saleAmount"]
        )
        nullable_fields = set(
            [
                "externalId",
                "tenantId",
                "programId",
                "partnerId",
                "expiredUrl",
                "password",
                "title",
                "description",
                "image",
                "video",
                "ios",
                "android",
                "geo",
                "tags",
                "folderId",
                "comments",
                "utm_source",
                "utm_medium",
                "utm_campaign",
                "utm_term",
                "utm_content",
                "testVariants",
                "userId",
                "tagId",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyClickTypedDict(TypedDict):
    id: str
    timestamp: str
    url: str
    country: str
    city: str
    region: str
    continent: str
    device: str
    browser: str
    os: str
    referer: str
    referer_url: str
    qr: bool
    ip: str
    trigger: NotRequired[Nullable[str]]


class ListEventsResponseBodyClick(BaseModel):
    id: str

    timestamp: str

    url: str

    country: str

    city: str

    region: str

    continent: str

    device: str

    browser: str

    os: str

    referer: str

    referer_url: Annotated[str, pydantic.Field(alias="refererUrl")]

    qr: bool

    ip: str

    trigger: OptionalNullable[str] = UNSET

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["trigger"])
        nullable_fields = set(["trigger"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ResponseBodyCustomerTypedDict(TypedDict):
    id: str
    r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""
    name: str
    r"""Name of the customer."""
    external_id: str
    r"""Unique identifier for the customer in the client's app."""
    created_at: str
    r"""The date the customer was created (usually the signup date or trial start date)."""
    email: NotRequired[Nullable[str]]
    r"""Email of the customer."""
    avatar: NotRequired[Nullable[str]]
    r"""Avatar URL of the customer."""
    stripe_customer_id: NotRequired[Nullable[str]]
    r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
    country: NotRequired[Nullable[str]]
    r"""Country of the customer."""
    sales: NotRequired[Nullable[float]]
    r"""Total number of sales for the customer."""
    sale_amount: NotRequired[Nullable[float]]
    r"""Total amount of sales for the customer."""
    first_sale_at: NotRequired[Nullable[str]]
    r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""
    subscription_canceled_at: NotRequired[Nullable[str]]
    r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""


class ResponseBodyCustomer(BaseModel):
    id: str
    r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""

    name: str
    r"""Name of the customer."""

    external_id: Annotated[str, pydantic.Field(alias="externalId")]
    r"""Unique identifier for the customer in the client's app."""

    created_at: Annotated[str, pydantic.Field(alias="createdAt")]
    r"""The date the customer was created (usually the signup date or trial start date)."""

    email: OptionalNullable[str] = UNSET
    r"""Email of the customer."""

    avatar: OptionalNullable[str] = UNSET
    r"""Avatar URL of the customer."""

    stripe_customer_id: Annotated[
        OptionalNullable[str], pydantic.Field(alias="stripeCustomerId")
    ] = UNSET
    r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""

    country: OptionalNullable[str] = UNSET
    r"""Country of the customer."""

    sales: OptionalNullable[float] = UNSET
    r"""Total number of sales for the customer."""

    sale_amount: Annotated[
        OptionalNullable[float], pydantic.Field(alias="saleAmount")
    ] = UNSET
    r"""Total amount of sales for the customer."""

    first_sale_at: Annotated[
        OptionalNullable[str], pydantic.Field(alias="firstSaleAt")
    ] = UNSET
    r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""

    subscription_canceled_at: Annotated[
        OptionalNullable[str], pydantic.Field(alias="subscriptionCanceledAt")
    ] = UNSET
    r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "email",
                "avatar",
                "stripeCustomerId",
                "country",
                "sales",
                "saleAmount",
                "firstSaleAt",
                "subscriptionCanceledAt",
            ]
        )
        nullable_fields = set(
            [
                "email",
                "avatar",
                "stripeCustomerId",
                "country",
                "sales",
                "saleAmount",
                "firstSaleAt",
                "subscriptionCanceledAt",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class SaleEventTypedDict(TypedDict):
    event: ListEventsResponseBodyEventsEvent
    timestamp: str
    event_id: str
    event_name: str
    sale: ResponseBodySaleTypedDict
    link: ListEventsResponseBodyLinkTypedDict
    click: ListEventsResponseBodyClickTypedDict
    customer: ResponseBodyCustomerTypedDict
    sale_amount: float
    r"""Deprecated: Use `sale.amount` instead."""
    invoice_id: str
    r"""Deprecated: Use `sale.invoiceId` instead."""
    payment_processor: str
    r"""Deprecated: Use `sale.paymentProcessor` instead."""
    click_id: str
    r"""Deprecated: Use `click.id` instead."""
    link_id: str
    r"""Deprecated: Use `link.id` instead."""
    domain: str
    r"""Deprecated: Use `link.domain` instead."""
    key: str
    r"""Deprecated: Use `link.key` instead."""
    url: str
    r"""Deprecated: Use `click.url` instead."""
    continent: str
    r"""Deprecated: Use `click.continent` instead."""
    country: str
    r"""Deprecated: Use `click.country` instead."""
    city: str
    r"""Deprecated: Use `click.city` instead."""
    device: str
    r"""Deprecated: Use `click.device` instead."""
    browser: str
    r"""Deprecated: Use `click.browser` instead."""
    os: str
    r"""Deprecated: Use `click.os` instead."""
    qr: float
    r"""Deprecated: Use `click.qr` instead."""
    ip: str
    r"""Deprecated: Use `click.ip` instead."""
    metadata: NotRequired[Nullable[Any]]


class SaleEvent(BaseModel):
    event: ListEventsResponseBodyEventsEvent

    timestamp: str

    event_id: Annotated[str, pydantic.Field(alias="eventId")]

    event_name: Annotated[str, pydantic.Field(alias="eventName")]

    sale: ResponseBodySale

    link: ListEventsResponseBodyLink

    click: ListEventsResponseBodyClick

    customer: ResponseBodyCustomer

    sale_amount: Annotated[
        float,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="saleAmount",
        ),
    ]
    r"""Deprecated: Use `sale.amount` instead."""

    invoice_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `sale.invoiceId` instead."""

    payment_processor: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `sale.paymentProcessor` instead."""

    click_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.id` instead."""

    link_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.id` instead."""

    domain: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.domain` instead."""

    key: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.key` instead."""

    url: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.url` instead."""

    continent: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.continent` instead."""

    country: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.country` instead."""

    city: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.city` instead."""

    device: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.device` instead."""

    browser: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.browser` instead."""

    os: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.os` instead."""

    qr: Annotated[
        float,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.qr` instead."""

    ip: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.ip` instead."""

    metadata: OptionalNullable[Any] = UNSET

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["metadata"])
        nullable_fields = set(["metadata"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyEvent(str, Enum):
    LEAD = "lead"


class ResponseBodyClickTypedDict(TypedDict):
    id: str
    timestamp: str
    url: str
    country: str
    city: str
    region: str
    continent: str
    device: str
    browser: str
    os: str
    referer: str
    referer_url: str
    qr: bool
    ip: str
    trigger: NotRequired[Nullable[str]]


class ResponseBodyClick(BaseModel):
    id: str

    timestamp: str

    url: str

    country: str

    city: str

    region: str

    continent: str

    device: str

    browser: str

    os: str

    referer: str

    referer_url: Annotated[str, pydantic.Field(alias="refererUrl")]

    qr: bool

    ip: str

    trigger: OptionalNullable[str] = UNSET

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["trigger"])
        nullable_fields = set(["trigger"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyTestVariantsTypedDict(TypedDict):
    url: str
    percentage: float


class ListEventsResponseBodyTestVariants(BaseModel):
    url: str

    percentage: float


class ResponseBodyLinkTypedDict(TypedDict):
    id: str
    r"""The unique ID of the short link."""
    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""
    url: str
    track_conversion: bool
    external_id: Nullable[str]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""
    tenant_id: Nullable[str]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""
    program_id: Nullable[str]
    r"""The ID of the program the short link is associated with."""
    partner_id: Nullable[str]
    r"""The ID of the partner the short link is associated with."""
    archived: bool
    expires_at: str
    expired_url: Nullable[str]
    disabled_at: str
    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""
    proxy: bool
    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""
    rewrite: bool
    do_index: bool
    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""
    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""
    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""
    public_stats: bool
    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutputTypedDict]]
    r"""The tags assigned to the short link."""
    folder_id: Nullable[str]
    r"""The unique ID of the folder assigned to the short link."""
    webhook_ids: List[str]
    r"""The IDs of the webhooks that the short link is associated with."""
    comments: Nullable[str]
    r"""The comments for the short link."""
    short_link: str
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""
    qr_code: str
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""
    utm_source: Nullable[str]
    r"""The UTM source of the short link."""
    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""
    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""
    utm_term: Nullable[str]
    r"""The UTM term of the short link."""
    utm_content: Nullable[str]
    r"""The UTM content of the short link."""
    test_started_at: str
    test_completed_at: str
    user_id: Nullable[str]
    workspace_id: str
    r"""The workspace ID of the short link."""
    last_clicked: str
    created_at: str
    updated_at: str
    tag_id: Nullable[str]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""
    project_id: str
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""
    test_variants: NotRequired[
        Nullable[List[ListEventsResponseBodyTestVariantsTypedDict]]
    ]
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""
    clicks: NotRequired[float]
    r"""The number of clicks on the short link."""
    leads: NotRequired[float]
    r"""The number of leads the short link has generated."""
    conversions: NotRequired[float]
    r"""The number of leads that converted to paying customers."""
    sales: NotRequired[float]
    r"""The total number of sales (includes recurring sales) generated by the short link."""
    sale_amount: NotRequired[float]
    r"""The total dollar value of sales (in cents) generated by the short link."""


class ResponseBodyLink(BaseModel):
    id: str
    r"""The unique ID of the short link."""

    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""

    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""

    url: str

    track_conversion: Annotated[bool, pydantic.Field(alias="trackConversion")]

    external_id: Annotated[Nullable[str], pydantic.Field(alias="externalId")]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""

    tenant_id: Annotated[Nullable[str], pydantic.Field(alias="tenantId")]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""

    program_id: Annotated[Nullable[str], pydantic.Field(alias="programId")]
    r"""The ID of the program the short link is associated with."""

    partner_id: Annotated[Nullable[str], pydantic.Field(alias="partnerId")]
    r"""The ID of the partner the short link is associated with."""

    archived: bool

    expires_at: Annotated[str, pydantic.Field(alias="expiresAt")]

    expired_url: Annotated[Nullable[str], pydantic.Field(alias="expiredUrl")]

    disabled_at: Annotated[str, pydantic.Field(alias="disabledAt")]

    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""

    proxy: bool

    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""

    rewrite: bool

    do_index: Annotated[bool, pydantic.Field(alias="doIndex")]

    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""

    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""

    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""

    public_stats: Annotated[bool, pydantic.Field(alias="publicStats")]

    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutput]]
    r"""The tags assigned to the short link."""

    folder_id: Annotated[Nullable[str], pydantic.Field(alias="folderId")]
    r"""The unique ID of the folder assigned to the short link."""

    webhook_ids: Annotated[List[str], pydantic.Field(alias="webhookIds")]
    r"""The IDs of the webhooks that the short link is associated with."""

    comments: Nullable[str]
    r"""The comments for the short link."""

    short_link: Annotated[str, pydantic.Field(alias="shortLink")]
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""

    qr_code: Annotated[str, pydantic.Field(alias="qrCode")]
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""

    utm_source: Nullable[str]
    r"""The UTM source of the short link."""

    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""

    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""

    utm_term: Nullable[str]
    r"""The UTM term of the short link."""

    utm_content: Nullable[str]
    r"""The UTM content of the short link."""

    test_started_at: Annotated[str, pydantic.Field(alias="testStartedAt")]

    test_completed_at: Annotated[str, pydantic.Field(alias="testCompletedAt")]

    user_id: Annotated[Nullable[str], pydantic.Field(alias="userId")]

    workspace_id: Annotated[str, pydantic.Field(alias="workspaceId")]
    r"""The workspace ID of the short link."""

    last_clicked: Annotated[str, pydantic.Field(alias="lastClicked")]

    created_at: Annotated[str, pydantic.Field(alias="createdAt")]

    updated_at: Annotated[str, pydantic.Field(alias="updatedAt")]

    tag_id: Annotated[
        Nullable[str],
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="tagId",
        ),
    ]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""

    project_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="projectId",
        ),
    ]
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""

    test_variants: Annotated[
        OptionalNullable[List[ListEventsResponseBodyTestVariants]],
        pydantic.Field(alias="testVariants"),
    ] = UNSET
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""

    clicks: Optional[float] = 0
    r"""The number of clicks on the short link."""

    leads: Optional[float] = 0
    r"""The number of leads the short link has generated."""

    conversions: Optional[float] = 0
    r"""The number of leads that converted to paying customers."""

    sales: Optional[float] = 0
    r"""The total number of sales (includes recurring sales) generated by the short link."""

    sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
    r"""The total dollar value of sales (in cents) generated by the short link."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            ["testVariants", "clicks", "leads", "conversions", "sales", "saleAmount"]
        )
        nullable_fields = set(
            [
                "externalId",
                "tenantId",
                "programId",
                "partnerId",
                "expiredUrl",
                "password",
                "title",
                "description",
                "image",
                "video",
                "ios",
                "android",
                "geo",
                "tags",
                "folderId",
                "comments",
                "utm_source",
                "utm_medium",
                "utm_campaign",
                "utm_term",
                "utm_content",
                "testVariants",
                "userId",
                "tagId",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ListEventsResponseBodyCustomerTypedDict(TypedDict):
    id: str
    r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""
    name: str
    r"""Name of the customer."""
    external_id: str
    r"""Unique identifier for the customer in the client's app."""
    created_at: str
    r"""The date the customer was created (usually the signup date or trial start date)."""
    email: NotRequired[Nullable[str]]
    r"""Email of the customer."""
    avatar: NotRequired[Nullable[str]]
    r"""Avatar URL of the customer."""
    stripe_customer_id: NotRequired[Nullable[str]]
    r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""
    country: NotRequired[Nullable[str]]
    r"""Country of the customer."""
    sales: NotRequired[Nullable[float]]
    r"""Total number of sales for the customer."""
    sale_amount: NotRequired[Nullable[float]]
    r"""Total amount of sales for the customer."""
    first_sale_at: NotRequired[Nullable[str]]
    r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""
    subscription_canceled_at: NotRequired[Nullable[str]]
    r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""


class ListEventsResponseBodyCustomer(BaseModel):
    id: str
    r"""The unique ID of the customer. You may use either the customer's `id` on Dub (obtained via `/customers` endpoint) or their `externalId` (unique ID within your system, prefixed with `ext_`, e.g. `ext_123`)."""

    name: str
    r"""Name of the customer."""

    external_id: Annotated[str, pydantic.Field(alias="externalId")]
    r"""Unique identifier for the customer in the client's app."""

    created_at: Annotated[str, pydantic.Field(alias="createdAt")]
    r"""The date the customer was created (usually the signup date or trial start date)."""

    email: OptionalNullable[str] = UNSET
    r"""Email of the customer."""

    avatar: OptionalNullable[str] = UNSET
    r"""Avatar URL of the customer."""

    stripe_customer_id: Annotated[
        OptionalNullable[str], pydantic.Field(alias="stripeCustomerId")
    ] = UNSET
    r"""The customer's Stripe customer ID. This is useful for attributing recurring sale events to the partner who referred the customer."""

    country: OptionalNullable[str] = UNSET
    r"""Country of the customer."""

    sales: OptionalNullable[float] = UNSET
    r"""Total number of sales for the customer."""

    sale_amount: Annotated[
        OptionalNullable[float], pydantic.Field(alias="saleAmount")
    ] = UNSET
    r"""Total amount of sales for the customer."""

    first_sale_at: Annotated[
        OptionalNullable[str], pydantic.Field(alias="firstSaleAt")
    ] = UNSET
    r"""The date the customer made their first sale. Useful for calculating the time to first sale and LTV."""

    subscription_canceled_at: Annotated[
        OptionalNullable[str], pydantic.Field(alias="subscriptionCanceledAt")
    ] = UNSET
    r"""The date the customer canceled their subscription. Useful for calculating LTV and churn rate."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "email",
                "avatar",
                "stripeCustomerId",
                "country",
                "sales",
                "saleAmount",
                "firstSaleAt",
                "subscriptionCanceledAt",
            ]
        )
        nullable_fields = set(
            [
                "email",
                "avatar",
                "stripeCustomerId",
                "country",
                "sales",
                "saleAmount",
                "firstSaleAt",
                "subscriptionCanceledAt",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class LeadEventTypedDict(TypedDict):
    event: ListEventsResponseBodyEvent
    timestamp: str
    event_id: str
    event_name: str
    click: ResponseBodyClickTypedDict
    link: ResponseBodyLinkTypedDict
    customer: ListEventsResponseBodyCustomerTypedDict
    click_id: str
    r"""Deprecated: Use `click.id` instead."""
    link_id: str
    r"""Deprecated: Use `link.id` instead."""
    domain: str
    r"""Deprecated: Use `link.domain` instead."""
    key: str
    r"""Deprecated: Use `link.key` instead."""
    url: str
    r"""Deprecated: Use `click.url` instead."""
    continent: str
    r"""Deprecated: Use `click.continent` instead."""
    country: str
    r"""Deprecated: Use `click.country` instead."""
    city: str
    r"""Deprecated: Use `click.city` instead."""
    device: str
    r"""Deprecated: Use `click.device` instead."""
    browser: str
    r"""Deprecated: Use `click.browser` instead."""
    os: str
    r"""Deprecated: Use `click.os` instead."""
    qr: float
    r"""Deprecated: Use `click.qr` instead."""
    ip: str
    r"""Deprecated: Use `click.ip` instead."""
    metadata: NotRequired[Nullable[Any]]


class LeadEvent(BaseModel):
    event: ListEventsResponseBodyEvent

    timestamp: str

    event_id: Annotated[str, pydantic.Field(alias="eventId")]

    event_name: Annotated[str, pydantic.Field(alias="eventName")]

    click: ResponseBodyClick

    link: ResponseBodyLink

    customer: ListEventsResponseBodyCustomer

    click_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.id` instead."""

    link_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.id` instead."""

    domain: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.domain` instead."""

    key: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.key` instead."""

    url: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.url` instead."""

    continent: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.continent` instead."""

    country: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.country` instead."""

    city: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.city` instead."""

    device: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.device` instead."""

    browser: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.browser` instead."""

    os: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.os` instead."""

    qr: Annotated[
        float,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.qr` instead."""

    ip: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.ip` instead."""

    metadata: OptionalNullable[Any] = UNSET

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["metadata"])
        nullable_fields = set(["metadata"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ResponseBodyEvent(str, Enum):
    CLICK = "click"


class ListEventsResponseBodyEventsClickTypedDict(TypedDict):
    id: str
    timestamp: str
    url: str
    country: str
    city: str
    region: str
    continent: str
    device: str
    browser: str
    os: str
    referer: str
    referer_url: str
    qr: bool
    ip: str
    trigger: NotRequired[Nullable[str]]


class ListEventsResponseBodyEventsClick(BaseModel):
    id: str

    timestamp: str

    url: str

    country: str

    city: str

    region: str

    continent: str

    device: str

    browser: str

    os: str

    referer: str

    referer_url: Annotated[str, pydantic.Field(alias="refererUrl")]

    qr: bool

    ip: str

    trigger: OptionalNullable[str] = UNSET

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["trigger"])
        nullable_fields = set(["trigger"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ResponseBodyTestVariantsTypedDict(TypedDict):
    url: str
    percentage: float


class ResponseBodyTestVariants(BaseModel):
    url: str

    percentage: float


class ListEventsResponseBodyEventsLinkTypedDict(TypedDict):
    id: str
    r"""The unique ID of the short link."""
    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""
    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""
    url: str
    track_conversion: bool
    external_id: Nullable[str]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""
    tenant_id: Nullable[str]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""
    program_id: Nullable[str]
    r"""The ID of the program the short link is associated with."""
    partner_id: Nullable[str]
    r"""The ID of the partner the short link is associated with."""
    archived: bool
    expires_at: str
    expired_url: Nullable[str]
    disabled_at: str
    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""
    proxy: bool
    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""
    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""
    rewrite: bool
    do_index: bool
    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""
    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""
    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""
    public_stats: bool
    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutputTypedDict]]
    r"""The tags assigned to the short link."""
    folder_id: Nullable[str]
    r"""The unique ID of the folder assigned to the short link."""
    webhook_ids: List[str]
    r"""The IDs of the webhooks that the short link is associated with."""
    comments: Nullable[str]
    r"""The comments for the short link."""
    short_link: str
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""
    qr_code: str
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""
    utm_source: Nullable[str]
    r"""The UTM source of the short link."""
    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""
    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""
    utm_term: Nullable[str]
    r"""The UTM term of the short link."""
    utm_content: Nullable[str]
    r"""The UTM content of the short link."""
    test_started_at: str
    test_completed_at: str
    user_id: Nullable[str]
    workspace_id: str
    r"""The workspace ID of the short link."""
    last_clicked: str
    created_at: str
    updated_at: str
    tag_id: Nullable[str]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""
    project_id: str
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""
    test_variants: NotRequired[Nullable[List[ResponseBodyTestVariantsTypedDict]]]
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""
    clicks: NotRequired[float]
    r"""The number of clicks on the short link."""
    leads: NotRequired[float]
    r"""The number of leads the short link has generated."""
    conversions: NotRequired[float]
    r"""The number of leads that converted to paying customers."""
    sales: NotRequired[float]
    r"""The total number of sales (includes recurring sales) generated by the short link."""
    sale_amount: NotRequired[float]
    r"""The total dollar value of sales (in cents) generated by the short link."""


class ListEventsResponseBodyEventsLink(BaseModel):
    id: str
    r"""The unique ID of the short link."""

    domain: str
    r"""The domain of the short link. If not provided, the primary domain for the workspace will be used (or `dub.sh` if the workspace has no domains)."""

    key: str
    r"""The short link slug. If not provided, a random 7-character slug will be generated."""

    url: str

    track_conversion: Annotated[bool, pydantic.Field(alias="trackConversion")]

    external_id: Annotated[Nullable[str], pydantic.Field(alias="externalId")]
    r"""The ID of the link in your database. If set, it can be used to identify the link in future API requests (must be prefixed with 'ext_' when passed as a query parameter). This key is unique across your workspace."""

    tenant_id: Annotated[Nullable[str], pydantic.Field(alias="tenantId")]
    r"""The ID of the tenant that created the link inside your system. If set, it can be used to fetch all links for a tenant."""

    program_id: Annotated[Nullable[str], pydantic.Field(alias="programId")]
    r"""The ID of the program the short link is associated with."""

    partner_id: Annotated[Nullable[str], pydantic.Field(alias="partnerId")]
    r"""The ID of the partner the short link is associated with."""

    archived: bool

    expires_at: Annotated[str, pydantic.Field(alias="expiresAt")]

    expired_url: Annotated[Nullable[str], pydantic.Field(alias="expiredUrl")]

    disabled_at: Annotated[str, pydantic.Field(alias="disabledAt")]

    password: Nullable[str]
    r"""The password required to access the destination URL of the short link."""

    proxy: bool

    title: Nullable[str]
    r"""The title of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    description: Nullable[str]
    r"""The description of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    image: Nullable[str]
    r"""The image of the short link. Will be used for Custom Link Previews if `proxy` is true."""

    video: Nullable[str]
    r"""The custom link preview video (og:video). Will be used for Custom Link Previews if `proxy` is true. Learn more: https://d.to/og"""

    rewrite: bool

    do_index: Annotated[bool, pydantic.Field(alias="doIndex")]

    ios: Nullable[str]
    r"""The iOS destination URL for the short link for iOS device targeting."""

    android: Nullable[str]
    r"""The Android destination URL for the short link for Android device targeting."""

    geo: Nullable[Dict[str, str]]
    r"""Geo targeting information for the short link in JSON format `{[COUNTRY]: https://example.com }`. See https://d.to/geo for more information."""

    public_stats: Annotated[bool, pydantic.Field(alias="publicStats")]

    tags: Nullable[List[components_linktagschemaoutput.LinkTagSchemaOutput]]
    r"""The tags assigned to the short link."""

    folder_id: Annotated[Nullable[str], pydantic.Field(alias="folderId")]
    r"""The unique ID of the folder assigned to the short link."""

    webhook_ids: Annotated[List[str], pydantic.Field(alias="webhookIds")]
    r"""The IDs of the webhooks that the short link is associated with."""

    comments: Nullable[str]
    r"""The comments for the short link."""

    short_link: Annotated[str, pydantic.Field(alias="shortLink")]
    r"""The full URL of the short link, including the https protocol (e.g. `https://dub.sh/try`)."""

    qr_code: Annotated[str, pydantic.Field(alias="qrCode")]
    r"""The full URL of the QR code for the short link (e.g. `https://api.dub.co/qr?url=https://dub.sh/try`)."""

    utm_source: Nullable[str]
    r"""The UTM source of the short link."""

    utm_medium: Nullable[str]
    r"""The UTM medium of the short link."""

    utm_campaign: Nullable[str]
    r"""The UTM campaign of the short link."""

    utm_term: Nullable[str]
    r"""The UTM term of the short link."""

    utm_content: Nullable[str]
    r"""The UTM content of the short link."""

    test_started_at: Annotated[str, pydantic.Field(alias="testStartedAt")]

    test_completed_at: Annotated[str, pydantic.Field(alias="testCompletedAt")]

    user_id: Annotated[Nullable[str], pydantic.Field(alias="userId")]

    workspace_id: Annotated[str, pydantic.Field(alias="workspaceId")]
    r"""The workspace ID of the short link."""

    last_clicked: Annotated[str, pydantic.Field(alias="lastClicked")]

    created_at: Annotated[str, pydantic.Field(alias="createdAt")]

    updated_at: Annotated[str, pydantic.Field(alias="updatedAt")]

    tag_id: Annotated[
        Nullable[str],
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="tagId",
        ),
    ]
    r"""Deprecated: Use `tags` instead. The unique ID of the tag assigned to the short link."""

    project_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible.",
            alias="projectId",
        ),
    ]
    r"""Deprecated: Use `workspaceId` instead. The project ID of the short link."""

    test_variants: Annotated[
        OptionalNullable[List[ResponseBodyTestVariants]],
        pydantic.Field(alias="testVariants"),
    ] = UNSET
    r"""An array of A/B test URLs and the percentage of traffic to send to each URL."""

    clicks: Optional[float] = 0
    r"""The number of clicks on the short link."""

    leads: Optional[float] = 0
    r"""The number of leads the short link has generated."""

    conversions: Optional[float] = 0
    r"""The number of leads that converted to paying customers."""

    sales: Optional[float] = 0
    r"""The total number of sales (includes recurring sales) generated by the short link."""

    sale_amount: Annotated[Optional[float], pydantic.Field(alias="saleAmount")] = 0
    r"""The total dollar value of sales (in cents) generated by the short link."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            ["testVariants", "clicks", "leads", "conversions", "sales", "saleAmount"]
        )
        nullable_fields = set(
            [
                "externalId",
                "tenantId",
                "programId",
                "partnerId",
                "expiredUrl",
                "password",
                "title",
                "description",
                "image",
                "video",
                "ios",
                "android",
                "geo",
                "tags",
                "folderId",
                "comments",
                "utm_source",
                "utm_medium",
                "utm_campaign",
                "utm_term",
                "utm_content",
                "testVariants",
                "userId",
                "tagId",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


class ClickEventTypedDict(TypedDict):
    event: ResponseBodyEvent
    timestamp: str
    click: ListEventsResponseBodyEventsClickTypedDict
    link: ListEventsResponseBodyEventsLinkTypedDict
    click_id: str
    r"""Deprecated: Use `click.id` instead."""
    link_id: str
    r"""Deprecated: Use `link.id` instead."""
    domain: str
    r"""Deprecated: Use `link.domain` instead."""
    key: str
    r"""Deprecated: Use `link.key` instead."""
    url: str
    r"""Deprecated: Use `click.url` instead."""
    continent: str
    r"""Deprecated: Use `click.continent` instead."""
    country: str
    r"""Deprecated: Use `click.country` instead."""
    city: str
    r"""Deprecated: Use `click.city` instead."""
    device: str
    r"""Deprecated: Use `click.device` instead."""
    browser: str
    r"""Deprecated: Use `click.browser` instead."""
    os: str
    r"""Deprecated: Use `click.os` instead."""
    qr: float
    r"""Deprecated: Use `click.qr` instead."""
    ip: str
    r"""Deprecated: Use `click.ip` instead."""


class ClickEvent(BaseModel):
    event: ResponseBodyEvent

    timestamp: str

    click: ListEventsResponseBodyEventsClick

    link: ListEventsResponseBodyEventsLink

    click_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.id` instead."""

    link_id: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.id` instead."""

    domain: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.domain` instead."""

    key: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `link.key` instead."""

    url: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.url` instead."""

    continent: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.continent` instead."""

    country: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.country` instead."""

    city: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.city` instead."""

    device: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.device` instead."""

    browser: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.browser` instead."""

    os: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.os` instead."""

    qr: Annotated[
        float,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.qr` instead."""

    ip: Annotated[
        str,
        pydantic.Field(
            deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
        ),
    ]
    r"""Deprecated: Use `click.ip` instead."""


ListEventsResponseBodyTypedDict = TypeAliasType(
    "ListEventsResponseBodyTypedDict",
    Union[ClickEventTypedDict, LeadEventTypedDict, SaleEventTypedDict],
)


ListEventsResponseBody = Annotated[
    Union[
        Annotated[ClickEvent, Tag("click")],
        Annotated[LeadEvent, Tag("lead")],
        Annotated[SaleEvent, Tag("sale")],
    ],
    Discriminator(lambda m: get_discriminator(m, "event", "event")),
]
