late-sdk 0.0.632 → 0.0.634

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e4989f6f565e38c5826d06bcc2f668238a6c2ce1cdcb3fe74a35f7b46a30927
4
- data.tar.gz: 472eda0eaab9e6106f9b499ad0daf32539b2b8034ccb4c6f3c7fd79508b86461
3
+ metadata.gz: bdf9665c2894873f1eab5aca327b773fbf305b3f17cf4c7c9e90e4df60d179b7
4
+ data.tar.gz: d4b502e2d9174810d704c8f07f9d33e6427f760523fbff07e2ee70dd46a8d010
5
5
  SHA512:
6
- metadata.gz: 0fb0359a7e6bb44e7471d53507f31331eaae73ea1c41c8f488d58f8e298de8be6fe3943a2bafc1ff69897c0dc15a22b3cc296f86ba50f556a8377229c5694cc8
7
- data.tar.gz: 36e3df320c8ec022e55ea73aeb05ece15595b966700c3a3a68856236b1f8408379625e1a523430361981c3557665911dac7516fa3d54ce5484f14ff1474008ca
6
+ metadata.gz: 972c791b8b7bea42860ac9dc58bff7516ae144ddd8a5406d2fcac7685f9af80caeb0a09dfacd5ecd07d17c75cc0a3452c195481197dc295bd9fe7764ea374dcb
7
+ data.tar.gz: 604d9c38a48d0410d3407a4262c89748ebe6f757b6099c635a47e20dfb14afe44e4f6a6c200ea8a71aadf6d9020bf41aa9ae5ffd7bd3d43c20005b4f3fe0ad97
@@ -387,7 +387,7 @@ end
387
387
 
388
388
  Delete a campaign
389
389
 
390
- Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime.
390
+ Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so it is invisible to `/v1/ads/tree` and this endpoint would 404. That state is produced by the two-step create flow (campaign, then ads via `existingCampaignId`) whenever Meta rejects the ad step. To delete such a shell, send `accountId` in the body: we skip the local lookup entirely and forward the delete to Meta. `accountId` is ignored when the campaign does have ads.
391
391
 
392
392
  ### Examples
393
393
 
@@ -1020,6 +1020,7 @@ end
1020
1020
 
1021
1021
  api_instance = Zernio::AdCampaignsApi.new
