/*
* 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.168.0
* Contact: support@zernio.com
* Generated by: https://openapi-generator.tech
*/
use crate::models;
use serde::{Deserialize, Serialize};
/// CtwaAdRequestBody : In addition to the `required` list, the request must use EXACTLY ONE of the two shapes: - Single-creative: `headline`, `body`, and one of `imageUrl` / `video`, OR `platformPostId` / `objectStoryId` to reuse an organic post. On POST /v1/ads/messaging, `placementAssets` can replace `imageUrl` / `video`. - Multi-creative: a non-empty `creatives[]` array. Top-level creative fields must NOT be set on this shape. Existing post references work on messaging and CTWA only (not call ads). They cannot be combined with each other or with headline, body, imageUrl or video. `welcomeMessage` works on them (it lives on the ad, not the post). No media is uploaded and the organic post is retained. Fresh creatives still require headline, body, and image or video. The route enforces this at the Zod boundary; OpenAPI's `required` cannot express the OR cleanly. Campaign, ad set and targeting fields match POST /v1/ads/create on Meta and run through the same builders: the full targeting set (including `rawTargeting`, `languages`, `gender`, exclusions and `savedTargetingId`), `budgetLevel` (campaign budget), `startDate` / `endDate` in the ad account timezone, and `existingCampaignId` to add a new ad set to a campaign you already have.
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct CtwaAdRequestBody {
/// 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 run as the media owner (resolved from the media on a Meta ads business-login connection, so no Instagram connection is needed). 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>,
/// Link description, independent of `headline` and `body` (Meta's `link_data.description`, `video_data.link_description` on video, and the shared description of a `placementAssets` feed). Meta shows it mainly on Facebook Feed placements, under the headline, when there is room; Instagram, Stories, Reels and Messenger placements do not display it. Also accepted per entry in `creatives[]`. Not allowed with an existing post creative.
#[serde(rename = "description", skip_serializing_if = "Option::is_none")]
pub description: 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`, `budgetLevel`, `startDate`, `endDate`, `objective`, `campaignStatus`, `existingCampaignId`, the special ad category fields and every targeting field except `ageMin`, `ageMax`, `placements` and `advantageAudience` 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>,
/// Create the new messaging ad set (and its ads) under this EXISTING Meta campaign instead of a new one, e.g. several audience ad sets under one campaign. The campaign's objective must be OUTCOME_ENGAGEMENT, OUTCOME_SALES or OUTCOME_LEADS (400 otherwise). If the campaign has a campaign budget, omit `budgetAmount` and `budgetType` (400 if sent); otherwise they are required and land on the new ad set. `objective`, `campaignName`, `campaignStatus`, `budgetLevel`, `specialAdCategories`, `specialAdCategoryCountry` and `adSetId` are rejected alongside it. To add ads to an existing ad set instead, use `adSetId`.
#[serde(rename = "existingCampaignId", skip_serializing_if = "Option::is_none")]
pub existing_campaign_id: Option<String>,
/// Where the budget lives. `adset` (default) puts it on the new ad set. `campaign` creates an Advantage campaign budget (CBO): the budget and bid strategy sit on the campaign and the ad set inherits them, same as POST /v1/ads/create. Not allowed with `adSetId` or `existingCampaignId`.
#[serde(rename = "budgetLevel", skip_serializing_if = "Option::is_none")]
pub budget_level: Option<BudgetLevel>,
/// 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 (the ad set owns it) or `existingCampaignId` names a campaign with a campaign budget.
#[serde(rename = "budgetAmount", skip_serializing_if = "Option::is_none")]
pub budget_amount: Option<f64>,
/// Required unless `adSetId` is set or `existingCampaignId` names a campaign with a campaign budget. `lifetime` requires `endDate`.
#[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>,
/// When the ad set starts delivering. ISO 8601 date or date-time. A value with an offset (`2027-01-15T10:00:00+01:00`, `...Z`) is used as is; one without an offset (`2027-01-15T10:00:00`) is read in the ad account's timezone, and a date-only value starts at 00:00 local. Defaults to now.
#[serde(rename = "startDate", skip_serializing_if = "Option::is_none")]
pub start_date: Option<String>,
/// ISO 8601 date or date-time, read like `startDate`; a date-only value ends at 23:59:59 local. 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>>,
/// Restrict the audience by gender (Meta `genders`). Omit or send all for everyone; all is ignored in adSetId attach mode. Stored on the ad and read back in `targeting.gender`.
#[serde(rename = "gender", skip_serializing_if = "Option::is_none")]
pub gender: Option<Gender>,
/// Audience languages (Meta `locales`). A bare ISO 639-1 code targets all regional variants (\"en\" = all English), a region-qualified code a specific one (\"en_GB\", \"pt_BR\"); unknown codes are rejected.
#[serde(rename = "languages", skip_serializing_if = "Option::is_none")]
pub languages: Option<Vec<String>>,
/// Meta place keys (from GET /v1/ads/targeting/search).
#[serde(rename = "places", skip_serializing_if = "Option::is_none")]
pub places: Option<Vec<models::CtwaAdRequestBodyPlacesInner>>,
/// Meta neighborhood keys (from GET /v1/ads/targeting/search).
#[serde(rename = "neighborhoods", skip_serializing_if = "Option::is_none")]
pub neighborhoods: Option<Vec<models::CtwaAdRequestBodyPlacesInner>>,
/// Geo to exclude, same shape as POST /v1/ads/create (countries, countryGroups, regions, cities, zips, places, neighborhoods, customLocations).
#[serde(rename = "excludedLocations", skip_serializing_if = "Option::is_none")]
pub excluded_locations: Option<std::collections::HashMap<String, serde_json::Value>>,
/// Meta behavior ids. Each dimension is its own flexible_spec entry: OR within, AND across.
#[serde(rename = "behaviors", skip_serializing_if = "Option::is_none")]
pub behaviors: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
#[serde(rename = "workPositions", skip_serializing_if = "Option::is_none")]
pub work_positions: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
#[serde(rename = "workEmployers", skip_serializing_if = "Option::is_none")]
pub work_employers: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
#[serde(rename = "workIndustries", skip_serializing_if = "Option::is_none")]
pub work_industries: Option<Vec<models::CreateStandaloneAdRequestBehaviorsInner>>,
/// Normalized household-income tier, same as POST /v1/ads/create. Incompatible with housing, employment and credit specialAdCategories.
#[serde(rename = "incomeTier", skip_serializing_if = "Option::is_none")]
pub income_tier: Option<IncomeTier>,
/// Meta `user_os`, e.g. [\"iOS_ver_14.0_and_above\"].
#[serde(rename = "userOs", skip_serializing_if = "Option::is_none")]
pub user_os: Option<Vec<String>>,
/// Meta `user_device`.
#[serde(rename = "userDevice", skip_serializing_if = "Option::is_none")]
pub user_device: Option<Vec<String>>,
/// Custom or lookalike audience ids to include.
#[serde(rename = "audienceInclude", skip_serializing_if = "Option::is_none")]
pub audience_include: Option<Vec<String>>,
/// Custom or lookalike audience ids to exclude.
#[serde(rename = "audienceExclude", skip_serializing_if = "Option::is_none")]
pub audience_exclude: Option<Vec<String>>,
/// ID of a saved_targeting audience (POST /v1/ads/audiences), expanded as the base targeting. Precedence: savedTargetingId, then `targeting`, then the flat fields.
#[serde(rename = "savedTargetingId", skip_serializing_if = "Option::is_none")]
pub saved_targeting_id: Option<String>,
/// Nested targeting object, same contract as POST /v1/ads/create and boost. Flat fields win per key.
#[serde(rename = "targeting", skip_serializing_if = "Option::is_none")]
pub targeting: Option<Box<models::TargetingSpec>>,
/// Meta targeting spec sent as the BASE layer of the ad set's `targeting`, exactly as POST /v1/ads/create does: use it for anything the flat fields cannot express, such as a layered `flexible_spec` (entries AND together, ids inside one entry OR). Flat fields you also send are layered on top and win per key. With rawTargeting present the US geo and `advantage_audience: 0` defaults are not injected, so include `targeting_automation` in it (or send `advantageAudience`), as Meta requires it on create.
#[serde(rename = "rawTargeting", skip_serializing_if = "Option::is_none")]
pub raw_targeting: Option<std::collections::HashMap<String, serde_json::Value>>,
/// Meta special ad categories on the new campaign.
#[serde(
rename = "specialAdCategories",
skip_serializing_if = "Option::is_none"
)]
pub special_ad_categories: Option<Vec<SpecialAdCategories>>,
/// Countries the special ad category applies to. Requires specialAdCategories.
#[serde(
rename = "specialAdCategoryCountry",
skip_serializing_if = "Option::is_none"
)]
pub special_ad_category_country: Option<Vec<String>>,
/// 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>>,
}
impl CtwaAdRequestBody {
/// In addition to the `required` list, the request must use EXACTLY ONE of the two shapes: - Single-creative: `headline`, `body`, and one of `imageUrl` / `video`, OR `platformPostId` / `objectStoryId` to reuse an organic post. On POST /v1/ads/messaging, `placementAssets` can replace `imageUrl` / `video`. - Multi-creative: a non-empty `creatives[]` array. Top-level creative fields must NOT be set on this shape. Existing post references work on messaging and CTWA only (not call ads). They cannot be combined with each other or with headline, body, imageUrl or video. `welcomeMessage` works on them (it lives on the ad, not the post). No media is uploaded and the organic post is retained. Fresh creatives still require headline, body, and image or video. The route enforces this at the Zod boundary; OpenAPI's `required` cannot express the OR cleanly. Campaign, ad set and targeting fields match POST /v1/ads/create on Meta and run through the same builders: the full targeting set (including `rawTargeting`, `languages`, `gender`, exclusions and `savedTargetingId`), `budgetLevel` (campaign budget), `startDate` / `endDate` in the ad account timezone, and `existingCampaignId` to add a new ad set to a campaign you already have.
pub fn new(account_id: String, ad_account_id: String, name: String) -> CtwaAdRequestBody {
CtwaAdRequestBody {
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,
description: None,
image_url: None,
video: None,
welcome_message: None,
creatives: None,
ad_set_id: None,
existing_campaign_id: None,
budget_level: None,
budget_amount: None,
budget_type: None,
currency: None,
start_date: 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,
gender: None,
languages: None,
places: None,
neighborhoods: None,
excluded_locations: None,
behaviors: None,
work_positions: None,
work_employers: None,
work_industries: None,
income_tier: None,
user_os: None,
user_device: None,
audience_include: None,
audience_exclude: None,
saved_targeting_id: None,
targeting: None,
raw_targeting: None,
special_ad_categories: None,
special_ad_category_country: 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,
}
}
}
/// 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
}
}
/// Where the budget lives. `adset` (default) puts it on the new ad set. `campaign` creates an Advantage campaign budget (CBO): the budget and bid strategy sit on the campaign and the ad set inherits them, same as POST /v1/ads/create. Not allowed with `adSetId` or `existingCampaignId`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum BudgetLevel {
#[serde(rename = "adset")]
Adset,
#[serde(rename = "campaign")]
Campaign,
}
impl Default for BudgetLevel {
fn default() -> BudgetLevel {
Self::Adset
}
}
/// Required unless `adSetId` is set or `existingCampaignId` names a campaign with a campaign budget. `lifetime` requires `endDate`.
#[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
}
}
/// Restrict the audience by gender (Meta `genders`). Omit or send all for everyone; all is ignored in adSetId attach mode. Stored on the ad and read back in `targeting.gender`.
#[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, same as POST /v1/ads/create. Incompatible with housing, employment and credit specialAdCategories.
#[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
}
}
/// Meta special ad categories on the new campaign.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum SpecialAdCategories {
#[serde(rename = "HOUSING")]
Housing,
#[serde(rename = "EMPLOYMENT")]
Employment,
#[serde(rename = "CREDIT")]
Credit,
#[serde(rename = "ISSUES_ELECTIONS_POLITICS")]
IssuesElectionsPolitics,
#[serde(rename = "FINANCIAL_PRODUCTS_SERVICES")]
FinancialProductsServices,
#[serde(rename = "ONLINE_GAMBLING_AND_GAMING")]
OnlineGamblingAndGaming,
}
impl Default for SpecialAdCategories {
fn default() -> SpecialAdCategories {
Self::Housing
}
}
/// 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
}
}