late 0.0.1102

API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema). Request ids: responses carry an X-Request-Id header with the id we log the request under. Quote it when reporting a problem. A valid x-request-id you send is reused as that id.
Documentation
/*
 * Zernio API
 *
 * API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api  Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal.  Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).  Request ids: responses carry an X-Request-Id header with the id we log the request under. Quote it when reporting a problem. A valid x-request-id you send is reused as that id.
 *
 * The version of the OpenAPI document: 1.182.0
 * Contact: support@zernio.com
 * Generated by: https://openapi-generator.tech
 */

use crate::models;
use serde::{Deserialize, Serialize};

/// TargetingSpec : Normalized, platform-agnostic ad-targeting spec. Every field is optional, an empty object targets the platform's default broadest audience. Field names are camelCase and identical across `POST /v1/ads/create` (the `targeting` object), `POST /v1/ads/targeting/reach-estimate`, and `saved_targeting` audiences, so a spec resolved once can be reused verbatim.  Entity ids (`regions[].key`, `cities[].key`, `zips[].key`, `metros[].key`, `interests[].id`, `behaviors[].id`) are the platform's opaque identifiers resolved via `GET /v1/ads/targeting/search`. A spec is therefore meaningful only for the platform it was built against, except the portable fields (`countries`, `ageMin`/`ageMax`, `gender`, `incomeTier`, `languages`) which carry across platforms. Fields a platform cannot honour are rejected at create time with `INVALID_FIELD_VALUE` naming the offending field (not silently dropped).
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct TargetingSpec {
    /// Meta only. Operating systems and version ranges, such as iOS_ver_14.0_and_above or Android. Emitted as user_os. May also be supplied inside targeting.
    #[serde(rename = "userOs", skip_serializing_if = "Option::is_none")]
    pub user_os: Option<Vec<String>>,
    /// Meta only. Device models such as iPhone. Emitted as user_device. May also be supplied inside targeting.
    #[serde(rename = "userDevice", skip_serializing_if = "Option::is_none")]
    pub user_device: Option<Vec<String>>,
    /// ISO 3166-1 alpha-2 country codes (e.g. ['US']).
    #[serde(rename = "countries", skip_serializing_if = "Option::is_none")]
    pub countries: Option<Vec<String>>,
    /// Region/state targeting. `key` is the platform location ID from /v1/ads/targeting/search?dimension=geo&geoType=region. An entry may also be that id as a plain string (`\"20321\"` is `{ key: \"20321\" }`).
    #[serde(rename = "regions", skip_serializing_if = "Option::is_none")]
    pub regions: Option<Vec<models::CreateStandaloneAdRequestZipsInner>>,
    /// City targeting. Optional `radius` + `distanceUnit` extend beyond the city limits; both must be set together or both omitted. `radius` is only honoured on platforms whose capability map allows city radius (Meta). An entry may also be the city id as a plain string (`\"1006410\"` is `{ key: \"1006410\" }`).
    #[serde(rename = "cities", skip_serializing_if = "Option::is_none")]
    pub cities: Option<Vec<models::TargetingSpecCitiesInner>>,
    /// Postal/ZIP targeting. `key` is the platform's postal location ID (e.g. Meta `US:94304`). Supported on Meta, Google, TikTok, Pinterest, X.
    #[serde(rename = "zips", skip_serializing_if = "Option::is_none")]
    pub zips:
        Option<Vec<models::UpdateCampaignTargetingRequestTargetingLocationsOneOfRegionsInnerOneOf>>,
    /// DMA / metro-area targeting. `key` is the platform's metro ID (e.g. Meta `DMA:807`).
    #[serde(rename = "metros", skip_serializing_if = "Option::is_none")]
    pub metros:
        Option<Vec<models::UpdateCampaignTargetingRequestTargetingLocationsOneOfRegionsInnerOneOf>>,
    /// Meta only. Continents and trade blocs (`geo_locations.country_groups`), for targeting a whole region without listing its countries. Combines with `countries` rather than replacing it, and is also accepted under `excludedLocations`. Discoverable via `GET /v1/ads/targeting/search?dimension=geo&geoType=country_group`.
    #[serde(rename = "countryGroups", skip_serializing_if = "Option::is_none")]
    pub country_groups: Option<Vec<CountryGroups>>,
    /// Point-radius (lat/lng) targeting (Meta custom_locations / Google proximity). Honoured on Meta and Google; ignored on platforms without radius support.
    #[serde(rename = "customLocations", skip_serializing_if = "Option::is_none")]
    pub custom_locations: Option<Vec<models::TargetingSpecCustomLocationsInner>>,
    #[serde(rename = "excludedLocations", skip_serializing_if = "Option::is_none")]
    pub excluded_locations: Option<Box<models::TargetingSpecExcludedLocations>>,
    /// Minimum age. Applied on Meta, TikTok and Pinterest; ignored on Google, LinkedIn and X. Each platform clamps to its own range: Meta and Pinterest effectively cap at 65 (65 = 65+), TikTok maps up to 100. Pinterest has no under-18 bucket, so an ageMin below 18 starts at 18 there.
    #[serde(rename = "ageMin", skip_serializing_if = "Option::is_none")]
    pub age_min: Option<i32>,
    /// Maximum age. Same per-platform application and clamping as ageMin.
    #[serde(rename = "ageMax", skip_serializing_if = "Option::is_none")]
    pub age_max: Option<i32>,
    /// Restrict by gender. 'all' (default) targets everyone. Applied on Meta, TikTok and Pinterest. Ignored on Google, LinkedIn and X.
    #[serde(rename = "gender", skip_serializing_if = "Option::is_none")]
    pub gender: Option<Gender>,
    /// Normalized household-income tier (ZIP/percentile based). Meta and TikTok express all four. Google maps only `top_10` (its INCOME_RANGE_90_UP); other tiers on Google, and any income tier on LinkedIn / X / Pinterest, are rejected. On Meta, income/zip targeting requires the relevant `specialAdCategories` to be unset (housing/employment/credit ads cannot use it).
    #[serde(rename = "incomeTier", skip_serializing_if = "Option::is_none")]
    pub income_tier: Option<IncomeTier>,
    /// Language codes restricting the audience by language. On Meta, ISO 639-1 codes (e.g. ['en']); a bare code targets all regional variants (\"en\" = all English), or use a region-qualified code (\"en_GB\", \"pt_BR\") for a specific one. Unknown codes are rejected.
    #[serde(rename = "languages", skip_serializing_if = "Option::is_none")]
    pub languages: Option<Vec<String>>,
    /// Interest entities from /v1/ads/targeting/search?dimension=interest. Each carries the platform's opaque id.
    #[serde(rename = "interests", skip_serializing_if = "Option::is_none")]
    pub interests: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// Behaviour entities from /v1/ads/targeting/search?dimension=behavior (Meta, TikTok and LinkedIn). On TikTok they target people who interacted with videos (watched to the end, liked, commented or shared, last 15 days) or creators (followed or viewed the profile) in the picked categories, and the ad group uses the TikTok placement only.
    #[serde(rename = "behaviors", skip_serializing_if = "Option::is_none")]
    pub behaviors: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// Meta only. Job title entities from /v1/ads/targeting/search?dimension=workPosition. Not interchangeable with the LinkedIn `jobTitles` URN fragments.
    #[serde(rename = "workPositions", skip_serializing_if = "Option::is_none")]
    pub work_positions: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// Meta only. Employer entities from /v1/ads/targeting/search?dimension=workEmployer.
    #[serde(rename = "workEmployers", skip_serializing_if = "Option::is_none")]
    pub work_employers: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// Meta only. Work-industry entities from /v1/ads/targeting/search?dimension=workIndustry. Not interchangeable with the LinkedIn `industries` URN fragments.
    #[serde(rename = "workIndustries", skip_serializing_if = "Option::is_none")]
    pub work_industries: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
    /// LinkedIn B2B only. Industry URN id fragments, or the full urn:li:industry:* URN from /v1/ads/targeting/search?dimension=industry.
    #[serde(rename = "industries", skip_serializing_if = "Option::is_none")]
    pub industries: Option<Vec<String>>,
    /// LinkedIn B2B only. Single-letter size codes (A to I), or the full urn:li:staffCountRange:* URN from /v1/ads/targeting/search?dimension=companySize.
    #[serde(rename = "companySizes", skip_serializing_if = "Option::is_none")]
    pub company_sizes: Option<Vec<String>>,
    /// LinkedIn B2B only. Seniority URN id fragments, or the full urn:li:seniority:* URN from /v1/ads/targeting/search?dimension=seniority.
    #[serde(rename = "seniorities", skip_serializing_if = "Option::is_none")]
    pub seniorities: Option<Vec<String>>,
    /// LinkedIn B2B only. Function URN id fragments, or the full urn:li:function:* URN from /v1/ads/targeting/search?dimension=jobFunction.
    #[serde(rename = "jobFunctions", skip_serializing_if = "Option::is_none")]
    pub job_functions: Option<Vec<String>>,
    /// Platform audience IDs to include, as returned by GET /v1/ads/audiences (Meta custom audience ids, TikTok audience ids, Pinterest customer list ids, LinkedIn segment ids (the platformAudienceId from GET /v1/ads/audiences; Zernio resolves it to the targetable LinkedIn ad segment, an unknown id returns 400), Google user list ids, X custom audience ids). Not supported on OpenAI (400).
    #[serde(rename = "audienceInclude", skip_serializing_if = "Option::is_none")]
    pub audience_include: Option<Vec<String>>,
    /// Platform audience IDs to exclude; same ID formats as audienceInclude. Not supported on OpenAI (400).
    #[serde(rename = "audienceExclude", skip_serializing_if = "Option::is_none")]
    pub audience_exclude: Option<Vec<String>>,
}