1022
1022
  opts = {
1023
+ include_empty: true, # Boolean | Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here — the state the two-step create (campaign, then ads via `existingCampaignId`) leaves behind whenever Meta rejects the ad step. Set true to list those too, with `adCount: 0` and zeroed metrics. Requires `accountId` and `adAccountId`, since an empty campaign has no ad row to resolve a token or ad account from.
1023
1024
  page: 56, # Integer | Page number (1-based)
1024
1025
  limit: 56, # Integer |
1025
1026
  source: 'zernio', # String | `all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that.
@@ -1064,6 +1065,7 @@ end
1064
1065
 
1065
1066
  | Name | Type | Description | Notes |
1066
1067
  | ---- | ---- | ----------- | ----- |
1068
+ | **include_empty** | **Boolean** | Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here — the state the two-step create (campaign, then ads via `existingCampaignId`) leaves behind whenever Meta rejects the ad step. Set true to list those too, with `adCount: 0` and zeroed metrics. Requires `accountId` and `adAccountId`, since an empty campaign has no ad row to resolve a token or ad account from. | [optional] |
1067
1069
  | **page** | **Integer** | Page number (1-based) | [optional][default to 1] |
1068
1070
  | **limit** | **Integer** | | [optional][default to 20] |
1069
1071
  | **source** | **String** | `all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that. | [optional][default to 'all'] |
@@ -1357,7 +1359,7 @@ end
1357
1359
 
1358
1360
  Update a campaign
1359
1361
 
1360
- Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1362
+ Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so this would 404 even though it exists on Meta. Send `accountId` in the body to skip the local lookup and forward the update to Meta. The response then carries `updated: 0`, since there are no local rows to mirror onto. `accountId` is ignored when the campaign does have ads. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1361
1363
 
1362
1364
  ### Examples
1363
1365
 
@@ -9,10 +9,10 @@
9
9
  | **name** | **String** | | |
10
10
  | **goal** | **String** | Mapped to the ODAX objective (same mapping as POST /v1/ads/create). | |
11
11
  | **special_ad_categories** | **Array<String>** | | [optional] |
12
- | **budget_amount** | **Float** | Campaign-level (CBO) budget in whole currency units. Requires budgetType. | [optional] |
12
+ | **budget_amount** | **Float** | Campaign-level (CBO) budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Requires budgetType. | [optional] |
13
13
  | **budget_type** | **String** | | [optional] |
14
14
  | **status** | **String** | | [optional][default to 'PAUSED'] |
15
- | **bid_strategy** | **String** | Campaign bid strategy. Meta puts `bid_strategy` where the budget lives, so this applies only alongside a campaign budget (CBO). Previously settable only via `PUT /v1/ads/campaigns/{campaignId}`. | [optional] |
15
+ | **bid_strategy** | **String** | Campaign bid strategy. Meta stores `bid_strategy` alongside the budget, so this REQUIRES `budgetAmount` + `budgetType` on the same request; sending it without a campaign budget is a 400. A campaign carrying a strategy without its `bid_amount` makes every ad set created under it fail with an error that names the ad set (code 100, subcode 1815857), so the bad state is rejected up front rather than accepted. To bid at ad-set level, set the strategy there instead. | [optional] |
16
16
  | **bid_amount** | **Float** | Whole currency units (USD: 5 = $5.00). Required for LOWEST_COST_WITH_BID_CAP and COST_CAP; ignored otherwise. | [optional] |
17
17
  | **roas_average_floor** | **Float** | Decimal ROAS multiplier (2.0 = 2.0x). Required for LOWEST_COST_WITH_MIN_ROAS. | [optional] |
18
18
 
@@ -18,7 +18,7 @@
18
18
  | **rf_prediction_id** | **String** | Meta only. The RESERVED prediction id the R&F ad set runs on (reserving mints a new id — pass that one). Requires buyingType RESERVED. | [optional] |
19
19
  | **creative_features** | **Hash<String, String>** | Meta only. Advantage+ creative enhancements: a partial map of Meta creative feature keys (snake_case, e.g. enhance_cta, image_brightness_and_contrast, text_optimizations) to enroll status, forwarded as degrees_of_freedom_spec.creative_features_spec. Meta validates the keys; unspecified features default to OPT_OUT. The legacy standard_enhancements bundle is deprecated by Meta and rejected. | [optional] |
20
20
  | **validate_only** | **Boolean** | Meta only, single standalone shape only (no creatives[], adSetId, or RESERVED). Dry-run: each node runs Meta's execution_options validate_only and NOTHING is created or persisted. Children need real parents, so a fresh tree validates the campaign + creative (the ad set needs its campaign to exist — pass existingCampaignId to validate it too; the ad itself is never validatable pre-create). A Meta validation failure returns the 400 verbatim; success returns 200 with per-node results instead of an ad. | [optional] |
21
- | **budget_amount** | **Float** | Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType). | [optional] |
21
+ | **budget_amount** | **Float** | Budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType). | [optional] |
22
22
  | **budget_type** | **String** | Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads accepts lifetime only (no daily-budget concept on the platform); sending daily returns 422. OpenAI Ads lifetime budgets require `endDate` to give the lifetime cap a spend window. | [optional] |
23
23
  | **status** | **String** | Meta and TikTok. Publish state of the created entities. Omitted or ACTIVE publishes live (default, back-compat); PAUSED creates them paused and skips activation, so you can review before they spend. On TikTok the whole campaign > ad group > ad hierarchy stays paused. | [optional] |
24
24
  | **budget_level** | **String** | Meta only. Where the budget lives, which selects the Meta budget model: - `adset` (default): ABO (Ad-set Budget Optimization). The budget is set on the ad set. This is the back-compatible behaviour — omit this field to keep it. - `campaign`: CBO (Campaign Budget Optimization / Advantage Campaign Budget). The budget AND `bidStrategy` are set on the CAMPAIGN, and Meta distributes spend across ad sets automatically. Meta requires the budget at exactly one level, never both. Non-Meta platforms ignore this field. Ignored on the attach shape (`adSetId`), which inherits the existing budget. | [optional][default to 'adset'] |
@@ -63,8 +63,8 @@
63
63
  | **instagram_account_id** | **String** | Meta only. Override the Instagram account the ad is delivered as — pass an Instagram Business Account ID (e.g. 17841...), mapped to the creative's `instagram_user_id`. When omitted we auto-resolve the IG account linked to the connected Facebook Page (the existing default). Useful when a Page has more than one eligible IG account. | [optional] |
64
64
  | **dynamic_creative** | [**CreateStandaloneAdRequestDynamicCreative**](CreateStandaloneAdRequestDynamicCreative.md) | | [optional] |
65
65
  | **carousel_cards** | [**Array<CreateStandaloneAdRequestCarouselCardsInner>**](CreateStandaloneAdRequestCarouselCardsInner.md) | Meta only. Hand-built carousel: 2-10 authored cards in DETERMINISTIC order, mapped to the creative's `link_data.child_attachments`. Unlike `dynamicCreative`, you control the card order and per-card copy/link. Requires top-level `body`, `linkUrl` and `callToAction`. Mutually exclusive with `imageUrl`/`video`, `creatives[]`, `dynamicCreative`, `placementAssets`, `existingCreativeId`, `adSetId`, `leadGenFormId` and goal `catalog_sales`. | [optional] |
66
- | **default_locale** | **String** | Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own. | [optional] |
67
- | **translations** | [**Array<CreateStandaloneAdRequestTranslationsInner>**](CreateStandaloneAdRequestTranslationsInner.md) | Meta only. Multi-language ads (Dynamic Language Optimization): ONE ad carrying per-locale copy and, optionally, per-locale media — the \"Languages\" toggle in Ads Manager. Keeps social proof (likes/comments/shares) on a SINGLE post instead of splitting it across one ad per language. The ad's top-level copy and media are the DEFAULT every unlisted locale falls back to, and a variant inherits any field it omits, so send only what differs per language. Media shared across languages is uploaded once. Mutually exclusive with `dynamicCreative`, `placementAssets`, `carouselCards` and `existingCreativeId` — Meta allows one `asset_feed_spec` shape per creative. | [optional] |
66
+ | **default_locale** | **String** | Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own. Must NOT also appear as an entry in `translations`. | [optional] |
67
+ | **translations** | [**Array<CreateStandaloneAdRequestTranslationsInner>**](CreateStandaloneAdRequestTranslationsInner.md) | Meta only. Multi-language ads (Dynamic Language Optimization): ONE ad carrying per-locale copy and, optionally, per-locale media — the \"Languages\" toggle in Ads Manager. Keeps social proof (likes/comments/shares) on a SINGLE post instead of splitting it across one ad per language. The ad's top-level copy is the DEFAULT shown to every locale you do NOT list, and it counts as one of the language variants. IMPORTANT, and the opposite of what you might expect: text does NOT inherit. Every entry must carry its own `headline`, `body` AND `description`, and all of them must be DISTINCT from each other and from the ad's top-level copy. Meta deduplicates identical strings inside the asset feed, so two locales sharing a string collapse into one asset and the create fails with a misleading \"Too few ... texts provided in asset creation\" (subcode 1885817) that names a field which is actually present. We validate this before calling Meta and return a 400 naming the offending locale and field. `description` is therefore effectively required on the ad whenever `translations` is present, even though it is optional otherwise. Do NOT list `defaultLocale` inside `translations`: Meta rejects the duplicate with \"The language asset feed includes an unsupported targeting field\" (subcode 1885985). Media DOES inherit and is uploaded once when shared. Note that Meta enforces Dynamic Creative image dimensions on language feeds, so an `imageUrl` that works on a normal ad may be rejected with \"The following images have invalid dimensions for Dynamic Creative\" (subcode 1885558). Video is not affected. Mutually exclusive with `dynamicCreative`, `placementAssets`, `carouselCards` and `existingCreativeId` — Meta allows one `asset_feed_spec` shape per creative. | [optional] |
68
68
  | **placement_assets** | [**CreateStandaloneAdRequestPlacementAssets**](CreateStandaloneAdRequestPlacementAssets.md) | | [optional] |
69
69
  | **audience_id** | **String** | Custom audience ID for targeting | [optional] |
70
70
  | **campaign_type** | **String** | Google only | [optional][default to 'display'] |
@@ -5,9 +5,9 @@
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
7
  | **locale** | **String** | Language code, resolved to Meta's numeric locale id. Bare codes target the '(All)' umbrella (`es` = every Spanish variant); region-qualified codes target the variant (`pt_BR`, `en_GB`). | |
8
- | **headline** | **String** | Headline for this language. Inherits the top-level `headline` when omitted. | [optional] |
9
- | **body** | **String** | Primary text for this language. Inherits the top-level `body` when omitted. | [optional] |
10
- | **description** | **String** | Link description for this language. Inherits the top-level `description` when omitted. | [optional] |
8
+ | **headline** | **String** | Headline for this language. REQUIRED, and must differ from every other locale and from the ad's top-level headline. | |
9
+ | **body** | **String** | Primary text for this language. REQUIRED, and must differ from every other locale and from the ad's top-level body. | |
10
+ | **description** | **String** | Link description for this language. REQUIRED, and must differ from every other locale and from the ad's top-level description. | |
11
11
  | **image_url** | **String** | Image for this language. Inherits the ad's `imageUrl` when omitted. The feed is all-image OR all-video. | [optional] |
12
12
  | **video_url** | **String** | Video for this language. Inherits the ad's `video.url` when omitted. The feed is all-image OR all-video. | [optional] |
13
13
  | **thumbnail_url** | **String** | Poster frame for this language's video. | [optional] |
@@ -5,6 +5,7 @@
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
7
  | **platform** | **String** | | |
8
+ | **account_id** | **String** | Zernio SocialAccount id owning the ad account. Required only to delete an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from. | [optional] |
8
9
 
9
10
  ## Example
10
11
 
@@ -12,7 +13,8 @@
12
13
  require 'zernio-sdk'
13
14
 
14
15
  instance = Zernio::DeleteAdCampaignRequest.new(
15
- platform: null
16
+ platform: null,
17
+ account_id: null
16
18
  )
17
19
  ```
18
20
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
+ | **account_id** | **String** | Zernio SocialAccount id owning the ad account. Required only to update an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from. | [optional] |
7
8
  | **platform** | **String** | | |
8
9
  | **budget** | [**UpdateAdCampaignRequestBudget**](UpdateAdCampaignRequestBudget.md) | | [optional] |
9
10
  | **bid_strategy** | [**BidStrategy**](BidStrategy.md) | Campaign-level default. Ad sets inherit this unless they override. | [optional] |
@@ -16,6 +17,7 @@
16
17
  require 'zernio-sdk'
17
18
 
18
19
  instance = Zernio::UpdateAdCampaignRequest.new(
20
+ account_id: null,
19
21
  platform: null,
20
22
  budget: null,
21
23
  bid_strategy: null,
@@ -369,7 +369,7 @@ module Zernio
369
369
  end
370
370
 
371
371
  # Delete a campaign
372
- # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime.
372
+ # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so it is invisible to `/v1/ads/tree` and this endpoint would 404. That state is produced by the two-step create flow (campaign, then ads via `existingCampaignId`) whenever Meta rejects the ad step. To delete such a shell, send `accountId` in the body: we skip the local lookup entirely and forward the delete to Meta. `accountId` is ignored when the campaign does have ads.
373
373
  # @param campaign_id [String] Platform campaign ID
374
374
  # @param delete_ad_campaign_request [DeleteAdCampaignRequest]
375
375
  # @param [Hash] opts the optional parameters
@@ -380,7 +380,7 @@ module Zernio
380
380
  end
381
381
 
382
382
  # Delete a campaign
383
- # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime.
383
+ # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked `status: cancelled`. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so it is invisible to `/v1/ads/tree` and this endpoint would 404. That state is produced by the two-step create flow (campaign, then ads via `existingCampaignId`) whenever Meta rejects the ad step. To delete such a shell, send `accountId` in the body: we skip the local lookup entirely and forward the delete to Meta. `accountId` is ignored when the campaign does have ads.
384
384
  # @param campaign_id [String] Platform campaign ID
385
385
  # @param delete_ad_campaign_request [DeleteAdCampaignRequest]
386
386
  # @param [Hash] opts the optional parameters
@@ -1034,6 +1034,7 @@ module Zernio
1034
1034
  # List campaigns
1035
1035
  # Returns campaigns as virtual aggregations over ad documents grouped by platform campaign ID. Metrics (spend, impressions, clicks, etc.) are summed across all ads in each campaign. Campaign status is derived from child ad statuses (active > pending_review > paused > error > completed > cancelled > rejected).
1036
1036
  # @param [Hash] opts the optional parameters
1037
+ # @option opts [Boolean] :include_empty Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here — the state the two-step create (campaign, then ads via `existingCampaignId`) leaves behind whenever Meta rejects the ad step. Set true to list those too, with `adCount: 0` and zeroed metrics. Requires `accountId` and `adAccountId`, since an empty campaign has no ad row to resolve a token or ad account from.
1037
1038
  # @option opts [Integer] :page Page number (1-based) (default to 1)
1038
1039
  # @option opts [Integer] :limit (default to 20)
1039
1040
  # @option opts [String] :source `all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that. (default to 'all')
@@ -1054,6 +1055,7 @@ module Zernio
1054
1055
  # List campaigns
1055
1056
  # Returns campaigns as virtual aggregations over ad documents grouped by platform campaign ID. Metrics (spend, impressions, clicks, etc.) are summed across all ads in each campaign. Campaign status is derived from child ad statuses (active > pending_review > paused > error > completed > cancelled > rejected).
1056
1057
  # @param [Hash] opts the optional parameters
1058
+ # @option opts [Boolean] :include_empty Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here — the state the two-step create (campaign, then ads via `existingCampaignId`) leaves behind whenever Meta rejects the ad step. Set true to list those too, with `adCount: 0` and zeroed metrics. Requires `accountId` and `adAccountId`, since an empty campaign has no ad row to resolve a token or ad account from.
1057
1059
  # @option opts [Integer] :page Page number (1-based) (default to 1)
1058
1060
  # @option opts [Integer] :limit (default to 20)
1059
1061
  # @option opts [String] :source `all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that. (default to 'all')
@@ -1095,6 +1097,7 @@ module Zernio
1095
1097
 
1096
1098
  # query parameters
1097
1099
  query_params = opts[:query_params] || {}
1100
+ query_params[:'includeEmpty'] = opts[:'include_empty'] if !opts[:'include_empty'].nil?
1098
1101
  query_params[:'page'] = opts[:'page'] if !opts[:'page'].nil?
1099
1102
  query_params[:'limit'] = opts[:'limit'] if !opts[:'limit'].nil?
1100
1103
  query_params[:'source'] = opts[:'source'] if !opts[:'source'].nil?
@@ -1452,7 +1455,7 @@ module Zernio
1452
1455
  end
1453
1456
 
1454
1457
  # Update a campaign
1455
- # Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1458
+ # Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so this would 404 even though it exists on Meta. Send `accountId` in the body to skip the local lookup and forward the update to Meta. The response then carries `updated: 0`, since there are no local rows to mirror onto. `accountId` is ignored when the campaign does have ads. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1456
1459
  # @param campaign_id [String] Platform campaign ID
1457
1460
  # @param update_ad_campaign_request [UpdateAdCampaignRequest]
1458
1461
  # @param [Hash] opts the optional parameters
@@ -1463,7 +1466,7 @@ module Zernio
1463
1466
  end
1464
1467
 
1465
1468
  # Update a campaign
1466
- # Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1469
+ # Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so this would 404 even though it exists on Meta. Send `accountId` in the body to skip the local lookup and forward the update to Meta. The response then carries `updated: 0`, since there are no local rows to mirror onto. `accountId` is ignored when the campaign does have ads. - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - `bidStrategy` sets the campaign-level default bid strategy. Per Meta's spec, `bid_amount` and `bid_constraints` do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - `platformSpecificData.spendCap` (Meta only) sets the campaign's lifetime spend cap, in the ad account's currency. Meta-only for now. Other platforms return 501 Not Implemented.
1467
1470
  # @param campaign_id [String] Platform campaign ID
1468
1471
  # @param update_ad_campaign_request [UpdateAdCampaignRequest]
1469
1472
  # @param [Hash] opts the optional parameters
@@ -28,14 +28,14 @@ module Zernio
28
28
 
29
29
  attr_accessor :special_ad_categories
30
30
 
31
- # Campaign-level (CBO) budget in whole currency units. Requires budgetType.
31
+ # Campaign-level (CBO) budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Requires budgetType.
32
32
  attr_accessor :budget_amount
33
33
 
34
34
  attr_accessor :budget_type
35
35
 
36
36
  attr_accessor :status
37
37
 
38
- # Campaign bid strategy. Meta puts `bid_strategy` where the budget lives, so this applies only alongside a campaign budget (CBO). Previously settable only via `PUT /v1/ads/campaigns/{campaignId}`.
38
+ # Campaign bid strategy. Meta stores `bid_strategy` alongside the budget, so this REQUIRES `budgetAmount` + `budgetType` on the same request; sending it without a campaign budget is a 400. A campaign carrying a strategy without its `bid_amount` makes every ad set created under it fail with an error that names the ad set (code 100, subcode 1815857), so the bad state is rejected up front rather than accepted. To bid at ad-set level, set the strategy there instead.
39
39
  attr_accessor :bid_strategy
40
40
 
41
41
  # Whole currency units (USD: 5 = $5.00). Required for LOWEST_COST_WITH_BID_CAP and COST_CAP; ignored otherwise.
@@ -53,7 +53,7 @@ module Zernio
53
53
  # Meta only, single standalone shape only (no creatives[], adSetId, or RESERVED). Dry-run: each node runs Meta's execution_options validate_only and NOTHING is created or persisted. Children need real parents, so a fresh tree validates the campaign + creative (the ad set needs its campaign to exist — pass existingCampaignId to validate it too; the ad itself is never validatable pre-create). A Meta validation failure returns the 400 verbatim; success returns 200 with per-node results instead of an ad.
54
54
  attr_accessor :validate_only
55
55
 
56
- # Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType).
56
+ # Budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType).
57
57
  attr_accessor :budget_amount
58
58
 
59
59
  # Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads accepts lifetime only (no daily-budget concept on the platform); sending daily returns 422. OpenAI Ads lifetime budgets require `endDate` to give the lifetime cap a spend window.
@@ -181,10 +181,10 @@ module Zernio
181
181
  # Meta only. Hand-built carousel: 2-10 authored cards in DETERMINISTIC order, mapped to the creative's `link_data.child_attachments`. Unlike `dynamicCreative`, you control the card order and per-card copy/link. Requires top-level `body`, `linkUrl` and `callToAction`. Mutually exclusive with `imageUrl`/`video`, `creatives[]`, `dynamicCreative`, `placementAssets`, `existingCreativeId`, `adSetId`, `leadGenFormId` and goal `catalog_sales`.
182
182
  attr_accessor :carousel_cards
183
183
 
184
- # Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own.
184
+ # Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own. Must NOT also appear as an entry in `translations`.
185
185
  attr_accessor :default_locale
186
186
 
187
- # Meta only. Multi-language ads (Dynamic Language Optimization): ONE ad carrying per-locale copy and, optionally, per-locale media — the \"Languages\" toggle in Ads Manager. Keeps social proof (likes/comments/shares) on a SINGLE post instead of splitting it across one ad per language. The ad's top-level copy and media are the DEFAULT every unlisted locale falls back to, and a variant inherits any field it omits, so send only what differs per language. Media shared across languages is uploaded once. Mutually exclusive with `dynamicCreative`, `placementAssets`, `carouselCards` and `existingCreativeId` — Meta allows one `asset_feed_spec` shape per creative.
187
+ # Meta only. Multi-language ads (Dynamic Language Optimization): ONE ad carrying per-locale copy and, optionally, per-locale media — the \"Languages\" toggle in Ads Manager. Keeps social proof (likes/comments/shares) on a SINGLE post instead of splitting it across one ad per language. The ad's top-level copy is the DEFAULT shown to every locale you do NOT list, and it counts as one of the language variants. IMPORTANT, and the opposite of what you might expect: text does NOT inherit. Every entry must carry its own `headline`, `body` AND `description`, and all of them must be DISTINCT from each other and from the ad's top-level copy. Meta deduplicates identical strings inside the asset feed, so two locales sharing a string collapse into one asset and the create fails with a misleading \"Too few ... texts provided in asset creation\" (subcode 1885817) that names a field which is actually present. We validate this before calling Meta and return a 400 naming the offending locale and field. `description` is therefore effectively required on the ad whenever `translations` is present, even though it is optional otherwise. Do NOT list `defaultLocale` inside `translations`: Meta rejects the duplicate with \"The language asset feed includes an unsupported targeting field\" (subcode 1885985). Media DOES inherit and is uploaded once when shared. Note that Meta enforces Dynamic Creative image dimensions on language feeds, so an `imageUrl` that works on a normal ad may be rejected with \"The following images have invalid dimensions for Dynamic Creative\" (subcode 1885558). Video is not affected. Mutually exclusive with `dynamicCreative`, `placementAssets`, `carouselCards` and `existingCreativeId` — Meta allows one `asset_feed_spec` shape per creative.
188
188
  attr_accessor :translations
189
189
 
190
190
  attr_accessor :placement_assets
@@ -18,13 +18,13 @@ module Zernio
18
18
  # Language code, resolved to Meta's numeric locale id. Bare codes target the '(All)' umbrella (`es` = every Spanish variant); region-qualified codes target the variant (`pt_BR`, `en_GB`).
19
19
  attr_accessor :locale
20
20
 
21
- # Headline for this language. Inherits the top-level `headline` when omitted.
21
+ # Headline for this language. REQUIRED, and must differ from every other locale and from the ad's top-level headline.
22
22
  attr_accessor :headline
23
23
 
24
- # Primary text for this language. Inherits the top-level `body` when omitted.
24
+ # Primary text for this language. REQUIRED, and must differ from every other locale and from the ad's top-level body.
25
25
  attr_accessor :body
26
26
 
27
- # Link description for this language. Inherits the top-level `description` when omitted.
27
+ # Link description for this language. REQUIRED, and must differ from every other locale and from the ad's top-level description.
28
28
  attr_accessor :description
29
29
 
30
30
  # Image for this language. Inherits the ad's `imageUrl` when omitted. The feed is all-image OR all-video.
@@ -102,14 +102,20 @@ module Zernio
102
102
 
103
103
  if attributes.key?(:'headline')
104
104
  self.headline = attributes[:'headline']
105
+ else
106
+ self.headline = nil
105
107
  end
106
108
 
107
109
  if attributes.key?(:'body')
108
110
  self.body = attributes[:'body']
111
+ else
112
+ self.body = nil
109
113
  end
110
114
 
111
115
  if attributes.key?(:'description')
112
116
  self.description = attributes[:'description']
117
+ else
118
+ self.description = nil
113
119
  end
114
120
 
115
121
  if attributes.key?(:'image_url')
@@ -134,11 +140,23 @@ module Zernio
134
140
  invalid_properties.push('invalid value for "locale", locale cannot be nil.')
135
141
  end
136
142
 
137
- if !@headline.nil? && @headline.to_s.length > 255
143
+ if @headline.nil?
144
+ invalid_properties.push('invalid value for "headline", headline cannot be nil.')
145
+ end
146
+
147
+ if @headline.to_s.length > 255
138
148
  invalid_properties.push('invalid value for "headline", the character length must be smaller than or equal to 255.')
139
149
  end
140
150
 
141
- if !@description.nil? && @description.to_s.length > 255
151
+ if @body.nil?
152
+ invalid_properties.push('invalid value for "body", body cannot be nil.')
153
+ end
154
+
155
+ if @description.nil?
156
+ invalid_properties.push('invalid value for "description", description cannot be nil.')
157
+ end
158
+
159
+ if @description.to_s.length > 255
142
160
  invalid_properties.push('invalid value for "description", the character length must be smaller than or equal to 255.')
143
161
  end
144
162
 
@@ -150,8 +168,11 @@ module Zernio
150
168
  def valid?
151
169
  warn '[DEPRECATED] the `valid?` method is obsolete'
152
170
  return false if @locale.nil?
153
- return false if !@headline.nil? && @headline.to_s.length > 255
154
- return false if !@description.nil? && @description.to_s.length > 255
171
+ return false if @headline.nil?
172
+ return false if @headline.to_s.length > 255
173
+ return false if @body.nil?
174
+ return false if @description.nil?
175
+ return false if @description.to_s.length > 255
155
176
  true
156
177
  end
157
178
 
@@ -179,6 +200,16 @@ module Zernio
179
200
  @headline = headline
180
201
  end
181
202
 
203
+ # Custom attribute writer method with validation
204
+ # @param [Object] body Value to be assigned
205
+ def body=(body)
206
+ if body.nil?
207
+ fail ArgumentError, 'body cannot be nil'
208
+ end
209
+
210
+ @body = body
211
+ end
212
+
182
213
  # Custom attribute writer method with validation
183
214
  # @param [Object] description Value to be assigned
184
215
  def description=(description)
@@ -17,6 +17,9 @@ module Zernio
17
17
  class DeleteAdCampaignRequest < ApiModelBase
18
18
  attr_accessor :platform
19
19
 
20
+ # Zernio SocialAccount id owning the ad account. Required only to delete an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from.
21
+ attr_accessor :account_id
22
+
20
23
  class EnumAttributeValidator
21
24
  attr_reader :datatype
22
25
  attr_reader :allowable_values
@@ -42,7 +45,8 @@ module Zernio
42
45
  # Attribute mapping from ruby-style variable name to JSON key.
43
46
  def self.attribute_map
44
47
  {
45
- :'platform' => :'platform'
48
+ :'platform' => :'platform',
49
+ :'account_id' => :'accountId'
46
50
  }
47
51
  end
48
52
 
@@ -59,7 +63,8 @@ module Zernio
59
63
  # Attribute type mapping.
60
64
  def self.openapi_types
61
65
  {
62
- :'platform' => :'String'
66
+ :'platform' => :'String',
67
+ :'account_id' => :'String'
63
68
  }
64
69
  end
65
70
 
@@ -90,6 +95,10 @@ module Zernio
90
95
  else
91
96
  self.platform = nil
92
97
  end
98
+
99
+ if attributes.key?(:'account_id')
100
+ self.account_id = attributes[:'account_id']
101
+ end
93
102
  end
94
103
 
95
104
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -129,7 +138,8 @@ module Zernio
129
138
  def ==(o)
130
139
  return true if self.equal?(o)
131
140
  self.class == o.class &&
132
- platform == o.platform
141
+ platform == o.platform &&
142
+ account_id == o.account_id
133
143
  end
134
144
 
135
145
  # @see the `==` method
@@ -141,7 +151,7 @@ module Zernio
141
151
  # Calculates hash code according to all attributes.
142
152
  # @return [Integer] Hash code
143
153
  def hash
144
- [platform].hash
154
+ [platform, account_id].hash
145
155
  end
146
156
 
147
157
  # Builds the object from hash
@@ -15,6 +15,9 @@ require 'time'
15
15
 
16
16
  module Zernio
17
17
  class UpdateAdCampaignRequest < ApiModelBase
18
+ # Zernio SocialAccount id owning the ad account. Required only to update an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from.
19
+ attr_accessor :account_id
20
+
18
21
  attr_accessor :platform
19
22
 
20
23
  attr_accessor :budget
@@ -52,6 +55,7 @@ module Zernio
52
55
  # Attribute mapping from ruby-style variable name to JSON key.
53
56
  def self.attribute_map
54
57
  {
58
+ :'account_id' => :'accountId',
55
59
  :'platform' => :'platform',
56
60
  :'budget' => :'budget',
57
61
  :'bid_strategy' => :'bidStrategy',
@@ -73,6 +77,7 @@ module Zernio
73
77
  # Attribute type mapping.
74
78
  def self.openapi_types
75
79
  {
80
+ :'account_id' => :'String',
76
81
  :'platform' => :'String',
77
82
  :'budget' => :'UpdateAdCampaignRequestBudget',
78
83
  :'bid_strategy' => :'BidStrategy',
@@ -103,6 +108,10 @@ module Zernio
103
108
  h[k.to_sym] = v
104
109
  }
105
110
 
111
+ if attributes.key?(:'account_id')
112
+ self.account_id = attributes[:'account_id']
113
+ end
114
+
106
115
  if attributes.key?(:'platform')
107
116
  self.platform = attributes[:'platform']
108
117
  else
@@ -182,6 +191,7 @@ module Zernio
182
191
  def ==(o)
183
192
  return true if self.equal?(o)
184
193
  self.class == o.class &&
194
+ account_id == o.account_id &&
185
195
  platform == o.platform &&
186
196
  budget == o.budget &&
187
197
  bid_strategy == o.bid_strategy &&
@@ -198,7 +208,7 @@ module Zernio
198
208
  # Calculates hash code according to all attributes.
199
209
  # @return [Integer] Hash code
200
210
  def hash
201
- [platform, budget, bid_strategy, name, platform_specific_data].hash
211
+ [account_id, platform, budget, bid_strategy, name, platform_specific_data].hash
202
212
  end
203
213
 
204
214
  # Builds the object from hash
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.632'
14
+ VERSION = '0.0.634'
15
15
  end
data/openapi.yaml CHANGED
@@ -34910,6 +34910,18 @@ paths:
34910
34910
  security:
34911
34911
  - bearerAuth: []
34912
34912
  parameters:
34913
+ - name: includeEmpty
34914
+ in: query
34915
+ required: false
34916
+ schema: { type: boolean }
34917
+ description: >-
34918
+ Meta only. Campaign reads aggregate over ad documents, so a campaign
34919
+ with ZERO ads is normally invisible here — the state the two-step
34920
+ create (campaign, then ads via `existingCampaignId`) leaves behind
34921
+ whenever Meta rejects the ad step. Set true to list those too, with
34922
+ `adCount: 0` and zeroed metrics. Requires `accountId` and
34923
+ `adAccountId`, since an empty campaign has no ad row to resolve a
34924
+ token or ad account from.
34913
34925
  - $ref: '#/components/parameters/PageParam'
34914
34926
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } }
34915
34927
  - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: all }, description: "`all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that." }
