late 0.0.203

API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
Documentation
/*
 * Zernio API
 *
 * API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
 *
 * The version of the OpenAPI document: 1.0.1
 * Contact: support@zernio.com
 * Generated by: https://openapi-generator.tech
 */

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

#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct CreateStandaloneAdRequest {
    #[serde(rename = "accountId")]
    pub account_id: String,
    #[serde(rename = "adAccountId")]
    pub ad_account_id: String,
    #[serde(rename = "name")]
    pub name: String,
    /// Required on legacy + multi-creative shapes. Inherited from the ad set on the attach shape. Available goals vary by platform. Meta-specific: `conversions` requires `promotedObject.pixelId` + `promotedObject.customEventType`; `app_promotion` requires `promotedObject.applicationId` + `promotedObject.objectStoreUrl`; `lead_generation` accepts an optional `promotedObject.pageId` (auto-filled from the connected Page when omitted).
    #[serde(rename = "goal", skip_serializing_if = "Option::is_none")]
    pub goal: Option<Goal>,
    /// Required on legacy + multi-creative shapes. Inherited on attach.
    #[serde(rename = "budgetAmount", skip_serializing_if = "Option::is_none")]
    pub budget_amount: Option<f64>,
    /// Required on legacy + multi-creative shapes. Inherited on attach.
    #[serde(rename = "budgetType", skip_serializing_if = "Option::is_none")]
    pub budget_type: Option<BudgetType>,
    #[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
    pub currency: Option<String>,
    /// Required for Meta, Google, and Pinterest on legacy + attach shapes (skip for multi-creative — use `creatives[].headline`). Ignored for TikTok and X/Twitter. Max: Meta=255, Google=30, Pinterest=100.
    #[serde(rename = "headline", skip_serializing_if = "Option::is_none")]
    pub headline: Option<String>,
    /// Google Display only. Defaults to `headline` if omitted.
    #[serde(rename = "longHeadline", skip_serializing_if = "Option::is_none")]
    pub long_headline: Option<String>,
    /// Required on legacy + attach shapes. For X/Twitter this is the tweet text (max 280 chars including a ~24-char URL when `linkUrl` is set). Max: Google=90, Pinterest=500.
    #[serde(rename = "body", skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    /// Required on legacy + attach shapes for Meta. Honoured on TikTok too — passes through to the Spark Ad creative's `call_to_action`. Ignored by other platforms.
    #[serde(rename = "callToAction", skip_serializing_if = "Option::is_none")]
    pub call_to_action: Option<CallToAction>,
    /// Required on legacy + attach shapes. Skip for multi-creative.
    #[serde(rename = "linkUrl", skip_serializing_if = "Option::is_none")]
    pub link_url: Option<String>,
    /// Image creative for Meta/Google/Pinterest on legacy + attach shapes (mutually exclusive with `video`). Not required for Google Search campaigns. For TikTok, this field carries the VIDEO URL (the TikTok ads endpoint is video-only; the field retains the `imageUrl` name for cross-platform consistency). Ignored for X/Twitter. For Google Display, treated as the landscape image (alias of `images.landscape`); supply `images.square` alongside or the request is rejected.
    #[serde(rename = "imageUrl", skip_serializing_if = "Option::is_none")]
    pub image_url: Option<String>,
    #[serde(rename = "images", skip_serializing_if = "Option::is_none")]
    pub images: Option<Box<models::CreateStandaloneAdRequestImages>>,
    #[serde(rename = "video", skip_serializing_if = "Option::is_none")]
    pub video: Option<Box<models::CreateStandaloneAdRequestVideo>>,
    /// Meta-only. When present, switches to the multi-creative shape: creates 1 campaign + 1 ad set + N ads (one per entry here). Top-level `headline` / `body` / `imageUrl` / `linkUrl` / `callToAction` are ignored in this mode. Mutually exclusive with `adSetId`.
    #[serde(rename = "creatives", skip_serializing_if = "Option::is_none")]
    pub creatives: Option<Vec<models::CreateStandaloneAdRequestCreativesInner>>,
    /// Meta-only. When present, switches to the attach shape: adds one new ad to this existing ad set without creating a new campaign. Budget, targeting, goal, schedule, AND bid strategy are inherited from the ad set on Meta — passing `bidStrategy` in attach mode returns 400. To change an existing ad set's bid, use `PUT /v1/ads/ad-sets/{adSetId}`. Mutually exclusive with `creatives[]`.  Supported on Meta (facebook, instagram) and TikTok. On TikTok the `adSetId` is the ad group ID; the new ad inherits the ad group's bid + budget + targeting.
    #[serde(rename = "adSetId", skip_serializing_if = "Option::is_none")]
    pub ad_set_id: Option<String>,
    /// Google Display only
    #[serde(rename = "businessName", skip_serializing_if = "Option::is_none")]
    pub business_name: Option<String>,
    /// Pinterest only. Board ID (auto-creates if not provided).
    #[serde(rename = "boardId", skip_serializing_if = "Option::is_none")]
    pub board_id: Option<String>,
    /// ISO 3166-1 alpha-2 country codes (e.g. ['NL']). Defaults to ['US'] when no `cities` or `regions` are provided.
    #[serde(rename = "countries", skip_serializing_if = "Option::is_none")]
    pub countries: Option<Vec<String>>,
    /// Meta-only. City-level geo targeting. Each city is targeted by Meta's opaque `key` (the city ID) which can be looked up via `GET /v1/ads/targeting/search?type=city&q=<name>&country_code=<ISO>`. Optional `radius` + `distance_unit` extend the targeting beyond the city limits (e.g. radius 25 km around the city center). Both must be set together, or both omitted (Meta defaults to ~16 km when omitted).  Cannot overlap with the same country in `countries` (Meta returns a \"locations overlap\" error). Either drop the country or scope it to a different country.
    #[serde(rename = "cities", skip_serializing_if = "Option::is_none")]
    pub cities: Option<Vec<models::CreateStandaloneAdRequestCitiesInner>>,
    /// Meta-only. Region-level (state/province) geo targeting. Each region is targeted by Meta's opaque `key` (the region ID) which can be looked up via `GET /v1/ads/targeting/search?type=region&q=<name>&country_code=<ISO>`.
    #[serde(rename = "regions", skip_serializing_if = "Option::is_none")]
    pub regions: Option<Vec<models::CreateStandaloneAdRequestRegionsInner>>,
    #[serde(rename = "ageMin", skip_serializing_if = "Option::is_none")]
    pub age_min: Option<i32>,
    #[serde(rename = "ageMax", skip_serializing_if = "Option::is_none")]
    pub age_max: Option<i32>,
    /// Interest objects from /v1/ads/interests. Each must include id and name.
    #[serde(rename = "interests", skip_serializing_if = "Option::is_none")]
    pub interests: Option<Vec<models::UpdateAdRequestTargetingInterestsInner>>,
    /// Required for lifetime budgets
    #[serde(rename = "endDate", skip_serializing_if = "Option::is_none")]
    pub end_date: Option<String>,
    /// Custom audience ID for targeting
    #[serde(rename = "audienceId", skip_serializing_if = "Option::is_none")]
    pub audience_id: Option<String>,
    /// Google only
    #[serde(rename = "campaignType", skip_serializing_if = "Option::is_none")]
    pub campaign_type: Option<CampaignType>,
    /// Google Search only
    #[serde(rename = "keywords", skip_serializing_if = "Option::is_none")]
    pub keywords: Option<Vec<String>>,
    /// Google Search RSA only. Extra headlines.
    #[serde(
        rename = "additionalHeadlines",
        skip_serializing_if = "Option::is_none"
    )]
    pub additional_headlines: Option<Vec<String>>,
    /// Google Search RSA only. Extra descriptions.
    #[serde(
        rename = "additionalDescriptions",
        skip_serializing_if = "Option::is_none"
    )]
    pub additional_descriptions: Option<Vec<String>>,
    /// Meta only. Controls the Advantage audience feature (targeting_automation). 0 = disabled (default), 1 = enabled. Meta Marketing API requires this field on all ad set creation requests.
    #[serde(rename = "advantageAudience", skip_serializing_if = "Option::is_none")]
    pub advantage_audience: Option<AdvantageAudience>,
    /// Meta only. Restrict the audience by gender. 'male' targets men only, 'female' targets women only, 'all' (default) targets everyone. Ignored by non-Meta platforms.
    #[serde(rename = "gender", skip_serializing_if = "Option::is_none")]
    pub gender: Option<Gender>,
    /// Meta bid strategy applied to the ad set.
    #[serde(rename = "bidStrategy", skip_serializing_if = "Option::is_none")]
    pub bid_strategy: Option<models::BidStrategy>,
    /// Bid cap in WHOLE currency units (USD: 5 = $5.00; JPY: 100 = ¥100). Required when `bidStrategy` is `LOWEST_COST_WITH_BID_CAP` or `COST_CAP`.
    #[serde(rename = "bidAmount", skip_serializing_if = "Option::is_none")]
    pub bid_amount: Option<f64>,
    /// Minimum ROAS as a decimal multiplier (e.g. 2.0 = 2.0x ROAS). Required when `bidStrategy` is `LOWEST_COST_WITH_MIN_ROAS`. Sent to Meta as `bid_constraints.roas_average_floor` × 10000.
    #[serde(rename = "roasAverageFloor", skip_serializing_if = "Option::is_none")]
    pub roas_average_floor: Option<f64>,
    /// Name of the legal entity benefiting from the ad. Required by Meta when targeting EU users (DSA Article 26). Not enforced at schema level; enforced server-side when targeting intersects EU member states.
    #[serde(rename = "dsaBeneficiary", skip_serializing_if = "Option::is_none")]
    pub dsa_beneficiary: Option<String>,
    /// Name of the legal entity paying for the ad. Required by Meta when targeting EU users (DSA Article 26). Note Meta API spelling: dsa_payor (not dsa_payer).
    #[serde(rename = "dsaPayor", skip_serializing_if = "Option::is_none")]
    pub dsa_payor: Option<String>,
    #[serde(rename = "brandIdentity", skip_serializing_if = "Option::is_none")]
    pub brand_identity: Option<Box<models::CreateStandaloneAdRequestBrandIdentity>>,
    /// TikTok only. Forces the identity attribution on the ad:    - `TT_USER`: the posting account's open_id (real @username     branding). Requires a connected TikTok posting account     on the same profile.   - `CUSTOMIZED_USER`: synthetic Brand Identity (display     name + avatar). Requires a configured Brand Identity     (cached on the `tiktokads` SocialAccount via     `PATCH /v1/connect/tiktok-ads`) or an inline     `brandIdentity` to create one on the fly.  When omitted, defaults to `TT_USER` if a posting account is connected on this profile, else `CUSTOMIZED_USER`. Spark Ads (`POST /v1/ads/boost`) always use `TT_USER` regardless of this field — TikTok requires the original organic post's author identity for Spark.
    #[serde(rename = "identityType", skip_serializing_if = "Option::is_none")]
    pub identity_type: Option<IdentityType>,
    #[serde(rename = "promotedObject", skip_serializing_if = "Option::is_none")]
    pub promoted_object: Option<Box<models::CreateStandaloneAdRequestPromotedObject>>,
}

