Add elements to, and edit campaign-level fields of, an existing **Channel-First / Native (N×N×N)** campaign — the one built with `create_native_structure_campaign` (channel.structureType=NATIVE, WizNativeAdContainer). This is the NATIVE counterpart of `add_and_edit_campaign_elements`: that tool edits Precision (1×1×1 / METADATA) campaigns; THIS tool edits Native (N×N×N) campaigns.
CRITICAL: PICK THE TOOL BY THE CAMPAIGN'S STRUCTURE (not by user phrasing):
• Native / Channel-First / Platform-First / N×N×N campaign → THIS tool (`add_and_edit_native_campaign_elements`).
• Precision Optimization / 1×1×1 / METADATA campaign → `add_and_edit_campaign_elements`.
Both tools guard: call THIS tool on a Precision/METADATA campaign and it returns an error telling you to use `add_and_edit_campaign_elements`, and vice-versa. So if you guess wrong, the error tells you the right one — no silent mis-write. If you don't know the structure, check the campaign first (its channels' structureType) or just try and follow the redirect.
WHAT THIS TOOL DOES:
- EDIT campaign-level fields: name, budgetGroup, startDate, endDate (same smart/partial semantics as the flat tool — only pushed when different / supplied).
- ADD new containers: each channel's `containers[]` APPENDS new WizNativeAdContainers (one audience × an `ad_offers` list of {ad, offer} pairs each, same shape as `create_native_structure_campaign`). Existing containers are PRESERVED — the channel's current container list is re-POSTed with the new ones appended.
- ADD bare target groups: each channel's optional `target_groups[]` (names, each matching one target group, ignoring case and surrounding spaces) attaches targeting groups to the native channel without a full container. Each one goes on the first container that has no audience and no target group, which is renamed after the target group; when there is none, it goes on a new container with no ads. It goes in a call of its own, never beside `modify_containers[]`; to put a target group on a SPECIFIC container, use `set_target_group` there instead.
- ATTACH negative keyword lists (Google Ads / Microsoft Ads only): the search channel block's optional `negative_keyword_lists[]` (names of EXISTING lists) attaches them channel-wide — valid with or without new containers. Names inside `containers[].negative_keyword_lists` are unioned in and applied at the same channel level. A name that doesn't resolve on the channel is reported in `errors[]`, never silently skipped.
- EDIT existing containers (PER CONTAINER): each channel's optional `modify_containers[]` targets an existing container by `name` and, within it, deletes specific Ad—Offer rows (`remove_ads`), clears an offer from one ad while keeping it on the OTHER ads (`clear_offers_on_ads`), removes this container's audience / targeting group / keywords / exclusion (`remove_audience` / `remove_target_group` / `remove_keywords` / `remove_exclude_audience`), puts a Targeting Group on this container (`set_target_group`, replacing any it has), or deletes the whole container (`delete_container`). This is the surgical counterpart to the channel-wide remove_* tools — use it when an audience/offer/ad is shared across containers and you only want to touch one. Removing a group clears it on that one container; a group reused by other containers stays alive for them, and an audience, target group or exclusion that no container uses any more (removed from its last container, or its container deleted) is deleted from the channel; keyword groups stay. A container an entry leaves holding ads with nothing to target them is named in the result's `warnings[]`: before launch, put a target group on it (`set_target_group`), have the user give it an audience in the platform UI, or delete it.
- REPLACE a container's audience with a target group: ONE `modify_containers[]` entry on that container with `remove_audience: true` and `set_target_group: "<name>"` (see the example below). The container keeps its name and ads, and the old audience is deleted from the channel when no other container uses it, so no follow-up remove_audiences_from_campaign call is needed. `target_groups[]` and `modify_containers[]` go in separate calls: a channel block with both is refused, because a bare target group goes on the first container with no audience and no target group and renames it.
WHAT THIS TOOL DOES NOT DO:
- It does not switch a campaign's structure (that's fixed at creation).
- For a change that spans ALL ads (remove an offer/ad everywhere it appears on the channel), use the channel-wide removal tools (remove_offers_from_campaign / remove_ad_from_campaign / remove_audiences_from_campaign / remove_target_groups_from_campaign / remove_keywords_from_campaign); `modify_containers` is only for a specific container/row.
CONTAINER RULES (same as create_native_structure_campaign):
- Each container is one audience × a LIST of (ad, offer) pairs (`ad_offers`, 1+). Group several ads/offers under one audience by adding pairs — e.g. 3 ads on the same offer = 3 pairs that repeat the same `offer` id. Send two containers only to run the audience as two separate ad-sets.
- `audience` / `exclude_audience` / `target_group` are NAMES (resolved server-side); the `ad` / `offer` inside each `ad_offers` pair are integer IDs.
- Audience names are resolved BEFORE anything is created: a container whose `audience` cannot be resolved is dropped with an error in `errors[]` that states whether retrying can help ("may still be matching") or not ("not available on this channel"); no keyword group or other element is left behind for a dropped container.
- `audience` is REQUIRED for LinkedIn/Facebook/Instagram/Reddit; OPTIONAL for Google/Microsoft search containers (keyword-only is valid — provide `keywords`/`keyword_ids` instead).
- Offer–channel lock still applies: a Lead Gen offer must be locked to the container's channel (LinkedIn→LINKEDIN, etc.); Google takes Landing Page offers only; Landing Page offers are universal.
RESPONSE: same top-level shape as `add_and_edit_campaign_elements` (success, campaign_id, changes {renamed, budget_group_reassigned, schedule_updated}, added_summary per channel {containers, target_groups, negative_keyword_lists, and — when modify_containers is used — ads_removed, offers_cleared, containers_deleted, audiences_removed, target_groups_removed, keywords_removed, excludes_removed, target_groups_set, groups_deleted (groups no container uses any more, deleted from the channel)}, optimization_group, campaign_url, full_response), plus `warnings[]` naming any container left with ads and nothing to target them. success=false only when NOTHING applied and something failed; every failure is in `errors[]`, so read it whenever it is present, success=true included. The rest of the edit still proceeds past a failed element.
EXAMPLE (append a LinkedIn container + rename):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"name": "Q3_ABM_Native_v2",
"linkedin": {"containers": [
{"name": "VPs > Demo > Form", "audience": "VPs - NA", "ad_offers": [{"ad": 156502, "offer": 57538}]}
]}
})
EXAMPLE (append a Google keyword-only container + bare target group):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"google": {
"containers": [
{"name": "Incident Response", "ad_offers": [{"ad": 210804, "offer": 67269}],
"keywords": ["incident response platform"], "negative_keyword_lists": ["Competitor Brands"]}
],
"target_groups": ["Tech Decision Makers"]
}
})
EXAMPLE (ROW-LEVEL: drop the offer from ONE ad in a container, keep it on the other ads):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"facebook": {"modify_containers": [
{"container": "ICP > 3 creatives > TOF offer",
"clear_offers_on_ads": ["Ungated-AI-in-Finance-v2-vert_FB"]}
]}
})
EXAMPLE (PER-CONTAINER: delete one Ad—Offer row in one container; delete a whole other container):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"linkedin": {"modify_containers": [
{"container": "VPs > Demo > Form", "remove_ads": ["Old Creative A"]},
{"container": "Retired ad-set", "delete_container": True}
]}
})
EXAMPLE (PER-CONTAINER: drop a reused audience from ONE container, keep it on the others):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"facebook": {"modify_containers": [
{"container": "ICP - A2", "remove_audience": True}
]}
})
EXAMPLE (PER-CONTAINER: replace a container's audience with a target group, keeping its ads):
add_and_edit_native_campaign_elements(campaign_data={
"campaignId": 159490,
"linkedin": {"modify_containers": [
{"container": "VPs > Demo > Form", "remove_audience": True,
"set_target_group": "VPs - In-House Only"}
]}
})