@@ -34982,13 +34994,13 @@ paths:
34982
34994
  specialAdCategories:
34983
34995
  type: array
34984
34996
  items: { type: string, enum: [HOUSING, EMPLOYMENT, CREDIT, ISSUES_ELECTIONS_POLITICS, FINANCIAL_PRODUCTS_SERVICES, ONLINE_GAMBLING_AND_GAMING] }
34985
- budgetAmount: { type: number, description: "Campaign-level (CBO) budget in whole currency units. Requires budgetType." }
34997
+ budgetAmount: { type: number, description: "Campaign-level (CBO) budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Requires budgetType." }
34986
34998
  budgetType: { type: string, enum: [daily, lifetime] }
34987
34999
  status: { type: string, enum: [ACTIVE, PAUSED], default: PAUSED }
34988
35000
  bidStrategy:
34989
35001
  type: string
34990
35002
  enum: [LOWEST_COST_WITHOUT_CAP, LOWEST_COST_WITH_BID_CAP, COST_CAP, LOWEST_COST_WITH_MIN_ROAS]
34991
- description: "Campaign bid strategy. Meta puts `bid_strategy` where the budget lives, so this applies only alongside a campaign budget (CBO). Previously settable only via `PUT /v1/ads/campaigns/{campaignId}`."
35003
+ description: "Campaign bid strategy. Meta stores `bid_strategy` alongside the budget, so this REQUIRES `budgetAmount` + `budgetType` on the same request; sending it without a campaign budget is a 400. A campaign carrying a strategy without its `bid_amount` makes every ad set created under it fail with an error that names the ad set (code 100, subcode 1815857), so the bad state is rejected up front rather than accepted. To bid at ad-set level, set the strategy there instead."
34992
35004
  bidAmount: { type: number, description: "Whole currency units (USD: 5 = $5.00). Required for LOWEST_COST_WITH_BID_CAP and COST_CAP; ignored otherwise." }
