Add & Edit Campaign Elements
add_and_edit_campaign_elementsAdd new elements and edit existing properties of a Precision Optimization (1×1×1 / METADATA) marketing campaign. This tool serves two purposes: 1. ADD new audiences, ads, offers, and keywords to campaigns across LinkedIn, Facebook, Instagram, Google Ads, and Reddit. 2. EDIT existing campaign level properties: name, budget group, schedule dates, and offers per channel.
CRITICAL: PRECISION / METADATA CAMPAIGNS ONLY — NATIVE CAMPAIGNS USE A DIFFERENT TOOL.
This tool edits **Precision Optimization (1×1×1 / METADATA)** campaigns. For a **Channel-First / Native / Platform-First (N×N×N)** campaign, use `add_and_edit_native_campaign_elements` instead (it takes container-shaped input). If you call this tool on a Native campaign it returns an error telling you to use the native tool (and vice-versa), so a wrong guess self-corrects — no silent mis-write. Pick by the campaign's structure, not by user phrasing.
CRITICAL: REMEMBER — CAMPAIGN STRUCTURE IS FIXED AT CREATION AND CANNOT BE CHANGED HERE.
A campaign's structure (Precision 1×1×1 vs Native N×N×N) is chosen at creation and this tool does NOT switch it. Changing structure means building a NEW campaign with create_campaign (Precision) or create_native_structure_campaign (Native).
WARNING: THIS IS THE TOOL TO USE WHEN THE USER WANTS TO:
- EDIT/UPDATE a campaign's name, budget group, start date, or end date
- CHANGE or REPLACE the offers assigned to a channel in a campaign
- ENABLE a channel on an existing campaign
- ADD new audiences, ads, ad groups, or keywords to a campaign
- Expand campaign reach without recreating the entire campaign
CRITICAL OFFER-CHANNEL PAIRING RULE (silent failure if violated)
Lead Gen offers are CHANNEL-LOCKED at creation time (the channel was set on create_update_offer via data.channel). When you populate any channel's "offers" array here, you MUST only pass offer_ids whose data.channel matches that slot — the API DOES NOT validate the pairing and will SILENTLY return a "successful" update on a campaign that cannot serve.
• linkedin.offers → only Lead Gen offer_ids with data.channel='LINKEDIN' (or Landing Page offer_ids).
• facebook.offers → only Lead Gen offer_ids with data.channel='FACEBOOK' (or Landing Page offer_ids).
• instagram.offers → only Lead Gen offer_ids with data.channel='INSTAGRAM' or 'FACEBOOK' (or Landing Page offer_ids).
• google.offers → ONLY Landing Page offer_ids (Google Ads does not support Lead Gen forms).
• reddit.offers → ONLY Landing Page offer_ids (Reddit does not support Lead Gen forms).
Because this tool's "offers" arrays are FULL REPLACEMENTS (not appends), a wrong id here will overwrite the channel's correct offers with broken ones. If you cannot remember an offer_id's channel, call get_offer(name=<offer_name>) BEFORE submitting and inspect the channel field.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EDIT CAPABILITIES (overwrites/replaces previous values):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- name → Renames the campaign (smart: only executes if new name differs from current)
- budgetGroup → Reassigns campaign to a different budget group (smart: only if different from current)
- startDate → Replaces the campaign start date (can be updated independently)
- endDate → Replaces the campaign end date (can be updated independently)
- offers → WARNING: FULL REPLACEMENT per channel. Sending offers OVERWRITES the entire offer list for that channel.
- Channel state → Enables any channel included in the payload (idempotent if already enabled)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ADD CAPABILITIES (appends alongside existing, non-destructive):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- audiences → Appended to existing audiences (POST)
- exclude_audiences → Appended as channel-level EXCLUDE (negative-targeting) audience groups (POST). This is the consolidated home for exclusion audiences (the standalone add_exclusion_audiences_to_campaign tool was retired).
- target_groups → Appended to existing target groups (POST)
- ads → Appended to existing ads/ad groups (POST)
- keywords (Google only) → Create keyword groups (free-text and/or existing keyword IDs); optionally LINK a group to a native ad container (NATIVE structure), or change an existing group's match type in place (set_match_type)
- negative_keyword_lists (Google only) → Assigned to Google Ads channel after processing
REQUIRED PARAMETERS:
- campaignId: Campaign ID (numeric identifier for the campaign)
- campaignType: "Lead Gen" or "Brand Awareness" (must match existing campaign)
- name: Campaign name
- startDate: Campaign start date in YYYY-MM-DD format
- endDate: Campaign end date in YYYY-MM-DD format
- budgetGroup: Budget group name
CHANNEL ELEMENTS:
WARNING: ADS — SEPARATE (default) vs BUNDLED INTO ONE GROUP (opt-in):
- "ads.list": ad IDs sent one per request. DEFAULT — use this unless the user
explicitly asks to group ads. A list of N ids produces N separate ads, not one bundle.
- "ads.groups" ([{name, ads:[ids]}]): bundles ads into named ad groups. ONLY when grouping is requested.
(LinkedIn has no ad groups — always use list.)
LinkedIn:
- audiences: Array of audience names (APPENDED)
- target_groups: Array of Targeting Group names (APPENDED)
- ads: Object with "groups" (ad group objects) and/or "list" (individual ad IDs) (APPENDED)
- offers: Array of offer IDs (WARNING: REPLACES all existing offers on this channel)
Facebook:
- audiences: Array of audience names (APPENDED)
- target_groups: Array of Targeting Group names (APPENDED)
- ads: Object with "groups" and/or "list" (APPENDED)
- offers: Array of offer IDs (WARNING: REPLACES all existing offers on this channel)
Instagram:
- audiences: Array of audience names (APPENDED)
- target_groups: Array of Targeting Group names (APPENDED)
- ads: Object with "groups" and/or "list" (APPENDED)
- offers: Array of offer IDs (WARNING: REPLACES all existing offers on this channel)
Google Ads:
- keywords: Object with "groups" and/or "set_match_type".
- groups: [{name, keywords?: [str], keyword_ids?: [int], match_type?: PHRASE|BROAD|EXACT, container?/container_id?}]
Creates keyword groups. A group naming a container/container_id is LINKED to that native ad container (NATIVE structure: keywordGroupId set by re-POSTing the channel's container list). A group with no container is appended unlinked.
- set_match_type: [{keyword_group_id? | container?/container_id?, match_type}] — change an existing group's match type in place (PATCH; non-destructive).
- audiences: Array of audience names (APPENDED)
- ads: Object with "groups" and/or "list" (APPENDED)
- offers: Array of offer IDs (WARNING: REPLACES all existing offers on this channel)
- negative_keyword_lists: Array of negative keyword list names (optional)
Example: ["Competitor Brands", "Low Intent Keywords"]
Assigned to the Google Ads channel after processing.
Names must match existing negative keyword lists (use list_negative_keywords_list to find them).
Reddit:
- audiences: Array of audience names (APPENDED)
- target_groups: Array of Targeting Group names (APPENDED; Reddit Target Groups come from create_reddit_target_group)
- ads: Object with "list" only — Reddit ads attach one per request, like LinkedIn (APPENDED)
- offers: Array of offer IDs (WARNING: REPLACES all existing offers on this channel)
- Channel settings (objective, comments, placements, conversion pixel) are NOT edited
here — use update_reddit_channel_settings. When this tool flips a disabled Reddit
channel to enabled, UI-equivalent defaults are applied (Lead Gen → CLICKS + AUTO_BID;
Brand Awareness → IMPRESSIONS + MANUAL_BID).
CHANNEL ACTIVATION LOGIC:
A channel is enabled if ANY of these conditions are met (OR logic):
- audiences array has at least 1 item, OR
- target_groups array has at least 1 item, OR
- ads object exists, OR
- offers array has at least 1 item, OR
- keywords exist (Google Ads only)
WARNING: AUDIENCES vs TARGET GROUPS — CRITICAL DISTINCTION:
- "audiences": standard Metadata audiences (Firmographic, Bombora Intent, Retargeting, LinkedIn/Facebook Native, etc.)
- "target_groups": Targeting Groups (also called Target Groups) created in the platform's Targeting Groups section.
Both are arrays of names (strings). Send each type in its own field — do NOT mix them.
If the user mentions a "Targeting Group" or "Target Group", it goes in "target_groups", NOT in "audiences".
EXAMPLES:
Edit campaign name and dates (no channel elements needed):
add_and_edit_campaign_elements({
"campaignId": 12345,
"campaignType": "Lead Gen",
"name": "NEW_CAMPAIGN_NAME_2025",
"startDate": "2025-09-01",
"endDate": "2025-12-31",
"budgetGroup": "BoFu"
})
Replace offers on LinkedIn:
add_and_edit_campaign_elements({
"campaignId": 12345,
"campaignType": "Lead Gen",
"name": "MD_LG_20252107161406",
"startDate": "2025-08-01",
"endDate": "2025-09-30",
"budgetGroup": "BoFu",
"linkedin": {
"offers": [57538, 57504]
}
})
Add audiences and ads to LinkedIn:
add_and_edit_campaign_elements({
"campaignId": 12345,
"campaignType": "Lead Gen",
"name": "MD_LG_20252107161406",
"startDate": "2025-08-01",
"endDate": "2025-09-30",
"budgetGroup": "BoFu",
"linkedin": {
"audiences": ["Test Native Audience", "EU Countries"],
"ads": {
"groups": [{"name": "1GOAT", "ads": [173669, 171805]}],
"list": [156502, 156485]
},
"offers": [57538, 57504]
}
})
Add Google keywords:
add_and_edit_campaign_elements({
"campaignId": 12345,
"campaignType": "Lead Gen",
"name": "MD_LG_20252107161406",
"startDate": "2025-08-01",
"endDate": "2025-09-30",
"budgetGroup": "BoFu",
"google": {
"keywords": {
"groups": [{"name": "CRM Keywords", "keywords": ["crm software", "lead gen tools"]}]
},
"audiences": ["SUP_SF_All-Customers-Contacts_ALL_3"],
"ads": {"list": [175258]},
"offers": [61054]
}
})
Mixed: edit budget group + add across multiple channels:
add_and_edit_campaign_elements({
"campaignId": 12345,
"campaignType": "Lead Gen",
"name": "MD_LG_20252107161406",
"startDate": "2025-08-01",
"endDate": "2025-09-30",
"budgetGroup": "ToFu",
"linkedin": {"audiences": ["New Audience"], "offers": [57538]},
"facebook": {"audiences": ["FB Audience"], "ads": {"list": [171806]}},
"google": {"keywords": {"groups": [{"name": "Keywords", "keywords": ["keyword"]}]}, "offers": [61054]}
})
VALIDATION:
- campaignId must match existing campaign
- All asset IDs (ads, offers) must exist
- Audience names must match existing audiences
- Budget group and name use smart filters: only updated if different from current values
- Dates support partial updates: you can change only startDate, only endDate, or both
RESPONSE: Returns
- success, campaign_id, campaign_name, campaign_type, status, status_label
- channels_updated: list of channel keys that had any edits
- elements_added: true if anything changed at the campaign or channel level
- added_summary: per-channel counts of what was ACTUALLY attached (audiences,
target_groups, ad_groups, individual_ads, offers, keyword_groups,
negative_keyword_lists) — not just what was requested
- changes: { renamed, budget_group_reassigned, schedule_updated }
reporting which campaign-level edits actually fired
- optimization_group: { id, tag_name } after the edit
- start_date, end_date, campaign_url, full_response (complete wizard state)
- errors[]: populated on partial failures; success=false if present
BID STRATEGY FOR NEWLY-ENABLED CHANNELS:
When a channel transitions from disabled → enabled as part of this edit, the
tool automatically applies the same auto-bid default used on create_campaign
(AUTO_BID on LI/FB/IG, TARGET_SPEND on Google, objective-driven on Reddit:
Lead Gen → CLICKS + AUTO_BID, Brand Awareness → IMPRESSIONS + MANUAL_BID)
so the channel is launch-ready.
Already-enabled channels keep their existing bid strategy untouched.
SMART-UPDATE BEHAVIOUR:
- name and budgetGroup are only pushed to the platform when different from
current values (prevents the UniqueWizardName validator from rejecting a
no-op rename, and avoids pointless tag churn).
- startDate / endDate are partial: supply either or both.
ERROR HANDLING: Validates campaign exists, verifies all asset IDs and audience
names. Failures on individual operations are collected into errors[] and the
rest of the edit proceeds — the campaign is not rolled back on partial errors.Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| campaign_data | Yes | Campaign data with fields to edit and/or elements to add |