impl TargetingSpec {
    /// Normalized, platform-agnostic ad-targeting spec. Every field is optional, an empty object targets the platform's default broadest audience. Field names are camelCase and identical across `POST /v1/ads/create` (the `targeting` object), `POST /v1/ads/targeting/reach-estimate`, and `saved_targeting` audiences, so a spec resolved once can be reused verbatim.  Entity ids (`regions[].key`, `cities[].key`, `zips[].key`, `metros[].key`, `interests[].id`, `behaviors[].id`) are the platform's opaque identifiers resolved via `GET /v1/ads/targeting/search`. A spec is therefore meaningful only for the platform it was built against, except the portable fields (`countries`, `ageMin`/`ageMax`, `gender`, `incomeTier`, `languages`) which carry across platforms. Fields a platform cannot honour are rejected at create time with `INVALID_FIELD_VALUE` naming the offending field (not silently dropped).
    pub fn new() -> TargetingSpec {
        TargetingSpec {
            user_os: None,
            user_device: None,
            countries: None,
            regions: None,
            cities: None,
            zips: None,
            metros: None,
            country_groups: None,
            custom_locations: None,
            excluded_locations: None,
            age_min: None,
            age_max: None,
            gender: None,
            income_tier: None,
            languages: None,
            interests: None,
            behaviors: None,
            work_positions: None,
            work_employers: None,
            work_industries: None,
            industries: None,
            company_sizes: None,
            seniorities: None,
            job_functions: None,
            audience_include: None,
            audience_exclude: None,
        }
    }
}
/// Meta only. Continents and trade blocs (`geo_locations.country_groups`), for targeting a whole region without listing its countries. Combines with `countries` rather than replacing it, and is also accepted under `excludedLocations`. Discoverable via `GET /v1/ads/targeting/search?dimension=geo&geoType=country_group`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum CountryGroups {
    #[serde(rename = "africa")]
    Africa,
    #[serde(rename = "asia")]
    Asia,
    #[serde(rename = "europe")]
    Europe,
    #[serde(rename = "north_america")]
    NorthAmerica,
    #[serde(rename = "south_america")]
    SouthAmerica,
    #[serde(rename = "oceania")]
    Oceania,
    #[serde(rename = "central_america")]
    CentralAmerica,
    #[serde(rename = "caribbean")]
    Caribbean,
    #[serde(rename = "eea")]
    Eea,
    #[serde(rename = "euro_area")]
    EuroArea,
    #[serde(rename = "nafta")]
    Nafta,
    #[serde(rename = "mercosur")]
    Mercosur,
    #[serde(rename = "afta")]
    Afta,
    #[serde(rename = "apec")]
    Apec,
    #[serde(rename = "gcc")]
    Gcc,
    #[serde(rename = "cisfta")]
    Cisfta,
    #[serde(rename = "emerging_markets")]
    EmergingMarkets,
    #[serde(rename = "itunes_app_store")]
    ItunesAppStore,
    #[serde(rename = "android_free_store")]
    AndroidFreeStore,
    #[serde(rename = "android_paid_store")]
    AndroidPaidStore,
}

impl Default for CountryGroups {
    fn default() -> CountryGroups {
        Self::Africa
    }
}
/// Restrict by gender. 'all' (default) targets everyone. Applied on Meta, TikTok and Pinterest. Ignored on Google, LinkedIn and X.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Gender {
    #[serde(rename = "all")]
    All,
    #[serde(rename = "male")]
    Male,
    #[serde(rename = "female")]
    Female,
}

impl Default for Gender {
    fn default() -> Gender {
        Self::All
    }
}
/// Normalized household-income tier (ZIP/percentile based). Meta and TikTok express all four. Google maps only `top_10` (its INCOME_RANGE_90_UP); other tiers on Google, and any income tier on LinkedIn / X / Pinterest, are rejected. On Meta, income/zip targeting requires the relevant `specialAdCategories` to be unset (housing/employment/credit ads cannot use it).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum IncomeTier {
    #[serde(rename = "top_5")]
    Top5,
    #[serde(rename = "top_10")]
    Top10,
    #[serde(rename = "top_10_25")]
    Top1025,
    #[serde(rename = "top_25_50")]
    Top2550,
}

impl Default for IncomeTier {
    fn default() -> IncomeTier {
        Self::Top5
    }
}