late 0.0.1112

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.199.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 on create, boost and targeting update with `INVALID_FIELD_VALUE` naming the offending field (never 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, Pinterest, LinkedIn, X and Google Search/Display (Google excludes the age ranges outside the request); rejected with 400 on OpenAI and on Google Performance Max / Demand Gen. Each platform clamps to its own range: Meta and Pinterest effectively cap at 65 (65 = 65+), TikTok maps up to 100. LinkedIn rounds out to its buckets (18-24, 25-34, 35-54, 55+) and has no under-18 audience; X rounds out to the narrowest of its fixed ranges (e.g. 25-34 becomes 25-49, 18-65 becomes 18+). 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, Pinterest, LinkedIn, X and Google Search/Display (Google excludes the other gender); rejected with 400 on OpenAI and on Google Performance Max / Demand Gen.
    #[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. Applied on Meta, Google, TikTok, LinkedIn, X and Pinterest; rejected with 400 on OpenAI. A code the platform cannot target returns 400 listing the ones it can. 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. Rejected with 400 on Google (use Demand Gen audience userInterests there) and OpenAI.
    #[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 on create, boost and targeting update with `INVALID_FIELD_VALUE` naming the offending field (never 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, Pinterest, LinkedIn, X and Google Search/Display (Google excludes the other gender); rejected with 400 on OpenAI and on Google Performance Max / Demand Gen.
#[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
    }
}