impl CreateStandaloneAdRequest {
    pub fn new(
        account_id: String,
        ad_account_id: String,
        name: String,
    ) -> CreateStandaloneAdRequest {
        CreateStandaloneAdRequest {
            account_id,
            ad_account_id,
            name,
            goal: None,
            budget_amount: None,
            budget_type: None,
            currency: None,
            headline: None,
            long_headline: None,
            body: None,
            call_to_action: None,
            link_url: None,
            image_url: None,
            images: None,
            video: None,
            creatives: None,
            ad_set_id: None,
            business_name: None,
            board_id: None,
            countries: None,
            cities: None,
            regions: None,
            age_min: None,
            age_max: None,
            interests: None,
            end_date: None,
            audience_id: None,
            campaign_type: None,
            keywords: None,
            additional_headlines: None,
            additional_descriptions: None,
            advantage_audience: None,
            gender: None,
            bid_strategy: None,
            bid_amount: None,
            roas_average_floor: None,
            dsa_beneficiary: None,
            dsa_payor: None,
            brand_identity: None,
            identity_type: None,
            promoted_object: None,
        }
    }
}
/// Required on legacy + multi-creative shapes. Inherited from the ad set on the attach shape. Available goals vary by platform. Meta-specific: `conversions` requires `promotedObject.pixelId` + `promotedObject.customEventType`; `app_promotion` requires `promotedObject.applicationId` + `promotedObject.objectStoreUrl`; `lead_generation` accepts an optional `promotedObject.pageId` (auto-filled from the connected Page when omitted).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Goal {
    #[serde(rename = "engagement")]
    Engagement,
    #[serde(rename = "traffic")]
    Traffic,
    #[serde(rename = "awareness")]
    Awareness,
    #[serde(rename = "video_views")]
    VideoViews,
    #[serde(rename = "lead_generation")]
    LeadGeneration,
    #[serde(rename = "conversions")]
    Conversions,
    #[serde(rename = "app_promotion")]
    AppPromotion,
}

