@@ -943,7 +943,8 @@ async def create_ad_creative(
943943 lead_gen_form_id : Optional [str ] = None ,
944944 instagram_actor_id : Optional [str ] = None ,
945945 ad_formats : Optional [List [str ]] = None ,
946- asset_customization_rules : Optional [List [Dict [str , Any ]]] = None
946+ asset_customization_rules : Optional [List [Dict [str , Any ]]] = None ,
947+ creative_features_spec : Optional [Dict [str , Any ]] = None
947948) -> str :
948949 """
949950 Create a new ad creative using an uploaded image hash or video ID.
@@ -989,6 +990,13 @@ async def create_ad_creative(
989990 ["AUTOMATIC_FORMAT"] (Flexible format). For video creatives, defaults to
990991 ["SINGLE_VIDEO"]. Otherwise defaults to ["SINGLE_IMAGE"].
991992 asset_customization_rules: List of placement-specific asset overrides for asset_feed_spec.
993+ creative_features_spec: Advantage+ Creative feature opt-ins/opt-outs. Controls individual
994+ creative enhancements like image_touchups, text_optimizations, inline_comment,
995+ add_text_overlay, music, 3d_animation, etc. Each feature is a dict with
996+ "enroll_status" set to "OPT_IN" or "OPT_OUT".
997+ Example: {"image_touchups": {"enroll_status": "OPT_IN"},
998+ "inline_comment": {"enroll_status": "OPT_IN"}}
999+ Sent to Meta as degrees_of_freedom_spec.creative_features_spec.
9921000 Lets you assign different images or videos to specific placement groups
9931001 (e.g., feed vs. stories). Only valid with image_hashes or plural asset params.
9941002 Each rule uses a user-friendly format that is automatically translated to
@@ -1024,6 +1032,14 @@ async def create_ad_creative(
10241032 except (json .JSONDecodeError , TypeError ):
10251033 pass
10261034
1035+ if isinstance (creative_features_spec , str ):
1036+ try :
1037+ _parsed = json .loads (creative_features_spec )
1038+ if isinstance (_parsed , dict ):
1039+ creative_features_spec = _parsed
1040+ except (json .JSONDecodeError , TypeError ):
1041+ pass
1042+
10271043 for _param_name , _param_val in [
10281044 ('image_hashes' , image_hashes ),
10291045 ('messages' , messages ),
@@ -1365,6 +1381,13 @@ async def create_ad_creative(
13651381 if dynamic_creative_spec :
13661382 creative_data ["dynamic_creative_spec" ] = dynamic_creative_spec
13671383
1384+ # Add Advantage+ Creative feature opt-ins if provided.
1385+ # Only sent when the user explicitly passes creative_features_spec.
1386+ if creative_features_spec :
1387+ creative_data ["degrees_of_freedom_spec" ] = {
1388+ "creative_features_spec" : creative_features_spec
1389+ }
1390+
13681391 # instagram_actor_id → instagram_user_id migration (Jan 2026).
13691392 # Meta deprecated instagram_actor_id; the replacement is instagram_user_id
13701393 # inside object_story_spec (sibling of page_id and video_data/link_data).
0 commit comments