/*
* 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.152.0
* 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 CreateCallAdRequest {
/// Meta enhancement settings for single or attached ads, and defaults for creatives[]. An item replaces the entire map, including with an empty object.
#[serde(rename = "creativeFeatures", skip_serializing_if = "Option::is_none")]
pub creative_features: Option<CreativeFeatures>,
#[serde(rename = "tracking", skip_serializing_if = "Option::is_none")]
pub tracking: Option<Box<models::AdTracking>>,
/// Facebook or Instagram SocialAccount ID.
#[serde(rename = "accountId")]
pub account_id: String,
/// Meta ad account ID, e.g. `act_123456789`.
#[serde(rename = "adAccountId")]
pub ad_account_id: String,
/// Ad display name. Used to derive campaign / ad set names. On the multi-creative shape, each ad's Meta name gets a \" #N\" suffix (1-indexed) so Ads Manager shows them as a numbered batch.
#[serde(rename = "name")]
pub name: String,
/// Exact name for the campaign this request provisions. Omitted keeps `<name> - Campaign`. Ignored with `adSetId` (the ad set already has a campaign).
#[serde(rename = "campaignName", skip_serializing_if = "Option::is_none")]
pub campaign_name: Option<String>,
/// Exact name for the ad set this request provisions. Omitted keeps `<name> - Ad Set`. Ignored with `adSetId`.
#[serde(rename = "adSetName", skip_serializing_if = "Option::is_none")]
pub ad_set_name: Option<String>,
/// Messaging and CTWA only. Platform post or reel ID, the same input boostPost takes as platformPostId. Facebook IDs become object_story_id; Instagram IDs become source_instagram_media_id using the connected Instagram identity. Mutually exclusive with objectStoryId and fresh creative fields.
#[serde(rename = "platformPostId", skip_serializing_if = "Option::is_none")]
pub platform_post_id: Option<String>,
/// Alias of platformPostId, kept for existing callers. Sending both with different values is a 400.
#[serde(rename = "existingPostId", skip_serializing_if = "Option::is_none")]
pub existing_post_id: Option<String>,
/// Messaging and CTWA only. Raw Facebook pageId_postId reference, used as object_story_id even with an Instagram account. Mutually exclusive with platformPostId and fresh creative fields.
#[serde(rename = "objectStoryId", skip_serializing_if = "Option::is_none")]
pub object_story_id: Option<String>,
/// Facebook Page the ad runs as, when the connection was granted several Pages. Defaults to the Page bound to the connection. Any Page granted to the connection is accepted; other ids answer 400 listing the granted Pages. Same semantics as `pageId` on POST /v1/ads/create.
#[serde(rename = "pageId", skip_serializing_if = "Option::is_none")]
pub page_id: Option<String>,
/// WhatsApp only. Optional E.164 number already paired with the Facebook Page. Omit to let Meta select the paired number. Sent to the creative CTA and, when creating a new ad set, its promoted_object. Attach requests do not change the existing ad set. Stored as creative.whatsappPhoneNumber on every created ad.
#[serde(
rename = "whatsappPhoneNumber",
skip_serializing_if = "Option::is_none"
)]
pub whatsapp_phone_number: Option<String>,
/// Single-creative shape only. Mutually exclusive with `creatives[]`.
#[serde(rename = "headline", skip_serializing_if = "Option::is_none")]
pub headline: Option<String>,
/// Primary text shown above the image / video. Single-creative shape only. Mutually exclusive with `creatives[]`.
#[serde(rename = "body", skip_serializing_if = "Option::is_none")]
pub body: Option<String>,
/// Image asset for single-creative shape. Mutually exclusive with `video` and with `creatives[]`. Required on the single-creative shape if neither `video` nor an existing post reference is supplied.
#[serde(rename = "imageUrl", skip_serializing_if = "Option::is_none")]
pub image_url: Option<String>,
#[serde(rename = "video", skip_serializing_if = "Option::is_none")]
pub video: Option<Box<models::CtwaAdRequestBodyVideo>>,
#[serde(rename = "welcomeMessage", skip_serializing_if = "Option::is_none")]
pub welcome_message: Option<Box<models::CtwaAdRequestBodyWelcomeMessage>>,
/// Multi-creative shape: N CTWA ads under one campaign + one ad set, sharing budget and targeting. Mutually exclusive with the top-level single-creative fields (`headline` / `body` / `imageUrl` / `video`): setting both is a 400, unlike `POST /v1/ads/create` where the top-level fields are silently ignored in multi-creative mode. Each entry supplies headline, body, and image/video, or a platformPostId or objectStoryId reference. Fresh and existing creatives can be mixed.
#[serde(rename = "creatives", skip_serializing_if = "Option::is_none")]
pub creatives: Option<Vec<models::CtwaAdRequestBodyCreativesInner>>,
/// Attach the creatives to this EXISTING messaging ad set instead of building a campaign, so the ad set keeps its learning phase. It then owns budget, targeting and schedule, so `budgetAmount`, `budgetType`, `endDate`, `objective`, `countries`, `interests`, `audienceId` and `campaignStatus` are rejected with a 400 alongside it. Its `destination_type` must match the ad's destination.
#[serde(rename = "adSetId", skip_serializing_if = "Option::is_none")]
pub ad_set_id: Option<String>,
/// Budget amount in the ad account's currency major units (e.g. dollars for USD, not cents). Must be > 0. Required unless `adSetId` is set, where the ad set owns it.
#[serde(rename = "budgetAmount", skip_serializing_if = "Option::is_none")]
pub budget_amount: Option<f64>,
/// Required unless `adSetId` is set.
#[serde(rename = "budgetType", skip_serializing_if = "Option::is_none")]
pub budget_type: Option<BudgetType>,
/// ISO 4217 currency code matching the ad account's currency (e.g. `USD`). Optional: Zernio resolves it from the ad account when omitted. The value selects the minor-unit exponent Zernio converts budget/bid amounts by before calling Meta (most currencies are cents; zero-decimal currencies like JPY/KRW are sent as-is).
#[serde(rename = "currency", skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
/// ISO 8601 datetime. Required when `budgetType` is `lifetime`.
#[serde(rename = "endDate", skip_serializing_if = "Option::is_none")]
pub end_date: Option<String>,
/// ISO 3166-1 alpha-2 country codes. Defaults to `[\"US\"]` only when no other geo (`cities`, `regions`, `zips`, `metros`, `customLocations`) is supplied.
#[serde(rename = "countries", skip_serializing_if = "Option::is_none")]
pub countries: Option<Vec<String>>,
/// City-level geo targeting for local CTWA campaigns. Each entry maps to Meta's TargetingGeoLocationCity. `key` is Meta's city ID. `radius` and `distance_unit` are coupled: set both or neither. Meta enforces a minimum city radius (~17 km / 10 mi); smaller values resolve to a 0-size audience and the ad fails at launch. For a tighter catchment use customLocations (lat/lng).
#[serde(rename = "cities", skip_serializing_if = "Option::is_none")]
pub cities: Option<Vec<models::CtwaAdRequestBodyCitiesInner>>,
/// Region / state-level geo targeting. `key` is Meta's region ID (lookupable via GET /v1/ads/targeting/search?type=region).
#[serde(rename = "regions", skip_serializing_if = "Option::is_none")]
pub regions: Option<Vec<models::CtwaAdRequestBodyRegionsInner>>,
/// ZIP / postal-code geo targeting. `key` is the platform's postal id resolved via /v1/ads/targeting/search.
#[serde(rename = "zips", skip_serializing_if = "Option::is_none")]
pub zips: Option<Vec<models::CtwaAdRequestBodyZipsInner>>,
/// DMA / metro-area geo targeting. `key` is Meta's metro id (e.g. `DMA:807`).
#[serde(rename = "metros", skip_serializing_if = "Option::is_none")]
pub metros: Option<Vec<models::CtwaAdRequestBodyZipsInner>>,
/// 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 geo (Meta `geo_locations.custom_locations`). Use for targeting a radius around a specific lat/long when no Meta city/region key fits. `distanceUnit` is required.
#[serde(rename = "customLocations", skip_serializing_if = "Option::is_none")]
pub custom_locations: Option<Vec<models::CreateStandaloneAdRequestCustomLocationsInner>>,
#[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>,
#[serde(rename = "interests", skip_serializing_if = "Option::is_none")]
pub interests: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
/// Custom audience ID to target.
#[serde(rename = "audienceId", skip_serializing_if = "Option::is_none")]
pub audience_id: Option<String>,
#[serde(rename = "placements", skip_serializing_if = "Option::is_none")]
pub placements: Option<Box<models::CtwaAdRequestBodyPlacements>>,
/// Meta's Advantage+ audience expansion. `0` (default) keeps targeting strict; `1` lets Meta expand beyond the supplied targeting when its delivery system finds better matches. Always sent on CREATE (Meta requires it).
#[serde(rename = "advantageAudience", skip_serializing_if = "Option::is_none")]
pub advantage_audience: Option<AdvantageAudience>,
/// Defaults to `OUTCOME_ENGAGEMENT`. `OUTCOME_SALES` and `OUTCOME_LEADS` require additional account configuration (Dataset linked to the WABA for sales) and may be rejected by Meta if missing.
#[serde(rename = "objective", skip_serializing_if = "Option::is_none")]
pub objective: Option<Objective>,
/// Defaults to `ACTIVE`. `PAUSED` pauses only the top-most object this call creates: the new campaign (ad set and ads switched on), or, with `adSetId`, the new ads themselves.
#[serde(rename = "status", skip_serializing_if = "Option::is_none")]
pub status: Option<Status>,
/// Campaign-level status, same semantics as `POST /v1/ads/create`. Defaults to `status`. `PAUSED` holds the new campaign off while the ad set and ads switch on (one resume call brings the whole hierarchy live); `ACTIVE` with `status: PAUSED` switches the campaign on and pauses the new ad set instead. Only meaningful when a new campaign is being created; rejected with a 400 alongside `adSetId` (the attach shape reuses an existing campaign).
#[serde(rename = "campaignStatus", skip_serializing_if = "Option::is_none")]
pub campaign_status: Option<CampaignStatus>,
/// Meta bid strategy applied to the shared ad set. Defaults to `LOWEST_COST_WITHOUT_CAP` (auto-bid) when omitted. `LOWEST_COST_WITH_BID_CAP` and `COST_CAP` require `bidAmount`. `LOWEST_COST_WITH_MIN_ROAS` requires `roasAverageFloor`. CTWA's `optimization_goal` is fixed to `CONVERSATIONS`, but the bid strategy is independent.
#[serde(rename = "bidStrategy", skip_serializing_if = "Option::is_none")]
pub bid_strategy: Option<BidStrategy>,
/// Whole currency units (e.g. `5` = $5.00 on a USD account). Required when `bidStrategy` is `LOWEST_COST_WITH_BID_CAP` or `COST_CAP`; rejected otherwise.
#[serde(rename = "bidAmount", skip_serializing_if = "Option::is_none")]
pub bid_amount: Option<f64>,
/// Decimal ROAS multiplier (e.g. `2.0` = 2.0× ROAS floor). Required when `bidStrategy` is `LOWEST_COST_WITH_MIN_ROAS`; rejected otherwise. Meta enforces its own upper bound server-side.
#[serde(rename = "roasAverageFloor", skip_serializing_if = "Option::is_none")]
pub roas_average_floor: Option<f64>,
/// Legal entity that benefits from the ad. Required when targeting EU users (EU DSA, Article 26). Optional if the ad account has a default beneficiary: set it once via `PATCH /v1/ads/accounts` or in Meta Ads Manager, and Meta fills it in whenever the field is omitted.
#[serde(rename = "dsaBeneficiary", skip_serializing_if = "Option::is_none")]
pub dsa_beneficiary: Option<String>,
/// Legal entity that pays for the ad. Can differ from `dsaBeneficiary` (for example, an agency paying for a client's ads). Same rules as `dsaBeneficiary`: required for EU targeting unless the ad account has a default payor.
#[serde(rename = "dsaPayor", skip_serializing_if = "Option::is_none")]
pub dsa_payor: Option<String>,
/// Meta only. Regional regulation categories required when the ad set targets certain countries (e.g. BRAZIL_REGULATION, SINGAPORE_UNIVERSAL, TAIWAN_UNIVERSAL, THAILAND_UNIVERSAL, AUSTRALIA_FINSERV, INDIA_FINSERV, TAIWAN_FINSERV). Forwarded to the ad set.
#[serde(
rename = "regionalRegulatedCategories",
skip_serializing_if = "Option::is_none"
)]
pub regional_regulated_categories: Option<Vec<String>>,
/// Meta only. Beneficiary/payer entity IDs required alongside regionalRegulatedCategories. Values are numeric IDs from the advertiser's Meta verification/authorization setup. Keys depend on the declared category: BRAZIL_REGULATION and THAILAND_UNIVERSAL use universal_beneficiary / universal_payer; SINGAPORE_UNIVERSAL uses singapore_universal_beneficiary / singapore_universal_payer; TAIWAN_UNIVERSAL uses taiwan_universal_beneficiary / taiwan_universal_payer; TAIWAN_FINSERV uses taiwan_finserv_beneficiary / taiwan_finserv_payer; AUSTRALIA_FINSERV uses australia_finserv_beneficiary / australia_finserv_payer; INDIA_FINSERV uses india_finserv_beneficiary / india_finserv_payer. Both beneficiary and payer must be included. If omitted and the advertiser has set defaults in Meta Ads Manager advertising settings, Meta auto-fills them.
#[serde(
rename = "regionalRegulationIdentities",
skip_serializing_if = "Option::is_none"
)]
pub regional_regulation_identities: Option<std::collections::HashMap<String, i32>>,
/// E.164 number the CALL_NOW CTA dials (e.g. +34600111222).
#[serde(rename = "phoneNumber")]
pub phone_number: String,
/// Website shown as the creative's link. Required: Meta rejects tel: as link_data.link; the phone number rides only the CTA.
#[serde(rename = "linkUrl")]
pub link_url: String,
}
impl CreateCallAdRequest {
pub fn new(
account_id: String,
ad_account_id: String,
name: String,
phone_number: String,
link_url: String,
) -> CreateCallAdRequest {
CreateCallAdRequest {
creative_features: None,
tracking: None,
account_id,
ad_account_id,
name,
campaign_name: None,
ad_set_name: None,
platform_post_id: None,
existing_post_id: None,
object_story_id: None,
page_id: None,
whatsapp_phone_number: None,
headline: None,
body: None,
image_url: None,
video: None,
welcome_message: None,
creatives: None,
ad_set_id: None,
budget_amount: None,
budget_type: None,
currency: None,
end_date: None,
countries: None,
cities: None,
regions: None,
zips: None,
metros: None,
country_groups: None,
custom_locations: None,
age_min: None,
age_max: None,
interests: None,
audience_id: None,
placements: None,
advantage_audience: None,
objective: None,
status: None,
campaign_status: None,
bid_strategy: None,
bid_amount: None,
roas_average_floor: None,
dsa_beneficiary: None,
dsa_payor: None,
regional_regulated_categories: None,
regional_regulation_identities: None,
phone_number,
link_url,
}
}
}
/// Meta enhancement settings for single or attached ads, and defaults for creatives[]. An item replaces the entire map, including with an empty object.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum CreativeFeatures {
#[serde(rename = "OPT_IN")]
OptIn,
#[serde(rename = "OPT_OUT")]
OptOut,
}
impl Default for CreativeFeatures {
fn default() -> CreativeFeatures {
Self::OptIn
}
}
/// Required unless `adSetId` is set.
#[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
}
}
/// 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
}
}
/// Meta's Advantage+ audience expansion. `0` (default) keeps targeting strict; `1` lets Meta expand beyond the supplied targeting when its delivery system finds better matches. Always sent on CREATE (Meta requires it).
#[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
}
}
/// Defaults to `OUTCOME_ENGAGEMENT`. `OUTCOME_SALES` and `OUTCOME_LEADS` require additional account configuration (Dataset linked to the WABA for sales) and may be rejected by Meta if missing.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Objective {
#[serde(rename = "OUTCOME_ENGAGEMENT")]
OutcomeEngagement,
#[serde(rename = "OUTCOME_SALES")]
OutcomeSales,
#[serde(rename = "OUTCOME_LEADS")]
OutcomeLeads,
}
impl Default for Objective {
fn default() -> Objective {
Self::OutcomeEngagement
}
}
/// Defaults to `ACTIVE`. `PAUSED` pauses only the top-most object this call creates: the new campaign (ad set and ads switched on), or, with `adSetId`, the new ads themselves.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Status {
#[serde(rename = "ACTIVE")]
Active,
#[serde(rename = "PAUSED")]
Paused,
}
impl Default for Status {
fn default() -> Status {
Self::Active
}
}
/// Campaign-level status, same semantics as `POST /v1/ads/create`. Defaults to `status`. `PAUSED` holds the new campaign off while the ad set and ads switch on (one resume call brings the whole hierarchy live); `ACTIVE` with `status: PAUSED` switches the campaign on and pauses the new ad set instead. Only meaningful when a new campaign is being created; rejected with a 400 alongside `adSetId` (the attach shape reuses an existing campaign).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum CampaignStatus {
#[serde(rename = "ACTIVE")]
Active,
#[serde(rename = "PAUSED")]
Paused,
}
impl Default for CampaignStatus {
fn default() -> CampaignStatus {
Self::Active
}
}
/// Meta bid strategy applied to the shared ad set. Defaults to `LOWEST_COST_WITHOUT_CAP` (auto-bid) when omitted. `LOWEST_COST_WITH_BID_CAP` and `COST_CAP` require `bidAmount`. `LOWEST_COST_WITH_MIN_ROAS` requires `roasAverageFloor`. CTWA's `optimization_goal` is fixed to `CONVERSATIONS`, but the bid strategy is independent.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum BidStrategy {
#[serde(rename = "LOWEST_COST_WITHOUT_CAP")]
LowestCostWithoutCap,
#[serde(rename = "LOWEST_COST_WITH_BID_CAP")]
LowestCostWithBidCap,
#[serde(rename = "COST_CAP")]
CostCap,
#[serde(rename = "LOWEST_COST_WITH_MIN_ROAS")]
LowestCostWithMinRoas,
}
impl Default for BidStrategy {
fn default() -> BidStrategy {
Self::LowestCostWithoutCap
}
}