impl Default for Goal {
    fn default() -> Goal {
        Self::Engagement
    }
}
/// Required on legacy + multi-creative shapes. Inherited on attach.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum BudgetType {
    #[serde(rename = "daily")]
    Daily,
    #[serde(rename = "lifetime")]
    Lifetime,
}

impl Default for BudgetType {
    fn default() -> BudgetType {
        Self::Daily
    }
}
/// Required on legacy + attach shapes for Meta. Honoured on TikTok too — passes through to the Spark Ad creative's `call_to_action`. Ignored by other platforms.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum CallToAction {
    #[serde(rename = "LEARN_MORE")]
    LearnMore,
    #[serde(rename = "SHOP_NOW")]
    ShopNow,
    #[serde(rename = "SIGN_UP")]
    SignUp,
    #[serde(rename = "BOOK_TRAVEL")]
    BookTravel,
    #[serde(rename = "CONTACT_US")]
    ContactUs,
    #[serde(rename = "DOWNLOAD")]
    Download,
    #[serde(rename = "GET_OFFER")]
    GetOffer,
    #[serde(rename = "GET_QUOTE")]
    GetQuote,
    #[serde(rename = "SUBSCRIBE")]
    Subscribe,
    #[serde(rename = "WATCH_MORE")]
    WatchMore,
}

