@@ -117,8 +117,29 @@ async def create_adset(
117117 lifetime_budget: Lifetime budget in account currency (in cents) as a string
118118 targeting: Targeting specifications including age, location, interests, etc.
119119 Use targeting_automation.advantage_audience=1 for automatic audience finding
120- bid_amount: Bid amount in account currency (in cents)
121- bid_strategy: Bid strategy (e.g., 'LOWEST_COST', 'LOWEST_COST_WITH_BID_CAP')
120+ bid_amount: Bid amount in account currency (in cents).
121+ REQUIRED for: LOWEST_COST_WITH_BID_CAP, COST_CAP, LOWEST_COST_WITH_MIN_ROAS.
122+ NOT REQUIRED for: LOWEST_COST_WITHOUT_CAP (recommended default).
123+ Note: May also be required if the parent campaign uses a bid strategy that requires it.
124+ bid_strategy: Bid strategy determines how Meta optimizes your bids.
125+ Valid values:
126+ - 'LOWEST_COST_WITHOUT_CAP' (recommended) - No bid_amount required, most flexible
127+ - 'LOWEST_COST_WITH_BID_CAP' - Sets max bid cap, REQUIRES bid_amount
128+ - 'COST_CAP' - Caps cost per result, REQUIRES bid_amount
129+ - 'LOWEST_COST_WITH_MIN_ROAS' - Sets minimum ROAS, REQUIRES bid_amount
130+
131+ IMPORTANT: 'LOWEST_COST' is NOT a valid value - use 'LOWEST_COST_WITHOUT_CAP' instead.
132+
133+ IMPORTANT: Campaign-level bid strategy constrains ad set choices. If the parent campaign
134+ uses LOWEST_COST_WITH_BID_CAP, all child ad sets MUST provide bid_amount regardless of
135+ their own bid_strategy setting.
136+
137+ Examples:
138+ 1. Recommended (no bid amount needed):
139+ bid_strategy="LOWEST_COST_WITHOUT_CAP"
140+
141+ 2. With bid cap (bid_amount required):
142+ bid_strategy="LOWEST_COST_WITH_BID_CAP", bid_amount=500
122143 start_time: Start time in ISO 8601 format (e.g., '2023-12-01T12:00:00-0800')
123144 end_time: End time in ISO 8601 format
124145 dsa_beneficiary: DSA beneficiary (person/organization benefiting from ads) for European compliance
@@ -209,6 +230,39 @@ async def create_adset(
209230 "targeting_automation" : {"advantage_audience" : 1 }
210231 }
211232
233+ # Validate bid_strategy and bid_amount requirements
234+ if bid_strategy :
235+ # Check for invalid 'LOWEST_COST' value (common mistake)
236+ if bid_strategy == 'LOWEST_COST' :
237+ return json .dumps ({
238+ "error" : "'LOWEST_COST' is not a valid bid_strategy value" ,
239+ "details" : "The 'LOWEST_COST' bid strategy is not valid in Meta Ads API v22.0" ,
240+ "workaround" : "Use 'LOWEST_COST_WITHOUT_CAP' instead (no bid_amount required)" ,
241+ "valid_values" : [
242+ "LOWEST_COST_WITHOUT_CAP (recommended - no bid_amount required)" ,
243+ "LOWEST_COST_WITH_BID_CAP (requires bid_amount)" ,
244+ "COST_CAP (requires bid_amount)" ,
245+ "LOWEST_COST_WITH_MIN_ROAS (requires bid_amount)"
246+ ],
247+ "example" : '{"bid_strategy": "LOWEST_COST_WITHOUT_CAP"}'
248+ }, indent = 2 )
249+
250+ # Bid strategies that require bid_amount
251+ strategies_requiring_bid_amount = [
252+ 'LOWEST_COST_WITH_BID_CAP' ,
253+ 'COST_CAP' ,
254+ 'LOWEST_COST_WITH_MIN_ROAS'
255+ ]
256+
257+ if bid_strategy in strategies_requiring_bid_amount and bid_amount is None :
258+ return json .dumps ({
259+ "error" : f"bid_amount is required when using bid_strategy '{ bid_strategy } '" ,
260+ "details" : f"The '{ bid_strategy } ' bid strategy requires you to specify a bid amount in cents" ,
261+ "workaround" : "Either provide the bid_amount parameter, or use bid_strategy='LOWEST_COST_WITHOUT_CAP' which does not require a bid amount" ,
262+ "example_with_bid_amount" : f'{{"bid_strategy": "{ bid_strategy } ", "bid_amount": 500}}' ,
263+ "example_without_bid_amount" : '{"bid_strategy": "LOWEST_COST_WITHOUT_CAP"}'
264+ }, indent = 2 )
265+
212266 endpoint = f"{ account_id } /adsets"
213267
214268 params = {
@@ -305,8 +359,16 @@ async def update_adset(adset_id: str, frequency_control_specs: Optional[List[Dic
305359 adset_id: Meta Ads ad set ID
306360 frequency_control_specs: List of frequency control specifications
307361 (e.g. [{"event": "IMPRESSIONS", "interval_days": 7, "max_frequency": 3}])
308- bid_strategy: Bid strategy (e.g., 'LOWEST_COST_WITH_BID_CAP')
309- bid_amount: Bid amount in account currency (in cents for USD)
362+ bid_strategy: Bid strategy determines how Meta optimizes your bids.
363+ Valid values:
364+ - 'LOWEST_COST_WITHOUT_CAP' (recommended) - No bid_amount required
365+ - 'LOWEST_COST_WITH_BID_CAP' - REQUIRES bid_amount
366+ - 'COST_CAP' - REQUIRES bid_amount
367+ - 'LOWEST_COST_WITH_MIN_ROAS' - REQUIRES bid_amount
368+
369+ IMPORTANT: 'LOWEST_COST' is NOT a valid value - use 'LOWEST_COST_WITHOUT_CAP' instead.
370+ bid_amount: Bid amount in account currency (in cents for USD).
371+ REQUIRED when using LOWEST_COST_WITH_BID_CAP, COST_CAP, or LOWEST_COST_WITH_MIN_ROAS.
310372 status: Update ad set status (ACTIVE, PAUSED, etc.)
311373 targeting: Complete targeting specifications (will replace existing targeting)
312374 (e.g. {"targeting_automation":{"advantage_audience":1}, "geo_locations": {"countries": ["US"]}})
@@ -319,6 +381,39 @@ async def update_adset(adset_id: str, frequency_control_specs: Optional[List[Dic
319381 if not adset_id :
320382 return json .dumps ({"error" : "No ad set ID provided" }, indent = 2 )
321383
384+ # Validate bid_strategy if provided
385+ if bid_strategy is not None :
386+ # Check for invalid 'LOWEST_COST' value (common mistake)
387+ if bid_strategy == 'LOWEST_COST' :
388+ return json .dumps ({
389+ "error" : "'LOWEST_COST' is not a valid bid_strategy value" ,
390+ "details" : "The 'LOWEST_COST' bid strategy is not valid in Meta Ads API v22.0" ,
391+ "workaround" : "Use 'LOWEST_COST_WITHOUT_CAP' instead (no bid_amount required)" ,
392+ "valid_values" : [
393+ "LOWEST_COST_WITHOUT_CAP (recommended - no bid_amount required)" ,
394+ "LOWEST_COST_WITH_BID_CAP (requires bid_amount)" ,
395+ "COST_CAP (requires bid_amount)" ,
396+ "LOWEST_COST_WITH_MIN_ROAS (requires bid_amount)"
397+ ],
398+ "example" : '{"bid_strategy": "LOWEST_COST_WITHOUT_CAP"}'
399+ }, indent = 2 )
400+
401+ # Bid strategies that require bid_amount
402+ strategies_requiring_bid_amount = [
403+ 'LOWEST_COST_WITH_BID_CAP' ,
404+ 'COST_CAP' ,
405+ 'LOWEST_COST_WITH_MIN_ROAS'
406+ ]
407+
408+ if bid_strategy in strategies_requiring_bid_amount and bid_amount is None :
409+ return json .dumps ({
410+ "error" : f"bid_amount is required when using bid_strategy '{ bid_strategy } '" ,
411+ "details" : f"The '{ bid_strategy } ' bid strategy requires you to specify a bid amount in cents" ,
412+ "workaround" : "Either provide the bid_amount parameter, or use bid_strategy='LOWEST_COST_WITHOUT_CAP' which does not require a bid amount" ,
413+ "example_with_bid_amount" : f'{{"bid_strategy": "{ bid_strategy } ", "bid_amount": 500}}' ,
414+ "example_without_bid_amount" : '{"bid_strategy": "LOWEST_COST_WITHOUT_CAP"}'
415+ }, indent = 2 )
416+
322417 params = {}
323418
324419 if frequency_control_specs is not None :
0 commit comments