34993
35005
  roasAverageFloor: { type: number, description: "Decimal ROAS multiplier (2.0 = 2.0x). Required for LOWEST_COST_WITH_MIN_ROAS." }
34994
35006
  responses:
@@ -35057,6 +35069,12 @@ paths:
35057
35069
  description: |
35058
35070
  Campaign-level edits. At least one of `budget`, `bidStrategy`, `name` or `platformSpecificData` is required.
35059
35071
 
35072
+ **Empty campaigns.** A campaign with zero ads has no local Ad documents to
35073
+ resolve, so this would 404 even though it exists on Meta. Send `accountId`
35074
+ in the body to skip the local lookup and forward the update to Meta. The
35075
+ response then carries `updated: 0`, since there are no local rows to mirror
35076
+ onto. `accountId` is ignored when the campaign does have ads.
35077
+
35060
35078
  - `budget` updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns
35061
35079
  (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint
35062
35080
  will return 409 with code BUDGET_LEVEL_MISMATCH.
@@ -35078,6 +35096,7 @@ paths:
35078
35096
  type: object
35079
35097
  required: [platform]
35080
35098
  properties:
35099
+ accountId: { type: string, description: "Zernio SocialAccount id owning the ad account. Required only to update an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from." }
35081
35100
  platform: { type: string, enum: [facebook, instagram] }
35082
35101
  budget:
35083
35102
  type: object
@@ -35128,6 +35147,14 @@ paths:
35128
35147
 
35129
35148
  Meta-only for now. Other platforms return 501 Not Implemented — fall
35130
35149
  back to DELETE /v1/ads/{adId} per ad in the meantime.
35150
+
35151
+ **Empty campaigns.** A campaign with zero ads has no local Ad documents
35152
+ to resolve, so it is invisible to `/v1/ads/tree` and this endpoint would
35153
+ 404. That state is produced by the two-step create flow (campaign, then
35154
+ ads via `existingCampaignId`) whenever Meta rejects the ad step. To
35155
+ delete such a shell, send `accountId` in the body: we skip the local
35156
+ lookup entirely and forward the delete to Meta. `accountId` is ignored
35157
+ when the campaign does have ads.
35131
35158
  security:
35132
35159
  - bearerAuth: []
35133
35160
  parameters:
@@ -35141,6 +35168,7 @@ paths:
35141
35168
  required: [platform]
35142
35169
  properties:
35143
35170
  platform: { type: string, enum: [facebook, instagram] }
35171
+ accountId: { type: string, description: "Zernio SocialAccount id owning the ad account. Required only to delete an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from." }
35144
35172
  responses:
35145
35173
  '200':
35146
35174
  description: Campaign deleted
@@ -37751,7 +37779,7 @@ paths:
37751
37779
  validateOnly:
37752
37780
  type: boolean
37753
37781
  description: 'Meta only, single standalone shape only (no creatives[], adSetId, or RESERVED). Dry-run: each node runs Meta''s execution_options validate_only and NOTHING is created or persisted. Children need real parents, so a fresh tree validates the campaign + creative (the ad set needs its campaign to exist — pass existingCampaignId to validate it too; the ad itself is never validatable pre-create). A Meta validation failure returns the 400 verbatim; success returns 200 with per-node results instead of an ad.'
37754
- budgetAmount: { type: number, description: "Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType)." }
37782
+ budgetAmount: { type: number, description: "Budget in WHOLE currency units (USD: 50 = $50.00), NOT cents — Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType)." }
37755
37783
  budgetType: { type: string, enum: [daily, lifetime], description: "Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads accepts lifetime only (no daily-budget concept on the platform); sending daily returns 422. OpenAI Ads lifetime budgets require `endDate` to give the lifetime cap a spend window." }
37756
37784
  status:
37757
37785
  type: string
@@ -38123,7 +38151,7 @@ paths:
38123
38151
  callToAction: { type: string, description: "Card CTA override. Defaults to the top-level callToAction; same enum." }
38124
38152
  defaultLocale:
38125
38153
  type: string
38126
- description: "Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own."
38154
+ description: "Meta only. Language the top-level copy is written in (e.g. `en`, `pt_BR`), used by the `translations` default rule. Defaults to `en`. Meta rejects a language asset feed whose default rule carries no locales of its own. Must NOT also appear as an entry in `translations`."
38127
38155
  translations:
38128
38156
  type: array
38129
38157
  minItems: 1
@@ -38134,20 +38162,39 @@ paths:
38134
38162
  Manager. Keeps social proof (likes/comments/shares) on a SINGLE post instead of
38135
38163
  splitting it across one ad per language.
38136
38164
 
38137
- The ad's top-level copy and media are the DEFAULT every unlisted locale falls back
38138
- to, and a variant inherits any field it omits, so send only what differs per
38139
- language. Media shared across languages is uploaded once.
38165
+ The ad's top-level copy is the DEFAULT shown to every locale you do NOT list,
38166
+ and it counts as one of the language variants.
38167
+
38168
+ IMPORTANT, and the opposite of what you might expect: text does NOT inherit.
38169
+ Every entry must carry its own `headline`, `body` AND `description`, and all of
38170
+ them must be DISTINCT from each other and from the ad's top-level copy. Meta
38171
+ deduplicates identical strings inside the asset feed, so two locales sharing a
38172
+ string collapse into one asset and the create fails with a misleading "Too few
38173
+ ... texts provided in asset creation" (subcode 1885817) that names a field which
38174
+ is actually present. We validate this before calling Meta and return a 400
38175
+ naming the offending locale and field. `description` is therefore effectively
38176
+ required on the ad whenever `translations` is present, even though it is
38177
+ optional otherwise.
38178
+
38179
+ Do NOT list `defaultLocale` inside `translations`: Meta rejects the duplicate
38180
+ with "The language asset feed includes an unsupported targeting field"
38181
+ (subcode 1885985).
38182
+
38183
+ Media DOES inherit and is uploaded once when shared. Note that Meta enforces
38184
+ Dynamic Creative image dimensions on language feeds, so an `imageUrl` that
38185
+ works on a normal ad may be rejected with "The following images have invalid
38186
+ dimensions for Dynamic Creative" (subcode 1885558). Video is not affected.
38140
38187
 
38141
38188
  Mutually exclusive with `dynamicCreative`, `placementAssets`, `carouselCards` and
38142
38189
  `existingCreativeId` — Meta allows one `asset_feed_spec` shape per creative.
38143
38190
  items:
38144
38191
  type: object
38145
- required: [locale]
38192
+ required: [locale, headline, body, description]
38146
38193
  properties:
38147
38194
  locale: { type: string, description: "Language code, resolved to Meta's numeric locale id. Bare codes target the '(All)' umbrella (`es` = every Spanish variant); region-qualified codes target the variant (`pt_BR`, `en_GB`)." }
38148
- headline: { type: string, maxLength: 255, description: "Headline for this language. Inherits the top-level `headline` when omitted." }
38149
- body: { type: string, description: "Primary text for this language. Inherits the top-level `body` when omitted." }
38150
- description: { type: string, maxLength: 255, description: "Link description for this language. Inherits the top-level `description` when omitted." }
38195
+ headline: { type: string, maxLength: 255, description: "Headline for this language. REQUIRED, and must differ from every other locale and from the ad's top-level headline." }
38196
+ body: { type: string, description: "Primary text for this language. REQUIRED, and must differ from every other locale and from the ad's top-level body." }
38197
+ description: { type: string, maxLength: 255, description: "Link description for this language. REQUIRED, and must differ from every other locale and from the ad's top-level description." }
38151
38198
  imageUrl: { type: string, format: uri, description: "Image for this language. Inherits the ad's `imageUrl` when omitted. The feed is all-image OR all-video." }
38152
38199
  videoUrl: { type: string, format: uri, description: "Video for this language. Inherits the ad's `video.url` when omitted. The feed is all-image OR all-video." }
38153
38200
  thumbnailUrl: { type: string, format: uri, description: "Poster frame for this language's video." }
@@ -96,7 +96,7 @@ describe 'AdCampaignsApi' do
96
96
 
97
97
  # unit tests for delete_ad_campaign
98
98
  # Delete a campaign
99
- # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked &#x60;status: cancelled&#x60;. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime.
99
+ # Deletes the whole campaign on the platform, cascading to its ad sets and ads. Locally, all Ad documents for this campaign are marked &#x60;status: cancelled&#x60;. Meta-only for now. Other platforms return 501 Not Implemented — fall back to DELETE /v1/ads/{adId} per ad in the meantime. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so it is invisible to &#x60;/v1/ads/tree&#x60; and this endpoint would 404. That state is produced by the two-step create flow (campaign, then ads via &#x60;existingCampaignId&#x60;) whenever Meta rejects the ad step. To delete such a shell, send &#x60;accountId&#x60; in the body: we skip the local lookup entirely and forward the delete to Meta. &#x60;accountId&#x60; is ignored when the campaign does have ads.
100
100
  # @param campaign_id Platform campaign ID
101
101
  # @param delete_ad_campaign_request
102
102
  # @param [Hash] opts the optional parameters
@@ -221,6 +221,7 @@ describe 'AdCampaignsApi' do
221
221
  # List campaigns
222
222
  # Returns campaigns as virtual aggregations over ad documents grouped by platform campaign ID. Metrics (spend, impressions, clicks, etc.) are summed across all ads in each campaign. Campaign status is derived from child ad statuses (active &gt; pending_review &gt; paused &gt; error &gt; completed &gt; cancelled &gt; rejected).
223
223
  # @param [Hash] opts the optional parameters
224
+ # @option opts [Boolean] :include_empty Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here — the state the two-step create (campaign, then ads via &#x60;existingCampaignId&#x60;) leaves behind whenever Meta rejects the ad step. Set true to list those too, with &#x60;adCount: 0&#x60; and zeroed metrics. Requires &#x60;accountId&#x60; and &#x60;adAccountId&#x60;, since an empty campaign has no ad row to resolve a token or ad account from.
224
225
  # @option opts [Integer] :page Page number (1-based)
225
226
  # @option opts [Integer] :limit
226
227
  # @option opts [String] :source &#x60;all&#x60; (default) returns both Zernio-created ads and those discovered from the platform&#39;s ad manager — matches the web UI&#39;s default view. Pass &#x60;zernio&#x60; to restrict to isExternal&#x3D;false only. Status is NOT filtered by default — use the &#x60;status&#x60; param for that.
@@ -302,7 +303,7 @@ describe 'AdCampaignsApi' do
302
303
 
303
304
  # unit tests for update_ad_campaign
304
305
  # Update a campaign
305
- # Campaign-level edits. At least one of &#x60;budget&#x60;, &#x60;bidStrategy&#x60;, &#x60;name&#x60; or &#x60;platformSpecificData&#x60; is required. - &#x60;budget&#x60; updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - &#x60;bidStrategy&#x60; sets the campaign-level default bid strategy. Per Meta&#39;s spec, &#x60;bid_amount&#x60; and &#x60;bid_constraints&#x60; do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - &#x60;platformSpecificData.spendCap&#x60; (Meta only) sets the campaign&#39;s lifetime spend cap, in the ad account&#39;s currency. Meta-only for now. Other platforms return 501 Not Implemented.
306
+ # Campaign-level edits. At least one of &#x60;budget&#x60;, &#x60;bidStrategy&#x60;, &#x60;name&#x60; or &#x60;platformSpecificData&#x60; is required. **Empty campaigns.** A campaign with zero ads has no local Ad documents to resolve, so this would 404 even though it exists on Meta. Send &#x60;accountId&#x60; in the body to skip the local lookup and forward the update to Meta. The response then carries &#x60;updated: 0&#x60;, since there are no local rows to mirror onto. &#x60;accountId&#x60; is ignored when the campaign does have ads. - &#x60;budget&#x60; updates the CBO (Campaign Budget Optimization) budget. For ABO campaigns (where the budget lives on the ad set), use PUT /v1/ads/ad-sets/{adSetId} instead — this endpoint will return 409 with code BUDGET_LEVEL_MISMATCH. - &#x60;bidStrategy&#x60; sets the campaign-level default bid strategy. Per Meta&#39;s spec, &#x60;bid_amount&#x60; and &#x60;bid_constraints&#x60; do NOT exist at the campaign level — pass them via PUT /v1/ads/ad-sets/{adSetId}. - &#x60;platformSpecificData.spendCap&#x60; (Meta only) sets the campaign&#39;s lifetime spend cap, in the ad account&#39;s currency. Meta-only for now. Other platforms return 501 Not Implemented.
306
307
  # @param campaign_id Platform campaign ID
307
308
  # @param update_ad_campaign_request
308
309
  # @param [Hash] opts the optional parameters
@@ -37,4 +37,10 @@ describe Zernio::DeleteAdCampaignRequest do
37
37
  end
38
38
  end
39
39
 
40
+ describe 'test attribute "account_id"' do
41
+ it 'should work' do
42
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
43
+ end
44
+ end
45
+
40
46
  end
@@ -27,6 +27,12 @@ describe Zernio::UpdateAdCampaignRequest do
27
27
  end
28
28
  end
29
29
 
30
+ describe 'test attribute "account_id"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
30
36
  describe 'test attribute "platform"' do
31
37
  it 'should work' do
32
38
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: late-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.632
4
+ version: 0.0.634
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenAPI-Generator
@@ -4919,7 +4919,7 @@ files:
4919
4919
  - spec/models/you_tube_video_retention_response_retention_curve_inner_spec.rb
4920
4920
  - spec/models/you_tube_video_retention_response_spec.rb
4921
4921
  - spec/spec_helper.rb
4922
- - zernio-sdk-0.0.632.gem
4922
+ - zernio-sdk-0.0.634.gem
4923
4923
  - zernio-sdk.gemspec
4924
4924
  homepage: https://openapi-generator.tech
4925
4925
  licenses:
Binary file