impl Default for CallToAction {
    fn default() -> CallToAction {
        Self::LearnMore
    }
}
/// Google only
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum CampaignType {
    #[serde(rename = "display")]
    Display,
    #[serde(rename = "search")]
    Search,
}

impl Default for CampaignType {
    fn default() -> CampaignType {
        Self::Display
    }
}
/// Meta only. Controls the Advantage audience feature (targeting_automation). 0 = disabled (default), 1 = enabled. Meta Marketing API requires this field on all ad set creation requests.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum AdvantageAudience {
    #[serde(rename = "0")]
    Variant0,
    #[serde(rename = "1")]
    Variant1,
}

impl Default for AdvantageAudience {
    fn default() -> AdvantageAudience {
        Self::Variant0
    }
}
/// Meta only. Restrict the audience by gender. 'male' targets men only, 'female' targets women only, 'all' (default) targets everyone. Ignored by non-Meta platforms.
#[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
    }
}
/// TikTok only. Forces the identity attribution on the ad:    - `TT_USER`: the posting account's open_id (real @username     branding). Requires a connected TikTok posting account     on the same profile.   - `CUSTOMIZED_USER`: synthetic Brand Identity (display     name + avatar). Requires a configured Brand Identity     (cached on the `tiktokads` SocialAccount via     `PATCH /v1/connect/tiktok-ads`) or an inline     `brandIdentity` to create one on the fly.  When omitted, defaults to `TT_USER` if a posting account is connected on this profile, else `CUSTOMIZED_USER`. Spark Ads (`POST /v1/ads/boost`) always use `TT_USER` regardless of this field — TikTok requires the original organic post's author identity for Spark.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum IdentityType {
    #[serde(rename = "TT_USER")]
    TtUser,
    #[serde(rename = "CUSTOMIZED_USER")]
    CustomizedUser,
}

impl Default for IdentityType {
    fn default() -> IdentityType {
        Self::TtUser
    }
}