Metadata
Manage B2B ad campaigns
- Category
- Marketing
- Primary Subcategory
- Ad Campaign Analytics & Reporting
Integration details
Description
Connect your Metadata account to create editable, on-brand ad concepts, look up audience targeting criteria and estimate reach, inspect campaign setup, and analyze advertising performance and pipeline attribution. Work with campaign workflows for Facebook, Instagram, LinkedIn, Reddit, Google Ads, and Microsoft Advertising, subject to your connected accounts, permissions, and the available tools. Review proposed changes before authorizing campaign launches or changes to live budgets. An existing Metadata account with MCP access is required.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Ad Campaign Analytics & Reporting
- Secondary Subcategories
- None listed
- Brand
- Metadata
- Access
- Account required
- First tracked
- 2026-09-19
- Tool count
- 171
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Get alerts for Metadata
Get updates when Metadata’s Discoverability Score or category rank changes.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competing in ChatGPT Ad Campaign Analytics & Reporting
View Category171 tools agents can invoke
Add 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.
add_and_edit_campaign_elements
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) attaches targeting groups to the native channel without a full container (places targetingGroupId on a reused/appended ad-less container). - 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`), 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. 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}, optimization_group, campaign_url, full_response). On partial failures, success=false plus `errors[]`; the rest of the edit still proceeds. 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} ]} })
add_and_edit_native_campaign_elements
Attach existing library extensions (sitelinks, callouts, etc.) to a native-structure Google Ads / Microsoft Ads campaign, so they actually serve when the campaign launches. ALSO KNOWN AS: add extension to campaign, attach sitelink, put sitelink on campaign, link extension to campaign, enable extension for campaign KEYWORDS: add, attach, link, bind, extension, sitelink, callout, campaign, native, native structure, channel first, google ads, microsoft ads, bing WHY THIS EXISTS: creating an extension only puts it in the account library — it is NOT attached to any campaign and will not serve. This tool performs the binding. WHEN TO USE: - "Add our 'Book a Demo' sitelink to campaign X" - "Attach these callouts to the native search campaign" - After create_google_sitelink_extension, when the user wants it live on a specific campaign WHEN NOT TO USE: - The campaign uses the Precision / METADATA structure — this tool covers native-structure campaigns only and will tell you so. Precision binds extensions per-creative and has no tool yet; direct the user to the platform UI. - You do not have the extension's internal id → call list_extensions first - Removing an attachment → use remove_extensions_from_native_campaign INPUTS (all required): - campaign_id: wizard campaign id - channel: GOOGLE_ADS or MICROSOFT_ADS - extension_ids: internal ids from list_extensions (the `id` field, NOT `externalId`) BEHAVIOUR: additive — existing attachments are preserved. Safe to re-run; already-attached ids are reported and left alone. ORDERING CAVEAT: add_and_edit_native_campaign_elements rebuilds the channel's native containers and CLEARS extension attachments. Attach extensions AFTER any native element edits, or re-attach afterwards. EXAMPLE: add_extensions_to_native_campaign(campaign_id=8421, channel="GOOGLE_ADS", extension_ids=[551, 552])
add_extensions_to_native_campaign
Add keywords to one or more existing Google Ads negative keyword lists. PURPOSE: Append keywords (typically search terms surfaced by list_search_terms) to one or more existing negative keyword lists, so future ads are blocked from matching them. Use this for the day-to-day "review search terms, exclude the wasteful ones" loop. WHEN TO USE: - Block search terms that consumed budget without producing clicks or conversions - Extend an existing "Keywords we don't wanna spend money on" list with new offenders - Apply the same keywords to multiple negative lists in a single call THIS IS NOT FOR CREATING A NEW LIST: To create a brand-new negative keyword list, use create_negative_keywords_list. This tool only appends to lists that already exist. LOOKING UP LIST IDS: Call list_negative_keywords_list first to find the id(s) of the list(s) you want to extend. The 'id' field returned there is what you pass here as negativeListIds. MATCH TYPE: Two ways to set the match type, pick whichever fits: (a) Single match type for the whole batch: pass keywords as plain strings and set the top-level match_type. Defaults to PHRASE (the same default the UI uses when adding from the search-terms page). (b) Mixed match types in a single call (preferred when recommending negatives after reviewing search terms, since it keeps the whole batch in one call): pass keywords as objects {text, match_type}. The per-item match_type wins over the top-level default. Items without a match_type fall back to the top-level default. Only PHRASE, BROAD, and EXACT are valid for negative keywords. COMMON USE CASES: 1. Add a single wasteful search term to one list (all-PHRASE): add_keywords_to_negative_lists( negativeListIds=[43256533], keywords=["free download"], ) 2. Add several terms to multiple lists, all exact-match: add_keywords_to_negative_lists( negativeListIds=[43256533, 43258891], keywords=["competitor a", "competitor b"], match_type="EXACT", ) 3. Mixed match types in ONE call (recommended after a search-terms review): add_keywords_to_negative_lists( negativeListIds=[43256533], keywords=[ {"text": "free download", "match_type": "PHRASE"}, {"text": "competitor a", "match_type": "EXACT"}, {"text": "how to", "match_type": "BROAD"}, ], ) 4. Mostly PHRASE with one EXACT override (mix strings + objects): add_keywords_to_negative_lists( negativeListIds=[43256533], keywords=[ "free download", "tutorial", {"text": "competitor a", "match_type": "EXACT"}, ], match_type="PHRASE", ) PARAMETERS: - negativeListIds (array of integers, required): IDs of the existing negative keyword lists to extend, as returned by list_negative_keywords_list. - keywords (array, required): each item is either a plain string (keyword text, uses the top-level match_type) or an object {text, match_type} where match_type overrides the top-level default. Min 1. - match_type (string, optional): EXACT, PHRASE, or BROAD. Default PHRASE. Used as the default for plain-string items and for object items that omit match_type. RESPONSE FORMAT: Returns the platform response describing the updated list(s). CHANNEL SCOPE: BOTH search channels are supported: pass channel=MICROSOFT_ADS for Microsoft Ads (Bing) and channel=GOOGLE_ADS for Google. The two channels hold SEPARATE lists, so never substitute one channel for the other to get "close enough" results.
add_keywords_to_negative_lists
Attach existing Google Ads negative keyword lists to campaigns that are ALREADY LAUNCHED — a live edit that syncs through to Google. CRITICAL: LIVE EDIT vs DRAFT EDIT — THE DISTINCTION THAT PICKS THIS TOOL: A campaign is a DRAFT until it is launched; every status after that (Launched, Launching, Editing, Finished, Error, Failed) is LIVE. Editing a live campaign is a different code path on the platform, not just a different status — the change has to be published to the running Google campaign, not only written to the wizard. • LIVE campaign (already launched) → THIS tool. It calls the platform's bulk live-edit endpoint, which publishes an update per running ad group so Google actually starts excluding the keywords. • DRAFT campaign (never launched) → the campaign-builder tools (`create_campaign` / `create_native_structure_campaign` / `add_and_edit_campaign_elements` / `add_and_edit_native_campaign_elements`, via their `negative_keyword_lists` field). Those write wizard state that gets pushed at launch. Pass a draft campaign here and it is SKIPPED with a reason rather than written — the draft path has different, destructive semantics, so this tool refuses to take it. If you are unsure which a campaign is, just call this tool: the per-campaign report tells you the status and which path applies. WORKS ON BOTH CAMPAIGN STRUCTURES. Negative keyword lists attach at the CHANNEL level, not to an ad group / container, so Precision Optimization (1×1×1) and Channel-First / Native (N×N×N) campaigns are handled identically. You do NOT need to know the structure, and you must NOT reach for `add_and_edit_native_campaign_elements` to do this on a live campaign — that tool rebuilds containers, which the platform forbids once experiments are launched. BULK BY DESIGN: pass every campaign the user named in ONE call. The platform endpoint takes a campaign list, and this tool groups them so campaigns needing the same final set share a single request. ADDS, DOES NOT REPLACE (default): the platform applies exactly the set of lists it is handed, so `mode="add"` first reads what each campaign already has and submits the union — attaching one list never silently detaches the others. Use `mode="replace"` ONLY when the user explicitly wants the campaign's negative lists to become exactly the ones named; the response's `detached` field reports what that removed. FINDING LISTS: pass `listNames` (what the user says) and/or `listIds` (from `list_negative_keywords_list`). Names must match an existing list EXACTLY (case-insensitive) — a name that matches nothing is reported in `warnings` and skipped, never swapped for a similar list. To attach a list that does not exist yet, create it first with `create_negative_keywords_list`. COMMON USE CASES: 1. Add one list to a running campaign: add_negative_keyword_lists_to_live_campaigns(campaignIds=[159490], listNames=["Competitor Brands"]) 2. Same lists across several live campaigns, one call: add_negative_keyword_lists_to_live_campaigns(campaignIds=[159490, 159502], listNames=["Job Seekers", "Free Content"]) 3. Make a campaign's negatives exactly one list (removes any others): add_negative_keyword_lists_to_live_campaigns(campaignIds=[159490], listIds=[43256533], mode="replace") RESPONSE FORMAT: Per campaign: status, `edit_path` ("live" / "draft"), `attached_before`, `newly_attached`, `already_attached`, `detached`, `attached_after`, and an `action` of submitted / no_change / skipped / failed. Top level carries `submitted_campaign_ids`, `warnings`, `errors`, and `delivery_note`. WARNING: ASYNC — REPORT IT HONESTLY: the platform accepts this in the background and answers with no body. `action: "submitted"` means ACCEPTED, not applied. It also drops campaigns server-side WITHOUT an error when they are locked by another pending change or when a launched campaign is not currently active/paused (e.g. completed). Tell the user the change was submitted and that it lands on Google shortly — do not claim it is live, and if they need certainty, re-check the campaign a little later. CHANNEL SCOPE: GOOGLE_ADS only — the platform endpoint is hardcoded to the Google Ads channel. It does NOT work for Microsoft Ads (Bing) even though Microsoft has the same negative-list concept; if the user asks for Microsoft, say this is not supported yet rather than calling with channel=GOOGLE_ADS.
add_negative_keyword_lists_to_live_campaigns
Archive (soft-delete) one or more ads on the Metadata platform. ARCHIVE IS HOW YOU DELETE AN AD. The platform has NO hard-delete endpoint for ads — archive is the soft-delete and the only way to remove an ad from the active library. When the user says "delete this ad", "remove this ad", "discard this ad", "trash this ad", or "get rid of this ad" → call archive_ad. Do NOT hallucinate a delete_ad or remove_ad tool; it does not exist. The archived ad is preserved on the platform (it still has its id, creative_json, and history) and can be restored with unarchive_ad. USE THIS TOOL WHEN: - User asks to delete, remove, discard, trash, drop, retire, or archive one or more ads. - User wants to clean up draft ads they no longer need. - User asks "make this ad go away" or similar. HOW TO GET THE id(s): - search_ads_by_names(ad_names=[...]) → returns active ad ids. - get_ad_details(ids=...) → confirms an ad exists if the id is already known (works for active ads). ALSO KNOWN AS: archive ad, delete ad, remove ad, discard ad, trash ad, drop ad, retire ad, soft-delete ad, get rid of ad. KEYWORDS: archive, delete, remove, discard, trash, drop, retire, soft-delete, hide, get rid of, clean up, ad cleanup. PARAMETERS: - ids: Array of integer ad ids (at least one). Bulk-friendly — pass several ids to archive multiple ads in a single call. RETURNS: { "success": true, "archived_ids": [123, 456], "count": 2 } To bring an archived ad back, call unarchive_ad with the same id(s).
archive_ad
Archive (delete) a custom audience from the Metadata platform. Use this tool when the user wants to archiveo or delete a custom audience from the entire System. You can identify the audience either by its numeric custom_audience_id or by its name. If only the audience name is provided, the tool will search existing audiences to resolve the correct ID before archiving. PARAMETERS: • custom_audience_id (optional): The numeric ID of the custom audience to archive. • audience_name (optional): The name of the custom audience to archive. Used to look up the ID if custom_audience_id is not provided. At least one of custom_audience_id or audience_name must be provided. RESPONSE: • actionStatus: "SUCCEEDED" if the audience was archived successfully.
archive_audience
Check whether a draft campaign is ready to launch, per channel. Reads the campaign's real configuration from the platform and reports, for each ENABLED channel, whether it has the ads, audience, offer, budget AND a live channel connection it needs to go live - plus a specific list of blockers for anything missing. KEYWORDS: campaign, launch, readiness, ready, preflight, can launch, blockers, missing, go live, validate, checklist WHEN TO USE: - Before launching a campaign, to confirm it is actually ready - After assembling or editing a draft, as the go/no-go check - When the user asks "is my campaign ready to launch?" or "what's missing?" RETURNS: A per-channel readiness report: - is_launchable: whether EVERY enabled channel is ready - verified: whether the platform's pre-launch check actually answered. When false, is_launchable is an assumption, NOT a verdict - say the check could not be run instead of telling the user the campaign is ready. - channels: [{channel, launchable, blockers[], ads, audiences, offers, budget}] - summary: a one-line human verdict This is a READ-ONLY check - it does NOT launch anything. Use launch_campaign to actually launch. CHANNEL CONNECTION: a channel with no live integration is reported as a blocker here, and the platform will refuse the launch itself. This is the ONLY point in a build where a missing connection matters - audiences, targeting, offers, creative and the draft campaign are all built without one on purpose. So do NOT ask the user to connect anything earlier; raise it here, name the channels, and offer to connect them. PARAMETERS: - campaign_id: The wizard campaign ID (integer, required) CAMPAIGN ID SOURCES: - search_campaigns_by_names tool (returns campaign IDs) - create_campaign tool response (returns campaign_id)
check_campaign_launch_readiness
Get the OAuth redirect URL to connect a specific CRM system to the Metadata platform. USAGE INSTRUCTIONS FOR LLM: Use this tool to obtain the authorization URL that users need to visit to connect their CRM accounts. This tool returns a redirect URL that initiates the OAuth flow for the selected CRM system. WHEN TO USE THIS TOOL: - User asks to "connect [CRM name]" - User wants to "add [CRM] integration" - User needs to "link [CRM] account" - User wants to "authorize [CRM] access" - User asks "how do I connect my Salesforce/HubSpot CRM?" - User needs to "set up [CRM] connection" - After disconnecting a CRM and wanting to reconnect - User asks "give me the link to connect [CRM]" SUPPORTED CRM SYSTEMS: - salesforce: Connect Salesforce CRM - hubspot: Connect HubSpot CRM IMPORTANT WORKFLOW - MUST FOLLOW THESE STEPS: 1. Call this tool to get the OAuth redirect URL 2. Display the URL to the user clearly and instruct them to open it in their browser 3. Explain that they need to complete the authorization process on the CRM's website 4. IMPORTANT: Ask the user to return to the chat and confirm when they have completed the connection 5. WAIT for the user's confirmation before proceeding with any other tasks 6. Once the user confirms the connection is complete, acknowledge it and continue REQUIRED USER INTERACTION: - The user MUST visit the returned URL in their browser to complete OAuth authorization - The URL will redirect to the CRM's authorization page - After authorization, the user will be redirected back to Metadata platform - The connection will be active once the OAuth flow is completed successfully - YOU MUST WAIT for user confirmation before proceeding COMMON SCENARIOS: Scenario 1 - Connect Salesforce: "I want to connect my Salesforce CRM" → Call connect_crm with crm="salesforce" → Show URL to user: "Please open this URL to connect your Salesforce CRM: [URL]" → "After completing the authorization, please return here and let me know it's done so we can proceed." → WAIT for user confirmation Scenario 2 - Connect HubSpot: "Connect HubSpot CRM" → Call connect_crm with crm="hubspot" → Show URL to user with instructions → WAIT for user confirmation Scenario 3 - Reconnect workflow: "I want to reconnect my Salesforce with different credentials" → First disconnect existing connection if needed → Call connect_crm with crm="salesforce" → Provide the URL to user → WAIT for user confirmation RESPONSE FORMAT: Returns an object containing the redirect URL for OAuth authorization. Example: {"redirectUrl": "https://login.salesforce.com/services/oauth2/authorize?..."} EXAMPLE: "Connect Salesforce" → connect_crm(crm="salesforce")
connect_crm
Get the OAuth redirect URL to connect a specific advertising channel to the Metadata platform. USAGE INSTRUCTIONS FOR LLM: Use this tool to obtain the authorization URL that users need to visit to connect their advertising channel accounts. This tool returns a redirect URL that initiates the OAuth flow for the selected channel. WHEN TO USE THIS TOOL: - User asks to "connect [channel name]" - User wants to "add [channel] integration" - User needs to "link [channel] account" - User wants to "authorize [channel] access" - User asks "how do I connect my Facebook/LinkedIn/Twitter/Reddit/Google account?" - User needs to "set up [channel] connection" - After disconnecting a channel and wanting to reconnect - User asks "give me the link to connect [channel]" SUPPORTED CHANNELS: - linkedin: Connect LinkedIn advertising account - meta: Connect Facebook/Instagram advertising accounts (Meta Business Suite) - google: Connect Google Ads account - reddit: Connect Reddit advertising account - x: Connect X (Twitter) advertising account IMPORTANT WORKFLOW - MUST FOLLOW THESE STEPS: 1. Call this tool to get the OAuth redirect URL 2. Display the URL to the user clearly and instruct them to open it in their browser 3. Explain that they need to complete the authorization process on the channel's website 4. IMPORTANT: Ask the user to return to the chat and confirm when they have completed the connection 5. WAIT for the user's confirmation before proceeding with any other tasks 6. Once the user confirms the connection is complete, acknowledge it and continue REQUIRED USER INTERACTION: - The user MUST visit the returned URL in their browser to complete OAuth authorization - The URL will redirect to the channel's authorization page - After authorization, the user will be redirected back to Metadata platform - The connection will be active once the OAuth flow is completed successfully - YOU MUST WAIT for user confirmation before proceeding COMMON SCENARIOS: Scenario 1 - Connect new channel: "I want to connect my LinkedIn account" → Call connect_channel with channel="linkedin" → Show URL to user: "Please open this URL to connect your LinkedIn account: [URL]" → "After completing the authorization, please return here and let me know it's done so we can proceed." → WAIT for user confirmation Scenario 2 - Reconnect after disconnect: "Get me the link to reconnect Facebook" → Call connect_channel with channel="meta" → Show URL to user with instructions → WAIT for user confirmation Scenario 3 - Setup new integration: "How do I add Google Ads?" → Call connect_channel with channel="google" → Explain OAuth process and provide URL → Ask user to confirm when complete → WAIT for user confirmation Scenario 4 - Add Twitter/X: "Connect my X account" → Call connect_channel with channel="x" → Provide the URL to user → WAIT for user confirmation RESPONSE FORMAT: Returns an object containing the redirect URL for OAuth authorization. Example: {"redirectUrl": "https://oauth.channel.com/authorize?client_id=..."} EXAMPLE: "Connect LinkedIn" → connect_channel(channel="linkedin")
connect_channel
Create a dynamic Insights Retargeting audience from a saved Insights (Spotlight) segment: the companies matching the segment inside a lookback window, refreshed automatically as the journey data changes. TWO VARIANTS (audience_type): - "contacts" (default): Insights Retargeting Contacts, platform type WEBSITE_RETARGETING. Contacts at the matching accounts, matched through the Metadata contact graph; usable on LinkedIn, Facebook, Instagram, X and Reddit. - "accounts": Insights Retargeting Accounts, platform type WEBSITE_ACCOUNT_RETARGETING. The matching COMPANIES pushed to LinkedIn as a matched company audience; LinkedIn only. The shape for account-level INCLUSION or EXCLUSION on LinkedIn, e.g. suppressing accounts that already received 200+ impressions from a sequenced program. WHEN: behaviour- or CRM-state-based retargeting and suppression ("retarget accounts that visited pricing", "exclude accounts we already saturated", "high engagement score not in the CRM"). NOT for firmographic / technographic / intent asks (use those audience tools), and NOT for LinkedIn ad-engagement retargeting (create_linkedin_engagement_retargeting_audience works off LinkedIn's own engagement signals; this one works off the Spotlight journey: website visits, impressions, clicks, scores, CRM state). WORKFLOW (each step is checked and a failure is refused with the reason): 1. list_segments, then get_segment_criteria(segment_id, lookback_window): the segment must exist, be READY, and match at least one account in the window. A segment matching 0 accounts is refused (widen the window, or create_segment with looser criteria). 2. lookback_window in days (1 to 365): the window the segment's metrics are evaluated over ("in the last 90 days" = 90). 3. Call this tool with a descriptive name. The audience appears in the library as "Insights Retargeting Contacts (Dynamic)" or "Insights Retargeting Accounts (Dynamic)". RETURNS: {success, id, audience_id, audience_name, status, audience_type, platform_audience_type, segment_id, segment_name, lookback_window, accounts_in_window, channels, expectedNumberOfCompanies, expectedNumberOfContacts, criteria}. Member matching is asynchronous: -1 or 0 right after creation means "not matched yet"; check again later with get_deep_audience_details. USED AS AN EXCLUSION: Ann attaches it through add_and_edit_campaign_elements (`exclude_audiences`) on the campaign that must not reach those accounts.
create_audience_from_segment
Create Bombora buyer intent audiences on the Metadata platform. Creates B2B audiences based on buyer intent topics, company firmographics, contact attributes, and geographic targeting. IMPORTANT PREREQUISITE: Before using this tool, call get_intent_topics first to verify that Bombora topics are available. If get_intent_topics returns NO topics (empty list), Bombora is NOT available for this account — do NOT suggest or use this tool. Instead, recommend creating a firmographic audience (create_firmographic_audience) as the preferred alternative. Firmographic audiences are the default and most commonly used audience type. WHEN TO USE: - ONLY after get_intent_topics confirms that Bombora topics are available - Create targeted B2B audiences based on buyer intent signals using Bombora data - Target companies by industry, size, and employee count - Target contacts by seniority level and job function - Target specific buyer intent topics (e.g., Pardot, Salesforce) - Set geographic targeting and contact limits per company BUYER INTENT TOPICS: Use the get_intent_topics tool to retrieve available intent topics before creating the audience. Intent topics represent buyer interest areas such as: - CRM solutions (e.g., Pardot, Salesforce) - Marketing automation platforms - Analytics and BI tools - And many others based on available topics TARGETING OPTIONS: - Intent Topics: Use topic values from get_intent_topics (required for Bombora audience) - Industries: Use industry IDs. Examples: 1=Defense & Space, 4=Computer Software, 6=Internet, 7=Semiconductors, 8=Telecommunications, 11=Management Consulting, 12=Biotechnology, 41=Banking, 42=Insurance, 43=Financial Services, 80=Marketing & Advertising, 96=Information Technology & Services - Employees: "FROM_1_TO_10", "FROM_10_TO_50", "FROM_50_TO_200", "FROM_200_TO_500", "FROM_500_TO_1000", "FROM_1000_TO_5000", "FROM_5000_TO_10000", "OVER_10000" - Job Function / Seniority / Job Title / Location: identical shape to the Firmographic + G2 tools (PRD-29704 — the old Bombora-specific names `function_ids` / `seniority_ids` / `countries` / `cities` were renamed to the canonical contact-criteria fields below so Max can transfer the same criteria across audience types). CONTACTS CRITERIA: Use the following parameters to filter and target specific contacts within accounts: GEOGRAPHIC TARGETING: - location_country_ids: Array of country IDs (e.g., [29] for Brazil, [229] for United States) - location_state_ids: Array of state IDs (e.g., [5] for California, [32] for New York) JOB TITLES: - job_title_includes: Array of free text strings to include (e.g., ["Software Engineer", "Manager"]) - job_title_excludes: Array of free text strings to exclude (e.g., ["Senior", "Lead"]) JOB FUNCTIONS: Valid job function IDs and their labels: - 1: Marketing, 2: Sales, 3: Customer Service, 4: Finance, 5: Human Resources, 6: Public Relations - 7: Media, 8: Design, 9: Engineering, 10: Operations, 11: Legal, 12: Education - 13: Health, 14: Real Estate, 15: Accounting, 16: Administrative, 17: Business Development - 18: Community and Social Services, 19: Consulting, 20: Entrepreneurship, 21: Information Technology - 22: Military and Protective Services, 23: Product Management, 24: Program and Project Management - 25: Purchasing, 26: Quality Assurance, 27: Research, 28: Trades - job_function_include_ids: Array of job function IDs to include (e.g., [9] for Engineering) - job_function_exclude_ids: Array of job function IDs to exclude SENIORITY LEVELS: Valid seniority IDs and their labels: - 2: Manager, 3: Director, 4: VP, 5: CXO, 6: Unpaid, 7: Training - 8: Senior, 9: Owner, 10: Entry, 11: Partner - seniority_include_ids: Array of seniority level IDs to include (e.g., [10, 7] for Entry and Training) - seniority_exclude_ids: Array of seniority level IDs to exclude CONTACT LIMITS: - contacts_per_company_limit: Maximum number of contacts to target per company (optional). Example: 20 USAGE NOTES: - All ID fields (countries, states, job functions, seniorities) use numeric IDs from the platform - Job titles are free text strings, not IDs - Use include parameters to specify which criteria to target - Use exclude parameters to filter out contacts matching specific criteria - Combine multiple criteria for precise targeting (e.g., Senior Engineers in California) - Criteria are combined with AND logic, so all conditions must be met CONTACTS CRITERIA PARAMETERS(Usually after other initial audience parameters to be described next): - location_country_ids: Array of country IDs (optional) - location_state_ids: Array of state IDs (optional) - job_title_includes: Array of job title keywords to include (optional) - job_title_excludes: Array of job title keywords to exclude (optional) - job_function_include_ids: Array of job function IDs (optional) - job_function_exclude_ids: Array of job function IDs (optional) - seniority_include_ids: Array of seniority level IDs (optional) - seniority_exclude_ids: Array of seniority level IDs (optional) - contacts_per_company_limit: Maximum contacts per company (optional) Returns audience details with ID, size estimation, and creation status.
create_bombora_audience
Create a **CSV Upload - LinkedIn Native** audience (platform `customAudienceType=NATIVE_TARGETING_CSV`). AUDIENCE TYPE (mirrors the UI's "Audience Type" dropdown): • UI label: "CSV Upload - LinkedIn Native" • Platform enum: NATIVE_TARGETING_CSV • Channel: LinkedIn only. • Two-step flow handled server-side: the CSV is uploaded as a NATIVE ABM list, then the audience is created from it with the LinkedIn-native firmographics + contact criteria applied. PREREQUISITE: • LinkedIn integration MUST be connected. WHEN TO USE (exact user phrasing this tool should match): • "CSV Upload - LinkedIn Native" • "Upload a CSV and target LinkedIn natively" • "LinkedIn native audience from this CSV" • The user attached a CSV of companies AND asked for LinkedIn-native targeting (employees / revenues / job titles / skills resolved via LinkedIn). WHEN NOT TO USE: • If the user asked for a plain "CSV Upload - Accounts" → use `upload_account_list_csv_audience` (creates FIRMOGRAPHIC_INCLUDE, NOT LinkedIn-native). • If the user asked for "Native Criteria - LinkedIn" without a CSV → use `create_linkedin_native_criteria_audience`. TWO WAYS TO SUPPLY THE ACCOUNT LIST — provide EXACTLY ONE of: • `companies`: inline `{<companyname>: <companywebsite>}` map (short ad-hoc lists). • `companies_source_csv_url`: URL of a CSV with header `companyname,companywebsite` (case-insensitive). The MCP server downloads, validates, and uploads it as a native ABM list. CRITERIA (all optional, LinkedIn-native shapes resolved server-side): • employees — LinkedIn employee ranges (e.g. "201-500", "501-1000"). • revenues — LinkedIn revenue ranges (e.g. "$1M-$10M"). • company_names — free-text company names (resolved to LinkedIn IDs). • location_country_ids — country IDs (e.g. 229=US). • job_titles — free-text titles (resolved to LinkedIn IDs). • skills — free-text skills (resolved to LinkedIn IDs). RETURNS: id, audience_id, audience_name, audience_type (NATIVE_TARGETING_CSV), status, abmSearchCriteriaId, companies_count, upload_filename, counts.
create_csv_upload_linkedin_native_audience
Create a multi-channel campaign using the platform's "Channel First Structure" (N×N×N) — the UI also labels it "Native Structure" / "Platform-First Structure". Your audiences, ads, and offers are organized into the ad platform's NATIVE structure (the WizNativeAdContainer entity) and optimized TOGETHER by the platform's own algorithm — ~1 experiment per channel (LinkedIn is the only exception: one experiment per container), with unified reporting and pacing. You specify the structure as explicit per-container groupings (each container is one audience + its `ad_offers` rows); the "N×N×N" label refers to the native structure holding your full set of audiences, ads, and offers together (it is NOT one isolated experiment per combination — that's Precision Optimization, `create_campaign`). Platform product copy: "Traditional hierarchical setup that leverages native platform algorithms while maintaining Metadata's pacing control, unified user experience and reporting." Sets channel.structureType=NATIVE. KEYWORDS (for tool discovery — many users ask by the math, not the product name): NxNxN, N×N×N, "NxNxN campaign", Channel First Structure, Native Structure, Platform-First Structure, channel-first, platform-first, native platform structure, WizNativeAdContainer, container-based campaign, traditional / hierarchical structure, unified reporting. NAMING CONVENTION (from the platform UI's "Campaign Structure" selector — match these exact labels): • "Channel First Structure (NxNxN)" = THIS tool (`create_native_structure_campaign`); the UI also shows "Native Structure" / "Platform-First Structure". Audiences/ads/offers grouped in the platform's native structure and optimized together (~1 experiment per channel). "native" / "platform" here = the native ad platform (LinkedIn / Facebook / Google) whose algorithms this leans on — and structureType=NATIVE matches. • "Precision Optimization (1x1x1)" = the OTHER tool, `create_campaign` — each audience×ad×offer combination tested as its own isolated experiment. Metadata's signature approach; the DEFAULT. Routing anchor: "native" / "channel first" / "platform first" / "NxNxN" → this tool; "precision" / "1x1x1" → create_campaign. ════════════════════════════════════════════════════════════════════════════════ WARNING: TWO CAMPAIGN-CREATION TOOLS EXIST — READ BEFORE PICKING ONE ════════════════════════════════════════════════════════════════════════════════ CRITICAL: REMEMBER — HOW TO CHOOSE THE STRUCTURE (the user's decision always wins): 1. If the user explicitly names one, RESPECT IT — "native" / "Native Structure" / "Channel First" / "Platform-First" / "NxNxN" → create_native_structure_campaign (this tool); "precision" / "Precision Optimization" / "1x1x1" → create_campaign. 2. ELSE, if the request involves MANY ads AND audiences (Precision Optimization makes one experiment per combination — a large experiment count), ASK the user which structure they want before creating — do not guess. 3. OTHERWISE, DEFAULT to Precision Optimization (1×1×1) → create_campaign (NOT this tool). The two build structurally different, non-swappable campaigns — so once the user decides, respect that decision for the rest of the campaign. USE THIS TOOL (`create_native_structure_campaign`) — "Channel First" / "Native Structure" (N×N×N) — WHEN: • The user says "native", "Native Structure", "Channel First Structure", "channel-first", "Platform-First Structure", "platform-first", "NxNxN", "N×N×N", "WizNativeAdContainer", or asks for the traditional / hierarchical / native-platform structure. • The user wants the ad platform's native structure to group and optimize audiences/ads/offers together (~1 experiment per channel, unified reporting) rather than an isolated experiment per combination. • The user provides explicit per-container groupings of one audience + its (ad, offer) pairs. USE `create_campaign` ("Precision Optimization", 1×1×1) INSTEAD — DO NOT USE THIS TOOL — WHEN: • The user says "Precision Optimization", "precision", "1x1x1", "1×1×1", or wants every audience×ad×offer combination tested separately in its own experiment. • The user wants maximum budget control / fastest per-combination learning. • No structure was specified — Precision Optimization (`create_campaign`) is the DEFAULT. If you're unsure whether the user wants isolated per-combination experiments (→ `create_campaign`, Precision Optimization) or the native-platform grouped structure (→ this tool, Channel First), ASK which structure they want — switching modes after creation requires rebuilding the campaign from scratch. The two tools produce structurally different campaigns on the backend (channel.structureType = METADATA for create_campaign, = NATIVE for this tool) and are NOT swappable mid-campaign. Pick correctly the first time. ════════════════════════════════════════════════════════════════════════════════ WHEN TO USE THIS TOOL: - The user explicitly asks for "Channel First Structure" / "Native Structure" / "Platform-First Structure" / N×N×N / WizNativeAdContainer / the native-platform structure. - You want the ad platform's algorithm to optimize audiences/ads/offers together under a unified structure (~1 experiment per channel) instead of isolating every combination. - You want a compact, platform-managed experiment footprint with unified reporting. WHEN NOT TO USE THIS TOOL: - The user wants "Precision Optimization" (1×1×1) — every combination tested as its own isolated experiment — use `create_campaign`. - No structure was specified (default is Precision Optimization) — use `create_campaign`. CAMPAIGN TYPES (same as create_campaign): 1. "Lead Gen" — only Lead Gen (LG) offers allowed in any container. 2. "Brand Awareness" — both LG and LP offers allowed. WARNING: OFFER-CHANNEL CHANNEL-LOCK STILL APPLIES Lead Gen offers are channel-locked at the offer's creation time. A container under `linkedin.containers` MUST reference an offer whose data.channel='LINKEDIN' (or any Landing Page offer). Cross-channel reuse silently produces a non-serving campaign. The server does NOT validate the pairing. Same rules as create_campaign: - linkedin.containers[i].ad_offers[].offer → LINKEDIN-locked LG OR any LP - facebook.containers[i].ad_offers[].offer → FACEBOOK-locked LG OR any LP - instagram.containers[i].ad_offers[].offer → FACEBOOK/INSTAGRAM-locked LG OR any LP - google.containers[i].ad_offers[].offer → Landing Page offers ONLY (Google Ads has no native LG form support) - reddit.containers[i].ad_offers[].offer → Landing Page offers ONLY (Reddit has no native LG form support) - microsoft.containers[i].ad_offers[].offer → MICROSOFT_ADS-locked LG OR any LP Each container is one audience × a LIST of (ad, offer) pairs (`ad_offers`, 1+). Put several pairs in one container to group multiple ads/offers under the same audience — the platform's native ad-set with multiple Ad/Offer rows. "1 audience → 3 ads → 1 offer" is ONE container whose `ad_offers` holds 3 pairs that repeat the same `offer` id. (Each pair is exactly one ad with one offer; to run the same audience as two separate ad-sets, send two containers instead.) WARNING: SEARCH CHANNELS ARE KEYWORD-FIRST — `audience` IS OPTIONAL FOR GOOGLE ADS & MICROSOFT ADS Google/Microsoft search ad groups are keyword-targeted, so a search container may OMIT `audience` and run keyword-only (just keywords + ad_offers). The platform allows audience-less native search containers, so this tool no longer forces an audience there. `audience` STAYS REQUIRED for the audience-targeted social channels (LinkedIn / Facebook / Instagram / Reddit). A search container with neither an audience nor keywords has nothing to target and is rejected. REQUIRED FIELDS: - campaignType: "Lead Gen" | "Brand Awareness" - name: unique campaign name - startDate / endDate: YYYY-MM-DD - budgetGroup: budget group name - At least one channel block with a non-empty containers list PER-CHANNEL SHAPE: Every channel block (linkedin / facebook / instagram / google / reddit / microsoft) takes: containers: [ { name: "string (<=255 chars) — visible in the platform UI", audience: "audience name (resolved server-side via the same matched-poll create_campaign uses). REQUIRED for LinkedIn/Facebook/Instagram/Reddit; OPTIONAL for Google/Microsoft search (omit it for keyword-only ad groups)", ad_offers: [ {ad: <int WizCreative ID>, offer: <int offer ID>}, ... ] // 1+ Ad/Offer pairs sharing this container's audience; repeat the same offer id to run several ads on it, target_group: "optional Targeting Group name (singular — one per container)", exclude_audience: "optional audience name to use as the exclude group for this container" } ] SEARCH-CHANNEL EXTRAS (Google Ads + Microsoft Ads, per container): keywords: ["string", ...] // free-text phrases — created in the keyword library and grouped into this container's keyword group keyword_ids: [<int>, ...] // optional; existing keyword-library IDs (from list_keywords) to put in this container's group — unioned with `keywords` match_type: "PHRASE"|"BROAD"|"EXACT" // optional; match type for this container's keyword group (default PHRASE) negative_keyword_lists: ["name", ...] // optional; applied at the channel level On a search channel `audience` is OPTIONAL: a keyword-only container (keywords + ad_offers, no audience) is valid and is how non-brand / pure-keyword search is normally structured. You can still pass an audience to layer one on. The keyword group is created and linked to the container automatically. A search container with neither an audience nor keywords (`keywords`/`keyword_ids`) is rejected (nothing to target). AUDIENCE NAME RESOLUTION: - `audience` and `exclude_audience` are NAMES, not IDs. Same lookup path as create_campaign — the tool waits up to ~20s per channel for a freshly-created audience to become attachable (firmographics + FB/IG can take 8-15s). - Audience names are resolved BEFORE any container elements are created: a container whose `audience` cannot be resolved is dropped up front (no keyword group or other element is left behind for it) and the failure is reported in the response `errors[]`. The error states whether retrying can help ("may still be matching") or not ("not available on this channel") — do NOT blind-retry the latter. The rest of the campaign still gets built. - On Google/Microsoft search containers `audience` may be omitted entirely (keyword-only) — only names that are actually provided are resolved, so leaving it out costs no polling and raises no error. AD AND OFFER ARE IDS (one `ad_offers` pair = one ad + one offer): - `ad` is the ID returned by `create_update_image_ad` or `create_update_video_ad`. - `offer` is the ID returned by `create_update_offer`. The tool looks up each unique offer to discover whether it's a Landing Page or Lead Gen Form and routes it into the right `nativeAds[].landingPageId` vs `nativeAds[].leadGenFormId` slot. Every pair becomes one `nativeAds[]` entry under the container. BID STRATEGY (automatic): Same defaults as create_campaign: - LinkedIn / Facebook / Instagram → AUTO_BID - Google Ads / Microsoft Ads → TARGET_SPEND (device modifiers reset) - Reddit → objective-driven, mirroring the platform UI: Lead Gen forces CLICKS (Traffic) + AUTO_BID; Brand Awareness keeps IMPRESSIONS + MANUAL_BID. Adjust later with update_reddit_channel_settings. WHAT THE TOOL DOES FOR YOU (single call, no follow-up needed): Creates the campaign shell and its budget group, enables each requested channel and sets it to the NATIVE structure, builds the per-container keyword group on Google / Microsoft Ads search channels, creates one native ad container per grouping with its ad/offer pairs, applies the bid strategy, and sets the schedule. The response reflects the final campaign state — you do not need to sequence or repeat any of this. RESPONSE: Same top-level shape as create_campaign (`success`, `campaign_id`, `campaign_url`, `status`, `optimization_group`, `summary`, `full_response`). The per-channel breakdown returns a `containers` array — `[{id, name, experiment_id, audience_group_id, targeting_group_id, group_exclude_id, keyword_group_id, native_ads: [{id, ad_id, landing_page_id, lead_gen_form_id}]}]` — instead of the legacy `audiences`/`ad_groups`/`lead_gen_forms` arrays. On partial failures, returns success=false plus `errors[]` with per-container detail. EXAMPLE (Lead Gen, LinkedIn-only, two containers): create_native_structure_campaign(campaign_data={ "campaignType": "Lead Gen", "name": "Q3_ABM_Native_2026", "startDate": "2026-06-01", "endDate": "2026-08-31", "budgetGroup": "BoFu", "linkedin": { "containers": [ {"name": "IT Mgrs > Demo > Form", "audience": "IT Managers - NA", "ad_offers": [{"ad": 156502, "offer": 57538}]}, {"name": "CTOs > Demo > Form", "audience": "CTOs - Tech", "ad_offers": [{"ad": 156485, "offer": 57504}]} ] } }) EXAMPLE (one audience → 3 ads on the SAME offer, ONE container — the multi-ad ad-set): create_native_structure_campaign(campaign_data={ "campaignType": "Brand Awareness", "name": "Q3_3Ads_1Offer_2026", "startDate": "2026-06-01", "endDate": "2026-07-31", "budgetGroup": "Brand", "facebook": { "containers": [ {"name": "ICP > 3 creatives > TOF offer", "audience": "26-Q2-ICP-AllPersonas-NA", "ad_offers": [ {"ad": 210801, "offer": 67269}, {"ad": 210802, "offer": 67269}, {"ad": 210803, "offer": 67269} ]} ] } }) EXAMPLE (Brand Awareness, Google + LinkedIn, with keywords): create_native_structure_campaign(campaign_data={ "campaignType": "Brand Awareness", "name": "Q3_Brand_Native_2026", "startDate": "2026-06-01", "endDate": "2026-07-31", "budgetGroup": "Brand", "linkedin": { "containers": [ {"name": "Professionals A", "audience": "Professional Audience", "ad_offers": [{"ad": 173669, "offer": 57538}]} ] }, "google": { "containers": [ {"name": "CRM Search", "audience": "Tech Decision Makers", "ad_offers": [{"ad": 175260, "offer": 57600}], "keywords": ["crm software", "lead gen tools"], "negative_keyword_lists": ["Competitor Brands"]} ] } }) EXAMPLE (Brand Awareness, Google keyword-only — NO audience, pure non-brand search): create_native_structure_campaign(campaign_data={ "campaignType": "Brand Awareness", "name": "Q3_NonBrand_Search_2026", "startDate": "2026-06-01", "endDate": "2026-07-31", "budgetGroup": "Search", "google": { "containers": [ {"name": "Incident Response", "ad_offers": [{"ad": 210804, "offer": 67269}], "keywords": ["incident response platform", "on-call alerting"], "negative_keyword_lists": ["Competitor Brands"]} # note: no "audience" key — keyword-targeted ad group ] } }) BEST PRACTICES: 1. Decide each container's audience and its `ad_offers` pairs up front — this tool will not invent pairings for you. Group several ads under one audience by adding pairs to `ad_offers`. On Google/Microsoft search, audience-less (keyword + ad_offers) containers are valid; pure non-brand search normally has no audience. On Reddit, targeting is the `target_group` (create_reddit_target_group) and `audience` is optional — an audience only exists on a channel the account has CONNECTED, so naming one on a disconnected Reddit loses the container. 2. Use descriptive container names — they show up in the platform UI as the ad-set/ad-group label. 3. For Google Ads, put related keywords in the same container (each container becomes one keyword group). Don't pile dozens of unrelated keywords into a single container. 4. Use Brand Awareness for any container that needs Landing Page offers — Lead Gen campaigns reject LP offers. 5. The campaign URL is returned in the response: https://platform.metadata.io/hub/advertise/campaigns/{campaign_id}
create_native_structure_campaign
Create multi-channel advertising campaigns for LinkedIn, Facebook, Instagram, Google Ads, Reddit, and Microsoft Ads using the platform's "Precision Optimization" (1×1×1) model — Metadata's signature approach. Every audience×ad×offer combination is tested as its OWN isolated experiment (each experiment = exactly 1 audience × 1 ad × 1 offer); you pass per-channel lists of audiences, ads, and offers and the backend creates one experiment per combination. Platform product copy: "Metadata's signature approach with maximum budget control and fastest learning through separate testing of each combination." This is the DEFAULT structure when the user hasn't chosen one. Sets channel.structureType=METADATA (no WizNativeAdContainer). KEYWORDS (for tool discovery — many users ask by the math, not the product name): 1x1x1, 1×1×1, "1x1x1 campaign", "one by one by one", Precision Optimization, separate testing of each combination, isolated per-combination experiments, maximum budget control, fastest learning. NAMING CONVENTION (from the platform UI's "Campaign Structure" selector — match these exact labels): • "Precision Optimization (1x1x1)" = THIS tool (`create_campaign`). Each experiment isolates one audience×ad×offer cell; the platform builds one per combination. Metadata's signature approach; the DEFAULT. • "Channel First Structure (NxNxN)" = the OTHER tool, `create_native_structure_campaign` (the UI also shows it as "Native Structure" / "Platform-First Structure"). Audiences/ads/offers are grouped in the ad platform's NATIVE structure (WizNativeAdContainer) and optimized together by the platform (~1 experiment per channel). Routing anchor: "precision" / "1x1x1" → this tool; "native" / "channel first" / "platform first" / "NxNxN" → create_native_structure_campaign. (structureType=METADATA here, NATIVE there — and that lines up, because "native" means the native-platform structure.) ════════════════════════════════════════════════════════════════════════════════ WARNING: TWO CAMPAIGN-CREATION TOOLS EXIST — READ BEFORE PICKING ONE ════════════════════════════════════════════════════════════════════════════════ CRITICAL: REMEMBER — HOW TO CHOOSE THE STRUCTURE (the user's decision always wins): 1. If the user explicitly names one, RESPECT IT — "precision" / "Precision Optimization" / "1x1x1" → create_campaign (this tool); "native" / "Native Structure" / "Channel First" / "Platform-First" / "NxNxN" → create_native_structure_campaign. 2. ELSE, if the request involves MANY ads AND audiences (Precision Optimization makes one experiment per combination — a large experiment count), ASK the user which structure they want before creating — do not guess. 3. OTHERWISE, DEFAULT to Precision Optimization (1×1×1) → this tool (create_campaign). The two build structurally different, non-swappable campaigns — so once the user decides, respect that decision for the rest of the campaign. USE THIS TOOL (`create_campaign`) — "Precision Optimization" (1×1×1) — WHEN: • The user says "Precision Optimization", "precision", "1x1x1", "1×1×1", "separate testing of each combination", or wants each combination tested in its own isolated experiment. • The user gives per-channel lists of audiences/ads/offers and wants the platform to test every combination separately (one experiment per audience×ad×offer). • The user wants maximum budget control / fastest per-combination learning. • No structure was specified — this is the DEFAULT. USE `create_native_structure_campaign` ("Channel First" / "Native Structure", N×N×N) INSTEAD — DO NOT USE THIS TOOL — WHEN: • The user says "native", "Native Structure", "Channel First Structure", "channel-first", "Platform-First Structure", "platform-first", "NxNxN", "N×N×N", "WizNativeAdContainer", or asks for the traditional / hierarchical / native-platform structure. • The user wants the ad platform's native structure to group and optimize audiences/ads/offers together (~1 experiment per channel, unified reporting) rather than one isolated experiment per combination. • The user is migrating a campaign FROM "Precision Optimization" (1×1×1) TO the native "Channel First" structure. Do not silently call this tool when the user has signalled Channel-First / native intent — the schemas and resulting platform state are different and not swappable after creation. Apply the structure-selection rule above: respect an explicit "precision"/"native" choice; if the user didn't choose, ASK only when there are MANY ads AND audiences; otherwise default to Precision Optimization (1×1×1, this tool). ════════════════════════════════════════════════════════════════════════════════ WHEN TO USE: - Create multi-channel marketing campaigns with unified configuration - Set up campaigns with specific start/end dates and budget groups - Configure Lead Generation or Brand Awareness campaigns - Organize ads into groups with specific targeting and offers - Set up Google Ads campaigns with keyword targeting CAMPAIGN TYPES: 1. "Lead Gen" - Lead generation campaigns 2. "Brand Awareness" - Brand awareness campaigns CRITICAL OFFER TYPE RULE: - "Lead Gen" campaigns: ONLY Lead Gen (LG) form offers allowed. Landing Page (LP) offers are FORBIDDEN. - "Brand Awareness" campaigns: Both LG and LP offers allowed. No restriction. 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). An offer_id created with channel="LINKEDIN" CANNOT be assigned to facebook.offers / instagram.offers / google.offers — and vice versa. This server DOES NOT validate the pairing and will RETURN SUCCESS on a mis-wired campaign that cannot actually serve. The only way the user finds out is when the campaign produces zero impressions in the platform. HARD RULES (verify each offer_id BEFORE submitting): 1. linkedin.offers MUST contain ONLY offer_ids whose creating call set data.channel="LINKEDIN" (or Landing Page offer_ids, which have no channel and are universal). 2. facebook.offers MUST contain ONLY offer_ids with data.channel="FACEBOOK" (or Landing Page offer_ids). 3. instagram.offers MUST contain ONLY offer_ids with data.channel="INSTAGRAM" or "FACEBOOK" (or Landing Page offer_ids). 4. google.offers MUST contain ONLY Landing Page offer_ids — Google Ads does NOT support Lead Gen forms. Putting any Lead Gen offer_id in google.offers is a HARD FAILURE. 5. reddit.offers MUST contain ONLY Landing Page offer_ids — Reddit does NOT support Lead Gen forms (create_update_offer rejects channel="REDDIT"). Putting any Lead Gen offer_id in reddit.offers is a HARD FAILURE. 6. microsoft.offers MUST contain ONLY offer_ids with data.channel="MICROSOFT_ADS" (or Landing Page offer_ids). Unlike Google, Microsoft Ads DOES accept Lead Gen offers, but only when channel-locked to MICROSOFT_ADS. 7. If the user's campaign requires Lead Gen on multiple channels, you MUST have called create_update_offer SEPARATELY for each channel (one call per channel per concept). Cross-channel reuse of a Lead Gen offer_id WILL break the campaign even though this API returns success. 8. If you cannot remember which channel an offer_id was created for, call get_offer(name=<offer_name>) first and read the channel field — DO NOT GUESS. REQUIRED FIELDS: - campaignType: "Lead Gen" or "Brand Awareness" - name: Unique campaign name - startDate / endDate: YYYY-MM-DD format - budgetGroup: Budget group name (e.g., "BoFu", "ToFu", "Brand") - Per-channel dailyBudget (optional, min $10): the channel's daily spend in USD. Set it whenever a budget split was approved (monthly channel budget / 30); a channel without it keeps the platform default of $50/day. - At least one channel must be configured CHANNEL-SPECIFIC CONFIGURATION: 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". WARNING: ADS — SEPARATE (default) vs BUNDLED INTO ONE GROUP (opt-in): The "ads" object has two slots and they map to two different platform structures: - "ads.list": a flat array of ad IDs. Each id is sent as its own request, so a list of N ids produces N separately managed ads, NOT one bundle. THIS IS THE DEFAULT — put ads here unless the user explicitly asks for ad groups. - "ads.groups": an array of {name, ads:[ids]} objects. Each object bundles its ad IDs into ONE named ad group. Use this ONLY when the user explicitly wants ads grouped together (e.g. "put these in an ad group", "group these ads"). LinkedIn has no ad-group concept — use list only. You may send both: ads in "list" stay separate, ads in "groups" get bundled. (Note: the platform wraps every ad in an ad-group record server-side, single ads included. That is outside this tool's control and does not change the two shapes above.) LINKEDIN (optional): - audiences: Array of audience names (required if linkedin included) Example: ["Test Native Audience", "EU Countries"] - target_groups: Array of Targeting Group names Example: ["My Target Group 1"] - ads: Object with ad organization (required if linkedin included) - list: Array of ad IDs, each sent as its own request (default). Example: [156502, 156485] (LinkedIn has no ad groups — always use list.) - offers: Array of offer IDs (required if linkedin included) Example: [57538, 57504] FACEBOOK (optional): - audiences: Array of Facebook audience names (required if facebook included) Example: ["fb-test", "automation-fb-retargeting-event-stage-blue"] - target_groups: Array of Targeting Group names - ads: Object with ad organization (required if facebook included) - list: Array of ad IDs, each sent as its own request (DEFAULT — use this) - groups: Array of ad group objects [{"name": str, "ads": [ids]}] — bundles ads into a named ad group. ONLY when the user explicitly asks for grouped ads. - offers: Array of offer IDs (required if facebook included) INSTAGRAM (optional): - audiences: Array of Instagram audience names (required if instagram included) - target_groups: Array of Targeting Group names - ads: Object with ad organization (required if instagram included) - list: Array of ad IDs, each sent as its own request (DEFAULT — use this) - groups: Array of ad group objects [{"name": str, "ads": [ids]}] — bundles ads into a named ad group. ONLY when the user explicitly asks for grouped ads. - offers: Array of offer IDs (required if instagram included) - Often shares same audiences and offers as Facebook GOOGLE ADS (optional): - keywords: Object with keyword organization (required if google included) - groups: [{"name": "CRM Keywords", "keywords": ["crm software", "lead gen tools"], "match_type": "PHRASE"}] Each group also accepts "keyword_ids": [<existing library keyword IDs from list_keywords>] and "match_type": PHRASE|BROAD|EXACT (default PHRASE). - audiences: Array of Google audience names (required if google included) Example: ["SUP_SF_All-Customers-Contacts_ALL_3"] - target_groups: Array of Targeting Group names - ads: Object with ad organization (required if google included) - list: [175258] — ad IDs each sent as their own request (DEFAULT — use this) - groups: [{"name": "GOAT", "ads": [175260, 175259]}] — bundles ads into a named ad group. ONLY when the user explicitly asks for grouped ads. - offers: Array of offer IDs (required if google included) - negative_keyword_lists: Array of negative keyword list names (optional) Example: ["Competitor Brands", "Low Intent Keywords"] These are assigned to the Google Ads channel AFTER campaign creation. List names must match existing negative keyword lists (use list_negative_keywords_list to find them). REDDIT (optional): - audiences: Array of Reddit audience names (required if reddit included) - target_groups: Array of Targeting Group names (Reddit Target Groups are created via create_reddit_target_group) - ads: Object with ad organization (required if reddit included) - list: Array of ad IDs, each sent as its own request. Reddit ads are created via create_update_image_ad / create_update_video_ad with channels=["REDDIT"]. (Like LinkedIn, always use list — no ad groups.) - offers: Array of offer IDs (required if reddit included). Landing Page offers ONLY — Reddit does not support Lead Gen forms. - Channel settings (objective, allow comments, placements, conversion pixel) get UI-equivalent defaults on creation — adjust them afterwards with update_reddit_channel_settings. MICROSOFT ADS (optional): - Search channel — mirrors Google Ads structurally. The platform pairs MICROSOFT_ADS with GOOGLE_ADS for the TARGET_SPEND bid default. - keywords: Object with keyword organization (required if microsoft included) - groups: [{"name": "CRM Keywords", "keywords": ["crm software", "lead gen tools"], "match_type": "PHRASE"}] Each group also accepts "keyword_ids": [<existing library keyword IDs from list_keywords>] and "match_type": PHRASE|BROAD|EXACT (default PHRASE). - audiences: Array of Microsoft Ads audience names (required if microsoft included) - target_groups: Array of Targeting Group names - ads: Object with ad organization (required if microsoft included) - list: Array of ad IDs, each sent as its own request (DEFAULT) - groups: [{"name": "MS Group A", "ads": [ids]}] — bundles ads into a named ad group. ONLY when the user explicitly asks for grouped ads. - offers: Array of offer IDs (required if microsoft included). Lead Gen offers must be MICROSOFT_ADS-locked (created with data.channel="MICROSOFT_ADS"); Landing Page offers are universal. - negative_keyword_lists: Array of negative keyword list names (optional) Example: ["Competitor Brands", "Low Intent Keywords"] Assigned to the Microsoft Ads channel after creation. Names must match existing lists (use list_negative_keywords_list to find them). VALIDATION: - Campaign name must be unique - Start date must be before end date - All referenced ad IDs, offer IDs, and audience names must exist - If a channel is included, its required fields (audiences, ads, offers) must be provided - WARNING: Lead Gen campaigns with Landing Page offers MUST be rejected OFFER VERIFICATION (Lead Gen only): 1. Call get_offer to check offer types before campaign creation 2. If any offer is Landing Page → reject and suggest switching to Brand Awareness or replacing with LG offers RESPONSE: Returns campaign_id, campaign_url, status, configured_channels, per-channel details, optimization_group (id + tag_name), and a `full_response` payload with the complete wizard state. On partial failures, returns success=false plus an `errors[]` list — the campaign shell is still created and partial work is preserved. Campaign URL: https://platform.metadata.io/hub/advertise/campaigns/{campaign_id} BID STRATEGY (automatic — no user input needed): Every enabled channel is set to a safe "auto" default immediately after creation so the campaign is launch-ready: - LinkedIn / Facebook / Instagram → AUTO_BID - Google Ads / Microsoft Ads → TARGET_SPEND (device modifiers reset to 0) - Reddit → follows the objective, mirroring the platform UI: Lead Gen campaigns force the CLICKS (Traffic) objective + AUTO_BID; Brand Awareness keeps the platform default IMPRESSIONS objective + MANUAL_BID. Change objective/bid afterwards with update_reddit_channel_settings. This happens regardless of account type and regardless of campaign goal (CPL / CTR). The user can still override bid strategy later via the platform UI or a dedicated tool. EXAMPLE (Lead Gen, multi-channel): create_campaign(campaign_data={ "campaignType": "Lead Gen", "name": "Q1_Multi_Channel_2025", "startDate": "2025-08-01", "endDate": "2025-09-30", "budgetGroup": "BoFu", "linkedin": { "audiences": ["Test Native Audience", "EU Countries"], "ads": {"list": [156502, 156485]}, "offers": [57538, 57504] } }) EXAMPLE (Brand Awareness, single-channel): create_campaign(campaign_data={ "campaignType": "Brand Awareness", "name": "LinkedIn_Brand_Jan2025", "startDate": "2025-01-15", "endDate": "2025-02-15", "budgetGroup": "Brand", "linkedin": { "audiences": ["Professional Audience"], "ads": {"list": [173669, 171805]}, "offers": [57538] } CAMPAIGN URL FORMAT: - All successful campaign creations return a direct URL to the campaign - URL format: https://platform.metadata.io/hub/advertise/campaigns/{campaign_id} - Use this URL to navigate directly to the campaign in the platform - Campaign URL is always included in successful responses - Provides immediate access to campaign management and monitoring BEST PRACTICES: 1. Use descriptive, unique campaign names with dates or identifiers 2. Ensure all referenced assets (ads, offers, audiences) exist before campaign creation 3. Plan campaign dates appropriately with buffer time for setup 4. Group related ads together for better organization and reporting 5. Use consistent naming conventions for ad groups across channels 6. Test with single-channel campaigns before creating multi-channel campaigns 7. Verify budget group names match existing budget groups in the system 8. Save the returned campaign URL for quick access to campaign management ERROR HANDLING: - Validates all required fields are provided - Checks that referenced ad IDs, offer IDs, and audience names exist - Ensures campaign name uniqueness - Validates date formats and logical date ranges - Verifies at least one channel is configured - Provides detailed error messages for troubleshooting INTEGRATION NOTES: - Supports both simple single-channel and complex multi-channel campaigns - Automatically handles channel-specific configuration requirements - Works in conjunction with ad and offer creation tools for complete campaign setup - Provides comprehensive campaign status and configuration feedback - Always returns the platform URL for immediate campaign access
create_campaign
Create a Facebook native criteria audience using Facebook-supported targeting criteria. Build audiences based on Facebook native industries, geographic location, job titles, interests, and age range. ESTIMATE-ONLY MODE: Pass estimate_only=true to preview audience size WITHOUT creating the audience. In this mode the tool returns expectedNumberOfContacts. Default is false. ALSO KNOWN AS: Facebook audience, FB criteria audience, native Facebook targeting, Facebook lead audience KEYWORDS: Facebook, native, criteria, audience, industry, location, job title, interest, age, lead, targeting WHEN TO USE: - Create targeted Facebook audiences using native Facebook criteria - Target users by Facebook industry categories (e.g., IT and Technical Services, Sales, Management) - Target by geographic countries, job titles, interests, and age range - Build lead generation audiences for Facebook campaigns INDUSTRIES: Facebook native industry categories - provide the industry name as a string: Administrative Services, Architecture and Engineering, Arts Entertainment Sports and Media, Business and Finance, Business decision maker titles and interests, Cleaning and Maintenance Services, Community and Social Services, Computation and Mathematics, Construction and Extraction, Education and Libraries, Farming Fishing and Forestry, Food and Restaurants, Government Employees (Global), Healthcare and Medical Services, Installation and Repair Services, IT and Technical Services, Large business-to-business enterprise employees (500+ employees), Legal Services, Life Physical and Social Sciences, Management, Medium business-to-business enterprise employees (200 - 500 employees), Production, Sales, Small business-to-business enterprise employees (10-200 employees), Transportation and Moving PARAMETERS: - name: Audience name (required) - min_age: Minimum age for targeting (required) - must be between 21 and 65 - max_age: Maximum age for targeting (required) - must be between 21 and 65, and >= min_age - industries: Array of Facebook native industry names (optional) - countries: List of country names for location targeting (optional) - each must match a country from the platform's supported countries list - job_titles: Array of free-text job title strings (optional) - e.g., ["Software Engineer", "Product Owner"] - interests: Array of free-text interest strings (optional) - e.g., ["Java", "Python", "Cloud Computing"] RETURNS: Parsed audience criteria with resolved Facebook reference IDs and validated parameters. IMPORTANT NOTES: - name, min_age and max_age are required, all other parameters are optional - Industries must be valid Facebook native industry names from the enum list - Countries must be valid country names from the platform's supported countries list - min_age and max_age must both be between 21 and 65, with min_age <= max_age - Job titles and interests are free-text arrays - Job titles and interests are validated by the backend API with the regex pattern [A-Za-z0-9 ]+ (only ASCII letters, digits, and spaces are allowed). Non-ASCII characters, hyphens, and special characters will be automatically replaced with spaces before resolving references (e.g., "co-founder" becomes "co founder"). When providing job titles or interests, use only alphanumeric characters and spaces.
create_facebook_native_criteria_audience
Create B2B company firmographic audiences for targeted advertising campaigns. Build audiences based on company attributes (industry, size, revenue) and contact-level criteria. ESTIMATE-ONLY MODE: Pass estimate_only=true to preview audience size (companies + contacts) WITHOUT creating the audience. In this mode the tool returns expectedNumberOfCompanies, expectedNumberOfContacts, and cappedContactCount. Default is false (audience is created). PREFERRED AUDIENCE TYPE: This is the DEFAULT and most commonly used audience type on the Metadata platform. When the user asks to create an audience without specifying a type, prefer this tool. Only suggest Bombora audiences if get_intent_topics returns available topics. Only suggest G2 audiences if G2 is confirmed as connected via get_integrations_status and the user specifically requests G2 targeting. ALSO KNOWN AS: company audience, target companies, B2B audience, business targeting, account-based audience, ABM list, company targeting KEYWORDS: company, companies, audience, target, targeting, B2B, business, firmographic, industry, size, employees, revenue, ABM, account-based, LinkedIn, Facebook WHEN TO USE: - Default choice when the user wants to create a B2B audience - Create targeted B2B audiences for LinkedIn, Facebook campaigns - Target companies by industry, size, revenue - Target contacts by seniority level and job function - Set geographic targeting and contact limits per company TARGETING OPTIONS: - Industries: Use industry IDs. Examples: 1=Defense & Space, 4=Computer Software, 6=Internet, 7=Semiconductors, 8=Telecommunications, 11=Management Consulting, 12=Biotechnology, 41=Banking, 42=Insurance, 43=Financial Services, 80=Marketing & Advertising, 96=Information Technology & Services, more values in detail in the input schema - Employees: "0 - 9", "10 - 49", "50 - 199", "200 - 499", "500 - 999", "1,000 - 4,999", "5,000 - 9,999", "10,000+" - Revenue: "$1M - $10M", "$10M - $50M", "$50M - $100M", "$100M - $200M", "$500M - $1B", "$1B+" CONTACTS CRITERIA: Use the following parameters to filter and target specific contacts within accounts: GEOGRAPHIC TARGETING: - location_country_ids: Array of country IDs (e.g., [29] for Brazil, [229] for United States) - location_state_ids: Array of state IDs (e.g., [5] for California, [32] for New York) JOB TITLES: - job_title_includes: Array of free text strings to include (e.g., ["Software Engineer", "Manager"]) - job_title_excludes: Array of free text strings to exclude (e.g., ["Senior", "Lead"]) JOB FUNCTIONS: Valid job function IDs and their labels: - 1: Marketing, 2: Sales, 3: Customer Service, 4: Finance, 5: Human Resources, 6: Public Relations - 7: Media, 8: Design, 9: Engineering, 10: Operations, 11: Legal, 12: Education - 13: Health, 14: Real Estate, 15: Accounting, 16: Administrative, 17: Business Development - 18: Community and Social Services, 19: Consulting, 20: Entrepreneurship, 21: Information Technology - 22: Military and Protective Services, 23: Product Management, 24: Program and Project Management - 25: Purchasing, 26: Quality Assurance, 27: Research, 28: Trades - job_function_include_ids: Array of job function IDs to include (e.g., [9] for Engineering) - job_function_exclude_ids: Array of job function IDs to exclude SENIORITY LEVELS: Valid seniority IDs and their labels: - 2: Manager, 3: Director, 4: VP, 5: CXO, 6: Unpaid, 7: Training - 8: Senior, 9: Owner, 10: Entry, 11: Partner - seniority_include_ids: Array of seniority level IDs to include (e.g., [10, 7] for Entry and Training) - seniority_exclude_ids: Array of seniority level IDs to exclude CONTACT LIMITS: - contacts_per_company_limit: Maximum number of contacts to target per company (optional). Example: 20 USAGE NOTES: - All ID fields (countries, states, job functions, seniorities) use numeric IDs from the platform - Job titles are free text strings, not IDs - Use include parameters to specify which criteria to target - Use exclude parameters to filter out contacts matching specific criteria - Combine multiple criteria for precise targeting (e.g., Senior Engineers in California) - Criteria are combined with AND logic, so all conditions must be met CONTACTS CRITERIA PARAMETERS(Usually after other initial audience parameters to be described next): - location_country_ids: Array of country IDs (optional) - location_state_ids: Array of state IDs (optional) - job_title_includes: Array of job title keywords to include (optional) - job_title_excludes: Array of job title keywords to exclude (optional) - job_function_include_ids: Array of job function IDs (optional) - job_function_exclude_ids: Array of job function IDs (optional) - seniority_include_ids: Array of seniority level IDs (optional) - seniority_exclude_ids: Array of seniority level IDs (optional) - contacts_per_company_limit: Maximum contacts per company (optional) PARAMETERS: - name: Audience name (required) - **IMPORTANT: Name MUST NOT exceed 50 characters. This is a mandatory requirement.** - industries: Array of industry IDs (optional) - employees: Array of employee count ranges (optional) - revenue: Array of revenue ranges (optional) RETURNS: Audience details with ID, size estimation, and creation status. COMMON USE CASES: - Target software companies with 50-500 employees - Find companies in specific industries with revenue ranges - Build audiences with contact-level filtering (seniority, job function, location) - Combine firmographic and contact criteria for precise B2B targeting IMPORTANT NOTES: - **CRITICAL: Audience name MUST NOT exceed 50 characters - this is mandatory and will cause creation to fail if exceeded** - name is the only required parameter - All other parameters are optional for flexible audience creation - Contact criteria fields work the same as in G2 metadata dynamic audiences - Audience size depends on firmographic filters and applied contacts criteria
create_firmographic_audience
Create a **G2 Intent (Dynamic)** audience (platform `customAudienceType=DYNAMIC_G2_CONTACT`). AUDIENCE TYPE (mirrors the UI's "Audience Type" dropdown): • UI label: "G2 Intent (Dynamic)" • Platform enum: DYNAMIC_G2_CONTACT • Refreshes daily as G2 intent signals update; uses generic contact criteria (not LinkedIn-native). PREREQUISITE: • G2 integration MUST be connected. If not, do NOT call this tool — recommend `create_firmographic_audience`. WHEN TO USE (exact user phrasing this tool should match): • "G2 Intent (Dynamic)" (without "LinkedIn Native") • "G2 intent dynamic audience" • "Dynamic G2 audience" • The user wants G2 intent that refreshes daily on Facebook/LinkedIn/other channels (not specifically LinkedIn-native). WHEN NOT TO USE: • If the user said "LinkedIn Native" → use `create_g2_intent_linkedin_native_dynamic_audience`. • If the user said "Static" → use `create_g2_intent_static_audience`. BUYING STAGES — REQUIRED BY THE PLATFORM: Same as the LinkedIn Native variant: ASK the user if missing. DO NOT default. CONTACTS CRITERIA: Use the following parameters to filter and target specific contacts within accounts: GEOGRAPHIC TARGETING: - location_country_ids: Array of country IDs (e.g., [29] for Brazil, [229] for United States) - location_state_ids: Array of state IDs (e.g., [5] for California, [32] for New York) JOB TITLES: - job_title_includes: Array of free text strings to include (e.g., ["Software Engineer", "Manager"]) - job_title_excludes: Array of free text strings to exclude (e.g., ["Senior", "Lead"]) JOB FUNCTIONS: Valid job function IDs and their labels: - 1: Marketing, 2: Sales, 3: Customer Service, 4: Finance, 5: Human Resources, 6: Public Relations - 7: Media, 8: Design, 9: Engineering, 10: Operations, 11: Legal, 12: Education - 13: Health, 14: Real Estate, 15: Accounting, 16: Administrative, 17: Business Development - 18: Community and Social Services, 19: Consulting, 20: Entrepreneurship, 21: Information Technology - 22: Military and Protective Services, 23: Product Management, 24: Program and Project Management - 25: Purchasing, 26: Quality Assurance, 27: Research, 28: Trades - job_function_include_ids: Array of job function IDs to include (e.g., [9] for Engineering) - job_function_exclude_ids: Array of job function IDs to exclude SENIORITY LEVELS: Valid seniority IDs and their labels: - 2: Manager, 3: Director, 4: VP, 5: CXO, 6: Unpaid, 7: Training - 8: Senior, 9: Owner, 10: Entry, 11: Partner - seniority_include_ids: Array of seniority level IDs to include (e.g., [10, 7] for Entry and Training) - seniority_exclude_ids: Array of seniority level IDs to exclude CONTACT LIMITS: - contacts_per_company_limit: Maximum number of contacts to target per company (optional). Example: 20 USAGE NOTES: - All ID fields (countries, states, job functions, seniorities) use numeric IDs from the platform - Job titles are free text strings, not IDs - Use include parameters to specify which criteria to target - Use exclude parameters to filter out contacts matching specific criteria - Combine multiple criteria for precise targeting (e.g., Senior Engineers in California) - Criteria are combined with AND logic, so all conditions must be met CONTACTS CRITERIA PARAMETERS(Usually after other initial audience parameters to be described next): - location_country_ids: Array of country IDs (optional) - location_state_ids: Array of state IDs (optional) - job_title_includes: Array of job title keywords to include (optional) - job_title_excludes: Array of job title keywords to exclude (optional) - job_function_include_ids: Array of job function IDs (optional) - job_function_exclude_ids: Array of job function IDs (optional) - seniority_include_ids: Array of seniority level IDs (optional) - seniority_exclude_ids: Array of seniority level IDs (optional) - contacts_per_company_limit: Maximum contacts per company (optional) PARAMETERS: • name (required, ≤ 50 chars) • intent_days (required, 1-365) • buying_stages (REQUIRED by platform — ask if missing) • Contact criteria as in CONTACTS CRITERIA above. RETURNS: id, audience_id, audience_name, audience_type (DYNAMIC_G2_CONTACT), status, buying_stages, intent_days, counts.
create_g2_intent_dynamic_audience
Create a **G2 Intent (Static)** audience (platform `customAudienceType=G2_ABM_CONTACT`). AUDIENCE TYPE (mirrors the UI's "Audience Type" dropdown): • UI label: "G2 Intent (Static)" • Platform enum: G2_ABM_CONTACT • SNAPSHOT at creation time — does NOT refresh daily. PREREQUISITE: • G2 integration MUST be connected. WHEN TO USE (exact user phrasing this tool should match): • "G2 Intent (Static)" • "Static G2 audience" • The user explicitly wants the static / snapshot variant rather than the daily-refreshing dynamic one. WHEN NOT TO USE: • If the user said "Dynamic" → use `create_g2_intent_dynamic_audience` or `create_g2_intent_linkedin_native_dynamic_audience`. BUYING STAGES — REQUIRED BY THE PLATFORM: ASK the user if missing. DO NOT default. CONTACTS CRITERIA: Use the following parameters to filter and target specific contacts within accounts: GEOGRAPHIC TARGETING: - location_country_ids: Array of country IDs (e.g., [29] for Brazil, [229] for United States) - location_state_ids: Array of state IDs (e.g., [5] for California, [32] for New York) JOB TITLES: - job_title_includes: Array of free text strings to include (e.g., ["Software Engineer", "Manager"]) - job_title_excludes: Array of free text strings to exclude (e.g., ["Senior", "Lead"]) JOB FUNCTIONS: Valid job function IDs and their labels: - 1: Marketing, 2: Sales, 3: Customer Service, 4: Finance, 5: Human Resources, 6: Public Relations - 7: Media, 8: Design, 9: Engineering, 10: Operations, 11: Legal, 12: Education - 13: Health, 14: Real Estate, 15: Accounting, 16: Administrative, 17: Business Development - 18: Community and Social Services, 19: Consulting, 20: Entrepreneurship, 21: Information Technology - 22: Military and Protective Services, 23: Product Management, 24: Program and Project Management - 25: Purchasing, 26: Quality Assurance, 27: Research, 28: Trades - job_function_include_ids: Array of job function IDs to include (e.g., [9] for Engineering) - job_function_exclude_ids: Array of job function IDs to exclude SENIORITY LEVELS: Valid seniority IDs and their labels: - 2: Manager, 3: Director, 4: VP, 5: CXO, 6: Unpaid, 7: Training - 8: Senior, 9: Owner, 10: Entry, 11: Partner - seniority_include_ids: Array of seniority level IDs to include (e.g., [10, 7] for Entry and Training) - seniority_exclude_ids: Array of seniority level IDs to exclude CONTACT LIMITS: - contacts_per_company_limit: Maximum number of contacts to target per company (optional). Example: 20 USAGE NOTES: - All ID fields (countries, states, job functions, seniorities) use numeric IDs from the platform - Job titles are free text strings, not IDs - Use include parameters to specify which criteria to target - Use exclude parameters to filter out contacts matching specific criteria - Combine multiple criteria for precise targeting (e.g., Senior Engineers in California) - Criteria are combined with AND logic, so all conditions must be met CONTACTS CRITERIA PARAMETERS(Usually after other initial audience parameters to be described next): - location_country_ids: Array of country IDs (optional) - location_state_ids: Array of state IDs (optional) - job_title_includes: Array of job title keywords to include (optional) - job_title_excludes: Array of job title keywords to exclude (optional) - job_function_include_ids: Array of job function IDs (optional) - job_function_exclude_ids: Array of job function IDs (optional) - seniority_include_ids: Array of seniority level IDs (optional) - seniority_exclude_ids: Array of seniority level IDs (optional) - contacts_per_company_limit: Maximum contacts per company (optional) PARAMETERS: • name (required, ≤ 50 chars) • intent_days (required, 1-365) • buying_stages (REQUIRED — ask if missing) • Contact criteria as in CONTACTS CRITERIA above. RETURNS: id, audience_id, audience_name, audience_type (G2_ABM_CONTACT), status, buying_stages, intent_days, counts.
create_g2_intent_static_audience
Create a **G2 Intent - LinkedIn Native (Dynamic)** audience (platform `customAudienceType=DYNAMIC_G2`). AUDIENCE TYPE (mirrors the UI's "Audience Type" dropdown): • UI label: "G2 Intent - LinkedIn Native (Dynamic)" • Platform enum: DYNAMIC_G2 • Refreshes daily as G2 intent signals update; targets LinkedIn natively. PREREQUISITE: • Both G2 and LinkedIn integrations MUST be connected. If either is missing, do NOT call this tool — recommend `create_firmographic_audience` instead. WHEN TO USE (exact user phrasing this tool should match): • "G2 Intent - LinkedIn Native (Dynamic)" • "G2 LinkedIn Native Dynamic" • "LinkedIn native G2 intent audience" • The user explicitly mentions BOTH G2 intent AND LinkedIn native targeting. WHEN NOT TO USE: • If the user asked for "G2 Intent (Dynamic)" without "LinkedIn Native" → use `create_g2_intent_dynamic_audience`. • If the user asked for "G2 Intent (Static)" → use `create_g2_intent_static_audience`. BUYING STAGES — REQUIRED BY THE PLATFORM: The platform UI marks Buying Stages as required. If the user did not name any stages, STOP and ask the user which of AWARENESS / CONSIDERATION / DECISION to target. DO NOT silently default — that produced wrong audiences in PRD-29702 / PRD-29703. CRITERIA (LinkedIn-native shapes; free-text fields are resolved server-side via the LinkedIn references API): • employees — LinkedIn-native employee ranges. Valid labels: see the schema (e.g. "201-500", "501-1000", "1001-5000"). • revenues — LinkedIn-native revenue ranges (e.g. "$1M-$10M", "$10M-$100M"). • company_names — free-text company names (resolved to LinkedIn company IDs). • location_country_ids — country IDs (e.g. 229=US, 228=UK). • job_titles — free-text titles (resolved to LinkedIn job-title IDs). • skills — free-text professional skills (resolved to LinkedIn skill IDs). PARAMETERS: • name (required, ≤ 50 chars) • intent_days (required, 1-365) • buying_stages (REQUIRED by platform — ask the user if missing; do NOT default) • employees, revenues, company_names, location_country_ids, job_titles, skills (all optional) RETURNS: id, audience_id, audience_name, audience_type (DYNAMIC_G2), status, buying_stages, intent_days, expectedNumberOfCompanies, expectedNumberOfContacts.
create_g2_intent_linkedin_native_dynamic_audience
Attach the business logo to a Google Ads text ad for brand recognition. BETA. References a single image-library asset (the logo) and optionally pairs it with the business name and domain (the latter two are also used when the same logo is reused for Microsoft Ads). ALSO KNOWN AS: business logo, brand logo, logo, company logo, brand mark, mark, identity asset KEYWORDS: logo, business logo, brand, brand mark, identity, company logo, brand recognition, BETA, google ads, extension WHEN TO USE: - "Add our business logo to our Google Ads" - "Create a logo extension referencing image library ID 123" - "Attach the Acme Corp logo to our search ads for brand lift" WHEN NOT TO USE: - Multiple product / lifestyle shots → use create_google_image_extension - The logo is not yet in the image library — upload it first, then call this with the resulting ID. - Same logo for Microsoft Ads / Bing → use create_microsoft_business_logo_extension INPUTS: - image_library_id (required): single image library ID pointing to the logo asset. - business_name: business name displayed alongside the logo (≤25 chars). Required if the same library entry is also used for Microsoft Ads. - domain_name: business domain (≤50 chars). Used by Microsoft Ads. EXAMPLE: create_google_business_logo_extension( image_library_id=123, business_name="Acme Corp", domain_name="acme.com", )
create_google_business_logo_extension
Add a short non-clickable selling-point snippet (callout) that appears beneath a Google Ads ad — short trust-builder phrases like "Free Shipping", "24/7 Support", "Money-Back Guarantee", or "No Setup Fees". Callouts reinforce value props without taking up headline space. ALSO KNOWN AS: callout, callout extension, selling point, trust badge, value prop, value proposition, tagline, ad badge KEYWORDS: callout, selling point, trust signal, value prop, badge, free shipping, money back, guarantee, support, no fees, google ads, extension WHEN TO USE: - "Add a 'Free Shipping' callout to our Google Ads library" - "Create a callout for 24/7 support" - "Register a new value-prop tag for the holiday campaigns" - "I want a 'Money-Back Guarantee' badge to show under our ads" WHEN NOT TO USE: - Want a clickable shortcut to a landing page → use create_google_sitelink_extension - Want a list of named items (e.g. "Brands: Nest, Nexus") → use create_google_structured_snippet_extension - Same callout for Microsoft Ads / Bing → use create_microsoft_callout_extension - Anything for Facebook / LinkedIn / Reddit — search-channel-only INPUTS: - callout_text: visible snippet (1-25 chars). EXAMPLE: create_google_callout_extension(callout_text="Free Shipping")
create_google_callout_extension
Attach visual imagery (1-20 product / lifestyle shots) to a Google Ads text ad to lift click-through. BETA. Re-uses assets already uploaded to the Metadata image library — pass their IDs, not raw files. ALSO KNOWN AS: image extension, image asset, ad image, visual extension, picture extension, photo extension, hero image KEYWORDS: image, image extension, photo, picture, visual, hero, asset, library, BETA, google ads, extension, CTR WHEN TO USE: - "Attach images to our Google Ads text ad" - "Add image library IDs 123 and 456 as an image extension" - "Create an image extension showing product photos under our search ads" WHEN NOT TO USE: - The image is a logo / brand mark → use create_google_business_logo_extension - You haven't uploaded the assets yet — image extensions reference library IDs, so upload to the image library first. - Want to drive clicks via text snippets → use create_google_sitelink_extension / callout - Same images for Microsoft Ads / Bing → use create_microsoft_image_extension INPUTS: - image_library_ids (required): 1-20 IDs from the Metadata image library. - alternative_text: accessibility alt text (≤90 chars). - display_text: short caption overlaid on the image (≤35 chars). E.g. "Shop Now". - destination_url: landing page when the image is clicked. EXAMPLE: create_google_image_extension( image_library_ids=[123, 456], alternative_text="Product hero shot", display_text="Shop Now", destination_url="https://example.com/landing", )
create_google_image_extension
Add an inline lead-capture form attached to a Google Ads ad — prospects submit their email plus optional contact and work info without leaving the SERP. Drives higher conversion than landing-page redirects and feeds leads straight into Metadata. ALSO KNOWN AS: lead form, lead gen form, inline form, lead capture, contact form, demo request form, in-ad form, form extension KEYWORDS: lead form, lead gen, lead capture, form, contact form, demo request, inline form, conversion, MQL, opt-in, signup, registration, google ads, extension WHEN TO USE: - "Add a lead form extension to capture demo requests under our search ads" - "Create an inline form asking for work email and job title" - "Set up a Google Ads lead-gen form with a 'Request Demo' CTA" - "Register a contact-us form extension for the homepage campaign" WHEN NOT TO USE: - Just want to drive clicks to a landing page (no inline form) → use create_google_sitelink_extension - Want to plug a single product / pricing tier under the ad → use create_google_price_extension - For Microsoft Ads / Bing — Microsoft does not surface inline lead forms via the platform; pick a different extension type or use a landing-page redirect. - For Facebook lead forms or LinkedIn LeadGen — those are separate channel surfaces, not search-channel ad-extensions. INPUTS (required): - headline: form headline (≤30 chars). - business_name: advertiser name shown in form (≤25 chars). - privacy_policy_url: link to your privacy policy (Google requires it). - post_submit_headline: thank-you screen headline (≤30 chars). - post_submit_description: thank-you screen body (≤200 chars). - post_submit_call_to_action_type: button on the thank-you screen. VISIT_SITE | DOWNLOAD | LEARN_MORE | SHOP_NOW. - call_to_action_type: main CTA on the ad. APPLY_NOW | BOOK_NOW | CONTACT_US | DOWNLOAD | GET_INFO | GET_OFFER | GET_QUOTE | GET_STARTED | JOIN_NOW | LEARN_MORE | REGISTER | REQUEST_DEMO | SIGN_UP | SUBSCRIBE. - call_to_action_description: sub-text under the CTA (≤30 chars). - email_lead_form_user_input_types: at least one of WORK_EMAIL, EMAIL. INPUTS (optional): - description: form body text (≤200 chars). - contact_lead_form_user_input_types: any of FIRST_NAME, LAST_NAME, PHONE_NUMBER, CITY, POSTAL_CODE, REGION, COUNTRY, STREET_ADDRESS. - work_lead_form_user_input_types: any of COMPANY_NAME, JOB_TITLE, WORK_PHONE. - url: thank-you-page URL after submit.
create_google_lead_form_extension
Add a price-list shown beneath a Google Ads ad — 3-8 tiles, each with a plan/product name, a short description, a USD amount, and a billing unit. Standard play for SaaS pricing tiers, subscription plans, course catalogs, service menus, or hotel night rates. ALSO KNOWN AS: price extension, pricing, price list, pricing tiers, plan pricing, subscription pricing, price tiles, rate card, fare list KEYWORDS: price, pricing, price list, plan, plans, tier, tiers, subscription, monthly, yearly, hourly, daily, fare, rate, cost, dollar, $, USD, google ads, extension WHEN TO USE: - "Show our pricing tiers under our Google Ads" - "Add a price extension with Basic / Pro / Scale plans" - "Register monthly subscription prices for the campaign" - "Create a rate card extension starting from $9.99" WHEN NOT TO USE: - Single time-bound discount (Black Friday 20% off, promo code) → use create_google_promotion_extension - Non-priced offerings list (just names, no amounts) → use create_google_structured_snippet_extension - Same price list for Microsoft Ads / Bing → use create_microsoft_price_extension INPUTS: - price_qualifier: prefix shown before each price. UNSPECIFIED (no prefix) | FROM ("From $X") | UP_TO ("Up to $X") | AVERAGE ("Avg $X"). - price_offerings: 3-8 tiles. Each tile: - url: landing page for that tier (non-blank, ≤2000 chars). - header: tier name (1-25 chars). E.g. "Basic", "Pro", "Scale". - description: short tagline (1-25 chars). E.g. "Starter plan". - amount: USD number (max 999999999.99, two decimals). - unit: billing cadence. UNSPECIFIED | PER_HOUR | PER_DAY | PER_WEEK | PER_MONTH | PER_YEAR | PER_NIGHT. EXAMPLE: create_google_price_extension( price_qualifier="FROM", price_offerings=[ {"url": "https://example.com/basic", "header": "Basic", "description": "Starter plan", "amount": 9.99, "unit": "PER_MONTH"}, {"url": "https://example.com/pro", "header": "Pro", "description": "Growing teams", "amount": 29.00, "unit": "PER_MONTH"}, {"url": "https://example.com/scale", "header": "Scale", "description": "Enterprise", "amount": 99.00, "unit": "PER_MONTH"}, ], )
create_google_price_extension
Add a time-bound promotional offer (sale, discount, promo code) that shows under a Google Ads ad — flag a holiday occasion, pick the discount style (% off or $ off), optionally attach a promo code or "on orders over $X" qualifier, and set the start/end window. Standard for Black Friday, Cyber Monday, seasonal sales, flash discounts, holiday campaigns. ALSO KNOWN AS: promotion, promo, discount, sale, offer, coupon, promo code, voucher, deal, holiday sale, seasonal offer KEYWORDS: promotion, promo, promo code, coupon, sale, discount, offer, deal, black friday, cyber monday, holiday, christmas, summer sale, percent off, dollar off, $ off, voucher, google ads, extension WHEN TO USE: - "Set up a Black Friday 20% off promotion for our Pro plan" - "Add a holiday promo extension with code SUMMER2026" - "Register a sale: $50 off orders over $200" - "Create a Cyber Monday discount extension running Nov 30 to Dec 2" WHEN NOT TO USE: - Permanent pricing tiers (not a limited-time discount) → use create_google_price_extension - Plain "Free Shipping" badge → use create_google_callout_extension - Lead-capture form attached to the ad → use create_google_lead_form_extension - Same promotion for Microsoft Ads / Bing → use create_microsoft_promotion_extension INPUTS (required): - occasion: holiday/event tag (NONE if no specific occasion). Available: NONE, BACK_TO_SCHOOL, BLACK_FRIDAY, BOXING_DAY, CARNIVAL, CHINESE_NEW_YEAR, CHRISTMAS, CYBER_MONDAY, DIWALI, EASTER, EID_AL_ADHA, EID_AL_FITR, END_OF_SEASON, EPIPHANY, FALL_SALE, FATHERS_DAY, HALLOWEEN, HANUKKAH, HOLI, INDEPENDENCE_DAY, LABOR_DAY, MOTHERS_DAY, NATIONAL_DAY, NAVRATRI, NEW_YEARS, PARENTS_DAY, PASSOVER, RAMADAN, ROSH_HASHANAH, SINGLES_DAY, SONGKRAN, SPRING_SALE, ST_NICHOLAS_DAY, SUMMER_SALE, VALENTINES_DAY, WINTER_SALE, WOMENS_DAY, YEAR_END_GIFT. - url: landing page for the promotion. - item: what's on sale (1-20 chars). E.g. "Pro subscription". - category_type: discount style. * MONETARY → "$X off". Provide category_amount. * UP_TO_MONETARY → "Up to $X off". Provide category_amount. * PERCENT → "X% off". Provide category_percent (≤100). * UP_TO_PERCENT → "Up to X% off". Provide category_percent (≤100). - details_type: optional qualifier. * NONE → no qualifier. * ON_ORDERS_OVER → "on orders over $X". Provide details_amount. * PROMO_CODE → "with code XXXX". Provide details_promo_code (≤15 chars). - start_date / end_date: ISO-8601 in pattern "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" (e.g. 2026-11-25T00:00:00.000Z). Both must be today or in the future. INPUTS (optional, see category_type / details_type above): - category_amount, category_percent, details_promo_code, details_amount. EXAMPLE — Black Friday 20% off Pro with promo code: create_google_promotion_extension( occasion="BLACK_FRIDAY", url="https://example.com/sale", item="Pro subscription", category_type="PERCENT", category_percent=20, details_type="PROMO_CODE", details_promo_code="BF2026", start_date="2026-11-25T00:00:00.000Z", end_date="2026-11-30T23:59:59.000Z", )
create_google_promotion_extension
Add an extra clickable shortcut (sitelink) that appears beneath a Google Ads ad — helpful deep-links like "See Pricing", "Book a Demo", or "Contact Sales" with two short description lines. Sitelinks lift click-through rate by giving searchers alternate landing paths to the same advertiser. ALSO KNOWN AS: sitelink, site link, extra link, ad link, secondary link, deep link, additional link, jump link KEYWORDS: sitelink, site link, link, deep link, shortcut, google ads, extension, pricing link, demo link, contact link, landing page, CTR, click through WHEN TO USE: - "Add a sitelink to our Google Ads library" - "Create a 'See Pricing' / 'Book a Demo' / 'Contact Sales' link extension" - "Register a new sitelink for the homepage redesign" - "I need a shortcut under our search ads that points to the new pricing page" WHEN NOT TO USE: - Want a non-clickable selling-point snippet ("Free Shipping", "24/7 Support") → use create_google_callout_extension - Want a labeled list of offerings (e.g. "Brands: Nest, Nexus") → use create_google_structured_snippet_extension - Same sitelink for Microsoft Ads / Bing → use create_microsoft_sitelink_extension (library entries are per-channel) - Anything for Facebook / LinkedIn / Reddit — ad extensions are a search-channel-only concept INPUTS (all required): - url: destination the sitelink opens. - link_text: visible link text (1-25 chars). - description1: first description line under the link (1-35 chars). - description2: second description line (1-35 chars). EXAMPLE: create_google_sitelink_extension( url="https://example.com/pricing", link_text="See Pricing", description1="Plans for every team size", description2="Start free, upgrade anytime", ) Returns the persisted extension (id, externalId, type=SITELINK, channel=GOOGLE_ADS). A 400 usually means a character-limit was exceeded.
create_google_sitelink_extension
Add a labeled list of offerings (structured snippet) shown beneath a Google Ads ad — a category header plus 3-10 short items, e.g. header "Brands" with values "Nest", "Nexus", "Chromebook", or header "Services" with "Hosting", "DNS", "CDN". Helps searchers self-qualify before clicking. ALSO KNOWN AS: structured snippet, snippet, category list, offering list, header values, product list, service list KEYWORDS: structured snippet, snippet, header, values, brands, services, products, courses, destinations, list, category, google ads, extension WHEN TO USE: - "Add a structured snippet listing our service tiers" - "Create a snippet under 'Brands' with Nest, Nexus, Chromebook" - "Register a list of supported integrations as a snippet extension" - "Show our product categories below our Google Ads" WHEN NOT TO USE: - Want a single phrase (e.g. "Free Shipping") → use create_google_callout_extension - Want clickable links to subpages → use create_google_sitelink_extension - Want a pricing table (with amounts) → use create_google_price_extension - Same snippet for Microsoft Ads / Bing → use create_microsoft_structured_snippet_extension INPUTS: - header: snippet category title (1-25 chars). The Google-Ads vocabulary requires picking one of Google's predefined header names ("Brands", "Models", "Service catalog", "Insurance coverage", etc.) — pass the chosen header string here. - values: 3-10 items, each 1-25 chars. EXAMPLE: create_google_structured_snippet_extension( header="Brands", values=["Nest", "Nexus", "Chromebook"], )
create_google_structured_snippet_extension
Create one or more positive keywords in the Metadata platform library. PURPOSE: Batch create positive keywords that can be used in advertising campaigns. Use this tool to expand your keyword library by adding new terms, variations, or related keywords for targeting and campaign optimization. WHEN TO USE: - Add new keywords to your campaign library - Build keyword lists for new product lines or services - Create variations of existing keywords - Expand keyword coverage for targeted advertising - Create keyword groups for seasonal campaigns - Add long-tail keywords for niche targeting - Build negative keyword lists (blocked keywords) - Bulk import keyword lists from external sources KEY FEATURES: - BATCH CREATION: Create multiple keywords in a single API request - SIMPLE FORMAT: Each keyword is simply a string - FLEXIBLE: Create 1 or 100+ keywords at once - LIBRARY INTEGRATION: Keywords are added to your keyword library and available for campaigns KEYWORD FORMAT: Each keyword in the batch should be a simple string: - "digital marketing" - "seo services" - "ppc advertising" BATCH SIZE RECOMMENDATIONS: - Small batches (5-50 keywords): Ideal for testing and quick additions - Medium batches (50-500 keywords): Good for standard imports - Large batches (500+ keywords): Use for bulk library imports - Maximum recommended: 1000 keywords per request for optimal performance KEYWORD NAMING CONVENTIONS: - Use lowercase for consistency with platform standards - Separate multi-word phrases (e.g., "digital marketing" not "DigitalMarketing") - Avoid special characters unless necessary for the keyword - Remove leading/trailing whitespace - the API will normalize - Empty strings are allowed but won't create keywords - Duplicate names in the batch will be deduplicated by the API COMMON USE CASES: 1. Create a single keyword: create_keywords(keywords=["marketing"]) 2. Create multiple related keywords: create_keywords(keywords=[ "digital marketing", "marketing automation", "email marketing" ]) 3. Create keyword variations: create_keywords(keywords=[ "seo", "seo services", "seo tools", "seo optimization" ]) 4. Create long-tail keywords: create_keywords(keywords=[ "best digital marketing agency in new york", "affordable seo services for small business", "enterprise marketing automation platform" ]) 5. Bulk import from external list: create_keywords(keywords=[ "keyword1", "keyword2", "keyword3", ... (repeat for all keywords) ]) 6. Create campaign-specific keywords: create_keywords(keywords=[ "black friday deals", "cyber monday sales", "holiday promotions" ]) 7. Create product-related keywords: create_keywords(keywords=[ "product a", "product a review", "buy product a", "product a price" ]) PARAMETERS: - keywords: Required. Array of keyword strings to create. Example: ["goku", "ssj", "ssj1"] - Each keyword is a string - Minimum: 1 keyword - Recommended maximum: 1000 keywords per request - Empty strings are allowed but won't create keywords - Duplicates will be deduplicated RESPONSE FORMAT: Returns a response containing: - Created keywords with their IDs and metadata - Success/failure status for each keyword - Any validation errors for invalid entries - Confirmation of keywords added to the library VALIDATION NOTES: - Empty strings or null values in the batch are skipped - Platform automatically removes duplicate names in the batch - Keywords are case-insensitive for deduplication - Special characters are preserved as provided - Platform validates keyword length (typically 2-100 characters recommended) PERFORMANCE TIPS: - Keep batch sizes under 1000 keywords for faster processing - Group related keywords together for better organization - Review the response to confirm all keywords were created successfully - Check your keyword library after creation to verify the additions EXAMPLES: - create_keywords(keywords=["marketing"]) - Create single keyword - create_keywords(keywords=["seo", "sem", "ppc"]) - Create multiple keywords - create_keywords(keywords=["digital marketing", "online marketing", "internet marketing"]) - Variations - create_keywords(keywords=["goku", "ssj", "ssj1", "ssj2"]) - Batch creation
create_keywords
Create a **LinkedIn Engagement Retargeting** audience: people who already engaged with the advertiser's LinkedIn ads, company page, or website. STEP 3 of the flow. This is NOT create_retargeting_audience, which imports an audience the ad account already has. This builds a NEW LinkedIn DMP segment from the engagement rule defined here. Once built it is a normal Metadata audience and can be attached to campaigns. **REQUIRED WORKFLOW — do not call this tool first:** 1. get_linkedin_engagement_source_types → choose `source_platform` + `engagement_trigger` 2. For every source type EXCEPT WEBSITE: search_linkedin_engagement_sources with that trigger and lookback → collect each chosen result's `id` into `engagement_source_urns` 3. Call this tool Source types, triggers and URNs are LinkedIn's own values, and only steps 1 and 2 can supply them. Do not invent, guess or reuse one from another account: a value that did not come from those steps either fails outright or, worse, is accepted and builds an audience that never populates. **TWO SHAPES, MUTUALLY EXCLUSIVE — mixing them is rejected:** A) NON-WEBSITE (VIDEO_ADS, SINGLE_IMAGE_ADS, DOCUMENT_ADS, CONVERSATION_ADS, LEAD_GEN_FORMS, ORGANIZATION_PAGES): pass `engagement_source_urns`. Do NOT pass page_set_name or url_match_groups. B) WEBSITE: pass `page_set_name` and `url_match_groups`. Do NOT pass engagement_source_urns. Metadata creates the LinkedIn page set from those URL rules for you. URL MATCH RULES (WEBSITE only) are a LIST OF GROUPS. Rules inside a group are ANDed; the groups are ORed. Each rule is {matchType, matchValue}, matchType being EXACT ("URL equals"), STARTS_WITH, or CONTAINS. [[A, B], [C]] means (A AND B) OR C Worked example — "anyone who hit pricing or any demo page": [[{"matchType": "STARTS_WITH", "matchValue": "https://example.com/pricing"}], [{"matchType": "CONTAINS", "matchValue": "/demo"}]] Use one rule per group for a simple OR list, which is what most requests mean. Reach for a multi-rule group only for a genuine AND, e.g. a path that also carries a campaign parameter. WHEN TO USE: - "Retarget everyone who watched our video ads in the last 90 days" - "Build an audience from people who submitted the lead form" - "Create an audience of visitors to our pricing and demo pages" - "Retarget people who visited our LinkedIn company page" - "Make a warm audience from last quarter's ad engagement" PARAMETERS: - name: audience name (required). Give it something descriptive of the rule, e.g. "Video 50% viewers 90d", so it is recognisable in the audience list later. - source_platform: the chosen `engagementSourceType` (required) - engagement_trigger: a trigger listed for THAT source type (required). NOTHING VALIDATES THE PAIRING — see the warning below. - lookback_window_days: 30, 60, 90, 180 or 365 — WEBSITE caps at 180 (required) - engagement_source_urns: LinkedIn URNs from search_linkedin_engagement_sources, copied verbatim. Required for every source type except WEBSITE. Several are normal: the audience is everyone who engaged with ANY of them. - page_set_name: internal label for the URL rule set (WEBSITE only, required there). Only ever seen inside LinkedIn, so a plain descriptive label is fine. - url_match_groups: the OR-of-ANDs URL expression (WEBSITE only, required there) RETURNS: Confirmation with the new audience `id` and name, the `criteria` that define it (source, trigger, lookback, how many sources), the channel, and a `note` on when it becomes usable. **WHAT TO TELL THE USER AFTER IT SUCCEEDS:** It is created but not yet populated. LinkedIn takes up to 48 hours to build the audience and a further 24 hours before it delivers, so it will show NO match count and NO contact or company numbers immediately. That is expected and correct, not a failure. Say so plainly rather than reporting the audience as empty or broken. IMPORTANT NOTES: - **THE TRIGGER MUST BELONG TO THE SOURCE TYPE, AND NOTHING CHECKS THAT FOR YOU.** A mismatched pair (e.g. VIDEO_ADS with LEAD_FORM_SUBMIT) is accepted by this tool, by the platform and by LinkedIn, with no error at any layer — it just builds an audience that can never populate, because the engagement it describes cannot happen. Verified on stage. Always take the trigger from the source type's own `triggers` list in step 1; never carry one over from another source type. - Requires a connected LinkedIn channel on the account. - **NEVER re-create the audience because it shows no members.** Zero right after creation is the normal state; creating it again just makes a duplicate. - This audience type NEVER reports contact or company counts the way a firmographic audience does. It lives on LinkedIn, so only LinkedIn's own match count applies. - WEBSITE additionally requires the LinkedIn Insight Tag installed and active on the pages the URL rules match. Without it the audience stays empty indefinitely, no matter how long you wait — mention this whenever you build a WEBSITE audience. - The lookback window doubles as the retention window: it sets both how far back engagement counts and how long someone stays in the audience. - Building from sources with no engagement produces an empty audience. If step 2 showed zeros everywhere, raise that with the user instead of creating anyway. - The rule cannot be edited afterwards. A different trigger or lookback means a new audience, so confirm the choice before creating when the user was vague. COMMON ERRORS AND WHAT THEY MEAN: - "engagement_source_urns is required" — you skipped step 2, or passed a WEBSITE-style payload for a non-website source type. - "must be one of [30, 60, 90, 180]" — WEBSITE was given a 365-day lookback. - "page_set_name / url_match_groups is required" — WEBSITE needs the URL rules, not URNs.
create_linkedin_engagement_retargeting_audience
Create a LinkedIn native criteria audience using LinkedIn-supported targeting criteria. Build audiences based on job titles, skills, company names, employee count ranges, revenue ranges, and geographic location. ESTIMATE-ONLY MODE: Pass estimate_only=true to preview audience size WITHOUT creating the audience. In this mode the tool returns expectedNumberOfContacts. Default is false. ALSO KNOWN AS: LinkedIn audience, LI criteria audience, native LinkedIn targeting, LinkedIn lead audience KEYWORDS: LinkedIn, native, criteria, audience, job title, skills, company, company name, employees, revenue, targeting, country, location WHEN TO USE: - Create targeted LinkedIn audiences using native LinkedIn criteria - Target users by job titles (e.g., Software Engineer, Product Manager) - Target by professional skills (e.g., HubSpot, Salesforce, Python) - Target by company names (e.g., Metadata, Google, Salesforce) - Filter by company employee count ranges (e.g., 201-500, 1001-5000) - Filter by company revenue ranges (e.g., $1M-$10M, $10M-$100M) - Target by country/geographic location (e.g., United States, United Kingdom) PARAMETERS: - name: Audience name (required, must be shorter than 50 characters) - job_titles: Array of free-text job title strings (optional) - e.g., ["Software Engineer", "Product Manager"] - skills: Array of free-text skill strings (optional) - e.g., ["HubSpot", "Salesforce", "Python"] - company_names: Array of free-text company name strings (optional) - e.g., ["Metadata", "Google", "Salesforce"] - employees: Array of LinkedIn employee count ranges (optional) - valid values: 1, 2-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, +10001 - revenues: Array of LinkedIn revenue ranges (optional) - valid values: Under $1M, $1M-$10M, $10M-$100M, $100M-$1B, $1B+ - location_country_ids: Array of country ID integers (optional) - e.g., [229] for United States RETURNS: Audience details with ID, status, and creation info. IMPORTANT NOTES: - name is the only required parameter, all other parameters are optional - Audience name must be shorter than 50 characters - Job titles, skills, company names, employees, and revenues are free-text arrays - Country IDs are integer identifiers (e.g., 229 = United States)
create_linkedin_native_criteria_audience
Create a Marketing-Automation-contacts custom audience (platform customAudienceType MA_CONTACTS_STATIC or MA_CONTACTS_DYNAMIC) from a provider library list. This is one of the audience types eligible for Microsoft Ads (Customer Match). Use it when a user wants a Marketing-Automation-sourced contacts audience, including for a Microsoft Ads campaign. PREREQUISITE: • The provider (HUBSPOT or MARKETO) MUST be connected — the platform validates this and returns a clear error if not. • A library_list_id from list_marketing_automation_lists — do NOT invent one. For HubSpot the list must be DONE; for Marketo READY. VARIANT (mirrors the UI's static/dynamic choice): • STATIC → MA_CONTACTS_STATIC — snapshot at creation, does not refresh. • DYNAMIC → MA_CONTACTS_DYNAMIC — refreshes as the provider data changes. • If the user did not say which, ASK — do NOT default and do NOT infer it from the source list's type. A HubSpot STATIC_LIST is not the same choice as a STATIC (snapshot) audience; the audience variant is the user's call, independent of the list's type. ASYNC: the platform creates the audience in the background and returns a flow id, NOT a ready audience id. The audience appears under the account's Marketing-Automation audiences once the flow completes, and its contact count fills in then. Do not expect to associate it to a campaign in the same turn. PARAMETERS: • custom_audience_name (required): the audience display name — must NOT contain '/'. • library_list_id (required): id from list_marketing_automation_lists. • provider (required): HUBSPOT or MARKETO. • variant (required): STATIC or DYNAMIC. • list_name (optional): the source list's own name (from the lookup), forwarded to the flow. RETURNS: { id, name, status, createdDate, audience_type, async: true } — `audience_type` is the MA_CONTACTS_* you created and `id` is a creation/flow id, not associable yet.
create_marketing_automation_contacts_audience
Attach the business logo to a Microsoft Ads (Bing) text ad for brand recognition. BETA. References a single image-library asset (the logo) and optionally pairs it with the business name and domain (which Bing surfaces alongside the logo on its SERP). ALSO KNOWN AS: business logo, brand logo, logo, company logo, brand mark, mark, identity asset KEYWORDS: logo, business logo, brand, brand mark, identity, company logo, brand recognition, BETA, microsoft ads, bing, extension WHEN TO USE: - "Add our business logo to our Microsoft Ads" - "Create a Bing logo extension referencing image library ID 123" - "Attach the Acme Corp logo to our Microsoft Ads search ads for brand lift" WHEN NOT TO USE: - Multiple product / lifestyle shots → use create_microsoft_image_extension - The logo is not yet in the image library — upload it first, then call this with the resulting ID. - Same logo for Google Ads → use create_google_business_logo_extension INPUTS: - image_library_id (required): single image library ID pointing to the logo asset. - business_name: business name displayed alongside the logo (≤25 chars). Microsoft Ads surfaces this on the SERP. - domain_name: business domain (≤50 chars). Microsoft Ads surfaces this on the SERP. EXAMPLE: create_microsoft_business_logo_extension( image_library_id=123, business_name="Acme Corp", domain_name="acme.com", )
create_microsoft_business_logo_extension
Add a short non-clickable selling-point snippet (callout) that appears beneath a Microsoft Ads (Bing) ad — short trust-builder phrases like "Free Shipping", "24/7 Support", "Money-Back Guarantee", or "No Setup Fees". Callouts reinforce value props without taking up headline space. ALSO KNOWN AS: callout, callout extension, selling point, trust badge, value prop, value proposition, tagline, ad badge KEYWORDS: callout, selling point, trust signal, value prop, badge, free shipping, money back, guarantee, support, no fees, microsoft ads, bing, extension WHEN TO USE: - "Add a 'Free Shipping' callout to our Microsoft Ads library" - "Create a Bing callout for 24/7 support" - "Register a new value-prop tag for the holiday Microsoft Ads campaigns" WHEN NOT TO USE: - Want a clickable shortcut to a landing page → use create_microsoft_sitelink_extension - Want a list of named items (e.g. "Brands: Nest, Nexus") → use create_microsoft_structured_snippet_extension - Same callout for Google Ads → use create_google_callout_extension - Anything for Facebook / LinkedIn / Reddit — search-channel-only INPUTS: - callout_text: visible snippet (1-25 chars). EXAMPLE: create_microsoft_callout_extension(callout_text="Free Shipping")
create_microsoft_callout_extension
Attach visual imagery (1-20 product / lifestyle shots) to a Microsoft Ads (Bing) text ad to lift click-through. BETA. Re-uses assets already uploaded to the Metadata image library — pass their IDs, not raw files. ALSO KNOWN AS: image extension, image asset, ad image, visual extension, picture extension, photo extension, hero image KEYWORDS: image, image extension, photo, picture, visual, hero, asset, library, BETA, microsoft ads, bing, extension, CTR WHEN TO USE: - "Attach images to our Microsoft Ads text ad" - "Add image library IDs 123 and 456 as a Bing image extension" - "Create a Microsoft Ads image extension showing product photos under our search ads" WHEN NOT TO USE: - The image is a logo / brand mark → use create_microsoft_business_logo_extension - You haven't uploaded the assets yet — image extensions reference library IDs, so upload to the image library first. - Want to drive clicks via text snippets → use create_microsoft_sitelink_extension / callout - Same images for Google Ads → use create_google_image_extension INPUTS: - image_library_ids (required): 1-20 IDs from the Metadata image library. - alternative_text: accessibility alt text (≤90 chars). - display_text: short caption overlaid on the image (≤35 chars). E.g. "Shop Now". - destination_url: landing page when the image is clicked. EXAMPLE: create_microsoft_image_extension( image_library_ids=[123, 456], alternative_text="Product hero shot", display_text="Shop Now", destination_url="https://example.com/landing", )
create_microsoft_image_extension
Add a price-list shown beneath a Microsoft Ads (Bing) ad — 3-8 tiles, each with a plan/product name, a short description, a USD amount, and a billing unit. Standard play for SaaS pricing tiers, subscription plans, course catalogs, service menus, or hotel night rates. ALSO KNOWN AS: price extension, pricing, price list, pricing tiers, plan pricing, subscription pricing, price tiles, rate card, fare list KEYWORDS: price, pricing, price list, plan, plans, tier, tiers, subscription, monthly, yearly, hourly, daily, fare, rate, cost, dollar, $, USD, microsoft ads, bing, extension WHEN TO USE: - "Show our pricing tiers under our Microsoft Ads" - "Add a Bing price extension with Basic / Pro / Scale plans" - "Register monthly subscription prices for the Microsoft Ads campaign" WHEN NOT TO USE: - Single time-bound discount (Black Friday 20% off, promo code) → use create_microsoft_promotion_extension - Non-priced offerings list (just names, no amounts) → use create_microsoft_structured_snippet_extension - Same price list for Google Ads → use create_google_price_extension INPUTS: - price_qualifier: prefix shown before each price. UNSPECIFIED (no prefix) | FROM ("From $X") | UP_TO ("Up to $X") | AVERAGE ("Avg $X"). - price_offerings: 3-8 tiles. Each tile: - url: landing page for that tier (non-blank, ≤2000 chars). - header: tier name (1-25 chars). E.g. "Basic", "Pro", "Scale". - description: short tagline (1-25 chars). E.g. "Starter plan". - amount: USD number (max 999999999.99, two decimals). - unit: billing cadence. UNSPECIFIED | PER_HOUR | PER_DAY | PER_WEEK | PER_MONTH | PER_YEAR | PER_NIGHT. EXAMPLE: create_microsoft_price_extension( price_qualifier="FROM", price_offerings=[ {"url": "https://example.com/basic", "header": "Basic", "description": "Starter plan", "amount": 9.99, "unit": "PER_MONTH"}, {"url": "https://example.com/pro", "header": "Pro", "description": "Growing teams", "amount": 29.00, "unit": "PER_MONTH"}, {"url": "https://example.com/scale", "header": "Scale", "description": "Enterprise", "amount": 99.00, "unit": "PER_MONTH"}, ], )
create_microsoft_price_extension
Add a time-bound promotional offer (sale, discount, promo code) that shows under a Microsoft Ads (Bing) ad — flag a holiday occasion, pick the discount style (% off or $ off), optionally attach a promo code or "on orders over $X" qualifier, and set the start/end window. Standard for Black Friday, Cyber Monday, seasonal sales, flash discounts, holiday campaigns. ALSO KNOWN AS: promotion, promo, discount, sale, offer, coupon, promo code, voucher, deal, holiday sale, seasonal offer KEYWORDS: promotion, promo, promo code, coupon, sale, discount, offer, deal, black friday, cyber monday, holiday, christmas, summer sale, percent off, dollar off, $ off, voucher, microsoft ads, bing, extension WHEN TO USE: - "Set up a Black Friday 20% off Microsoft Ads promotion for our Pro plan" - "Add a Bing holiday promo extension with code SUMMER2026" - "Register a Microsoft Ads sale: $50 off orders over $200" WHEN NOT TO USE: - Permanent pricing tiers (not a limited-time discount) → use create_microsoft_price_extension - Plain "Free Shipping" badge → use create_microsoft_callout_extension - Same promotion for Google Ads → use create_google_promotion_extension INPUTS (required): - occasion: holiday/event tag (NONE if no specific occasion). Available: NONE, BACK_TO_SCHOOL, BLACK_FRIDAY, BOXING_DAY, CARNIVAL, CHINESE_NEW_YEAR, CHRISTMAS, CYBER_MONDAY, DIWALI, EASTER, EID_AL_ADHA, EID_AL_FITR, END_OF_SEASON, EPIPHANY, FALL_SALE, FATHERS_DAY, HALLOWEEN, HANUKKAH, HOLI, INDEPENDENCE_DAY, LABOR_DAY, MOTHERS_DAY, NATIONAL_DAY, NAVRATRI, NEW_YEARS, PARENTS_DAY, PASSOVER, RAMADAN, ROSH_HASHANAH, SINGLES_DAY, SONGKRAN, SPRING_SALE, ST_NICHOLAS_DAY, SUMMER_SALE, VALENTINES_DAY, WINTER_SALE, WOMENS_DAY, YEAR_END_GIFT. - url: landing page for the promotion. - item: what's on sale (1-20 chars). E.g. "Pro subscription". - category_type: discount style. * MONETARY → "$X off". Provide category_amount. * UP_TO_MONETARY → "Up to $X off". Provide category_amount. * PERCENT → "X% off". Provide category_percent (≤100). * UP_TO_PERCENT → "Up to X% off". Provide category_percent (≤100). - details_type: optional qualifier. * NONE → no qualifier. * ON_ORDERS_OVER → "on orders over $X". Provide details_amount. * PROMO_CODE → "with code XXXX". Provide details_promo_code (≤15 chars). - start_date / end_date: ISO-8601 in pattern "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" (e.g. 2026-11-25T00:00:00.000Z). Both must be today or in the future. INPUTS (optional, see category_type / details_type above): - category_amount, category_percent, details_promo_code, details_amount. EXAMPLE — Black Friday 20% off Pro with promo code: create_microsoft_promotion_extension( occasion="BLACK_FRIDAY", url="https://example.com/sale", item="Pro subscription", category_type="PERCENT", category_percent=20, details_type="PROMO_CODE", details_promo_code="BF2026", start_date="2026-11-25T00:00:00.000Z", end_date="2026-11-30T23:59:59.000Z", )
create_microsoft_promotion_extension
Add an extra clickable shortcut (sitelink) that appears beneath a Microsoft Ads (Bing) ad — helpful deep-links like "See Pricing", "Book a Demo", or "Contact Sales" with two short description lines. Sitelinks lift click-through rate by giving searchers alternate landing paths to the same advertiser. ALSO KNOWN AS: sitelink, site link, extra link, ad link, secondary link, deep link, additional link, jump link KEYWORDS: sitelink, site link, link, deep link, shortcut, microsoft ads, bing, extension, pricing link, demo link, contact link, landing page, CTR, click through WHEN TO USE: - "Add a sitelink to our Microsoft Ads / Bing library" - "Create a 'See Pricing' / 'Book a Demo' / 'Contact Sales' link extension for Bing" - "Register a new Microsoft Ads sitelink for the homepage redesign" WHEN NOT TO USE: - Want a non-clickable selling-point snippet ("Free Shipping", "24/7 Support") → use create_microsoft_callout_extension - Want a labeled list of offerings (e.g. "Brands: Nest, Nexus") → use create_microsoft_structured_snippet_extension - Same sitelink for Google Ads → use create_google_sitelink_extension (library entries are per-channel) - Anything for Facebook / LinkedIn / Reddit — ad extensions are a search-channel-only concept INPUTS (all required): - url: destination the sitelink opens. - link_text: visible link text (1-25 chars). - description1: first description line under the link (1-35 chars). - description2: second description line (1-35 chars). EXAMPLE: create_microsoft_sitelink_extension( url="https://example.com/pricing", link_text="See Pricing", description1="Plans for every team size", description2="Start free, upgrade anytime", ) Returns the persisted extension (id, externalId, type=SITELINK, channel=MICROSOFT_ADS). A 400 usually means a character-limit was exceeded.
create_microsoft_sitelink_extension
Add a labeled list of offerings (structured snippet) shown beneath a Microsoft Ads (Bing) ad — a category header plus 3-10 short items, e.g. header "Brands" with values "Nest", "Nexus", "Chromebook", or header "Services" with "Hosting", "DNS", "CDN". Helps searchers self-qualify before clicking. ALSO KNOWN AS: structured snippet, snippet, category list, offering list, header values, product list, service list KEYWORDS: structured snippet, snippet, header, values, brands, services, products, courses, destinations, list, category, microsoft ads, bing, extension WHEN TO USE: - "Add a structured snippet listing our service tiers on Microsoft Ads" - "Create a Bing snippet under 'Brands' with Nest, Nexus, Chromebook" - "Register a list of supported integrations as a Microsoft Ads snippet extension" WHEN NOT TO USE: - Want a single phrase (e.g. "Free Shipping") → use create_microsoft_callout_extension - Want clickable links to subpages → use create_microsoft_sitelink_extension - Want a pricing table (with amounts) → use create_microsoft_price_extension - Same snippet for Google Ads → use create_google_structured_snippet_extension INPUTS: - header: snippet category title (1-25 chars). Microsoft Ads mirrors Google's predefined header vocabulary ("Brands", "Models", "Service catalog", "Insurance coverage", etc.) — pass the chosen header string here. - values: 3-10 items, each 1-25 chars. EXAMPLE: create_microsoft_structured_snippet_extension( header="Brands", values=["Nest", "Nexus", "Chromebook"], )
create_microsoft_structured_snippet_extension
Create a new negative keywords list in the Metadata platform with Google Ads integration. PURPOSE: Batch create a negative keywords list that can be used in Google Ads campaigns to exclude specific search terms from triggering your ads. Use this tool to build negative keyword exclusion lists for campaign optimization and to prevent wasted ad spend on irrelevant searches. ACCOUNT LIMIT: WARNING: MAXIMUM 20 NEGATIVE KEYWORDS LISTS PER ACCOUNT Users can have a maximum of 20 negative keyword lists. The system will validate this limit before creating a new list and return an error if the limit has been reached. To create a new list, you must delete or archive existing lists to free up space. WHEN TO USE: - Create a new negative keywords list for Google Ads campaigns - Build competitor blocking lists (block competitor brand names) - Create category exclusions (block unwanted product categories) - Create seasonal exclusion lists (block irrelevant seasonal terms) - Build intent-based negative lists (block non-commercial searches) - Prevent wasted spend on irrelevant keywords - Manage brand protection by blocking misused terms KEY FEATURES: - BATCH CREATION: Create one or more negative keywords in a single request - MATCH TYPE CONTROL: Specify match type for all keywords (EXACT, PHRASE, BROAD) - FLEXIBLE NAMING: Custom names for organizing negative keyword lists - GOOGLE ADS INTEGRATION: Lists are created ready for use in Google Ads campaigns - SIMPLE INTERFACE: Just provide keywords as strings, API handles formatting - AUTOMATIC VALIDATION: System checks against 20-list limit before creation KEYWORD MATCH TYPES: The 'matchType' parameter controls how broadly the negative keyword blocks ads: 1. EXACT ("Exact Match"): - Blocks ads only for searches that exactly match the keyword - Most restrictive and precise blocking - Example: Keyword "free" with EXACT blocks only searches for "free", not "free shipping" - Best for: High-value keyword protection, brand safety 2. PHRASE ("Phrase Match"): - Blocks ads when the keyword appears as a phrase within the search - Moderate blocking scope - Example: Keyword "vintage furniture" with PHRASE blocks "vintage furniture sale" but not "furniture vintage" - Best for: Competitive category blocking 3. BROAD ("Broad Match"): - Blocks ads for searches containing any of the keyword terms - Least restrictive and broadest blocking - Example: Keyword "free" with BROAD blocks any search containing "free" - Best for: General category exclusions MATCH TYPE SELECTION GUIDE: - Use EXACT for specific brand names or exact competitor terms - Use PHRASE for specific multi-word concepts or phrases - Use BROAD for general categories or very broad exclusions LIST NAMING CONVENTIONS: - Use descriptive names that indicate the list's purpose - Examples: "Competitor Brands", "Low Intent Keywords", "Seasonal Exclusions" - Avoid special characters - use hyphens or underscores for clarity - Keep names concise and meaningful BATCH SIZE RECOMMENDATIONS: - Small batches (1-10 keywords): For targeted blocking - Medium batches (10-50 keywords): For category-based lists - Large batches (50+ keywords): For comprehensive blocking lists - Maximum recommended: 100+ keywords per list NEGATIVE KEYWORDS VS POSITIVE KEYWORDS: - Positive keywords: Terms you WANT to show ads for (create_keywords) - Negative keywords: Terms you DON'T want to show ads for (create_negative_keywords_list) - Use together for optimal campaign performance COMMON USE CASES: 1. Create competitor blocking list (EXACT match): create_negative_keywords_list( name="Competitor Brands", keywords=["competitor a", "competitor b"], match_type="EXACT" ) 2. Create low-intent keyword list (BROAD match): create_negative_keywords_list( name="Low Intent Keywords", keywords=["free", "how to", "tutorial"], match_type="BROAD" ) 3. Create job seeker exclusion list (PHRASE match): create_negative_keywords_list( name="Job Seekers", keywords=["job search", "hiring", "career"], match_type="PHRASE" ) 4. Create seasonal exclusion list: create_negative_keywords_list( name="Summer Sale Exclusions", keywords=["winter coats", "snow gear"], match_type="PHRASE" ) 5. Create product category exclusions: create_negative_keywords_list( name="Non-Ecommerce", keywords=["news", "forum", "wikipedia"], match_type="EXACT" ) PARAMETERS: - name: Required. Name of the negative keywords list (string) Example: "Competitor Brands", "Low Intent Keywords" Use descriptive, meaningful names for easy identification - keywords: Required. Array of keyword strings to block Example: ["raichu", "blastoise", "charizard"] - Minimum: 1 keyword - Recommended maximum: 100+ keywords per request - Each item is a simple string representing the keyword - matchType: Required. Match type for all keywords - EXACT, PHRASE, or BROAD Example: "EXACT" Options: EXACT (exact match), PHRASE (phrase match), BROAD (broad match) RESPONSE FORMAT: Returns a response containing: - Confirmation of the negative keywords list creation - List ID for future reference and management - Success/failure status - Details of keywords added to the list VALIDATION NOTES: - Name is required and must be a non-empty string - Keywords array must have at least 1 keyword - matchType must be exactly one of: EXACT, PHRASE, BROAD (case-sensitive) - Empty strings in keyword list are not allowed - Duplicate keywords in the batch will be handled by the API PERFORMANCE TIPS: - Create lists with related keywords for better organization - Group keywords by blocking strategy (competitor, seasonal, intent-based) - Use EXACT match for high-value keyword protection - Use BROAD match for general category exclusions - Review created lists regularly and update as needed - Can use list_negative_keywords_list() to verify creation INTEGRATION WITH OTHER TOOLS: - Use list_negative_keywords_list() to find and manage existing lists - Use create_keywords() for positive keyword lists - Combine with campaign creation for comprehensive keyword strategies EXAMPLES: - create_negative_keywords_list(name="Competitors", keywords=["competitor1"], matchType="EXACT") - create_negative_keywords_list(name="Free Content", keywords=["free", "no cost"], matchType="BROAD") - create_negative_keywords_list(name="Brand Safety", keywords=["controversial term"], matchType="PHRASE") CHANNEL SCOPE: BOTH search channels are supported: pass channel=MICROSOFT_ADS for Microsoft Ads (Bing) and channel=GOOGLE_ADS for Google. The two channels hold SEPARATE lists, so never substitute one channel for the other to get "close enough" results.
create_negative_keywords_list
Create a new Reddit target group with name and targeting criteria (communities, interests, keywords, location). PREREQUISITE: All references MUST come from search_reddit_criteria. estimate_target_group with channel="REDDIT" first is MANDATORY: verify isMatchCountTooSmall=false and report the reach to the user BEFORE creating. Same bar as create_target_group and update_target_group (PRD-31759). Reddit estimation went live with PRD-31996; before it there was no way to size one of these, which is why a Reddit target group could be created at zero reach with nothing noticing. USE FOR: "create a Reddit target group named X targeting r/technology", "save this Reddit audience as X". WARNING: CHANNEL: Only use this tool when the user explicitly asked for a REDDIT target group. Do NOT infer REDDIT from the underlying audience NAMES (e.g. an audience called "Reddit Conquest Mktg LI_n7q" does NOT mean the user wants a REDDIT target group — audience naming is human convention, not a routing signal). Default to `create_target_group` (LINKEDIN) when channel is unspecified; ask the user if unsure. TARGETING STRUCTURE (LOCATION must be the FIRST include block with isModifiable=false): { "include": [ { "isModifiable": false, "criteria": [{"type": "LOCATION", "data": { "countries": [229], "states": [] }}], "audiences": [] }, { "isModifiable": true, "criteria": [{"type": "COMMUNITIES", "data": [ {"externalId": "t5_2qh1i", "name": "r/technology"} ]}], "audiences": [] } ], "exclude": { "isModifiable": true, "criteria": [{"type": "KEYWORDS", "data": [{"externalId": "kw_123", "name": "crypto"}]}], "audiences": [] } } REDDIT CRITERIA TYPES (all references from search_reddit_criteria): - LOCATION: {"countries": [<id>, ...], "states": [<id>, ...]} — arrays of NUMERIC Metadata IDs (use the numeric `id` from search_reddit_criteria locations, NOT the {id, name} object). MANDATORY FIRST in include, isModifiable=false - COMMUNITIES: Array of {externalId, name} — subreddits (e.g. r/technology) - INTERESTS: Array of {externalId, name} — Reddit interest categories - KEYWORDS: Array of {externalId, name} — contextual keywords INCLUDE: Array of rule blocks (AND-joined). EXCLUDE: single object with `criteria` and `audiences`. AUDIENCES (combine with the criteria above to build complex target groups): each include block and the exclude object also accept an `audiences` array, so you can mix existing Metadata audiences with the Reddit criteria in the same block. Get them from the audience listing tools / get_matched_audiences. Each audience entry: {mdAudienceId, name, type, matchCount, matchCountType: "FIXED_SIZE", inactive, criteria: [the audience's own criteria]}. `mdAudienceId` MUST be the numeric Custom Audience ID (integer, e.g. 49067): the `customAudienceId` / `mdAudienceId` field of a get_matched_audiences row, NEVER that row's `id` (the channel row id) and NEVER the audience name string; the platform's `mdAudienceId` is typed `Long`, the tool rejects non-integer values pre-flight, and it resolves every id on the platform before the write so a wrong id, an archived audience or one with no live segment on the channel is refused with the reason instead of a "too small" error. In the exclude block, use the EXCLUDE variant of the type (e.g. RETARGETING_EXCLUDE). RESPONSE: {id, name, channel, audienceSize, status, createdDate, targeting} WORKFLOW: search_reddit_criteria → build targeting (LOCATION first) → confirm → create_reddit_target_group
create_reddit_target_group
Create a new retargeting audience on the Metadata platform from native channel audiences. This tool creates a retargeting audience by importing an existing audience from a native advertising channel (Google Ads, LinkedIn, or Facebook). The audience can be selected from the list of available retargeting audiences returned by the get_retargeting_audiences tool. **REQUIRED TWO-STEP WORKFLOW:** STEP 1: Get available audiences for your channel - Call get_retargeting_audiences with your channel (GOOGLE_ADS, LINKEDIN, or FACEBOOK) - Review the returned list of available audiences with their details (name, matchCount, etc.) - Select the audience you want to import by its ID or by matching its properties STEP 2: Create the retargeting audience - Use this tool (create_retargeting_audience) with the audience data from Step 1 - Provide the audience details from the get_retargeting_audiences response - The audience will be created and imported into the Metadata platform SUPPORTED CHANNELS: - GOOGLE_ADS: Google Ads retargeting audiences - LINKEDIN: LinkedIn retargeting audiences - FACEBOOK: Facebook retargeting audiences WHEN TO USE: - "Create a retargeting audience from [audience name] in [channel]" - "Import [native channel] audience into Metadata" - "Add [audience name] from [channel] as a retargeting audience" - "Create a new retargeting audience based on [channel] native audience" WORKFLOW EXAMPLE: User: "Create a retargeting audience from my Google Ads campaign audience" 1. Call get_retargeting_audiences(channel="GOOGLE_ADS") to list available audiences 2. Select the desired audience from the results 3. Call create_retargeting_audience with the audience object from the results PARAMETERS: - audience_data: Complete audience object from get_retargeting_audiences response (required) Should include: id, name, type, subtype, channel, matchCount, externalAccountId Note: This is typically the entire audience object returned by get_retargeting_audiences AUDIENCE DATA STRUCTURE: The audience_data parameter should be a dictionary containing: - id: Unique audience ID (required) - name: Audience name (required) - type: Audience type (e.g., GoogleAdsAudience, LinkedInAudience, FacebookAudience) (required) - subtype: Audience subtype (e.g., GOOGLE_ADS_RETARGETING, LINKEDIN_RETARGETING) (required) - channel: Channel type identifier (required) - matchCount: Number of matches/members in the audience - externalAccountId: Associated account ID on the advertising platform (required) - mdId: Metadata ID (optional, typically null for new imports) - externalName: External name (optional) - externalSubType: External subtype (optional) - seedSourcePlatform: Source platform for the audience seed (optional) RETURNS: Success confirmation with details about the created retargeting audience including: - Audience ID - Audience name - Type and subtype - Channel - Match count - Creation status COMMON USE CASES: - Create retargeting audiences from Google Ads native audiences - Import LinkedIn retargeting audiences into Metadata - Setup Facebook retargeting audiences for multi-channel campaigns - Consolidate native channel audiences into Metadata platform IMPORTANT NOTES: - Audience must be selected from get_retargeting_audiences results - The audience object must contain all required fields - Channel must be GOOGLE_ADS, LINKEDIN, or FACEBOOK - Audience creation is immediate and the audience becomes available for targeting - Once created, the audience can be used in campaigns across channels
create_retargeting_audience
Create a Salesforce-contacts custom audience (platform customAudienceType SFDC_CONTACTS_STATIC or SFDC_CONTACTS_DYNAMIC) from a Salesforce mixed-criteria. This is one of the audience types eligible for Microsoft Ads (Customer Match). Use it when a user wants a Salesforce-sourced contacts audience, including for a Microsoft Ads campaign. PREREQUISITE: • Salesforce integration MUST be connected — the tool checks this and, if not connected, creates nothing and returns { warning, connected: false }. • A criteria_id from list_salesforce_mixed_criteria — do NOT invent one. VARIANT (mirrors the UI's static/dynamic choice): • STATIC → SFDC_CONTACTS_STATIC — snapshot at creation, does not refresh. • DYNAMIC → SFDC_CONTACTS_DYNAMIC — refreshes as the Salesforce data changes. • If the user did not say which, ASK; do not default silently. ASYNC: the platform creates the audience in the background and returns a flow id, NOT a ready audience id. The audience appears under the account's Salesforce audiences once the flow completes, and its contact count fills in then. Do not expect to associate it to a campaign in the same turn. PARAMETERS: • name (required): audience display name. • criteria_id (required): id from list_salesforce_mixed_criteria. • variant (required): STATIC or DYNAMIC. RETURNS: { id, name, status, createdDate, audience_type, async: true } — `audience_type` is the SFDC_CONTACTS_* you created and `id` is a creation/flow id, not associable yet. If Salesforce is not connected: { warning, connected: false }, and nothing is created.
create_salesforce_contacts_audience
Create a saved Insights (Spotlight) account-journey segment: a reusable filter over the account's engaged companies, and the input of create_audience_from_segment (and of get_insights_report). WHEN: the audience or list is defined by BEHAVIOUR or CRM STATE rather than by firmographics alone: "accounts that visited /pricing", "high engagement score and not in the CRM", "accounts we already served more than 200 LinkedIn impressions" (a saturation exclusion for a sequenced program), "open opportunities that went cold". Plain firmographic / technographic / intent asks do NOT need a segment: use those audience tools directly. WORKFLOW: 1. search_insights_criteria_fields (omit keywords for the full catalog) for exact field names, types, operators and picklist options. 2. list_segments: reuse a segment that already expresses the ask. This tool refuses a duplicate name. 3. create_segment with a descriptive name and the criteria below. Pass lookback_window to get `accounts` counted inside the window the audience will use. 4. create_audience_from_segment(segment_id, name, lookback_window, audience_type). REQUIRES an active Insights (Spotlight) subscription on the account: the platform gates segment creation on it, and this tool checks it before writing. A refusal naming the subscription state (expired, trial expired, no plan) is final: tell the user the subscription must be renewed, and do not retry with other criteria. Reading existing segments and building audiences from them keep working. CRITERIA SHAPE: a group {"operator": "AND"|"OR", "match": [criterion | nested group]}, up to three nested levels. Each criterion: {"field": <NAME>, "operator": <one of the field's operators>, "type": <the field's type>, "value": ...}. Before the call every criterion is checked against the live catalog: a missing `type` is filled in, names and operators are case-normalised, and an unknown field, an operator the field does not accept, or a picklist value that is not one of its options is refused with the valid choices (nothing is created). VALUES BY TYPE: - NUMERIC: a number; operators EQUALS, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL. Metrics (LINKEDIN_IMPRESSIONS, LINKEDIN_ADS_ENGAGEMENT, WEBSITE_VISITS, TOTAL_PAGE_VIEWS, FORM_SUBMISSIONS, ...) are summed over the lookback window the audience is created with, so "more than 200 impressions in the last 90 days" is {"field": "LINKEDIN_IMPRESSIONS", "operator": "GREATER_THAN", "type": "NUMERIC", "value": 200} plus lookback_window 90 on the audience. - MULTIPICKLIST: a list of options; plain strings are accepted and matched to the catalog options by name or label; operators IN, NOT_IN. - BOOLEAN: true or false, operator null (or omitted). - STRING: text; EQUALS, NOT_EQUAL, LIKE (contains), NOT_LIKE. PAGE_URL LIKE "/pricing" is the page-visit filter. - ARRAY (UTM_* and REFERRER): a list of strings; IN, NOT_IN, LIKE, NOT_LIKE. - DATE (CRM date fields): {"days": N} with IN_THE_LAST / NOT_IN_THE_LAST / IN_THE_NEXT, or {"startDate", "endDate"} (ISO) with BETWEEN. - CRM (dynamic) fields: {"field": "DYNAMIC", "entity": <from the catalog>, "property": <field name>, "operator", "type", "value"}. EXAMPLE, saturation exclusion for a sequenced LinkedIn program: {"name": "Saturated: 200+ LinkedIn impressions", "lookback_window": 90, "criteria": {"operator": "AND", "match": [{"field": "LINKEDIN_IMPRESSIONS", "operator": "GREATER_THAN", "type": "NUMERIC", "value": 200}]}} EXAMPLE, warm accounts not yet in the CRM: {"operator": "AND", "match": [{"field": "SCORE", "operator": "IN", "type": "MULTIPICKLIST", "value": ["High"]}, {"field": "IN_CRM", "operator": null, "type": "BOOLEAN", "value": false}]} RETURNS: {success, id, name, status (READY | PENDING | FAILED), last_updated_date, lookback_window, accounts, criteria (as stored), notes}. PENDING means a CRM field is still being extracted: wait and re-check with get_segment_criteria before building an audience. `accounts` of 0 means an audience would be empty: loosen the criteria or widen the window.
create_segment
Create a new target group with name and targeting criteria. Supports BOTH include AND exclude rules — including excluding existing Metadata audiences. PREREQUISITE: All criteria IDs MUST come from search_target_group_criteria. estimate_target_group first is MANDATORY: verify isMatchCountTooSmall=false and report the reach to the user BEFORE creating. A target group created without an estimate can land at zero matches and nothing downstream will notice (PRD-31759). Same bar as update_target_group. USE FOR: "create target group named X with criteria Y", "save this target group as X", "create new audience called X", "create target group excluding companies Z", "create target group that excludes audience X". WARNING: CHANNEL: This tool creates LINKEDIN target groups only. Do NOT infer channel from the underlying audience NAMES (e.g. an audience called "Reddit Conquest Mktg LI_n7q" does NOT mean the user wants a REDDIT target group — audience naming is human convention, not a routing signal). Use REDDIT only when the user explicitly named the REDDIT channel in the request; in that case use `create_reddit_target_group` instead. When in doubt, ask the user which channel. **CRITICAL FOR LINKEDIN**: LOCATION must be FIRST criteria in include array with isModifiable=false. TARGETING STRUCTURE (full example with include + exclude criteria + exclude audiences): { "include": [ { "isModifiable": false, "criteria": [{"type": "NATIVE_LOCATION", "data": [ {"externalId": "urn:li:geo:101165590", "name": "United Kingdom"}, {"externalId": "urn:li:geo:103644278", "name": "United States"} ]}], "audiences": [] }, { "isModifiable": true, "criteria": [{"type": "AGE", "data": [{"externalId": "urn:li:ageRange:(25,34)", "name": "25 to 34"}]}], "audiences": [] } ], "exclude": { "isModifiable": true, "criteria": [ {"type": "COMPANY_NAME", "data": [{"externalId": "urn:li:organization:1090", "name": "Philips"}]} ], "audiences": [ { "mdAudienceId": 45316, "name": "ICP Pharma LifeSci Leaders", "type": "FIRMOGRAPHIC_EXCLUDE", "matchCount": 213127, "matchCountType": "FIXED_SIZE", "inactive": false, "criteria": [{"type": "NATIVE_LOCATION", "data": [{"externalId": "urn:li:geo:103644278", "name": "United States"}]}] } ] } } INCLUDE: Array of rule blocks (AND-joined). Each block holds a criteria group. EXCLUDE: Single object (NOT array) with `criteria` and `audiences`. Anything matching exclude is removed. WARNING: AUDIENCES ≠ TARGET GROUPS. Both `include[].audiences` and `exclude.audiences` accept Custom Audience records ONLY (the entities returned by `get_matched_audiences`). Target Groups (the entities returned by `list_target_groups` / `retrieve_target_group_by_id`) are a separate entity in a separate ID space and CANNOT be attached here; the platform silently drops or rejects them. If the user names "X" and only `list_target_groups` matches it (not `get_matched_audiences`), do NOT pass the Target Group's id as `mdAudienceId`. Stop, tell the user "X is a Target Group, not a Custom Audience", and offer to rebuild X as a Custom Audience (e.g. via `create_audiences` with the same criteria) before retrying. INCLUDE AUDIENCES: `include[].audiences` accepts ANY Metadata audience type — there is NO allow-list and NO restriction to specific types. The audience must be live on the channel, though: a row with inactive=true (LinkedIn segment archived, failed or still building) is refused by the platform and sized at 0, so pick an active row. Pass any audience returned by the audience listing tools (e.g. FIRMOGRAPHIC_INCLUDE, FIRMOGRAPHIC_INCLUDE_SFDC, NATIVE_LINKEDIN, NATIVE_FACEBOOK, RETARGETING, TECHNOGRAPHIC, SFDC_ACCOUNT_DYNAMIC, MA_CONTACTS_DYNAMIC, CONTACT_LIST, and any other type, including types not enumerated in any tool schema). Type-name enums seen in `create_audiences` / `search_audiences` describe how audiences are CLASSIFIED, not which can be attached here. Caveat: estimates may under-report (or return zero) when combining server-resolved audiences (e.g. SFDC dynamic, retargeting) with native LinkedIn criteria — that is an estimate-side reconciliation issue, not a creation constraint, so a zero estimate does not necessarily mean the platform will reject the create call. If a zero estimate is suspected to be a reconciliation artifact, attempt the create and verify in the UI. HOW TO EXCLUDE AN EXISTING METADATA CUSTOM AUDIENCE: Add it as an object in `exclude.audiences`. The tool pre-flight-rejects placeholder values — never invent ids or types when you don't know them, call `get_matched_audiences` (or `search_audiences`) first and use the real values from the response. Required fields: - `mdAudienceId` (integer, REQUIRED): The numeric Custom Audience ID from `get_matched_audiences`, its `customAudienceId` / `mdAudienceId` field (e.g. 49067, 45316), NEVER that row's `id` (the channel row id). NEVER the audience name string, NEVER a placeholder like 1/2/3/4 (real Custom Audience IDs are 5-digit numbers; the tool rejects anything under 100), and NEVER a Target Group id (those come from `list_target_groups`; see the AUDIENCES ≠ TARGET GROUPS note above). - `name` (string): Audience name. - `type` (string): MUST be the EXCLUDE variant of the audience type, e.g. `FIRMOGRAPHIC_EXCLUDE`, `RETARGETING_EXCLUDE`, `CONTACT_LIST_EXCLUDE`. NEVER the placeholder string "AUDIENCE" — the tool rejects that pre-flight. - `matchCount` (int), `matchCountType` ("FIXED_SIZE"), `inactive` (bool): copy from audience record. The tool pre-flight-rejects entries with `inactive: true` (an audience still matching after creation cannot be attached yet — attach it once it is active). - `criteria`: The audience's own criteria array (copy from the audience's definition). CRITERIA TYPES (all IDs from search_target_group_criteria), valid in BOTH include and exclude: - NATIVE_LOCATION / LOCATION: location data — MANDATORY FIRST in include. Multi-country geo goes in ONE location criterion with one {externalId, name} entry per country (e.g. "Canada and USA" = 2 entries in the same data array). Never silently drop a country the user named. - AGE, COMPANY_CATEGORY, COMPANY_GROWTH_RATE, INDUSTRY, COMPANY_NAME, REVENUE, EMPLOYEE: Array of {externalId, name} - JOB_FUNCTION, JOB_TITLE, MEMBER_GROUP, MEMBER_INTEREST, MEMBER_SKILL, MEMBER_BEHAVIOR, SENIORITY, FOLLOWED_COMPANIES: Array of {externalId, name} - YEARS_OF_EXPERIENCE_RANGE: {"min": 4, "max": 5} WORKFLOW: search_target_group_criteria → build targeting (include + optional exclude criteria/audiences) → estimate_target_group → confirm → create_target_group RESPONSE: {id, name, channel, audienceSize, status, createdDate, targeting}
create_target_group
Creates B2B audiences based on technology stack, software usage, and firmographic attributes. ESTIMATE-ONLY MODE: Pass estimate_only=true to preview audience size (companies + contacts) WITHOUT creating the audience. In this mode the tool returns expectedNumberOfCompanies, expectedNumberOfContacts, and cappedContactCount. Default is false (audience is created). WHEN TO USE: - Target companies using specific technologies or software - Create audiences based on technology adoption patterns - Target by technology categories (CRM, Marketing Automation, Analytics, etc.) - Combine technology targeting with firmographic filters - Build tech-savvy audience segments for B2B campaigns - User wants to target companies and contacts that are familiar/using some specific software like hubspot, g2, etc. TECHNOLOGY CATEGORIES: - CRM: Salesforce, HubSpot, Microsoft Dynamics, Zoho, Pipedrive - Marketing Automation: Marketo, Pardot, Eloqua, HubSpot, Mailchimp - Analytics: Google Analytics, Adobe Analytics, Mixpanel, Amplitude - E-commerce: Shopify, Magento, WooCommerce, BigCommerce - Content Management: WordPress, Drupal, Joomla, Adobe Experience Manager - Collaboration: Slack, Microsoft Teams, Zoom, Asana, Monday.com - Cloud Infrastructure: AWS, Azure, Google Cloud, Oracle Cloud - Database: MySQL, PostgreSQL, MongoDB, Oracle, SQL Server - And many more technology categories available FIRMOGRAPHIC FILTERS (OPTIONAL): - Industries: Use industry IDs (1-148, same as firmographic audiences) - Employees: "LESS_THAN_10", "FROM_10_TO_50", "FROM_50_TO_200", "FROM_200_TO_500", "FROM_500_TO_1000", "FROM_1000_TO_5000", "FROM_5000_TO_10000", "OVER_10000" - Revenue: "LESS_THAN_1M", "FROM_1M_TO_10M", "FROM_10M_TO_50M", "FROM_50M_TO_100M", "FROM_100M_TO_200M", "FROM_200M_TO_500M", "FROM_500M_TO_1000M", "OVER_1000M" CONTACTS CRITERIA: Use the following parameters to filter and target specific contacts within accounts: GEOGRAPHIC TARGETING: - location_country_ids: Array of country IDs (e.g., [29] for Brazil, [229] for United States) - location_state_ids: Array of state IDs (e.g., [5] for California, [32] for New York) JOB TITLES: - job_title_includes: Array of free text strings to include (e.g., ["Software Engineer", "Manager"]) - job_title_excludes: Array of free text strings to exclude (e.g., ["Senior", "Lead"]) JOB FUNCTIONS: Valid job function IDs and their labels: - 1: Marketing, 2: Sales, 3: Customer Service, 4: Finance, 5: Human Resources, 6: Public Relations - 7: Media, 8: Design, 9: Engineering, 10: Operations, 11: Legal, 12: Education - 13: Health, 14: Real Estate, 15: Accounting, 16: Administrative, 17: Business Development - 18: Community and Social Services, 19: Consulting, 20: Entrepreneurship, 21: Information Technology - 22: Military and Protective Services, 23: Product Management, 24: Program and Project Management - 25: Purchasing, 26: Quality Assurance, 27: Research, 28: Trades - job_function_include_ids: Array of job function IDs to include (e.g., [9] for Engineering) - job_function_exclude_ids: Array of job function IDs to exclude SENIORITY LEVELS: Valid seniority IDs and their labels: - 2: Manager, 3: Director, 4: VP, 5: CXO, 6: Unpaid, 7: Training - 8: Senior, 9: Owner, 10: Entry, 11: Partner - seniority_include_ids: Array of seniority level IDs to include (e.g., [10, 7] for Entry and Training) - seniority_exclude_ids: Array of seniority level IDs to exclude CONTACT LIMITS: - contacts_per_company_limit: Maximum number of contacts to target per company (optional). Example: 20 USAGE NOTES: - All ID fields (countries, states, job functions, seniorities) use numeric IDs from the platform - Job titles are free text strings, not IDs - Use include parameters to specify which criteria to target - Use exclude parameters to filter out contacts matching specific criteria - Combine multiple criteria for precise targeting (e.g., Senior Engineers in California) - Criteria are combined with AND logic, so all conditions must be met CONTACTS CRITERIA PARAMETERS(Usually after other initial audience parameters to be described next): - location_country_ids: Array of country IDs (optional) - location_state_ids: Array of state IDs (optional) - job_title_includes: Array of job title keywords to include (optional) - job_title_excludes: Array of job title keywords to exclude (optional) - job_function_include_ids: Array of job function IDs (optional) - job_function_exclude_ids: Array of job function IDs (optional) - seniority_include_ids: Array of seniority level IDs (optional) - seniority_exclude_ids: Array of seniority level IDs (optional) - contacts_per_company_limit: Maximum contacts per company (optional) PARAMETERS: - name: Audience name (required) - **IMPORTANT: Name MUST NOT exceed 50 characters. This is a mandatory requirement.** - technologies: Array of technology names (required) - industries: Array of industry IDs (optional) - employees: Array of employee count ranges (optional) - revenue: Array of revenue ranges (optional) RETURNS: Audience details with ID, size estimation, and creation status, plus `technologies_requested`, `technologies_targeted` (the indexed names actually sent) and `technology_resolution`. COMMON USE CASES: - Target companies using Salesforce and HubSpot - Find AWS users in the software industry - Build audiences of companies using specific MarTech stacks - Combine technology and firmographic targeting for precise B2B campaigns IMPORTANT NOTES: - **CRITICAL: Audience name MUST NOT exceed 50 characters - this is mandatory and will cause creation to fail if exceeded** - name and technologies are required parameters - All other parameters are optional for flexible audience creation - Technology names are resolved against the platform's indexed product catalog: an exact name is used as given; otherwise the closest indexed match is used and reported back in `technology_resolution` (requested, used, exact_match, alternatives) plus a plain-words `technology_note`. A name with no catalog match fails the call with an error; nothing is dropped silently. - When the call fails as too small and the error names a substituted technology, retry with one of the listed alternatives or a broader technology name. Do NOT loosen industries, seniority, employee bands or countries first: the substituted product is the cause. - Contact criteria fields work the same as in other audience types - Audience size depends on technology filters and applied criteria
create_technographic_audience
Create or update advertising budget and spending allocation. Set up budget groups to control how much money campaigns can spend. ALSO KNOWN AS: set budget, allocate spend, create spending plan, budget allocation, ad budget, campaign budget KEYWORDS: budget, spend, spending, money, dollars, $, quarter, monthly, allocation, cost, funds, cap, limit SUPPORTED TYPES: - Lead Generation (default): goal=CPL, groupMetric=CPL, optimizerFormula=CPL_2 (or CPC_2), autoPauseConfigurationId=14, enableBooster=true. Requires benchmark and groupMetric. Dates follow budgetType, not the goal (see DATE RULES): FIXED_BUDGET sends startDate AND endDate, MONTHLY_RESET sends neither. - Brand Awareness: goal=CTR, autoPauseConfigurationId=9, enableBooster=false, budgetType=MONTHLY_RESET. Two formula variants: • CPC variant: groupMetric=CPC, optimizerFormula=CPC_2 (benchmark is a CPC target, e.g. 10) • CTR variant: groupMetric=CTR, optimizerFormula=CTR (benchmark is a CTR target in basis-points style, e.g. 10000) budgetRedistributionStrategy may be PERFORMANCE or PACING_ONLY. MONTHLY_RESET: omit BOTH startDate and endDate. WARNING: BUDGET-GROUP TYPE MUST FOLLOW THE CAMPAIGN GOAL (do not mix): - A CPL / Lead Generation campaign (campaignType "Lead Gen") REQUIRES a Lead Generation (CPL) budget group: goal=CPL, groupMetric=CPL, optimizerFormula=CPL_2, enableBooster=true, autoPauseConfigurationId=14. - A Brand Awareness campaign (campaignType "Brand Awareness") REQUIRES a Brand Awareness budget group: goal=CTR, enableBooster=false, budgetType=MONTHLY_RESET, autoPauseConfigurationId=9 (CPC or CTR formula variant per SUPPORTED TYPES above). - NEVER attach a Brand-Awareness (CTR) budget group to a CPL campaign, or a Lead-Generation (CPL) budget group to a Brand Awareness campaign — the optimizer goal must match the campaign's objective. If the campaign goal is unknown, confirm it before creating the budget group. To UPDATE: include 'id' field with the budget group ID. To CREATE: omit the 'id' field. Pass all fields inside the `data` object. Dates must be ISO 8601 UTC with exactly 3 ms digits, e.g. 2026-01-15T12:00:00.000Z (format example only — compute the real values). CRITICAL DATE RULES: - startDate and endDate travel TOGETHER: send both or neither. The platform rejects one without the other with 400 VALIDATION_DATE ("End Date can not be empty" / "Start Date can not be empty"). budgetType decides which: FIXED_BUDGET = both required; MONTHLY_RESET = omit both. This holds for EVERY goal, CPL included: a Lead Gen group with a monthly budget is MONTHLY_RESET with no dates at all, never MONTHLY_RESET plus a startDate. - You do NOT inherently know today's date. If you are not already certain of it, call get_current_date FIRST and anchor every rule below to that real value — never guess. - The endDate MUST ALWAYS be in the future (strictly after today's real date). - NEVER set an endDate that is today or in the past — this will cause the budget group to be immediately expired. - "this month" → endDate = the last day of the current month. "this quarter" → endDate = the last day of the current quarter. "next month" / "next quarter" → compute relative to today's real date. - If the user provides a specific end date that is in the past, WARN THEM and ask for a valid future date. Do NOT submit a past endDate. - startDate can be today or in the future, but never in the past for new budget groups. REMARKS: - If the user doesn't EXPLICITLY states that their budget is by month or MONTHLY, then use FIXED_BUDGET as budgetType. - In other words, the default value is FIXED_BUDGET unless the user explicitly says MONTHLY or BY MONTH. - IF the user says "this month" then also use FIXED_BUDGET and start date should be today, end date should be the last day of the month. - When you use FIXED_BUDGET (fixed-date) but the user's timing expectations/goals are NOT clear, ASK for an explicit start-date and end-date before creating — do not silently invent a date range. Only skip the question when the dates are already unambiguous (e.g. the user gave a range, or said "this month"/"this quarter"). - monthlyCap is the user's money: when the user has NOT explicitly stated a budget / monthly cap (or confirmed a figure you proposed), ASK for it before creating — do not silently invent a cap. This applies to campaign-creation flows too: a budget group needed by a new campaign still requires a user-chosen cap. Same when an update would change monthlyCap. - If the user says "set a monthly budget of $X" or equivalent then use MONTHLY_RESET as budgetType (MONTHLY is NOT a valid value, the platform rejects it) - Before an update, refresh the information by using get_budget_group to avoid overwriting fields unintentionally. - The campaign doesn't need to be in a launched state for its budget group to be updated. WHEN TO USE: - User wants to create a new budget group with specific settings - We're creating a campaign and need to set up its budget group. - User requests to update an existing budget group with new parameters - User requests to update the budget of a campaign INTEGRATION WITH OTHER TOOLS: - If the ID for a budget group update is unknown there are a few options: - if you have the campaign name, use search_campaigns_by_name. In its response, `$.optimizationGroup.id` is the budget group ID. - From search_campaigns_by_names's response, you get the property `$.optimizationGroup.id`. That's the budget group ID. - You can also use get_budget_group if you have the budget group name to retrieve its ID. Anchor every date calculation to the REAL current date — if you are not certain what today is, call get_current_date before computing start/end dates.
create_budget_group
Create a new or update an existing Google Ads text ad on the Metadata platform. IMPORTANT: This tool is ONLY for Google Ads (GOOGLE_ADS channel) text ads. Do NOT use this tool for Facebook, LinkedIn, or Instagram ads. For other channels or ad types use the dedicated tools: create_update_image_ad (IMAGE/GIF) or create_update_video_ad (VIDEO). CAROUSEL is not yet covered by the new tools — flag it if you hit that case. BEHAVIOR: - If "id" is NOT provided → creates a new Google Ads text ad. - If "id" IS provided → updates the existing Google Ads text ad with that ID. CRITICAL — GOOGLE ADS CHARACTER LIMITS (HARD LIMITS — API WILL REJECT IF EXCEEDED) - Headlines: MAXIMUM 30 characters each (minimum 3, maximum 15 headlines) - Descriptions: MAXIMUM 90 characters each (2 to 4 descriptions). Each description string MUST be 90 characters or fewer. Count every letter, space, and punctuation mark. 90 is the absolute maximum. - Ad name: MAXIMUM 50 characters WARNING: DESCRIPTIONS — 90 CHARACTER HARD LIMIT — READ THIS CAREFULLY THIS IS THE #1 MOST COMMON FAILURE MODE. DO NOT SKIP THIS SECTION. - 90 characters is an ABSOLUTE, NON-NEGOTIABLE HARD CEILING. - 91 characters = REJECTION. 100 characters = REJECTION. 89 characters = OK. - "Characters" means EVERY character: letters, digits, spaces, punctuation, apostrophes, hyphens, slashes, line breaks, and emoji code points. ALL count. - There is NO grace, NO rounding, NO partial credit. The boundary is exact. - The MCP schema enforces maxLength=90 — an over-length string is rejected before your tool call even runs. The server ALSO truncates as a backstop, meaning your over-length copy will be SILENTLY CUT MID-SENTENCE if it somehow slips through. Either way, you will not get the description you wrote. - This rule applies to EACH description independently. 4 descriptions of 80 chars each is fine. 1 description of 91 chars is NOT fine. - Do NOT pad descriptions to "use the space." Shorter is always safer. - Do NOT rely on the user noticing — you are responsible for compliance. COMMON WAYS LLMs BLOW THE 90-CHAR LIMIT (avoid these): - Writing a "complete sentence" without counting first. - Adding a CTA at the end ("Sign up today!") that pushes past 90. - Including the company name AND a tagline AND a benefit in one description. - Using em dashes (—), ellipses (…), or smart quotes (" ") which still count as characters and often appear longer than expected when counted. - Trusting your "feel" for length — LLMs systematically underestimate by 5-15 characters. ALWAYS COUNT. RECOMMENDED SAFETY MARGIN: - Target 70-85 characters per description. This leaves headroom for sanitization (smart-quote conversion, whitespace normalization) and avoids edge-case rejections. 90 is the cliff — do not write to the cliff. MANDATORY PRE-CALL VALIDATION — YOU MUST DO THIS BEFORE EVERY CALL: 1. Write out each headline and count its characters — each MUST be ≤ 30 characters 2. Write out each description and count its characters — each MUST be ≤ 90 characters (this is the most common error — descriptions MUST NOT exceed 90 characters) 3. For EACH description, do an explicit character count: len(description). If the number is 91 or higher, REWRITE before calling. Do not "estimate" — count. 4. If any text exceeds the limit, rewrite and shorten it BEFORE calling the tool 5. Do NOT rely on the API to catch these errors — validate client-side first 6. When in doubt, make descriptions shorter. A 70-character description is better than a rejected 91-character one 7. If a user provides copy that is too long, shorten it yourself and proceed — do NOT submit known-bad copy and hope for the best. EXAMPLES — DESCRIPTIONS AT THE 90-CHAR BOUNDARY: - "Shop the best deals online." (27 chars) SAFE - "Free shipping on every order over fifty dollars. Sign up today!" (63 chars) SAFE - "Discover our award-winning marketing platform built for B2B teams of every size today" (89 chars) SAFE — at the edge - "Discover our award-winning marketing platform built for modern B2B teams of every size today" (94 chars) REJECTED — 4 over - "Transform your B2B marketing strategy with AI-powered automation that drives real revenue today!" (98 chars) REJECTED — REWRITE USAGE INSTRUCTIONS FOR LLM: Use this tool when users want to: - Create a new Google Ads text ad - Update an existing Google Ads text ad (headlines, descriptions, or name) - Set up a Google Ads responsive search ad with headlines and descriptions WHEN TO USE: - User asks "create a Google Ads ad" - User wants to create a text ad for Google Ads - User says "make a new Google ad with these headlines and descriptions" - User wants to update the headlines or descriptions of an existing Google Ads ad - User says "update Google ad 23149 with new headlines" WHEN NOT TO USE: - User wants to create a Facebook, LinkedIn, Instagram, or Reddit IMAGE ad → use create_update_image_ad - User wants to create a Facebook, LinkedIn, Instagram, or Reddit VIDEO ad → use create_update_video_ad - User wants to update a non-Google Ads ad → use create_update_image_ad or create_update_video_ad (whichever matches the ad's adType) INPUT PARAMETERS: - id: The ad ID (optional). If provided, the ad with this ID will be updated. If omitted, a new ad is created. This is the adLibraryId inside the creatives of the google channel in campaign response. - name: The name/label for the ad (required, max 50 characters) - headlines: Array of headline text strings (required, minimum 3, maximum 15 headlines, each STRICT MAX 30 CHARACTERS) - descriptions: Array of description text strings (required, 2 to 4 descriptions, each STRICT MAX 90 CHARACTERS — count characters carefully, this is the most common validation failure) EXAMPLE USAGE (Create): create_update_google_ads_ad( name="My Google Ad Q1 2025", headlines=["Buy Now", "Best Deals", "Free Shipping"], descriptions=["Shop the best deals online.", "Free shipping on all orders."] ) EXAMPLE USAGE (Update): create_update_google_ads_ad( id=23149, name="My Google Ad Q1 2025 Updated", headlines=["Updated Headline 1", "Updated Headline 2", "Updated Headline 3"], descriptions=["Updated description 1.", "Updated description 2."] )
create_update_google_ads_ad
Create OR update an IMAGE (or GIF) ad on Facebook, Instagram, LinkedIn, and/or Reddit. TO UPDATE: include `id`; to CREATE: omit it. CREATIVE WORKFLOW: 1. Upload the image/GIF via `upload_image_creative` → response gives `id` (the imageLibraryId). 2. Pass that integer as `creativeID` here. - Need a new image? `generate_brand_creative` → `upload_image_creative` → `create_update_image_ad`. ALSO KNOWN AS: create image ad, update image ad, edit image ad, modify image ad, image creative, post image, image post, photo ad. KEYWORDS: image, gif, create, update, edit, modify, ad, ads, image ad, image ads, image creative, photo, picture, banner, image campaign, image upload, LinkedIn image, Facebook image, Instagram image, Reddit image, IG post. CLIENT-SIDE VALIDATION (refuses what the platform UI would also reject): - adName: required, max 50 chars, pattern `[a-zA-Z0-9 _.?,:'/+\-=&;%$#\[\]|()]`. - creativeID: required integer (imageLibraryId from `upload_image_creative`). - Landing-page URL is per channel (`facebookDisplayURL`, `instagramDisplayURL`, `linkedinDisplayURL`, `redditDisplayURL`). Required for FB/IG/LinkedIn, optional for Reddit. Per-channel caps: LinkedIn max 2000, Reddit max 100, FB/IG no length rule. URL format accepts both `metadata.io` and `https://metadata.io` for IMAGE ads. If only one channel's URL is set the server fans it across the other targeted channels; each channel's cap is then enforced per channel. - LinkedIn: linkedinText (required, max 3000), linkedinHeadline (required, max 200), linkedinDescription (optional, max 300 — IMAGE only), linkedinCTA (required, must be a valid LinkedIn CTA enum). - Facebook: metaCTA (required), facebookText (required, no length rule on Facebook), facebookHeadline (required, max 250), facebookDescription (optional, max 300). - Instagram: metaCTA (required), instagramText (required, max 125), instagramHeadline (required, max 40), instagramDescription (optional, max 30). - FB+IG ad with one body text: set just one of facebookText / instagramText and the server copies it across (capped at the receiving channel's limit). Set both explicitly only when you want per-channel copy. - Reddit: redditHeadline (required, max 300), redditCTA (required, must be a valid Reddit CTA enum). redditThumbnailLibraryId is optional and defaults to creativeID. COMMON CTA VALUES: - LinkedIn: LEARN_MORE, REGISTER, APPLY_NOW, DOWNLOAD, JOIN, SIGN_UP, GET_QUOTE, ATTEND, REQUEST_DEMO, SUBSCRIBE. (UNLOCK_FULL_DOCUMENT is DOCUMENT-only — use create_update_document_ad, not this tool.) - Facebook/Instagram: APPLY_NOW, DOWNLOAD, GET_QUOTE, LEARN_MORE, SIGN_UP, SUBSCRIBE. (SCREAMING_SNAKE form only; the platform supports a strict subset of Meta's native catalog. Out-of-set values like BOOK_NOW / GET_STARTED are rejected.) - Reddit: Apply Now, Contact Us, Download, Get a Quote, Learn More, Play Now, Sign Up, View More, Watch Now, Book Now, Listen Now, Read More, Subscribe. See `create_update_video_ad` for video-creative ads (different libraryId source + stricter URL format).
create_update_image_ad
Create OR update a LinkedIn CTV (Connected TV) video ad. LinkedIn only. TO UPDATE: include `id`; to CREATE: omit it. CTV ads play on streaming TV inventory through the LinkedIn Audience Network. On the platform they are LinkedIn VIDEO ads with adType=CTV, and they carry rules the campaign must meet: - Campaign type Brand Awareness only (never Lead Gen); the LinkedIn channel launches as objective BRAND_AWARENESS optimized for REACH. - The LinkedIn channel MUST use AUTO_BID (a manual bid fails pre-launch validation); `update_linkedin_channel_settings` sets it. - Audiences and target groups may target the United States and Canada ONLY; any other location fails pre-launch validation. - Video spec, enforced when the creative is uploaded: 6 to 60 seconds, 1920x1080 or 1280x720, at most 500 MB. LinkedIn recommends exactly 15, 30, 45 or 60 seconds for delivery. CREATIVE WORKFLOW: 1. Upload the video via `upload_video_creative` with `usage_type: "CTV"` -> response gives `id` (the videoLibraryId). The platform runs the CTV checks at that step and rejects a non-compliant file. 2. Pass that integer as `creativeID` here. A video uploaded without the CTV usage type is not eligible for a CTV ad. 3. Ann attaches the returned ad id to a Brand Awareness campaign's LinkedIn channel like any other ad. ALSO KNOWN AS: connected tv ad, ctv ad, streaming tv ad, linkedin tv ad, ott ad, tv commercial on linkedin. KEYWORDS: ctv, connected tv, streaming, tv, ott, linkedin ctv, video, brand awareness, reach, audience network, commercial. CLIENT-SIDE VALIDATION (refuses what the platform UI would also reject): - adName: required, max 50 chars, same pattern as the other ad tools. - creativeID: required integer (videoLibraryId). - linkedinDisplayURL: required, ABSOLUTE (http:// or https://), max 2000. - linkedinHeadline: required, max 200. linkedinCTA: required enum. - linkedinText: optional, max 3000. No description field (same DTO as LinkedIn VIDEO ads). COMMON CTA VALUES: same as `create_update_video_ad` on LinkedIn. RESPONSE: same envelope as `create_update_video_ad` (`created_ads[]` with adType "CTV", channelType "LINKEDIN"). See `create_update_video_ad` for in-feed video ads and `create_update_image_ad` for image / GIF ads.
create_update_ctv_ad
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are Metadata alternatives on ChatGPT?
As of 2026-09-21, Metadata competes with Ad Superpowers, AdKit - Ads Manager, AdPage, adplane, Adspirer, Adszy, AgencyAnalytics, Agentio, Billy Grace Insights, Channel99, DashThis, Data Bloo, Delivra, Dynamoi, Flyweel, HYPD AI - Paid Ads & Analytics, Jepto, Kreel, Lead Recorder, Lily Apple Ads, LoomaScale, Markifact - Ads & Analytics, Masha, Momently, Nexoya, Optmyzr, PaidSync, Reportei, Roivenue, StoreAdOps, Supermetrics, Triple Whale, Voluum, Wask, Whatagraph, Windsor.ai Facebook Ads, Windsor.ai Google Ads, Windsor.ai TikTok Ads in ChatGPT Ad Campaign Analytics & Reporting, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.