account_funnel_reports
ChatGPTAccount-level funnel performance across stages. USE FOR: Account progression through funnel stages, account engagement/conversion analysis, social media account reach, account-level pipeline/revenue tracking. REQUIRED: startDate, endDate, reportTab REPORT TABS: - REACHED: Accounts reached by campaigns - ENGAGED: Accounts that engaged with content - CONVERTED: Accounts that converted (leads) - MQL: Marketing qualified accounts - OPPS: Accounts with opportunities - WON: Accounts with closed-won deals Include company name AND domain when available in results.
account_level_stats
ChatGPTAccount-level statistics and channel breakdown for a timeframe. USE FOR: General account stats by period, channel breakdown, high-level metrics (ROI, spending, leads, opportunities), custom date ranges. NOT FOR: Campaign-level info (use experiment_performance_stats), specific experiments (use get_experiments). CHANNELS: FACEBOOK, LINKEDIN, GOOGLE ADS, ALL TIMEFRAME LOGIC: - 'quarter'/'Q1-Q4' → timeframe='QUARTER' - 'week'/'weekly' → timeframe='WEEK' - ≤3 months → timeframe='MONTH' - >3 months → timeframe='QUARTER' - Default: timeframe='MONTH' CUSTOM DATE RANGE: Provide ONLY startDate + endDate (NO timeframe). Format: ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ) NO DELIVERY: a period with no delivery comes back with empty totals and an empty channelBreakDown (the platform sends null for both); read that as zeros for every channel, not as missing data. METRICS: impressions, clicks, spent, leads, mqls | opens, sends, actionClicks (CONVO/MESSAGE ads) | triggeredOpps, triggeredOppsAmount, influencedOpps, influencedOppsAmount | triggeredClosedWonOpps, triggeredClosedWonOppsAmount | roiInfluencedOpp, roiTriggeredOpp | cpc, cpl, cpm, ctr, conversionRate | costPerOpen, costPerSend (CONVO/MESSAGE ads) | customFields array CONVO/MESSAGE AD CAVEAT: opens, sends, actionClicks (and their per-cost derivatives) are the success metrics for CONVO and MESSAGE (LinkedIn message) ad types. clicks/ctr/cpc are typically 0 for these ads — do not treat that as "no performance". If account-level data shows high spend with 0 clicks, drill into experiment_performance_stats or get_ad_details to confirm ad type before drawing conclusions.
account_list_performance
ChatGPTAccount list information with engagement metrics and statistics. USE FOR: Account list performance/engagement, ABM list effectiveness, account journey metrics (reached, engaged, converted, qualified), account list pipeline/opportunities, comparing account lists, conversion funnel analysis. NOT FOR: Campaign-level details (use experiment_performance_stats), individual experiment performance (use performance_metrics), budget group analysis (use budget_group_performance). CHANNELS: FACEBOOK, LINKEDIN, GOOGLE_ADS, INSTAGRAM (comma-separated) METRICS: accounts, reachedAccounts, engagedAccounts, convertedAccounts | qualifiedAccounts, influencedOppsAccounts, triggeredOppsAccounts, wonAccounts | impressions, clicks, leads, mqls | influencedOpps, influencedAmount, triggeredOpps, triggeredAmount | id, name, lastUpdatedDate Returns paginated response with totalElements, totalPages, and data array.
add_and_edit_campaign_elements
ChatGPTAdd 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-te…
add_and_edit_native_campaign_elements
ChatGPTAdd elements to, and edit campaign-level fields of, an existing Channel-First / Native (N×N×N) campaign — the one built with create_native_structure_campaign (channel.structureType=NATIVE, WizNativeAdContainer). This is the NATIVE counterpart of add_and_edit_campaign_elements: that tool edits Precision (1×1×1 / METADATA) campaigns; THIS tool edits Native (N×N×N) campaigns. CRITICAL: PICK THE TOOL BY THE CAMPAIGN'S STRUCTURE (not by user phrasing): • Native / Channel-First / Platform-First / N×N×N campaign → THIS tool (add_and_edit_native_campaign_elements). • Precision Optimization / 1×1×1 / METADATA campaign → add_and_edit_campaign_elements. Both tools guard: call THIS tool on a Precision/METADATA campaign and it returns an error telling you to use add_and_edit_campaign_elements, and vice-versa. So if you guess wrong, the error tells you the right one — no silent mis-write. If you don't know the structure, check the campaign first (its channels' structureType) or just try and follow the redirect. WHAT THIS TOOL DOES: - EDIT campaign-level fields: name, budgetGroup, startDate, endDate (same smart/partial semantics as the flat tool — only pushed when different / supplied). - ADD new containers: each channel's containers[] APPENDS new WizNativeAdContainers (one audience × an ad_offers list of {ad, offer} pairs each, same shape as create_native_structure_campaign). Existing containers are PRESERVED — the channel's current container list is re-POSTed with the new ones appended. - ADD bare target groups: each channel's optional target_groups[] (names, each matching one target group, ignoring case and surrounding spaces) attaches targeting groups to the native channel without a full container. Each one goes on the first container that has no audience and no target group, which is renamed after the target group; when there is none, it goes on a new container with no ads. It goes in a call of its own, never beside modify_containers[]; to put a target group on a SPECIFIC container, use set_target_group there instead. - ATTACH negative keyword lists (Google Ads / Microsoft Ads only): the search channel block's optional negative_keyword_lists[] (names of EXISTING lists) attaches them channel-wide — valid with or without new containers. Names inside containers[].negative_keyword_lists are unioned in and applied at the same channel level. A name that doesn't resolve on the channel is reported in errors[], never silently skipped. - EDIT existing containers (PER CONTAINER): each channel's optional modify_containers[] targets an existing container by name and, within it, deletes specific Ad—Offer rows (remove_ads), clears an offer from one ad while keeping it on the OTHER ads (clear_offers_on_ads), removes this container's audience / targeting group / keywords / exclusion (remove_audience / remove_target_group / remove_keywords / remove_exclude_audience), puts a Targeting Group on this container (set_target_group, replacing any it has), or deletes the whole container (delete_container). This is the surgical counterpart to the channel-wide remove_* tools — use it when an audience/offer/ad is shared across containers and you only want to touch one. Removing a group clears it on that one container; a group reused by other containers stays alive for them, and an audience, target group or exclusion that no container uses any more (removed from its last container, or its container deleted) is deleted from the channel; keyword groups stay. A container an entry leaves holding ads with nothing to target them is named in the result's warnings[]: before launch, put a target group on it (set_target_group), have the user give it an audience in the platform UI, or delete it. - REPLACE a container's audience with a target group: ONE modify_containers[] entry on that container with remove_audience: true and set_target_group: "<name>" (see the example below). The container keeps its name and ads, and the old audience is deleted from the channel when no other container uses it, so no follow-up…
add_extensions_to_native_campaign
ChatGPTAttach 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_keywords_to_negative_lists
ChatGPTAdd 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_negative_keyword_lists_to_live_campaigns
ChatGPTAttach 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 plat…
archive_ad
ChatGPTArchive (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_audience
ChatGPTArchive (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_campaigns
ChatGPTArchive one or more campaigns, with a result per campaign. Archiving is how a campaign is deleted: the platform has no hard delete. An archived campaign is hidden, releases its name (a new campaign may take it) and can be put back with unarchive_campaigns. A campaign with live experiments (active, in review or waiting for a channel reconnect) cannot be archived. KEYWORDS: archive, delete, remove, discard, trash, retire, campaign, draft WHEN TO USE: - The user asks to archive, delete or remove campaigns they named - The user agreed to archive the drafts a rebuild replaced WARNING: archive only campaigns the user named or agreed to, and only on an exact name match: search_campaigns_by_names also returns partial matches. Each campaign is processed on its own, so one that cannot be archived does not stop the others. results holds one entry per campaign with its outcome: - archived (a message notes a pending launch it suspended) - already_archived: it was archived before; nothing changed - not_in_account: no campaign with that id in this account - native_imported: imported from an ad channel account, which is never archived here - in_progress: it is being launched or edited right now; archive it once that finishes - live_experiments: it has live experiments; an Active campaign can be paused with manage_campaign first - not_attempted: the call stopped early (a rejected session or rate limiting) before reaching it - unknown: the platform's answer was lost; check the campaign before trying again - error: the platform refused it; message says why REQUIRED PARAMETERS: - campaign_ids: 1 to 50 campaign ids, from search_campaigns_by_names or list_wizard_campaigns
budget_group_performance
ChatGPTPerformance statistics for a specific budget group by name. IMPORTANT: Accepts budget group NAME directly - no need to look up ID first. Do NOT call get_budget_group before this tool. USE FOR: Budget group CPL/ROI/Pipeline/MQL analysis, spending and conversion metrics, experiment performance within budget group, efficiency analysis. NOT FOR: Comparing ALL budget groups (use list_budget_groups), individual experiments without budget group context (use experiment_performance_stats), account-level aggregates (use account_level_stats), budget group config WITHOUT performance (use get_budget_group). HOW IT WORKS: Takes name → looks up ID → fetches experiments tagged with budget group → returns detailed performance. METRICS RETURNED: spent, impressions, clicks | leads, mqls, conversions | ctr, cpl, cpc, cpm, conversionRate, mqlRate | oppsAmount, triggeredAmount, totalOpps, totalTriggered | name, status, channel, dates DATE HANDLING: No dates = all-time data. Supports ISO 8601 date ranges.
check_campaign_launch_readiness
ChatGPTCheck 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. Enabled Facebook/Instagram VIDEO creatives must contain a usable saved Meta video_id in their creative JSON. A later library upload becoming READY does not heal a creative saved without it; rebuild/update the ad after upload completion, refresh the campaign creative, then recheck. launch_campaign repeats this observed video check before any ad completion. 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)
clear_default_ma_list
ChatGPTClear the account's default marketing automation (MA) destination list. USAGE INSTRUCTIONS FOR LLM: WARNING: this only affects future campaign creation. Channels that already inherited the default at creation time keep their snapshotted value unchanged — clearing the default never retroactively removes it from existing channels. WHEN TO USE THIS TOOL: - User wants to stop new campaign channels from inheriting a default MA list - User wants to unset the default before setting a different one RESPONSE FORMAT: Returns {"status": "CLEARED", "listId": null, "provider": null, "name": null}. EXAMPLE: "Clear the default marketing automation list" -> clear_default_ma_list()
connect_channel
ChatGPTGet 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_crm
ChatGPTGet 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")
create_audience_from_segment
ChatGPTCreate 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_bombora_audience
ChatGPTCreate 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 …
create_budget_group
ChatGPTCreate 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 CREATION TYPES (these are not required for cap-only updates): - Lead Generation (default): goal=CPL, groupMetric=CPL, optimizerFormula=CPL_2 (or CPC_2), 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. • MQL variant (the plan's KPI is MQLs / cost per MQL): goal=CPL, groupMetric=CPMQL, optimizerFormula=MQL, benchmark = the cost-per-MQL target. MQL is NOT a value of goal or groupMetric; the platform rejects it. Keep the CPL goal and express MQL through groupMetric=CPMQL + optimizerFormula=MQL. • Influenced-opportunity variant: goal=CPL, groupMetric=CPL, optimizerFormula=INFLUENCED_OPP. This is a supported platform formula, not cost per lead. Preserve it on existing groups. - Brand Awareness: goal=CTR, 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; such a group starts over every month and keeps funding its campaigns past any month end until it is switched off. WARNING: BUDGET-GROUP TYPE MUST FOLLOW THE CAMPAIGN GOAL (do not mix): - A CPL / Lead Generation campaign (campaignType "Lead Gen") REQUIRES a compatible Lead Generation budget group with goal=CPL. Its confirmed optimization metric and formula follow the selected variant above; cap-only updates preserve the existing variant. - A Brand Awareness campaign (campaignType "Brand Awareness") REQUIRES a Brand Awareness budget group: goal=CTR, enableBooster=false, budgetType=MONTHLY_RESET (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. AUTO PAUSE RULE SETS belong to the account, and each one holds both the lead generation rules and the brand awareness rules, applied by each campaign's goal. On create, omit autoPauseConfigurationId to use the account's default rule set, for Brand Awareness as for Lead Generation. On update, omitting it keeps the group's current rule set; moving the group to another of the account's rule sets, the default included, means sending that rule set's id. get_budget_group lists the account's rule sets (accountAutoPauseRuleSets: id, name, default) next to the group's current one. Send only an id the user chose from that list; any other id is refused and nothing changes. MONTHLY CAP ONLY: use data containing only id and monthlyCap, e.g. {"id": 16900, "monthlyCap": 5000}. Read the exact existing group first. This update preserves its saved optimizerFormula, goal, metric, benchmark, booster, funnels, dates and campaign membership, including INFLUENCED_OPP and formulas outside the creation choices below. Do not resend creation defaults or convert the group to CPL or MQL. A zero cap is allowed, but the platform rejects caps below already-spent money; report that failure without changing optimization or bypassing it. Verify budget_update_verification.verified before claiming success or continuing to another group. If false, stop without retry or rollback. To UPDATE other settings: include 'id' 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.000…
create_campaign
ChatGPTCreate 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×…
create_csv_upload_linkedin_native_audience
ChatGPTCreate 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); only the companywebsite values are required, the name column may be empty. 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 (the rows sent, each with a website), dropped_without_website (up to 25 rows left out for having no website; pass such a company in company_names to target it as a LinkedIn organization) and dropped_without_website_count, upload_filename, counts, and companies_summary (status, list_companies, linkedin_organizations resolved from company_names, total). Quote company counts from companies_summary.
create_facebook_native_criteria_audience
ChatGPTCreate 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_firmographic_audience
ChatGPTCreate 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…
create_g2_intent_dynamic_audience
ChatGPTCreate 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_…
create_g2_intent_linkedin_native_dynamic_audience
ChatGPTCreate 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_static_audience
ChatGPTCreate 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_google_business_logo_extension
ChatGPTAttach 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_callout_extension
ChatGPTAdd 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_image_extension
ChatGPTAttach 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_lead_form_extension
ChatGPTAdd 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_price_extension
ChatGPTAdd 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_promotion_extension
ChatGPTAdd 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_sitelink_extension
ChatGPTAdd 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_structured_snippet_extension
ChatGPTAdd 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_keywords
ChatGPTCreate 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(keywo…
create_linkedin_engagement_retargeting_audience
ChatGPTCreate 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 — i…
create_linkedin_native_criteria_audience
ChatGPTCreate 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_marketing_automation_contacts_audience
ChatGPTCreate 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_microsoft_business_logo_extension
ChatGPTAttach 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_callout_extension
ChatGPTAdd 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_image_extension
ChatGPTAttach 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_price_extension
ChatGPTAdd 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_promotion_extension
ChatGPTAdd 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_sitelink_extension
ChatGPTAdd 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_structured_snippet_extension
ChatGPTAdd 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_native_structure_campaign
ChatGPTCreate 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 ow…
create_negative_keywords_list
ChatGPTCreate 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 Exclu…
create_reddit_target_group
ChatGPTCreate 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_retargeting_audience
ChatGPTCreate 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_salesforce_contacts_audience
ChatGPTCreate 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_segment
ChatGPTCreate 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_target_group
ChatGPTCreate 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 the audience tool schemas 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 cre…
create_technographic_audience
ChatGPTCreates 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_…
create_update_carousel_ad
ChatGPTCreate OR update a CAROUSEL ad on Reddit (Reddit only). TO UPDATE: include id; to CREATE: omit it. A carousel is a SINGLE ad with 2 to 6 swipeable cards. Each card is an image with its own optional CTA; the headline is shared across the whole ad. CREATIVE WORKFLOW: 1. Upload each card image via upload_image_creative -> response gives id (the imageLibraryId). 2. Pass those ids as cards[].imageLibraryId here (2 to 6 cards, no duplicate images). 3. Optionally upload a separate thumbnail image and pass its id as thumbnailLibraryId. ALSO KNOWN AS: create carousel ad, update carousel ad, edit carousel ad, modify carousel ad, multi-image ad, swipeable ad, Reddit carousel. CLIENT-SIDE VALIDATION (mirrors what the platform UI rejects): - adName: required, max 50 chars. - headline: required, max 300 (shared across all cards). - cards: 2 to 6 items; each needs imageLibraryId; no duplicate images. - cards[].cta: optional, must be a valid Reddit CTA enum. - text: optional body, max 2000. - thumbnailLibraryId: optional. REDDIT CTA VALUES: 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_image_ad / create_update_video_ad for single-creative Reddit ads.
create_update_convo_ad
ChatGPTCreate or update a LinkedIn Conversation Ad ("convo ad") — a branching in-message chat where each step contains a message bubble and a list of button actions that drive the conversation forward. BEHAVIOR: - If id is provided → UPDATES the existing convo ad with that ID. - If id is omitted → CREATES a new convo ad. PREREQUISITES (MUST DO BEFORE CALLING): 1. Call get_linkedin_senders to get a valid (senderId, senderName) pair. These are LinkedIn-issued IDs — do NOT invent them. 2. If using a banner image: upload it via upload_image_creative and pass the returned imageLibraryId as bannerCreativeLibraryId. The banner is OPTIONAL — omit the field to skip it. THE STEP GRAPH: A convo is a directed graph of message "steps". Each step has: - stepId — unique integer; stepId=1 is ALWAYS the entry message. - message — the bubble text; HTML allowed (e.g., '<p style="margin:0">Hi!</p>'). - actions — the buttons under the bubble (1 to 5). ACTIONS — each action has a type from this enum: - NEXT_STEP → click jumps to another step by nextStepId. Use this to build branches ("Interested? YES / NO"). - WEBSITE_URL → click opens an external URL given in link. Use this for "learn more" / external resources. - MAIN_CTA → click opens the offer attached at campaign launch (either a lead-gen form OR a landing page, depending on the offer). DO NOT set link or nextStepId on a MAIN_CTA — they are resolved by the campaign builder later. WARNING: STRUCTURAL RULES (validated client-side before POST): 1. Every action.type MUST be one of NEXT_STEP / WEBSITE_URL / MAIN_CTA. 2. NEXT_STEP MUST have nextStepId pointing to an existing stepId, and cannot point at itself. 3. WEBSITE_URL MUST have a non-empty link. 4. MAIN_CTA needs neither link nor nextStepId. 5. The flow MUST terminate — any step with NO NEXT_STEP action must include at least one MAIN_CTA or WEBSITE_URL so the user has an exit. 6. stepId=1 MUST exist — it is the entry point. 7. stepIds must be unique. A single step CAN mix action types — e.g., step 1 can offer "Tell me more" (NEXT_STEP), "Visit site" (WEBSITE_URL), and "Book demo" (MAIN_CTA) all at once. INPUT PARAMETERS: - name (required, max 50 chars): Ad name in the platform library. - senderId (required): From get_linkedin_senders. - senderName (required): Matching display name from get_linkedin_senders. - headlineText (required): Subject line shown above the message thread. - bannerCreativeLibraryId (optional): imageLibraryId for the banner image above the chat. Omit to skip the banner. - completionStatus (optional, default "DRAFT"): "DRAFT" or "COMPLETED". - flowId (optional, default 7): LinkedIn convo flow version ID. - templateId (optional, default 1): LinkedIn convo template ID. - id (optional): For UPDATE only — existing ad ID. - steps (required, ≥1): The step graph (see schema). EXAMPLE — TWO-STEP BRANCH WITH MULTI-ACTION FIRST STEP: create_update_convo_ad( name="DemoConvo_Q4", senderId="fQdRPtecbv", senderName="Josh Desmarais", headlineText="Quick question about your marketing stack", completionStatus="DRAFT", steps=[ { "stepId": 1, "message": "<p style=\"margin:0\">Want a 15-min demo?</p>", "actions": [ {"type": "NEXT_STEP", "text": "Tell me more", "nextStepId": 2}, {"type": "WEBSITE_URL", "text": "Visit site", "link": "https://metadata.io"}, {"type": "MAIN_CTA", "text": "Book demo"} ] }, { "stepId": 2, "message": "<p style=\"margin:0\">More info — ready to book?</p>", "actions": [ {"type": "MAIN_CTA", "text": "Yes, book"} ] } ] ) SUCCESS RESPONSE: { "success": true, "id": 21241, "ad_url": "https://platform.metadata.io/hub/library/ads?adId=21241", "name": "DemoConvo_Q4", "channelType": "LINKEDIN", "adType": "CONVO", "completionStatus": "DRAFT", "request": { "convo": { ... } } } COMMON MISTAKES: - Inventing a senderId — IDs MUST come from get_linkedin_senders. - Putting link on a MAIN_CTA — the offer link is set at campaign launch. - Putting nextStepId on a MAIN_CTA / WEBSITE_URL — only NEXT_STEP uses it. - Forgetting the terminator — every leaf must end with MAIN_CTA or WEBSITE_URL. - Skipping st…
create_update_ctv_ad
ChatGPTCreate 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_document_ad
ChatGPTCreate a new or update an existing LinkedIn Document Ad on the Metadata platform. A LinkedIn Document Ad promotes a multi-page document (a PDF — e.g. a whitepaper, ebook, report, or guide) natively in the LinkedIn feed. Members preview the first few pages inline, then unlock the full document (typically gated behind a lead form). It is LinkedIn-only. IMPORTANT: This tool is ONLY for LinkedIn Document Ads (channelType=LINKEDIN, adType=DOCUMENT). For IMAGE/GIF ads use create_update_image_ad; for VIDEO ads use create_update_video_ad; for CONVO use create_update_convo_ad; for Sponsored Messaging use create_update_linkedin_message_ad. BEHAVIOR: - If id is NOT provided -> creates a new Document Ad. - If id IS provided -> updates the existing Document Ad with that ID. CREATIVE WORKFLOW (MUST DO BEFORE CALLING): 1. The document must already exist in the creative library as a DOCUMENT asset. Find it with search_library_creatives_by_name(contentTypes="DOCUMENT"), or confirm a specific id with fetch_creative_details. 2. Pass that asset's integer id as libraryId. It MUST be a DOCUMENT-type creative — an image or video id will be rejected by LinkedIn. Unlike IMAGE/VIDEO ads there is NO display URL: the gated document is the destination, so no link field is accepted. CHARACTER LIMITS (mirror the LinkedIn ad limits the platform UI enforces): - name <= 50 chars (ad name in the library) - headline <= 200 chars (the headline shown with the document) - text <= 3000 chars (the introductory text) INPUT PARAMETERS: - id (optional): Existing Document Ad ID. Provide to UPDATE; omit to CREATE. - name (required, <= 50): Ad name in the library. - libraryId (required): Integer id of the DOCUMENT creative in the library (contentType=DOCUMENT). NOT an image/video id. - headline (required, <= 200): Headline shown with the document. - text (required, <= 3000): Introductory text shown with the document. - ctaType (optional, default UNLOCK_FULL_DOCUMENT): the call-to-action. UNLOCK_FULL_DOCUMENT is the document-gate CTA. - maxPreviewPages (optional, default 1): how many pages of the document are previewable before the unlock gate. Positive integer. - completionStatus (optional, default DRAFT): "DRAFT" or "COMPLETED". Use COMPLETED only when every required field is final. WHEN TO USE: - User asks to "create a LinkedIn Document Ad" / "whitepaper ad" / "promote a PDF / ebook / report on LinkedIn". - User wants to update an existing Document Ad. WHEN NOT TO USE: - Feed image / GIF ad -> create_update_image_ad - Feed video ad -> create_update_video_ad - Branching conversation flow -> create_update_convo_ad - One-shot Sponsored Message -> create_update_linkedin_message_ad EXAMPLE USAGE (Create): create_update_document_ad( name="Q3_Whitepaper_LI_Document", libraryId=15791, headline="The 2026 State of B2B Marketing", text="Download our latest research on pipeline attribution.", maxPreviewPages=2, ) EXAMPLE USAGE (Update): create_update_document_ad( id=29144, name="Q3_Whitepaper_LI_Document_v2", libraryId=15791, headline="The 2026 State of B2B Marketing (Updated)", text="Now with fresh benchmarks.", ) COMMON MISTAKES: - Passing an IMAGE/VIDEO libraryId — the asset must be a DOCUMENT (use search_library_creatives_by_name(contentTypes="DOCUMENT")). - Passing a display / landing URL — Document Ads have no link field. - Using this tool for a non-LinkedIn channel — Document Ads are LinkedIn-only.
create_update_google_ads_ad
ChatGPTCreate 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 y…
create_update_image_ad
ChatGPTCreate 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_linkedin_message_ad
ChatGPTCreate a new or update an existing LinkedIn Message Ad on the Metadata platform. A LinkedIn Message Ad is a Sponsored Messaging asset: a one-shot direct message delivered to a member's LinkedIn inbox from a specific sender, with a subject line, a body, an optional banner image, and a single call-to-action button. It is NOT a Conversation Ad — there is no branching step graph. Use create_update_convo_ad for multi-step convos. IMPORTANT: This tool is ONLY for LinkedIn Sponsored Messaging (channelType=LINKEDIN, adType=MESSAGE). For IMAGE/GIF ads use create_update_image_ad; for VIDEO ads use create_update_video_ad; for CONVO use create_update_convo_ad; for Google Ads text ads use create_update_google_ads_ad; for DOCUMENT ads use create_update_document_ad. SPOTLIGHT / FOLLOWER are not yet covered by the dedicated tools; LinkedIn CTV (Connected TV) ads use create_update_ctv_ad. BEHAVIOR: - If id is NOT provided → creates a new Message Ad. - If id IS provided → updates the existing Message Ad with that ID. PREREQUISITES (MUST DO BEFORE CALLING): 1. Call get_linkedin_senders to fetch a valid (senderId, senderName) pair. Message Ads share LinkedIn's sponsored-messaging sender allow-list with Conversation Ads — both pull from the same endpoint. Do NOT invent sender IDs. 2. If using a banner image: upload it via upload_image_creative and pass the returned imageLibraryId as bannerCreativeLibraryId. The banner is OPTIONAL — omit the field to skip it. LinkedIn requires an IMAGE creative ≤ 2 MB; oversize banners are rejected upstream. CHARACTER LIMITS (enforced by the platform; mirror the UI validator at metadata-ui-v3/.../li/message/edit/validation.ts): - name ≤ 50 chars (ad name in the library) - headlineText ≤ 60 chars (the message subject line) - messageText ≤ 2000 chars (the message body) - actionText ≤ 20 chars (the CTA button label) PERSONALIZATION MACROS IN messageText: The body supports LinkedIn personalization macros. Pass them verbatim inside %...% — the platform substitutes at send time. The validator accepts ONLY these five macros (any other %...% token is rejected): %FIRSTNAME% %LASTNAME% %COMPANYNAME% %JOBTITLE% %INDUSTRY% Do not use {firstName} or any other syntax — only %MACRO%. USAGE INSTRUCTIONS FOR LLM: Use this tool when users want to: - Create a new LinkedIn Sponsored Message ad - Update an existing Message Ad (subject, body, CTA, sender, or banner) WHEN TO USE: - User asks "create a LinkedIn Message Ad" / "InMail ad" / "Sponsored Messaging ad" - User wants a one-shot LinkedIn DM with subject + body + CTA - User wants to update an existing Message Ad WHEN NOT TO USE: - User wants a branching conversation flow → use create_update_convo_ad - User wants a feed image / GIF ad → use create_update_image_ad - User wants a feed video ad → use create_update_video_ad - User wants a Google Ads text ad → use create_update_google_ads_ad INPUT PARAMETERS: - id (optional): Existing Message Ad ID. Provide to UPDATE; omit to CREATE. - name (required, ≤ 50): Ad name in the library. - senderId (required): LinkedIn sender ID from get_linkedin_senders. - senderName (required): Display name matching senderId. - headlineText (required, ≤ 60): Subject line shown in the inbox. - messageText (required, ≤ 2000): Message body. Supports the five %MACRO% tokens listed above. - actionText (required, ≤ 20): CTA button label. - bannerCreativeLibraryId (optional): imageLibraryId of the banner image. Upload first via upload_image_creative. Omit to skip the banner. - completionStatus (optional, default DRAFT): "DRAFT" or "COMPLETED". Use COMPLETED only when every required field is final. EXAMPLE USAGE (Create): create_update_linkedin_message_ad( name="Q1_Demo_Outreach_LI_Message", senderId="fQdRPtecbv", senderName="Josh Desmarais", headlineText="Quick question about your marketing stack", messageText="Hi %FIRSTNAME%, as a %JOBTITLE% at %COMPANYNAME% you know how hard pipeline attribution is. Want a 15-min walkthrough?", actionText="Book a demo", bannerCreativeLibraryId=482931, ) EXAMPLE USAGE (Update): create_update_linkedin_message_ad( …
create_update_microsoft_ads_ad
ChatGPTCreate a new or update an existing Microsoft Ads (Bing) text ad on the Metadata platform. IMPORTANT: This tool is ONLY for Microsoft Ads (MICROSOFT_ADS channel) text ads. Ad library entries are PER-CHANNEL: a Google RSA can NOT be attached to a Microsoft Ads channel, and vice versa. Building the "same" ad for both channels means two calls, one per tool. For Google Ads text ads use create_update_google_ads_ad. Do NOT use this tool for Facebook, LinkedIn, Instagram or Reddit ads: use create_update_image_ad (IMAGE/GIF) or create_update_video_ad (VIDEO). ALSO KNOWN AS: Microsoft Ads text ad, Bing text ad, Bing search ad, MS Ads ad, Microsoft responsive search ad BEHAVIOR: - If "id" is NOT provided -> creates a new Microsoft Ads text ad. - If "id" IS provided -> updates the existing Microsoft Ads text ad with that ID. CHARACTER LIMITS (HARD LIMITS — THE API REJECTS ANYTHING OVER) Microsoft Ads and Google Ads share one text-ad shape on the platform, so the limits are identical: - Headlines: MAXIMUM 30 characters each (minimum 3, maximum 15 headlines) - Descriptions: MAXIMUM 90 characters each (minimum 2, maximum 4 descriptions) - Ad name: MAXIMUM 50 characters DESCRIPTIONS — 90 CHARACTER HARD LIMIT — READ THIS CAREFULLY THIS IS THE #1 MOST COMMON FAILURE MODE. - 90 characters is an ABSOLUTE ceiling. 91 = REJECTION. 89 = OK. - EVERY character counts: letters, digits, spaces, punctuation, apostrophes, hyphens, line breaks, emoji. - The MCP schema enforces maxLength=90, and the server truncates as a backstop, so over-length copy is either rejected outright or SILENTLY CUT MID-SENTENCE. - Target 70-85 characters per description. Do not write to the cliff. - LLMs systematically underestimate length by 5-15 characters. ALWAYS COUNT, never estimate. EVERY HEADLINE AND EVERY DESCRIPTION MUST BE UNIQUE The platform rejects the WHOLE ad when two headlines carry identical text ("Enter a headline that is different from: '<text>'"), and applies the same rule to descriptions. Writing 12 real headlines plus 3 near-copies of them is the second most common rejection. Make every line genuinely different. NO EXCLAMATION MARK IN A HEADLINE "!" is rejected in headline text ("! is not supported"). Descriptions accept it. DYNAMIC KEYWORD INSERTION A headline may use the "{KeyWord:fallback text}" form; the platform measures the 30-character limit against the fallback text inside the braces. MANDATORY PRE-CALL VALIDATION — DO THIS BEFORE EVERY CALL: 1. Count each headline: every one MUST be 30 characters or fewer, and free of "!". 2. Count each description: every one MUST be 90 characters or fewer. 3. Check for repeats across headlines, and across descriptions. Rewrite any duplicate. 4. Rewrite anything over the limit BEFORE calling. Do not submit known-bad copy and hope. USAGE INSTRUCTIONS FOR LLM: Use this tool when users want to: - Create a new Microsoft Ads / Bing text ad - Update an existing Microsoft Ads text ad (headlines, descriptions, or name) - Give a Microsoft Ads campaign the ad it needs to become launch-ready WHEN TO USE: - User asks "create a Microsoft Ads ad" / "Bing ad" / "MS Ads search ad" - A campaign has Microsoft Ads enabled and the channel has no ad yet - User says "update Microsoft ad 23149 with new headlines" WHEN NOT TO USE: - User wants the Google Ads version of the ad -> use create_update_google_ads_ad - User wants a Facebook, LinkedIn, Instagram or Reddit IMAGE ad -> use create_update_image_ad - User wants a Facebook, LinkedIn, Instagram or Reddit VIDEO ad -> use create_update_video_ad - User wants a sitelink, callout or other extension -> use the create_microsoft_*_extension tools INPUT PARAMETERS: - id: The ad ID (optional). If provided, that ad is updated. If omitted, a new ad is created. This is the adLibraryId inside the creatives of the microsoft channel in a campaign response. - name: The name/label for the ad (required, max 50 characters) - headlines: Array of headline text strings (required, minimum 3, maximum 15, each STRICT MAX 30 CHARACTERS, all distinct, no "!") - descriptions: Array of description text strings …
create_update_offer
ChatGPTCreate or update Lead Gen or Landing Page offers in Metadata platform. Returns direct URL to access the offer in the platform. OPERATION MODE: - CREATE: When 'id' field is NOT included in data - UPDATE: When 'id' field IS included in data OFFER TYPES: 1. Lead Gen - Native forms rendered inside LinkedIn, Facebook, or Instagram. User never leaves the platform. 2. Landing Page - External page hosted on the advertiser's website. Works on EVERY channel (LinkedIn, Facebook, Instagram, Google Ads, Reddit, Microsoft Ads). WARNING: LEAD GEN ON LINKEDIN / META CAN BE DONE TWO WAYS — pick the right one for the user's intent: - Native Lead Gen form (offer_type='Lead Gen', data.channel=<channel>, goal=CPL): user fills the form INSIDE LinkedIn/Meta. Lower friction, higher conversion, but leads stay in the ad platform until synced. Channel-locked — see below. - Landing Page lead capture (offer_type='Landing Page', goal=CPL, landingPageUrl + thankYouUrl + EMAIL field): user clicks through to the advertiser's own landing page and submits the form there. Choose this when the user wants branded landing pages, tracking pixels, or server-side enrichment. Channel-agnostic — one offer works on every channel. Both flows count as Lead Gen (goal=CPL). Default to native Lead Gen for LinkedIn/Meta unless the user explicitly wants their own landing page. WARNING: CHANNEL-LOCK ON NATIVE LEAD GEN OFFERS (read this BEFORE planning your offer batch) The data.channel value you set on a Lead Gen offer PERMANENTLY locks the returned offer_id to that one channel. The same offer_id CANNOT be used in another channel's slot inside create_campaign / add_and_edit_campaign_elements — those tools accept the mismatch SILENTLY and produce a broken campaign that returns a successful response but cannot serve. Landing Page offers are NOT channel-locked and can be safely reused across channels. What this means for planning: - Want a native Lead Gen "Demo" concept on BOTH LinkedIn AND Facebook? You MUST call create_update_offer TWICE for that one concept — once with data.channel='LINKEDIN', once with data.channel='FACEBOOK'. Track both offer_ids and assign each to the matching channel slot. - Three concepts × two native Lead Gen channels = SIX create_update_offer calls. That is correct, not over-creation. The "2-3 offers" guidance refers to distinct CONCEPTS, not call count. - Want a single offer that works on every channel including Google? Use offer_type='Landing Page' (omit data.channel — Landing Pages have no channel field and are channel-agnostic). Google Ads ONLY accepts Landing Page offers. - Want Lead Gen on LinkedIn using the advertiser's OWN landing page instead of LinkedIn's native form? Use offer_type='Landing Page' with goal='CPL' — then assign the returned offer_id to linkedin.offers[]. This is fully supported and a single LP offer_id can serve LinkedIn, Meta, Google simultaneously. Right after each successful create_update_offer call, write down (offer_id, channel, concept) so you can correctly map them in the create_campaign call later. If you lose track, call get_offer(name=<offer_name>) to look up the offer and read back the channel field before submitting a campaign. REQUIRED PARAMETERS: - offer_type: "Lead Gen" or "Landing Page" - data: Offer configuration object - id: (optional) Include only when updating an existing offer IMPORTANT LIMITS: - offerName: MUST be unique AND under 50 characters. If name + timestamp exceeds 49 chars, shorten the base name. WARNING: ALLOWED CHARACTERS: letters (a-z, A-Z), numbers (0-9), spaces, and these punctuation marks ONLY: _ . ? , : ' / + - = & ; % $ [ ] | ( ) Any other character (em-dashes, smart quotes, emoji, non-ASCII letters, ©, ™, !, @, *, {, }, <, >, ", \, ^, ~, `) will be REJECTED by the platform on Landing Page offers and stripped by this tool before the request is sent. Stick to ASCII letters/digits/space and the punctuation set above. - offerHeader: max 60 chars - offerDetails: max 160 chars - thankYouMessage: max 60 chars (LinkedIn) - privacyText: max 70 chars (Facebook/Instagram) - Fields should alway…
create_update_video_ad
ChatGPTCreate OR update a VIDEO ad on Facebook, Instagram, LinkedIn, and/or Reddit. TO UPDATE: include id; to CREATE: omit it. CREATIVE WORKFLOW: 1. Upload the video via upload_video_creative → response gives id (the videoLibraryId). 2. Pass that integer as creativeID here. - For Reddit, ALSO upload a still thumbnail via upload_image_creative and pass its imageLibraryId as redditThumbnailLibraryId (required; the video cannot be its own thumbnail). ALSO KNOWN AS: create video ad, update video ad, edit video ad, modify video ad, video creative, post video, video post, motion ad. KEYWORDS: video, create, update, edit, modify, ad, ads, video ad, video ads, mp4, motion, video creative, video campaign, video upload, video post, video promo, LinkedIn video, Facebook video, Instagram video, Reddit video, IG reel. CLIENT-SIDE VALIDATION (refuses what the platform UI would also reject): - adName: required, max 50 chars, pattern [a-zA-Z0-9 _.?,:'/+\-=&;%$#\[\]|()]. - creativeID: required integer (videoLibraryId from upload_video_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. For VIDEO the URL MUST be ABSOLUTE (http:// or https:// is required); inputs like metadata.io or www.foo.com are rejected the same way the UI rejects them. If only one channel's URL is set the server fans it across the other targeted channels. - LinkedIn: linkedinText (max 3000, OPTIONAL for VIDEO unlike IMAGE), linkedinHeadline (required, max 200), linkedinCTA (required, valid enum). linkedinDescription is NOT accepted on VIDEO ads (the platform DTO does not declare it). - 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, valid enum), redditThumbnailLibraryId (REQUIRED — separate IMAGE library id). COMMON CTA VALUES: same as create_update_image_ad (see that tool for the lists). META UPLOAD READINESS: a video library id means ingestion, not completion of Facebook/Instagram's asynchronous upload. The entire ad batch is refused before writes unless every requested Meta video channel reports READY. Read fetch_creative_details later; do not build campaigns from a refused call, busy-poll or claim an unfinished ad is ready. Existing ads saved without a Meta video id must be rebuilt or updated after upload completion and refreshed in the campaign. See create_update_image_ad for image/GIF ads (the URL rule is looser there). For LinkedIn CTV (Connected TV) ads use create_update_ctv_ad; the video must be uploaded with upload_video_creative(usage_type="CTV").
deep_funnel_stats
ChatGPTComprehensive funnel conversion analysis: funnel conversions, ROI statistics, experiment performance. USE FOR: Funnel conversion analysis, stage progression, ROI metrics, pipeline attribution, experiment performance within funnels, conversion rate optimization. REQUIRED: funnel_id, date range (YYYY-MM-DD to YYYY-MM-DD format) OPPORTUNITY MODELS: ALL (default), TRIGGERED, INFLUENCED
delete_negative_keyword_lists
ChatGPTPermanently delete one or more entire Google Ads negative keyword lists, only when the user has explicitly asked. PURPOSE: Wipe negative keyword lists that the user has named for deletion. The platform supports a multi-id delete in one HTTP call, so batch every list the user identified into a single tool call instead of calling once per list. ONLY CALL THIS TOOL WHEN THE USER HAS EXPLICITLY NAMED LISTS TO DELETE. Examples that qualify: - "Delete the 'Old competitors' list" - "Drop these three lists: A, B, C" - "Yes, delete the one I just showed you" Examples that do NOT qualify: - "Create a new list called X" — even if the 20-list account cap blocks the create call, do NOT pick a list and delete it. Surface the cap to the user (via list_negative_keywords_list so they see what's there), and ask which list(s) THEY want to delete before calling this tool. - "Clean up my lists" — too vague; first list_negative_keywords_list, present the current set, and let the user pick which to drop. WARNING: This deletes the LIST itself (every keyword in it goes with it, and any campaigns attaching the list lose the attachment). To remove specific keywords inside a list without dropping the list, use remove_keywords_from_negative_list instead. LOOKING UP LIST IDS: Call list_negative_keywords_list to map the names the user gave you to ids. The 'id' field returned there is what you pass here. COMMON USE CASES: 1. Delete a single list the user named: delete_negative_keyword_lists(listIds=[43256533]) 2. Delete several at once (mirrors the UI's "Select rows -> Delete" action): delete_negative_keyword_lists(listIds=[43256533, 43258891, 43261107]) PARAMETERS: - listIds (array of integers, required, min 1): IDs of the negative keyword lists the user asked to delete, as returned by list_negative_keywords_list. RESPONSE FORMAT: Returns the platform response. The channels service typically responds with 204 No Content on success, in which case the wrapper returns a code 204 + Success envelope with the ids that were deleted. 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.
demographic_country_stats
ChatGPTPerformance metrics grouped by Country. USE FOR: Performance by country/geography, country-level spending/conversions, geographic comparison, international campaign effectiveness, regional ROI/pipeline. NOT FOR: Account-level aggregates (use account_level_stats), campaign-level details (use experiment_performance_stats), ingredient-level (use performance_metrics). CHANNELS: FACEBOOK, LINKEDIN, GOOGLE_ADS, INSTAGRAM (comma-separated for multiple) TIMEFRAME: Supports standard (this/last quarter/month/week/year), period-based (today, yesterday), custom ranges ("last two months", "last 20 days"). ISO 8601 format. Default: current month. METRICS: spent, impressions, clicks, leads, mqls | ctr, cpl, cpc, cpm, conversionRate, formConversionRate, mqlRate | totalOpps, totalTriggered, oppsAmount, triggeredAmount | cpMql, cpOppInfluenced, cpOppTriggered | channel
disconnect_channel
ChatGPTDisconnect a specific advertising channel from the Metadata platform. USAGE INSTRUCTIONS FOR LLM: Use this tool to disconnect/remove integration connections for advertising channels. This is useful when users need to remove a channel integration or reconnect with different credentials. WHEN TO USE THIS TOOL: - User asks to "disconnect [channel name]" - User wants to "remove [channel] integration" - User needs to "unlink [channel] account" - User wants to "revoke [channel] access" - User asks to "disconnect my Facebook/LinkedIn/Twitter/Reddit/Google account" - User needs to "reset [channel] connection" - Preparing to reconnect a channel with different credentials SUPPORTED CHANNELS: - facebook: Disconnect Facebook advertising account - instagram: Disconnect Instagram advertising account - linkedin: Disconnect LinkedIn advertising account - twitter: Disconnect Twitter/X advertising account - reddit: Disconnect Reddit advertising account - google: Disconnect Google Ads account IMPORTANT NOTES: - This action will disconnect the channel immediately - Any active campaigns on this channel may be affected - The user will need to reconnect the channel to resume advertising - Always confirm with the user before disconnecting a channel - Check integration status first using get_integrations_status to verify the channel is connected COMMON SCENARIOS: Scenario 1 - Disconnect single channel: "Disconnect my LinkedIn account" → Call disconnect_channel with channel="linkedin" Scenario 2 - Reconnect workflow: "I want to reconnect Facebook with a different account" → First call disconnect_channel with channel="facebook", then guide user to reconnect Scenario 3 - Remove access: "Remove Google Ads integration" → Call disconnect_channel with channel="google" RESPONSE FORMAT: Returns a success/failure status indicating whether the channel was disconnected successfully. EXAMPLE: "Disconnect Facebook" → disconnect_channel(channel="facebook")
duplicate_campaign
ChatGPTDuplicate (copy) an existing campaign into a NEW DRAFT campaign. KEYWORDS: duplicate, copy, clone, replicate, reuse, campaign, draft, copy of WHAT IT DOES: Creates a brand-new campaign that is a DEEP COPY of an existing one. The new campaign is created in DRAFT status and spends no budget. This mirrors the platform UI's "Duplicate campaign" action. WHAT GETS COPIED (server-side, automatic — there are NO toggles to choose): - Goal (Lead Gen / Brand Awareness) - Optimization (budget) group / tag - All landing pages - Every channel that is currently ENABLED FOR THE ACCOUNT, together with that channel's audiences, ads/creatives, keywords, offers and bid settings. (Channels that are disabled for the account are skipped — connect/enable the channel on the account first if you need it carried over.) WHAT IS NOT COPIED / CHANGES: - The new campaign starts in DRAFT (the original's live/active state is NOT copied). - Start/end dates are not carried as a live schedule — set them on the new draft. - Only the new name is caller-controlled. REQUIRED PARAMETERS: - campaign_id (integer): The wizard/campaign ID of the campaign to duplicate. Must be in status Launched, Launching, Editing, or Draft. OPTIONAL PARAMETERS: - name (string): The name for the NEW campaign. Must be non-blank, <= 255 chars, and UNIQUE across the account's campaigns. If omitted, a unique name is auto-generated as "<original name>_copy_<UTC timestamp>" (e.g. "Q1_2026_Campaign_copy_20260115120000"). If you pass a name that already exists on the account, the platform rejects it — choose a unique name or omit it to auto-generate one. CAMPAIGN ID SOURCES: - search_campaigns_by_names tool (recommended) - list_wizard_campaigns tool - get_campaign_by_wizard_id tool WORKFLOW: 1. Find the source campaign ID (search_campaigns_by_names / list_wizard_campaigns). 2. duplicate_campaign(campaign_id=..., name="..." name optional). 3. The response contains the NEW campaign's id and full configuration. 4. Review the new DRAFT campaign and MODIFY it with the edit tools below (it is a normal editable draft — change anything you want). AFTER DUPLICATING — HOW TO MODIFY THE NEW DRAFT: The copy is a regular DRAFT campaign, so use the standard campaign-editing tools on the NEW campaign id (NOT the original). The main ones: - add_and_edit_campaign_elements — the primary editor: rename, change budget group, start/end dates, enable channels, replace per-channel offers, and ADD audiences, exclusion audiences, ads, ad groups, and keywords. (Native / N×N×N campaigns: use add_and_edit_native_campaign_elements.) - update_experiments_daily_budgets — adjust per-experiment daily budgets. - update_reddit_channel_settings — Reddit-specific channel/bid/pixel settings. - remove_channels_from_campaign / remove_audiences_from_campaign / remove_ad_from_campaign / remove_keywords_from_campaign / remove_offers_from_campaign / remove_target_groups_from_campaign — remove elements from the copy. - manage_campaign — pause/restart (lifecycle). Tip: call get_campaign_by_wizard_id on the new id first to see what was copied, then edit. Use search_campaigns_by_names to re-locate the copy by its new name. EXAMPLE: User: "Make a copy of campaign 54050 called 'Q2 Relaunch'" Call: duplicate_campaign(campaign_id=54050, name="Q2 Relaunch") Then: add_and_edit_campaign_elements(campaign_id=<new id>, ...) to tweak the copy. RESPONSE FORMAT: Returns the full configuration of the newly created DRAFT campaign — including its new campaign id, name, status (Draft), goal, optimization group, and copied channels. Use the returned id with get_campaign_by_wizard_id and the edit tools. Anchor any date-derived naming to the REAL current date — call get_current_date if unsure.
duplicate_negative_keywords_list
ChatGPTDuplicate (copy) a negative keyword list from one search channel to the other: Google Ads to Microsoft Ads (Bing), or Microsoft Ads to Google Ads. KEYWORDS: duplicate, copy, clone, replicate, negative keywords, Bing, Microsoft Ads, Google Ads PURPOSE: Users who run the same campaigns on Google and Bing keep the two negative keyword libraries in sync by hand. This tool copies an existing negative keyword list to the other search channel in one call: the platform reads the source list's keywords, adapts match types for the target channel, and creates a new list there. WHAT IT DOES (server-side, automatic): - Reads every keyword in the source list. - Remaps match types for the target: Microsoft Ads does not support BROAD negative keywords, so BROAD (and untyped) keywords become PHRASE when the target is Microsoft Ads. EXACT and PHRASE are kept as-is. Google-bound copies keep all match types unchanged. - Creates a NEW list on the target channel. The source list is never modified. DRY RUN (preview): Call with dryRun=true first when the source list may contain BROAD keywords. Nothing is created; the response reports keywordsCopied and broadRemappedToPhrase so you can tell the user "N broad keywords will become phrase match on Microsoft" and let them confirm. Then repeat the call with dryRun=false to actually create. PARAMETERS: - sourceListId: Required. The id of the negative keyword list to copy, as returned by list_negative_keywords_list. - sourceChannel: Channel the source list lives on. Default GOOGLE_ADS. - targetChannel: Channel to create the copy on. Default MICROSOFT_ADS. Must differ from sourceChannel - only cross-channel copies are supported. - name: Optional name for the new list. When omitted the platform derives "<source name> (<target>)", e.g. "Competitor Brands (Microsoft)". - dryRun: Optional, default false. When true, preview without creating. RESPONSE FORMAT: { "id": 456, // new list id on the target channel; null on dry run "name": "Competitor Brands (Microsoft)", "keywordsCopied": 32, "broadRemappedToPhrase": 5, // 0 when target is Google Ads "dryRun": false } WORKFLOW: 1. Find the source list id with list_negative_keywords_list (or ask the user). 2. Optional: duplicate_negative_keywords_list(sourceListId=..., dryRun=true) to preview the match-type conversion and confirm with the user. 3. duplicate_negative_keywords_list(sourceListId=...) to create the copy. 4. The new list exists on the target channel; attach it to campaigns like any other negative keyword list. ERROR CASES: - Source list not found (or empty) on the source channel: the platform rejects the copy with a not-found error - re-check the id and sourceChannel. - Same source and target channel: rejected; use the platform UI's same-channel duplicate instead. - Accounts are capped at 20 negative keyword lists per channel; if the target channel is at the cap the creation fails - delete a list there first. EXAMPLES: - "Copy my Google negative list to Bing": duplicate_negative_keywords_list(sourceListId=123) - Preview first: duplicate_negative_keywords_list(sourceListId=123, dryRun=true) - Custom name, Microsoft to Google: duplicate_negative_keywords_list(sourceListId=77, sourceChannel="MICROSOFT_ADS", targetChannel="GOOGLE_ADS", name="Brand Safety (Google)") RELATED TOOLS: - list_negative_keywords_list / get_negative_keywords_list_details: find the source list and inspect its keywords (currently Google Ads only). - create_negative_keywords_list: build a brand-new list from scratch instead.
edit_brand_creative
ChatGPTMake an edited copy of an existing creative image, using AI-powered editing while preserving brand consistency. USE FOR: Modify headline/CTA/hero graphic, add/remove elements, adjust styling, create variations, iterate on designs. EDITABLE: Headlines, text, CTA buttons, hero graphics, badges/icons, colors, stats, any combination in single request. EXAMPLES: - Single: "Change headline to 'BOOST YOUR ROI'" - Multiple: "Change headline to 'DRIVE PIPELINE', update CTA to 'LEARN MORE', add +50% badge" PRESERVES (unless asked to change): Logo position/size, brand colors, typography, composition, dimensions. CHAINED EDITS: Use output URL as input for next edit (Edit → URL_1 → Edit → URL_2 → final). OUTPUT: the URL of a NEW image, stored temporarily outside the creatives library. Nothing is edited in place: the source image, and any library creative and id it came from, stay exactly as they were. To keep an edit of a library image, upload the new URL with upload_image_creative, which gives it a NEW library id.
estimate_target_group
ChatGPTEstimate audience size for target group criteria before creating. Supports BOTH include AND exclude rules (criteria + audiences). USE FOR: Validate audience size before creating, "how many people will this reach?", "preview audience size", test targeting combinations, preview impact of exclusion criteria/audiences. CHANNELS: LINKEDIN (default) and REDDIT. Pass channel="REDDIT" to size a Reddit target group before create_reddit_target_group; its criteria ids come from search_reddit_criteria rather than search_target_group_criteria, and the rest of the call is identical (PRD-31759). PREREQUISITE: All criteria IDs MUST come from search_target_group_criteria first (search_reddit_criteria for REDDIT). 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: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. Each block = AND-group of criteria; multiple blocks are AND'd together. EXCLUDE: Single object (NOT array) with criteria and audiences. Anyone matching exclude is removed from results. 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 the audience tool schemas 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. EXCLUDE AUDIENCES: To exclude an existing Metadata Custom Audience, provide its full 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 first and use the real values from the response: - mdAudienceId (integer, REQUIRED): The numeric Custom Audience ID from get_matched_audiences, its `custom…
experiment_performance_stats
ChatGPTExperiment-level performance statistics from Metadata.io Experiments API. USE FOR: - Experiment-level metrics (spent, leads, impressions, clicks, cpl, ctr, mql) - Campaign comparisons (A vs B, time periods) - Triggered/influenced opportunities analysis - Pipeline opportunity analysis from campaigns - Campaign ingredients (audience size, channel, audience/ad/offer used) - ROI analysis, trend analysis, top performers - Creative usage by experiments - Filtering by experiment/campaign names - Filtering by launch status via launchedExperimentStatuses (FAILED / DISCONNECTED experiments are excluded by default — see that parameter) NOT FOR: - Experiment pacing status ("which experiments are underpacing") - Ad-level triggered opportunities - Ingredient-level analysis (use performance_metrics) RETURNED DATA: spent, clicks, impressions, leads, mqls, cpl, cpc, cpm, ctr | opens, sends, actionClicks, costPerOpen, costPerSend (CONVO/MESSAGE ads) | adTypes (list of ad types in this experiment) | triggeredAmount, oppsAmount, cpMql, mqlRate, conversionRate | experimentName, campaignName, audienceName, offerName, offerType, adName | audienceTypes, audienceSize, channel, goal | imageLibraryName | startDate, endDate, pacing, quarterIndex CONVO/MESSAGE AD CAVEAT: when adTypes contains CONVO or MESSAGE, success is measured by opens, sends, and actionClicks (and costPerOpen / costPerSend), NOT clicks/ctr/cpc. An experiment with $100K+ spend and 0 clicks where adTypes includes CONVO can be a top performer — assess on the right metric. To rank conversational performance explicitly, use sort='actionClicks,desc' or sort='opens,desc' instead of the lead-gen defaults. GOAL CAVEAT: every row carries the goal the experiment was launched with ('goal': CPL for Lead Generation, CTR for Brand Awareness / traffic) and, when the platform sends it, its offer type ('offerType': LG is a native lead gen form, LP a landing page offer). A CTR-goal experiment is measured on impressions, clicks, CTR and CPC and captures no leads by design, so leads=0 on it is expected and is NOT a conversion or tracking failure. On a CPL-goal row a landing page offer captures leads through the form the platform requires on it (Google Ads and Reddit have no native form, so their lead gen always runs on an LP offer), so zero leads there is a real funnel question; stats alone cannot tell a broken form or thank-you page from a page that never had a form, so read the offer (get_offer: its goal, form and thank-you page) before naming a cause. A CTR-goal row also carries 'leadCaptureNote' saying exactly this. LEAD DATES: these rows carry no lead or conversion date. For when an experiment's most recent lead arrived, call get_converted_leads with experimentName set to the row's name and size=1 (sorted creationDate,desc by default; experimentName is a substring match, so confirm the returned lead's experiment). A claim that two lead reports disagree rests on those lead records too, compared over the same window and scope. Where get_converted_leads is unavailable, get_converted_leads_summary with experimentName, startDate and endDate shows whether any lead arrived in a window; otherwise say the date cannot be read from these rows. Never infer a lead date from this report. LINK FORMAT: /hub/advertise/experiments?name={wizExperimentName} RULES: - 'cpl2Score,desc' for Lead Gen/unspecified, 'cpc2Score,desc' for Brand Awareness - 'triggeredAmount,desc' for ROI/pipeline, 'oppsAmount,desc' for influenced pipeline - size=1 for 'top' singular, size=requested for 'top X', size=50 for plural, size=15 default - failed/non-launched experiments are excluded by default; pass launchedExperimentStatuses=['Failed'] ONLY when the user explicitly asks about failures - this layer returns EVERY launched experiment with delivery in the window, including zero-lead and zero-spend ones, unless you set a min filter yourself. An empty or short result means nothing matched the filters you sent, NOT that campaign-level reporting is broken or stale; re-run without the min filters before telling the user anything is wrong…
experiments_keywords_stats
ChatGPTKeyword performance data from active experiments with date range filtering. USE FOR: Keyword performance across experiments, Google Ads / Microsoft Ads keyword metrics/trends, keyword ROI and conversions, search term effectiveness. REQUIRED: Date range in YYYY-MM-DD to YYYY-MM-DD format. PAGING: the response is one page: 'totalElements' is the full row count for the window and 'totalPages' the number of pages at the requested 'size'. When totalElements exceeds the rows returned, request the next 'page' (or repeat with a larger 'size') before compiling a keyword list; never report the remaining rows as unavailable.
fetch_creative_details
ChatGPTGet detailed information for specific creative assets by their IDs. Looks up each creative ID individually. WHEN TO USE: - Get metadata for specific creative assets - Lookup creative names and content types - Verify creative asset properties before using in ads - Audit creative asset details and status - Validate library IDs before ad creation RETURNED INFORMATION: - Creative asset name and ID - Content type (IMAGE, VIDEO, GIF, DOCUMENT) - File properties (size, dimensions, format) - Upload and modification timestamps - Visibility status and permissions - Preview URLs and download links - Associated metadata and tags FEATURES: - Batch lookup of multiple creative IDs - Individual error handling for invalid/missing IDs - Returns None for failed lookups while continuing others - Detailed logging of API requests and responses - Comprehensive metadata for each valid asset
find_offer_url
ChatGPTLocate the BEST specific landing-page URL for a marketing offer on a given domain. Runs three discovery strategies in parallel: 1. Direct path probe — conventional paths per offer_type (e.g. /request-demo, /case-studies, /roi-calculator) 2. Sitemap scan — <loc> entries filtered by offer-type keywords + optional topic 3. Footer/body scrape — CTA/nav links matching the offer intent Candidates are scored by specificity. Generic hub pages (/resources/, /content/, /library/, homepages) are HARD REJECTED — this tool exists precisely to avoid shipping them. USE THIS BEFORE create_update_offer WHENEVER offer_type = "Landing Page" AND the user did NOT provide an explicit URL. Do NOT guess a URL. Do NOT rely on web_search for landing pages — this tool is more reliable. USER-PROVIDED URL OVERRIDE (HARD RULE): If the user already specified a landing-page URL in their request (e.g. "use https://acme.com/demo-fintech" or "point offers at our pricing page"), DO NOT call find_offer_url — use the user's URL verbatim in create_update_offer. Never overwrite an explicit user-provided URL, even if it looks generic. WHEN TO USE: - Before every create_update_offer call with offer_type="Landing Page" - When you need a specific demo / case-study / whitepaper / ROI calculator / guide URL - When web_search returned only generic /resources/ or homepage URLs FALLBACK BEHAVIOR: - On success: use offer_url verbatim in create_update_offer.landingPageUrl - On success=false: DO NOT create a Landing Page offer. Switch to offer_type="Lead Gen" instead. RETURNS: { "success": true, "domain": "snowflake.com", "offer_type": "case_study", "topic": "fintech", "offer_url": "https://www.snowflake.com/customers/square/", "source": "sitemap", "link_text": "Square", "score": 95, "steps_tried": ["direct-probe", "sitemap", "footer-scrape"], "candidate_count": 42 } On failure: { "success": false, "suggestion": "Switch offer_type to 'Lead Gen'..." } EXAMPLES: - find_offer_url(domain="snowflake.com", offer_type="case_study", topic="fintech") - find_offer_url(domain="servicenow.com", offer_type="demo") - find_offer_url(domain="mongodb.com", offer_type="roi_calculator")
find_privacy_url
ChatGPTLocate the privacy-policy URL for a given website domain. Uses a waterfall strategy for maximum reliability: 1. robots.txt → extract Sitemap directives 2. sitemap.xml → search for privacy-related URLs in <loc> entries 3. Page scrape → footer / page body links (most reliable fallback) USE FOR: - Find a company's privacy policy URL before creating Lead Gen offers - Auto-populate privacyUrl field in create_update_offer - Verify privacy URL exists for GDPR/CCPA compliance checks - Look up privacy page for any domain WHEN TO USE: - User asks "find the privacy URL for example.com" - User wants to create an offer but doesn't know the privacy URL - Before calling create_update_offer to auto-fill privacyUrl - User asks "does this site have a privacy policy?" RETURNS: { "privacy_url": "https://example.com/privacy-policy", "source": "footer", "link_text": "Privacy Policy", "steps_tried": ["robots.txt + sitemap", "playwright-footer"], "success": true } EXAMPLE: find_privacy_url(domain="metadata.io")
fix_flexible_creative
ChatGPTApply a free-text AI edit to a flexible creative's BACKGROUND image and return the edited image URL. Instruction-based image-to-image edit (like edit_brand_creative), scoped to the background so the crisp editable text/logo layers are never touched. It edits a flat image the same way, such as a library creative with its text baked in. WARNING: on a flat image the baked-in text is repainted with the rest and can come back altered or unreadable; to change a layered creative's text, change its text layers instead. USE FOR: "remove the glare", "make the sky warmer", "clean up the left side", "swap the desk for a laptop". OUTPUT: the URL of a NEW image, at the source image's pixel size (longest edge at most 2000 px) whenever the model paints a shape close to the source's (every channel canvas), stored temporarily outside the creatives library. Nothing is edited in place: the source image, and the library creative and id it came from, stay exactly as they were. The editor swaps the new image in as a flexible creative's background. To keep an edit of a library image, upload the new URL with upload_image_creative, which gives it a NEW library id.
generate_brand_creative
ChatGPTGenerate branded advertising images and designs using AI and company Brand DNA. FLAT vs EDITABLE: this is the FLAT generator — it bakes the headline + CTA into the pixels and returns one finished PNG. For a creative the user can rearrange / retype / restyle before finalizing (the DEFAULT for a standalone "make me a creative" request), use generate_flexible_brand_creative instead. Use THIS flat tool when building an ad or feeding a campaign (the image flows straight into upload_image_creative -> create_update_image_ad, with no human edit-and-save step), or when a finished flat image / a batch of quick variations is explicitly wanted. ALSO KNOWN AS: design ad, create ad image, make creative, generate banner, create advertisement visual, design campaign image, ad design, advertising artwork KEYWORDS: design, creative, image, banner, ad, advertisement, visual, generate, create, artwork, graphic, brand, branded, logo, campaign asset USE FOR: - Creating new ad images/banners/creatives for campaigns - Generating LinkedIn/Facebook/Instagram/Display ad visuals - Making branded advertisements that match company style - Designing campaign creative assets WORKFLOW CONTEXT: - PREREQUISITE: Call get_brand_kit first to check if brand exists - NEXT STEPS: Use upload_image_creative to add to library, then create_update_image_ad - PART OF: Campaign creation workflow (brand → creative → upload → ad → campaign) COMMON QUERIES THAT NEED THIS: - "create ads for my company" - "design advertising images" - "make branded banners" - "generate creative for LinkedIn campaign" - "I need ad visuals" KEYWORDS: ad, advertisement, creative, image, banner, design, visual, brand, generate, create, linkedin, facebook, instagram, display, campaign asset PROCESS: Checks for existing brand kit → (Creates brand kit only if missing) → Selects top 3 aligned reference ads → Enhances prompt with brand patterns → Generates optimized image → Returns URL (must upload before use in ads). TEXT RULES: - Wrap text in quotes: "Your Headline Here" - Max 25 chars per phrase, 2-3 phrases max - Good: "Boost ROI 30%" (13 chars) | Bad: "Supercharge Your Marketing Performance Today" (44 chars) PLATFORMS: LinkedIn (16:9, B2B) | Facebook (1:1, eye-catching) | Instagram (4:5, mobile-first) | Display (16:9, high impact) OUTPUT: Returns image URL. ALWAYS display/link the image for user to see.
generate_brand_kit
ChatGPTAnalyze a company's brand from their website and extract brand identity. Fetch brand assets (logo, colors, fonts) and create a brand DNA document for consistent advertising. ALSO KNOWN AS: analyze brand, get brand from website, extract brand identity, brand analysis, company branding, fetch brand, brand style guide USE THIS TOOL WHEN USER WANTS TO: - Analyze their brand from website - Extract brand colors, logo, fonts - Match their existing brand style - Get brand identity for ads - Create brand guidelines COMMON USER PHRASES THAT NEED THIS TOOL: - "match my brand" - "my company website is [URL]" - "analyze my brand" - "get my brand colors" - "brand style" - "company branding" - "use my brand" WORKFLOW: 1. Call this tool with company domain 2. Returns brand DNA (colors, fonts, logo, style) 3. Use brand info in generate_brand_creative PARAMETERS: - domain: Company website URL (e.g., "dapta.ai", "example.com") - brand_name: Optional brand name override - force_regenerate: Set true to refresh existing brand kit OUTPUT: - Logo variations and usage guidelines - Brand colors (primary, secondary, accent) - Typography/fonts - Messaging framework - Channel-specific guidelines IMPORTANT: Automatically checks if brand kit exists. Returns existing kit if found. RETRY SCOPE: This tool handles ONE domain per call. When the user asks to retry or regenerate the kit for specific named domain(s), call it ONLY for those domain(s), with force_regenerate=true, starting with the domain the user named. NEVER widen the request: domains the user did not name stay untouched, even if their kits were generated together as a batch earlier in the conversation. KEYWORDS: brand, website, URL, domain, logo, colors, fonts, identity, style, company, analyze, extract, branding, guidelines
generate_flexible_brand_creative
ChatGPTGenerate an EDITABLE, layered brand creative: a clean AI background scene (no baked text) plus AI-placed, editable text/CTA/logo layers. Returns a structured layout document (JSON), NOT a flat image — the UI renders it in an editor the user can rearrange before saving. USE FOR: - The DEFAULT for a standalone creative the user will review, refine, or use — "make me a creative", "design an ad", "give me options", "a creative I can tweak/edit". - Any request where the user should be able to move/retype the headline, restyle the CTA, swap the logo, add layers, or regenerate the background before finalizing. DIFFERENT FROM generate_brand_creative: PREFER THIS for standalone creative requests. generate_brand_creative bakes headline + CTA into the pixels and returns one finished PNG; use that flat tool only when building an ad / feeding a campaign inline (the flat image flows straight into an ad, with no human edit-and-save step) or when a finished flat image is explicitly requested. COPY DISCIPLINE: fewer layers = a cleaner layout the user can actually edit. Default to headline + cta (add subheadline only when it genuinely earns its place); pass body / disclaimer ONLY when the user explicitly asked for that copy. COPY LIMITS (image copy is shorter than ad text): headline at most 45 characters and 8 words on a 1:1, 4:3, 4:5 or 9:16 canvas (55 characters and 10 words on 16:9 or 1.91:1); cta at most 3 words and 18 characters; subheadline at most 90 characters. Copy over a limit is rejected with the limit named: shorten it and call again rather than splitting it across layers. CANVAS: the creative is made at the ad channel's own recommended size for its shape: 'platform' is the channel and 'aspect_ratio' one of the shapes it takes (each channel's shapes and sizes are listed under aspect_ratio). A shape the channel does not take is refused before anything is generated, with the channel's shapes named. FINISHED CHECK: the combined background, text, logo and CTA are checked before this tool returns the draft. If the returned document has a warning, repeat it beside the draft card; a failed or unavailable check leaves the draft editable for review. RETURNS: a layered document — canvas dimensions (the channel's exact size), background image URL, brand colors/logo, and an ordered list of layers (headline, subheadline, body, cta, disclaimer, logo) with normalized positions and styling.
get_abm_account_lists
ChatGPTGet account lists from the Metadata ABM Lists library. Retrieves uploaded CSV account lists, website retargeting lists, and their metadata. WHEN TO USE: - List all available account lists with pagination and filtering - Search for specific account lists by filename - Review account list details including status, type, and account counts - Find lists by type (CSV, WEBSITE_RETARGETING, etc.) - Check list readiness and report status PARAMETERS: - filename: Filter by filename (partial matching) - page: Page number (default: 0) - size: Results per page (default: 100, max: 100) - sort: Sort criteria (default: "createdDate,desc") - status: Filter by status (READY, PROCESSING, etc.) - type: Filter by type (CSV, WEBSITE_RETARGETING, etc.) RESPONSE INCLUDES: - List metadata (id, name, filename, status, type) - Account counts and audience associations - Creation dates and file hashes - Native targeting status - Account report status EXAMPLES: - get_abm_account_lists() - Get all account lists - get_abm_account_lists(filename="test_acl.csv") - Find specific list - get_abm_account_lists(type="CSV") - Get only CSV lists - get_abm_account_lists(status="READY") - Get ready lists
get_account_details
ChatGPTCurrent user and account information. USE FOR: "Which account am I using?", "Who am I logged in as?", "What's my account name/status?", "What channels are enabled?", "What's my subscription/plan?" Returns authenticated user details and associated account information. effectiveAccountId and effectiveAccountName name the account every tool acts on: the account the session is switched into, when there is one, otherwise the user's own. accountId and accountName can name the user's home account instead, so answer "which account am I using?" from the effective fields. switchedIntoAccount is true when the platform reported the switch apart from the home account.
get_account_opportunities_insights
ChatGPTGet opportunities for domain(s) with status filtering and pagination. STATUS VALUES: NO_OPPS, OPEN, CLOSED_WON, CLOSED_LOST SORT OPTIONS: lastTouchDate (default), status, name, amount RETURNS: one entry per requested domain, in request order, each carrying its domain. Read each account's opportunities from the entry carrying ITS domain only. A domain the platform could not answer comes back as {domain, error, data: []} in its own slot. PAGINATION: page and size apply per domain. Use small page sizes (25-50) with sequential calls.
get_account_summary_insights
ChatGPTGet comprehensive account details for specific domain(s). USE FOR: Quick lookup of specific company information, engagement metrics, revenue data. DO NOT USE FOR: Bulk analysis or complex filtering (use get_insights_report instead). RETURNS: one entry per requested domain, in request order, each carrying its domain: engagement metrics (totalTouches, channels, websiteVisits), revenue data (openOppsAmount, closedWonOppsAmount), company info (name, industry, employees, engagementScore). A domain the platform could not answer comes back as {domain, error, data: []} in its own slot.
get_account_utm_defaults
ChatGPTRead the ACCOUNT-level UTM defaults - the tracking parameters every campaign channel inherits unless it stores its own. KEYWORDS: utm, utms, utm_source, utm_medium, utm_campaign, utm_term, utm_content, tracking parameters, account default, defaults, inherited, placeholder, UPDATE ME USE THIS TOOL WHEN THE USER ASKS: - "What are our default UTMs?" / "What UTM settings does the account use?" - "Which channels have customised UTM defaults?" - As the baseline before judging whether a campaign overrides anything. INHERITANCE RULE - READ BEFORE ANSWERING ANY UTM QUESTION: UTMs are inherited, never blank. A campaign channel with an empty stored mapping does NOT have "no UTMs" - it tracks with the account's UTM defaults, and where the account set nothing it tracks with the Metadata platform default. Roughly half of all channel rows in production are in that inherited state. NEVER report "no UTMs configured" from an empty stored field: report the resolved value and its origin. ORIGIN IS PER CHANNEL, not per key: a channel with an empty stored mapping inherits the account default whole, so a channel whose resolved mapping differs at all from that is stored on the campaign and every one of its values is an override. The per-key same_as_default flag says whether that one key happens to match the default anyway. ORIGIN VALUES: - campaign_override: stored on this campaign channel, differs from what it would inherit. - account_default: inherited from this account's UTM defaults. - platform_default: inherited from the Metadata-wide default (account set nothing). - not_set: the channel really has no UTM mapping (non-sponsored channels only). HONEST LIMIT: a campaign that stores a mapping identical to the default it would inherit is reported as inherited. The platform returns resolved values with no provenance, so that case cannot be distinguished - say so rather than claiming the campaign has no override. TRACKING TIMING AND TOKEN MEANING: Leads using server-resolved campaign UTMs use the current saved mapping when the platform processes them, without waiting for an ad republish. Captured URL or caller-supplied values can follow a different ingestion path, so do not generalize this timing to every new lead. Native click-time macros retain values captured from the lead's click URL. Ad click URLs have a separate publication timeline: a draft uses the saved mapping at launch, and launched ads use it on their next campaign publish. Saving a launched Microsoft Ads campaign triggers a live UTM push. AD_NAME is a dynamic token, not necessarily an individual ad name: standard experiments use their ad group name when present, otherwise their creative name; native ad structures use the native ad's own name. CAMPAIGN_NAME uses the wizard campaign name. Saving a launched campaign can also queue an asynchronous existing-lead UTM refresh. Do not assume historical rows are immutable or that all old rows have already refreshed. Verify the saved mapping with get_campaign_utms and actual lead values and ingestion timing separately from live ad click URLs; a supplied or backfilled lead creation date alone does not prove when its UTMs were resolved. Takes no parameters - the account comes from the caller's credentials. There is no cross-account lookup. RESPONSE SHAPE: { "channels": { "LINKEDIN": {"origin": "account_default", "values": {"UTM_SOURCE": "Acme", ...}}, "FACEBOOK": {"origin": "platform_default", "values": {"UTM_SOURCE": "Metadata", ...}} }, "platform_default": {"UTM_SOURCE": "Metadata", "UTM_MEDIUM": "AD_CHANNEL", ...}, "notes": ["..."] } A channel reported as platform_default was never customised on this account; the values shown are the ones campaigns actually inherit, not a blank. READ-ONLY. No tool here edits the defaults (set_campaign_utms edits ONE campaign channel's mapping, never the account defaults).
get_ad_details
ChatGPTGet complete details and configuration for one or more ads from the Metadata platform. USAGE INSTRUCTIONS FOR LLM: Use this tool when users want to: - Get complete ad details by ad ID - Retrieve ad configuration including content, targeting, and creative assets - Check existing ad settings before making modifications - Analyze ad performance data and configuration - Get creative library information associated with ads - Extract ad content like text, headline, CTA, links for reference - the value returned libraryCreative labelName corresponds to the library/image name. WHEN TO USE: - User asks "show me ad details for ID X" - User wants to see ad configuration: "what's in ad 182124?" - User needs ad content: "get the text/headline/CTA from ad Y" - User wants to check ad settings before editing - User asks "what creative is used in ad Z?" - User needs to analyze existing ad setup INPUT PARAMETERS: - ids: Flexible format for specifying ad IDs: Single integer: 182124 Comma-separated string: "182124,182123,182125" EXAMPLE CALLS: - get_ad_details(ids=182124) (single) - get_ad_details(ids="182124,182123,182125") (multiple) DETAILED RESPONSE INCLUDES: AD CONFIGURATION: - Basic info: id, name, channelType (FACEBOOK/LINKEDIN), adType (IMAGE/VIDEO/etc.) - Status: completionStatus, aiState, renameAllowed AD CONTENT: - text: Main ad copy/body text - headline: Ad headline text - link: Landing page URL - description: Additional ad description - ctaType: Call-to-action button (e.g., "Get_Demo", "Learn_More") CREATIVE ASSET DETAILS: - libraryId: Creative asset ID reference - libraryCreative object with: - id, labelName (filename) - url: Full-size creative asset URL - thumbnail: Thumbnail URL - dimensions: width, height in pixels - sizeInKb: File size - content_type: image/png, image/jpeg, etc. - created_date: When creative was uploaded METADATA: - tags: Ad tags/labels - created/modified dates - AI processing state ERROR HANDLING: - If ad ID doesn't exist, API returns empty array - Always validate that IDs are integers before making request - Handle both single ID and multiple ID requests EXAMPLE USAGE: - get_ad_details(ids=182124) - Single ad by integer - get_ad_details(ids="182124,182123,182125") - Multiple ads by comma-separated string
get_audience_details
ChatGPTCustom audience information from Metadata platform: configurations, targeting criteria, size metrics, performance. A NAME IS REQUIRED: this is the by-name lookup, not the account-wide browse. USE FOR: resolve an audience the user named (partial match, paged, sortable), read its configuration and targeting, review its size and performance.
get_brand_kit
ChatGPTRetrieve current brand kit configuration for a company. USE FOR: Check stored brand info, review colors/fonts/logos before updating, verify brand kit exists, view brand guidelines. RETURNS: domain, longDescription, logos[], colors[], fonts[], industries Accepts URLs with/without protocol, normalizes to domain (e.g., "www.example.com" → "example_com.json"). Requires brand kit to exist (created via generate_brand_kit).
get_budget_group
ChatGPTGet configuration and settings for a budget group (NOT performance data). KEYWORDS: budget, group, settings, configuration, details, allocation, campaigns WHEN TO USE: - "Show me the [group name] budget group settings/configuration" - "What campaigns are in the [group name] budget group?" - "What's the budget allocation for [group name]?" - Getting budget group metadata without performance metrics WHEN NOT TO USE: - Performance questions (spend, CPL, leads, conversions) → use budget_group_performance instead - Questions like "how did X perform" or "total spend for X" → use budget_group_performance instead NOTE: If the user is asking about performance metrics (spend, leads, CPL, etc.), use budget_group_performance directly - it accepts the name and handles ID lookup internally. Matches the full stored name across search pages, ignoring letter case and outer whitespace, whether switched on or off. Refuses ambiguous names instead of selecting a different group. Returns complete budget group information including campaigns, budget allocation, and settings, plus the account's auto pause rule sets (accountAutoPauseRuleSets: id, name, default) a rule set switch can choose from. A MONTHLY_RESET or CUSTOM_RESET group starts over every period and runs until switched off; its currentPeriodStart and currentPeriodEnd only bound the current period, so never present them as the group ending or offer to extend it.
get_campaign_by_wizard_id
ChatGPTGet full campaign details by its wizard campaign ID, including channels, audiences, ads, and budget configuration. KEYWORDS: campaign, get, details, wizard, id, lookup, channels, audiences, ads, budget, configuration WHEN TO USE: - User wants to see full details of a specific campaign by its ID - User needs to inspect channel configurations, audiences, ad groups, or budget settings for a campaign - After creating a campaign, to verify its full configuration - To retrieve the complete campaign structure including all channel details RETURNS: Full campaign details in a structured format including: - Campaign ID, name, status, dates - Optimization group / budget group details - Per-channel configuration (enabled, daily budget, audiences, ad groups, lead gen forms, bid strategy) - Summary statistics (total channels, enabled channels, total daily budget, goal) 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) - Campaign management interface URLs
get_campaign_targeting_locations
ChatGPTWhere a campaign actually TARGETS, by channel, with the platform's location ids resolved to country and state names. KEYWORDS: campaign, targeting, location, geo, country, region, where, targets, germany, dach, emea, market, geographic WHEN TO USE: - "Which campaigns target <country>?" / "Do we run anything in Germany?" - "Where is this campaign targeted?" before editing or launching it - Any question about geographic TARGETING DO NOT ANSWER GEO TARGETING FROM demographic_country_stats. That tool reports where ads were SERVED (delivery); this one reports where they are AIMED. The two disagree routinely, and answering a targeting question from delivery data is how the agent once told an account with 68 Germany campaigns that it had none. RETURNS: - campaigns: [{campaignId, name, status, channels[], summary}] - channels[]: {channel, enabled, geoSource, targeting{resolved, countries[{id,name}], states[], ...}, exclusions} geoSource is "search_ad_location" (Google/Microsoft, held on the channel) or "native_audience" (LinkedIn/Meta/Reddit, held on included audiences or target groups). - Native targeting also carries audienceIds, targetGroupIds and resolvedFrom with the attached group names and member audience ids. Target group criteria supply that group's geo; its exclusion criteria are never included in the targeted country list. - summary: {countries[], unresolvedIds[], partial} - query: {countryFilter, scanned, matched, unreadable[]} - limitations: [] READING THE RESULT - these three distinctions are the whole point: - countries: [] is not evidence that no audience is attached. Check audienceIds, targetGroupIds and resolvedFrom. A target group can be attached without a direct audience id. resolvedFrom.countrySource member_audience identifies countries derived from its included member audiences when the group has only non-country location criteria. targeting.resolved false means its geographic scope could NOT BE fully READ, including a native city or region whose country could not be derived. Never report that as no audience or no targeting. - exclusions.readable is ALWAYS false: the platform offers no GET for negative locations. Never state that a campaign excludes, or does not exclude, anywhere. - summary.partial true means this answer is incomplete. Say so rather than presenting it as a full list. - If limitations mentions truncation, you have NOT seen the whole account. Re-call with a higher max_campaigns before answering "there are none". PARAMETERS: - campaign_ids: specific wizard campaign ids (optional) - country_names: filter to campaigns targeting these, e.g. ["Germany"] (optional). Names must match the platform catalog; unmatched names are reported, never silently dropped. - max_campaigns: cap when scanning the account (default 25, max 100) With neither campaign_ids nor country_names, returns the most recent campaigns up to max_campaigns.
get_campaign_utms
ChatGPTRead ONE campaign's resolved UTM tracking parameters per channel, each value tagged with where it came from. KEYWORDS: utm, utms, utm_source, utm_medium, utm_campaign, utm_term, utm_content, tracking parameters, final url suffix, placeholder, UPDATE ME, inherited, account default, campaign override USE THIS TOOL WHEN THE USER ASKS: - "What UTMs does campaign X use?" / "Show me the tracking parameters on this campaign" - "Does this campaign override the account UTM defaults?" - "Does campaign X still have the UPDATE ME placeholder in its UTMs?" INHERITANCE RULE - READ BEFORE ANSWERING ANY UTM QUESTION: UTMs are inherited, never blank. A campaign channel with an empty stored mapping does NOT have "no UTMs" - it tracks with the account's UTM defaults, and where the account set nothing it tracks with the Metadata platform default. Roughly half of all channel rows in production are in that inherited state. NEVER report "no UTMs configured" from an empty stored field: report the resolved value and its origin. ORIGIN IS PER CHANNEL, not per key: a channel with an empty stored mapping inherits the account default whole, so a channel whose resolved mapping differs at all from that is stored on the campaign and every one of its values is an override. The per-key same_as_default flag says whether that one key happens to match the default anyway. ORIGIN VALUES: - campaign_override: stored on this campaign channel, differs from what it would inherit. - account_default: inherited from this account's UTM defaults. - platform_default: inherited from the Metadata-wide default (account set nothing). - not_set: the channel really has no UTM mapping (non-sponsored channels only). HONEST LIMIT: a campaign that stores a mapping identical to the default it would inherit is reported as inherited. The platform returns resolved values with no provenance, so that case cannot be distinguished - say so rather than claiming the campaign has no override. TRACKING TIMING AND TOKEN MEANING: Leads using server-resolved campaign UTMs use the current saved mapping when the platform processes them, without waiting for an ad republish. Captured URL or caller-supplied values can follow a different ingestion path, so do not generalize this timing to every new lead. Native click-time macros retain values captured from the lead's click URL. Ad click URLs have a separate publication timeline: a draft uses the saved mapping at launch, and launched ads use it on their next campaign publish. Saving a launched Microsoft Ads campaign triggers a live UTM push. AD_NAME is a dynamic token, not necessarily an individual ad name: standard experiments use their ad group name when present, otherwise their creative name; native ad structures use the native ad's own name. CAMPAIGN_NAME uses the wizard campaign name. Saving a launched campaign can also queue an asynchronous existing-lead UTM refresh. Do not assume historical rows are immutable or that all old rows have already refreshed. Verify the saved mapping with get_campaign_utms and actual lead values and ingestion timing separately from live ad click URLs; a supplied or backfilled lead creation date alone does not prove when its UTMs were resolved. INPUT: campaign_id - the WIZARD campaign id (the id field returned by list_wizard_campaigns / search_campaigns_by_names). Not an experiment id. RESPONSE SHAPE: { "campaign_id": 173290, "is_editable": true, "channels": { "LINKEDIN": { "origin": "campaign_override", "inherited_from": "account_default", "values": { "UTM_SOURCE": {"value": "UPDATE ME", "origin": "campaign_override", "same_as_default": false, "placeholder": true}, "UTM_MEDIUM": {"value": "AD_CHANNEL", "origin": "campaign_override", "same_as_default": true, "placeholder": false} } } }, "account_defaults": {"LINKEDIN": {"UTM_SOURCE": "Metadata", ...}, ...}, "platform_default": {"UTM_SOURCE": "Metadata", "UTM_MEDIUM": "AD_CHANNEL", ...}, "notes": ["..."] } placeholder: true marks a value that still carries the UPDATE ME placeholder - that is a real tracking defect worth reporting to the user. Values like AD_CHAN…
get_converted_leads_summary
ChatGPTFast aggregate summary of the account's converted leads (Smart Leads) — counts and rates only, no lead rows. ALSO KNOWN AS: leads summary, lead totals, lead overview, MQL rate, lead-to-MQL conversion, smart leads summary. KEYWORDS: LEAD COUNT, LEAD TOTALS, HOW MANY LEADS, LEADS SUMMARY, LEAD OVERVIEW, SMART LEADS, CONVERTED LEADS, MQL RATE, LEAD-TO-MQL, MQLS, UNIQUE LEADS, UNIQUE DOMAINS, LEAD CHANNEL MIX, LEADS BY CHANNEL, ENRICHMENT COVERAGE, SYNCED TO MARKETING AUTOMATION, LEAD QUALITY BASELINE, LEAD AUDIT BASELINE, PIPELINE FROM LEADS, TRIGGERED OPPORTUNITIES, INFLUENCED OPPORTUNITIES, LEAD SANITY CHECK USE FOR: "How many leads do we have?", MQL rate and lead-to-MQL sanity checks, channel mix of leads (Facebook/Instagram/LinkedIn/Google Ads/display), enrichment coverage, leads synced to marketing automation, unique leads vs unique company domains, pipeline tie-back (triggered/influenced opportunities and amounts). ALWAYS call this FIRST in a lead audit to set the baseline before pulling rows with get_converted_leads. NOT FOR: Inspecting individual leads or job-title/ICP distributions (use get_converted_leads); campaign performance metrics (use experiment_performance_stats). RETURNED DATA: total | totalFacebook, totalInstagram, totalLinkedin, totalGoogleAds | fullyEnriched, autoEnriched, unenriched | syncedToMa | uniqueLeads, uniqueDomain | mqls, uniqueMqls, mqlRate, uniqueMqlRate | influencedOpps, triggeredOpps, influencedAmount, triggeredAmount. RULES: - Accepts the same filters as get_converted_leads (no pagination/sort) — scope by campaignName/channels/startDate+endDate to summarize a slice. - mqlRate is a useful lead-quality indicator, but clients define MQL criteria differently and it rarely matches a true MQL — treat it as a secondary signal next to job-title/ICP fit. - uniqueDomain vs total shows lead concentration: many leads from few domains can mean a few companies dominate the results.
get_credit_balance
ChatGPTGet the current Metadata AI credit balance for the account this token belongs to. USAGE INSTRUCTIONS FOR LLM: Tool calls against this server consume AI credits. When the balance reaches zero or goes negative, billable tools may refuse with an OUT OF CREDITS error. This tool is how you check the balance before that happens, and how you confirm a top-up has landed. WHEN TO USE THIS TOOL: - Another tool just failed with OUT OF CREDITS — check here before retrying - The account owner says they have paid, and you need to know if it landed yet - The user asks "how many credits do I have?" or "what's my AI balance?" - Before starting a long batch of tool calls, to confirm there is headroom IMPORTANT — AFTER A TOP-UP, POLL, DO NOT SPIN: Payment settles ASYNCHRONOUSLY. A card can be charged successfully and the balance still read as exhausted for a minute or two while the payment clears. Poll this tool every 20-30 seconds, not continuously. Resume the work you were doing only once is_exhausted is false. EXPECTED RESPONSE FORMAT: { "account_id": "1234", "balance_usd": 42.5, // may be NEGATIVE — that is a real state "updated_at": "2026-08-07T12:00:00", "is_exhausted": false // true means other tools will refuse } On failure returns {"error": "..."} — treat an unreadable balance as unknown, not as zero, and do not tell the user they are out of credits because of it.
get_credit_transactions
ChatGPTGet recent AI credit movements for the account this token belongs to, newest first. USAGE INSTRUCTIONS FOR LLM: Use this to explain WHERE credit went, or to show that a purchase was recorded. Each row is one movement: a negative amountUsd is a charge, a positive one is a top-up or an adjustment. source says what kind of usage it was (for example direct_mcp for tool calls made from an external client like this one, image_generation, opik_ai_chat, maxio_topup for a purchase). WHEN TO USE THIS TOOL: - User asks "what have I been charged for?" or "where did my credits go?" - User disputes a charge and wants the detail behind it - After a payment, to show the customer the top-up on their history - To find the referenceId of a purchase so you can pass it to get_payment_status EXPECTED RESPONSE FORMAT: { "account_id": "1234", "transactions": [ {"amountUsd": -0.04, "source": "direct_mcp", "description": "MCP tool: ...", "referenceId": "...", "createdAt": "...", "markup": "4.000000"} ], "total_elements": 210, "total_pages": 9, "page": 0 }
get_current_date
ChatGPTReturn the REAL current date and time (UTC). WARNING: You do NOT inherently know today's date — never guess it or rely on training-time assumptions. Whenever a task depends on "today" — setting campaign/budget start & end dates, interpreting "this month" / "next quarter" / "last 30 days", validating that an endDate is in the future, or any relative date math — you MUST anchor to the real current date. If you are not already certain what today is, CALL THIS TOOL FIRST and use its current_date for all subsequent date calculations. Takes no parameters. RETURNS: { "current_date": "2026-09-30", "current_datetime_utc": "2026-09-30T12:00:00.000Z", "current_year": 2026, "current_quarter": "Q3", "timezone": "UTC" }
get_deep_audience_details
ChatGPTGet detailed information about audiences including criteria and advanced configuration. This tool returns comprehensive audience data beyond the basic summary, including: - Complete audience criteria and targeting configuration - Segment information and settings - Lookback window configuration - Advanced configuration details and metadata - Full audience structure and composition WHEN TO USE: - Retrieve complete audience criteria and configuration - Analyze detailed targeting setup for an audience - Export or review full audience specifications - Understand advanced audience configuration - Compare detailed configuration across multiple audiences PARAMETERS: - audience_ids: Array of audience IDs to retrieve details for (required) Example: [42828, 42829, 42831] AUDIENCE ID SOURCES: Use the get_audience_details tool first to: - List all available audiences in your account - Find the IDs of audiences you want detailed information for - Get the basic summary before requesting deep details EXAMPLE WORKFLOW: 1. Call get_audience_details() to see all audiences and their IDs 2. Identify which audiences you need deep details for 3. Call get_deep_audience_details(audience_ids=[42828, 42831]) to get full configuration RETURNS: Detailed audience information including: - Audience ID, name, and type - Complete targeting criteria - Segment configuration (if applicable) - Lookback window settings - Advanced metadata and configuration - Full audience composition details - companies_summary on a CSV company list (a LinkedIn native CSV or an account list): status (final, matching or failed), list_companies (the platform's stored count, null until final), submitted_companies (rows an account list handed to matching, null on a native list), dropped_by_matching (submitted minus stored, once final), linkedin_organizations (company name criteria on a native list, counted apart from the list) and total. Quote company counts from it, and never report a count that is still matching as final. IMPORTANT NOTES: - All provided audience IDs must exist and be valid - IDs must be positive integers - You can request details for multiple audiences in a single call - Results include complete audience configuration data
get_default_ma_list
ChatGPTGet the account's default marketing automation (MA) destination list. USAGE INSTRUCTIONS FOR LLM: Use this to check whether the account has a default MA destination list configured, and its current health. Newly-created eligible campaign channels (not CTR goal, not Reddit) snapshot this value ONCE at creation time — it is not a live reference, so a later change here never retroactively updates channels already created. WHEN TO USE THIS TOOL: - User asks "what's our default marketing automation list?" - Checking configuration health before troubleshooting a campaign's MA destination - Before deciding whether to call set_default_ma_list or clear_default_ma_list RESPONSE FORMAT: Returns "status" as one of: - NOT_CONFIGURED: no default has ever been set - AVAILABLE: a default is set and resolves correctly (listId, provider, name populated) - PROVIDER_MISMATCH: the default was set for a provider the account is no longer connected to (name is null; a different MA tool is connected now) - DISCONNECTED: the default was set but no MA tool is connected at all (name is null) - NOT_FOUND: the default list itself was deleted in the MA tool (name is null) Also returns "listId" and "provider". EXAMPLE: "What's the default MA list?" -> get_default_ma_list()
get_insights_report
ChatGPTQuery account journey insights with filtering, sorting, and pagination. USE FOR: Filtering/searching multiple accounts, bulk analysis, trends, building segments. DO NOT USE FOR: Single account lookup (use get_account_summary_insights). TO CREATE AUDIENCE: 1) create_segment with criteria, 2) create_audience_from_segment. CRITERIA BUILDING: 1. Use search_insights_criteria_fields to discover fields 2. Build criteria: {"operator": "AND|OR", "match": [{field, operator, type, value}, ...]} 3. Or use get_segment_criteria to get saved segment's criteria OPERATORS: EQUALS, NOT_EQUAL, LIKE, NOT_LIKE, IN, NOT_IN, GREATER_THAN, GREATER_OR_EQUAL, LESS_THAN, LESS_OR_EQUAL, IN_THE_LAST, NOT_IN_THE_LAST, BETWEEN, IN_THE_NEXT BOOLEAN FIELDS: Use without operator: {"field":"IN_CRM","operator":null,"type":"BOOLEAN","value":false} SORT OPTIONS: timeInJourney, revenue, oppCreatedAmount, highIntentDetails, engagementScoreClassificationDelta, engagementScoreClassification, inCrm, lastTouchDate (default), totalTouches, pageViews, sessions, uniqueVisitors, companyName. Append ,desc or ,asc.
get_integrations_status
ChatGPTGet comprehensive integration connection status for all channels, martech platforms, and CRM systems in the Metadata platform. USAGE INSTRUCTIONS FOR LLM: Use this tool to identify which platforms and services are connected or disconnected from the Metadata platform. This is essential for understanding the current state of integrations and diagnosing connectivity issues. WHEN TO USE THIS TOOL: - User asks "which channels are connected?" - User wants to check "integration status" - User asks "is [platform name] connected?" (e.g., "is LinkedIn connected?", "is Facebook connected?") - User wants to know "what martech tools are integrated?" - User asks about "CRM connection status" or "which CRM is connected?" - User asks "show me all connected platforms" - User wants to troubleshoot "why campaigns aren't running" (often related to disconnected channels) - User needs to "check if [service] needs reconnection" - User asks about "available ad channels" or "active advertising platforms" EXPECTED RESPONSE FORMAT: Returns object with three main sections: channels, martech, apps Each integration has: connected (bool), enabled (bool), type (string), businessAccountId, businessAccountName, currency, connectedAt (ISO timestamp), userFullName, errors (array) CHANNELS: Array of advertising platforms (FACEBOOK, INSTAGRAM, LINKEDIN, GOOGLE_ADS, MICROSOFT_ADS, TWITTER, REDDIT) MARTECH: Object with crm (array), marketingAutomation (array), googleAnalytics (object) - CRM types: SALESFORCE, HUBSPOT - Marketing Automation: HUBSPOT, PARDOT, ELOQUA, MARKETO APPS: Array of third-party integrations (G2, SLACK with channelName/channelId) USE CASES: 1. Audit and Compliance: "Generate a report of all connected marketing platforms for security review" 2. Integration Health Monitoring: "Check if any integrations need token refresh or reconnection" 3. Capability Discovery: "What advertising channels can I use based on current connections?" COMMON SCENARIOS: Scenario 1 - Check channel: "Is Facebook connected?" → Parse response.channels, find type="FACEBOOK", check connected=true Scenario 2 - List connected channels: "Show me all connected advertising platforms" → Parse response.channels, filter where connected=true Scenario 3 - Disconnected integrations: "What needs reconnection?" → Check all sections for connected=false Scenario 4 - CRM status: "Is Salesforce connected?" → Parse response.martech.crm, find type="SALESFORCE", check connected=true OPTIONAL PARAMETERS: integrationType (CHANNEL/MARTECH/CRM), connectionStatus (CONNECTED/DISCONNECTED), platformName EXAMPLE: "What's the status of my integrations?" → Present summary of connected/disconnected by category
get_intent_topics
ChatGPTGet available intent topics for BOMBOORA audience creation. IMPORTANT: Call this tool first before suggesting or creating any Bombora audience. If the response returns NO topics (empty list), Bombora is NOT available for this account — do NOT suggest Bombora audiences. Instead, recommend creating a firmographic audience (create_firmographic_audience) as the preferred alternative. Retrieves the list of available buyer intent topics that can be used when creating BOMBOORA intent topic audiences. These intent topics represent different buyer interest areas and purchasing signals that can be used for precise audience targeting. WHEN TO USE: - Always call this BEFORE suggesting or creating a Bombora audience to verify topic availability - Discover available intent topics before creating a BOMBOORA intent topic audience - Understand what buyer intent signals are available for targeting - Build audiences based on specific buyer interests and purchasing signals - Integrate intent topic selection into the audience creation flow RETURNS: List of available intent topics with their details including: - Topic ID/name - Topic description - Available packages or categories - Any additional metadata for targeting configuration NEXT STEPS: After retrieving intent topics, use the intent topic IDs with the audience creation tool to create BOMBOORA intent topic based audiences.
get_linkedin_engagement_source_types
ChatGPTList the LinkedIn engagement source types and their triggers. STEP 1 of building a LinkedIn Engagement Retargeting audience. WHAT THIS AUDIENCE TYPE IS: An audience of people who ALREADY interacted with this advertiser on LinkedIn or on their website: watched a video ad, opened a lead form, clicked a document ad, visited the company page, or hit specific URLs. It is warm-traffic retargeting, built from first-party engagement, and it needs no contact list and no CSV. NOT THE SAME AS create_retargeting_audience. That tool IMPORTS an audience that already exists inside the native ad account. This flow BUILDS a new LinkedIn DMP segment from an engagement rule you define. If the user says "import my existing LinkedIn audience", use the other tool. If they describe PEOPLE WHO DID SOMETHING ("watched", "clicked", "visited", "opened", "engaged with"), use this flow. THE THREE-STEP FLOW: 1. get_linkedin_engagement_source_types (this tool) — choose a source type + trigger 2. search_linkedin_engagement_sources — choose which campaigns / pages to retarget (SKIP THIS STEP for the WEBSITE source type, which uses URL rules instead) 3. create_linkedin_engagement_retargeting_audience — build it SOURCE TYPES AND WHAT EACH RETARGETS (verified live; the response is authoritative and may differ per account, so never assume a value that is not in it): - VIDEO_ADS ........... viewers of the account's video ads - SINGLE_IMAGE_ADS .... people who engaged with single-image ads - DOCUMENT_ADS ........ people who engaged with or downloaded document ads - CONVERSATION_ADS .... people who opened or clicked a conversation ad - LEAD_GEN_FORMS ...... people who opened or submitted a lead gen form - ORGANIZATION_PAGES .. visitors to the LinkedIn company page - WEBSITE ............. visitors to specific URLs on the advertiser's own site TRIGGERS DEFINE INTENT DEPTH, and each source type has its own set: - VIDEO_ADS: FIRST_QUARTILE (>=25% viewed, the default) · MIDPOINT (>=50%) · THIRD_QUARTILE (>=75%) · FULL_COMPLETE (>=97%). Deeper means smaller and warmer. - SINGLE_IMAGE_ADS / DOCUMENT_ADS: ENGAGEMENT (any interaction, default) · CLICK (chargeable clicks only). DOCUMENT_ADS adds DOWNLOAD_CLICK (downloaded it). - CONVERSATION_ADS: OPEN (default) · ANY_CTA_CLICK (clicked a call-to-action). - LEAD_GEN_FORMS: VIEW_FORM (opened it, includes submitters, default) · LEAD_FORM_SUBMIT (submitted only — the hottest signal available). - ORGANIZATION_PAGES: VIEW (visited the page, default) · CTA_CLICK (clicked the page header CTA). - WEBSITE: VISIT. CHOOSING FOR THE USER'S INTENT: - "warm up a broad audience" / top of funnel → a shallow trigger (ENGAGEMENT, VIEW, FIRST_QUARTILE, VIEW_FORM) and a long lookback. - "high intent" / "ready to buy" / bottom of funnel → a deep trigger (LEAD_FORM_SUBMIT, FULL_COMPLETE, DOWNLOAD_CLICK, ANY_CTA_CLICK) and a short one. - When the user does not say, prefer the trigger marked default — it is LinkedIn's own recommended choice for that source type. - Only ever use a trigger from the source type you picked. The pairing is not validated anywhere downstream, so a trigger borrowed from another source type builds a permanently empty audience with no error to warn you. LOOKBACK WINDOW is both how far back engagement counts AND how long someone stays in the audience. Longer means bigger and colder; shorter means smaller and warmer. 30 / 60 / 90 / 180 / 365 days, except WEBSITE which LinkedIn caps at 180. 90 is a reasonable default when the user does not say. WHEN TO USE: - "Create an engagement retargeting audience" - "Retarget people who watched my LinkedIn video ads" - "Build an audience of people who opened / submitted my lead gen form" - "Retarget visitors to our pricing page" (WEBSITE) - "Who visited our LinkedIn company page?" (ORGANIZATION_PAGES) - "Retarget everyone who engaged with our ads last quarter" - Any request to retarget people by something they DID, on LinkedIn or the site PARAMETERS: none. It always reports the whole catalog for the caller's account. RETURNS: - sourceTypes[]: engagementSourceType, a human `…
get_matched_audiences
ChatGPTGet matched audiences (custom audiences) from the Campaign Wizard based on audience type and targeting options. Retrieves custom audiences that match specific targeting configurations. Use this to find available audiences for campaign targeting on a given advertising channel. This is the canonical tool to call when you need an audience id to attach to a campaign or a target group's include[].audiences / exclude.audiences arrays. Each row is a CHANNEL row: its id is the row id, and customAudienceId (mirrored as mdAudienceId) is the Custom Audience id. For a target group copy mdAudienceId, name, type, matchCount, matchCountType and inactive from the row; NEVER put the row id into mdAudienceId (the platform cannot resolve it and answers 'Targeting group is too small'). Rows with inactive=true have no live segment on the channel and are refused by the platform; pick an active row or wait for matching to finish. It draws on the same source the main UI's target-group audience-chooser uses, so what this tool returns is what the platform considers attachable. AUDIENCE TARGETING TYPES AVAILABLE: • FIRMOGRAPHIC_INCLUDE: Firmographic inclusion filters (company size, industry, location) • FIRMOGRAPHIC_EXCLUDE: Firmographic exclusion filters • FIRMOGRAPHIC_EXCLUDE_BASIC: Basic firmographic exclusions • FIRMOGRAPHIC_INCLUDE_SFDC: Salesforce firmographic inclusions • NATIVE_TARGETING_CSV: CSV-based native targeting • NATIVE_TARGETING_DYNAMIC: Dynamic native targeting lists • NATIVE_TARGETING_STATIC: Static native targeting lists • CONTACT_LIST: Custom contact list targeting • STORELEADS: Store leads targeting • DYNAMIC_G2: Dynamic G2 crowd data • DYNAMIC_G2_CONTACT: Dynamic G2 contact data • G2_ABM_CONTACT: G2 ABM contact targeting • LEADSIFT: LeadSift intent data targeting • BUYER_INTENT: Buyer intent data targeting • MA_ACCOUNTS_STATIC: Marketing automation static accounts • MA_ACCOUNTS_DYNAMIC: Marketing automation dynamic accounts • MA_CONTACTS_STATIC: Marketing automation static contacts • MA_CONTACTS_DYNAMIC: Marketing automation dynamic contacts • NATIVE_LINKEDIN: Native LinkedIn targeting options • LINKEDIN_RETARGETING: LinkedIn retargeting audiences • SFDC_CONTACTS_DYNAMIC: Salesforce dynamic contacts • SFDC_CONTACTS_STATIC: Salesforce static contacts • SFDC_ACCOUNT_DYNAMIC: Salesforce dynamic accounts • WEBSITE_RETARGETING: Website visitor retargeting • WEBSITE_ACCOUNT_RETARGETING: Website account-based retargeting • TECHNOLOGY: Technology stack targeting • SLINTEL_TECHNOLOGY: Slintel technology targeting COMMON USE CASES: - Find all LinkedIn audiences using firmographic targeting - Get audiences with website retargeting enabled - List audiences using G2 intent data - Search for audiences with Salesforce integration - Identify audiences using specific MA platforms - Find dynamic vs static audience configurations - Discover available contact lists and store leads PARAMETERS: - type: Array of targeting types to match (defaults to all types if not specified) - channel: Advertising channel (LINKEDIN, FACEBOOK, GOOGLE_ADS, INSTAGRAM, TWITTER, YOUTUBE, REDDIT, MICROSOFT_ADS) - page: Page number for pagination (0-indexed) - sort: Sort field and direction (e.g., 'createdDate,desc', 'name,asc') - size: Number of results per page (1-200) RETURNS: Paginated list of custom audiences matching the specified targeting criteria. Each audience includes: - id: Audience ID - name: Audience name - matchCount: Number of matches in the audience - type: Targeting type (e.g., FIRMOGRAPHIC_INCLUDE, MA_CONTACTS_DYNAMIC) - channel: Channel the audience is for - createdDate: When the audience was created - inactive: Whether the audience is active or inactive - tags: Associated tags
get_negative_keywords_list_details
ChatGPTFetch the keywords inside a single Google Ads negative keyword list. PURPOSE: List_negative_keywords_list only returns each list's name + id; it does NOT expose the individual keywords inside. Use this tool to see what's actually in a given list (text, match type, resourceName) before deciding to add or remove entries. WHEN TO USE: - Inspect what's already excluded before adding more negatives - Filter by substring with the 'text' query parameter - Look up an entry to confirm it exists before calling remove_keywords_from_negative_list (which matches by text internally) RESPONSE FORMAT: Returns the list payload: { "id": 43256533, "name": "Keywords we don't wanna spend money", "totalKeywords": 87, "totalPages": 4, "keywords": [ { "resourceName": "customers/123/sharedCriteria/456~789", "text": "free download", "keywordMatchType": "PHRASE" }, ... ] } PARAMETERS: - listId (integer, required): the id from list_negative_keywords_list. - text (string, optional): substring filter on keyword text. - page (integer, optional): 0-based page index. Default 0. - size (integer, optional): rows per page. Default 25, max 100. - sort (string, optional): "<field>,<direction>". Default "text,asc". 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.
get_offer
ChatGPTGet offer information by name or list all offers. USE FOR: "Show me the [offer name] offer", "What's in [offer name]?", "Find offer called [name]", "List all offers" If name provided: returns detailed offer info (name, description, assets, configuration). If no name: returns list of all available offers.
get_payment_status
ChatGPTCheck whether a specific credit payment has settled onto the account's ledger. USAGE INSTRUCTIONS FOR LLM: A credit purchase is charged immediately but CREDITED asynchronously — the money settles at the billing provider, whose webhook then reaches Metadata and records the credit. So "the card was charged" and "the balance is usable" are separate moments, usually seconds to a couple of minutes apart. This tool tells them apart for one specific payment. WHEN TO USE THIS TOOL: - The account owner has paid and given you a payment/transaction reference - You want to confirm a specific purchase landed, rather than just seeing that the balance moved IF YOU DO NOT HAVE A REFERENCE, USE get_credit_balance INSTEAD. That is the normal way to wait for a top-up — you rarely need the reference. Poll every 20-30 seconds, not continuously. status is "pending" until it lands and "settled" after. EXPECTED RESPONSE FORMAT: { "reference_id": "maxio:txn:987654", "status": "settled", // or "pending" "settled": true, "amount_usd": 50.0, // null while pending "settled_at": "2026-08-07T12:01:00", "balance_usd": 37.5, // the balance right now "is_exhausted": false // false means you can resume work }
get_retargeting_audiences
ChatGPTGet all available retargeting audiences for a specific advertising channel. This tool retrieves all retargeting audiences and native audiences available for the specified advertising channel (GOOGLE_ADS, LINKEDIN, or FACEBOOK) that can be used to create new retargeting audiences. This is useful when you need to discover existing audiences before creating or targeting them. SUPPORTED CHANNELS: - GOOGLE_ADS: Google Ads retargeting audiences - LINKEDIN: LinkedIn retargeting audiences - FACEBOOK: Facebook retargeting audiences WHEN TO USE: - Discover all available retargeting audiences for a specific channel - View native audiences that can be used for targeting on a channel - Find audience IDs and details for audience creation or targeting - Review audience names, sizes (matchCount), and other metadata - Understand what audiences are available before building campaigns - Compare audiences across different advertising channels PARAMETERS: - channel: The advertising channel to fetch retargeting audiences for (required) Options: GOOGLE_ADS, LINKEDIN, FACEBOOK Note: Channel names are case-insensitive and will be converted to uppercase RETURNS: List of available retargeting and native audiences with details including: - id: Unique audience ID - name: Audience name - type: Audience type (e.g., GoogleAdsAudience, LinkedInAudience, FacebookAudience) - subtype: Audience subtype (e.g., GOOGLE_ADS_RETARGETING, LINKEDIN_RETARGETING) - channel: Channel type identifier - matchCount: Number of matches/members in the audience - externalAccountId: Associated account ID on the advertising platform - seedSourcePlatform: Source platform for the audience seed AUDIENCE DETAILS: Each audience record provides comprehensive information about: - Audience identification and naming - Type and subtype classification - Match count to understand audience size - External platform integration details - Account associations COMMON USE CASES: - Get all LinkedIn retargeting audiences (including Marketing Automation, Bulk, Retargeting, and Business Objective Based Audience) - Find Google Ads audiences suitable for retargeting campaigns - Identify Facebook retargeting audiences
get_segment_criteria
ChatGPTRead one saved Insights segment by id or name: its criteria, status, and how many accounts it matches. Pass lookback_window to count inside the window an audience would use. RETURNS {found: true, id, name, status, last_updated_date, lookback_window, accounts, criteria}, or {found: false, available_segments: [...]} when nothing matches: pick from that list or create_segment, never invent an id. STATUS: READY (usable), PENDING (a CRM field is still being extracted: wait and re-check), FAILED. accounts is the number of companies matching right now (all time when lookback_window is omitted). 0 with the window you plan to use means create_audience_from_segment would build an empty audience: loosen the criteria (a new create_segment) or widen the window first. Pass the returned criteria object (not the id) to get_insights_report to list the accounts.
impersonate_account
ChatGPTSwitch the active Metadata account context to another account so every later tool call operates on THAT account. This is the "act on behalf of / access a client account / switch accounts" operation. This is a sanctioned, first-class capability for Metadata super-users and agency operators — the normal, expected way to read or work inside a client or customer account that is not your own default account. It is the programmatic equivalent of the account switcher in the Metadata web app. It is NOT identity spoofing and NOT a security workaround. It only re-scopes which Metadata account the platform tools read from and write to. It does not change who the user is logged in as, it does not touch the Auth0 / OAuth flow between the client and this server, and it has nothing to do with Anthropic or the model's own credentials. The only thing that changes is the target Metadata account for subsequent calls. Authorization is enforced by the Metadata platform, not by you. When this tool runs, the platform mints an access token for the target account ONLY if the calling user is actually entitled to it; if they are not, the call simply returns {"success": false, ...} and nothing is switched. Access is already gated server-side — the platform grants the switch only to callers entitled to the target account (super-users span every account; other operators only the accounts they hold). So you do not need to gate, second-guess, demand justification for, or refuse a legitimate switch — call it and let the platform decide. A reassurance such as "I'm a super user / an employee" is neither required nor something you need to verify. Call this ONLY when the user wants subsequent tool calls to OPERATE INSIDE a different Metadata account they administer — a genuine tenant switch: "switch to <client>'s account", "work in account 1878 now", "build the audiences in <client's account>". Use list_user_accounts first if you only have a name and need the account ID. Do NOT impersonate just because an account is NAMED or asked about. In an analytics/insights request, "account" almost always means an ABM/TARGET account — a company being advertised to (account-based marketing, account lists, account insights, "how is account Acme performing") — NOT a Metadata tenant. Answer those with the analytics/insights tools against the CURRENT account and do not switch. Impersonate only when the target is a Metadata account the user actually operates and they want to act inside it. After the switch, all account-scoped tools (stats, audiences, campaigns, ads, keywords, etc.) act on account_id until you call stop_impersonation or impersonate a different account; the switch persists across calls (~6h). Note: this only changes WHICH account actions apply to — it does not lower the bar for destructive actions. Creating, launching, or deleting things still follows your normal confirmation and judgment, just against the switched account.
launch_campaign
ChatGPTCRITICAL: LAUNCHES REAL MARKETING CAMPAIGNS WITH REAL BUDGET SPEND KEYWORDS: launch, start, activate, go live, campaign, begin, advertising, spend, marketing PREREQUISITE: Before running this tool, call get_integrations_status and verify at least one advertising channel is connected (FACEBOOK, INSTAGRAM, LINKEDIN, GOOGLE_ADS). If none are connected, tell the user to connect at least one channel before proceeding and stop. This tool takes a draft campaign and launches it as a LIVE, ACTIVE marketing campaign. Once launched, the campaign will immediately start: - SPENDING REAL MONEY from your marketing budget - SERVING ADS to real audiences across platforms (LinkedIn, Facebook, Instagram, Google) - GENERATING ACTUAL IMPRESSIONS, CLICKS, AND CONVERSIONS - COMPETING in real ad auctions with real bid amounts CRITICAL SAFETY REQUIREMENTS This tool will ALWAYS require explicit user confirmation before launching any campaign. The user must understand they are launching a real campaign with real budget implications. WHEN TO USE: - Launch a draft campaign to start real advertising and budget spend - Activate a campaign after final review, approval, and budget confirmation - Begin live ad serving across configured channels - Transition from campaign testing/setup phase to live marketing execution REQUIRED PARAMETERS: - campaign_id: The unique identifier of the draft campaign to launch (integer, required) MANDATORY CONFIRMATION PROCESS: Before launching any real campaign, this tool MUST: 1. Display the campaign ID and retrieve campaign details if possible 2. Show estimated daily/total budget that will be spent 3. List all channels where ads will go live (LinkedIn, Facebook, Instagram, Google) 4. Warn that this starts REAL BUDGET SPENDING immediately 5. Require explicit "YES, LAUNCH REAL CAMPAIGN" confirmation 6. Confirm the user understands this is not a test or simulation 7. Only proceed after receiving unambiguous user approval 8. Provide immediate launch status and live campaign monitoring URL CAMPAIGN ID SOURCES: Campaign IDs can be obtained from: - search_campaigns_by_names tool (recommended) - create_campaign tool response (returns campaign_id) - Campaign management interface URLs EXAMPLE CONFIRMATION FLOW: User: launch_campaign(campaign_id=159490) System Response: "CRITICAL: REAL CAMPAIGN LAUNCH REQUEST Campaign ID: 159490 Campaign Name: 'Q1_2026_Multi_Channel_Campaign' Channels: LinkedIn, Facebook, Instagram, Google Ads Budget Group: 'BoFu' Estimated Daily Spend: $500-800 Total Budget Allocation: $15,000 WARNING: This will launch a REAL marketing campaign - Real money will be spent immediately - Ads will serve to real audiences - This is NOT a test or simulation Type 'YES, LAUNCH REAL CAMPAIGN' to confirm you want to proceed with live campaign launch:" Only after explicit confirmation will the campaign launch proceed. RESPONSE FORMAT: Success Response (launched — ONLY when "waitingAudiencesToLaunch" is false or absent): { "success": true, "campaign_id": 159490, "status": "LIVE - ACTIVELY SPENDING BUDGET", "campaign_url": "https://platform.metadata.io/hub/advertise/campaigns/159490", "launch_timestamp": "2026-01-15T12:00:00Z", "message": "REAL CAMPAIGN IS NOW LIVE - Budget spending has begun", "live_channels": ["LinkedIn", "Facebook", "Instagram", "Google Ads"], "budget_status": "Active - Real spend initiated", "immediate_actions_required": [ "CRITICAL: MONITOR SPEND IMMEDIATELY - Real money is being spent", "Check live ad performance in dashboard", "Set up budget alerts if not already configured", "Monitor audience engagement in first 2 hours", "Prepare to pause campaign if performance issues arise" ] } DEFERRED LAUNCH — CHECK THIS BEFORE YOU REPORT A LAUNCH: A 202 does NOT always mean the campaign went live. When the response carries "waitingAudiencesToLaunch": true (it comes back with "status": "Draft", not "Launching"), the platform has QUEUED the campaign rather than launched it. It is NOT live, it is NOT serving ads, and it is NOT spending budget. The response also carries a "context" block that states this in plain lang…
list_audiences
ChatGPTList the account's custom audiences, newest first: the same inventory the Metadata Audiences page shows. This is the BROWSE read: one row per audience, any type, searchable by name. Use it to answer "what audiences do I have", to find an audience by name, or to confirm that one the user just built exists. get_matched_audiences is a different view and cannot answer these: it lists a row per audience PER CHANNEL, it requires a type filter whose enum omits several platform audience types, and it has no name search. NOT THE SOURCE FOR CAMPAIGN OR TARGET-GROUP ATTACH. These rows carry no liveness: nothing here says whether the audience has a live segment on the channel you are targeting, and the platform refuses a target group that references one that does not. When you need an audience for a target group's include[].audiences / exclude.audiences, or for any campaign build, call get_matched_audiences for the channel and copy mdAudienceId, type, matchCount, matchCountType and inactive from ITS rows. Use this tool to work out WHICH audience the user means, never to build the entry you attach. PARAMETERS: - name: Contains-search on the audience name (optional) - type: Array of CustomAudienceType values to filter by (optional; omit for every type) - page: Page number, 0-indexed (default: 0) - size: Rows per page, 1-100 (default: 25) RETURNS: One page of audiences, newest first, each carrying: - id: Custom Audience ID - name: Audience name - type: CustomAudienceType (FIRMOGRAPHIC_INCLUDE, CONTACT_LIST, NATIVE_TARGETING_CSV, ...) - companies / contacts: the expected companies and contacts, or null while the platform is still counting them - status: the audience's own build status. READY, COMPLETED, Finished and DynamicComplete mean it is built; New and WaitingDataNodeCallback mean it is still being built; ACTIVE is the fallback for an audience with no build flow - created: when it was created Plus total, totalPages, page and size for paging. Archived audiences are excluded, as on the Audiences page. For one audience's criteria and counts use get_audience_details or get_deep_audience_details.
list_budget_groups
ChatGPTBrowse and list all available budget groups in the Metadata platform with customizable sorting. Default results include both switched-on and switched-off groups. Omit status for inventory and spreadsheet updates; use status=true or status=false only when the user requests that switch state. Reading a switched-off group does not switch it on. Paginate through totalPages before declaring a named group missing. A MONTHLY_RESET or CUSTOM_RESET group starts over every period and keeps funding its campaigns until it is switched off; its currentPeriodStart, currentPeriodEnd and remaining days only measure the current period, so never present them as the group ending or offer to extend it. Only a FIXED_BUDGET group's endDate ends it. KEYWORDS: budget, group, list, all, browse, spending, allocation, optimization, overview DIFFERENCE FROM get_budget_group: - get_budget_group: Searches for ONE specific group BY NAME (requires group name input) - list_budget_groups: Returns a paginated list of groups (supports flexible sorting) USE THIS TOOL WHEN THE USER ASKS: - "Show me all budget groups" or "List all budget groups" - "What budget groups do we have?" - "Display all available groups" - "Show groups sorted by [metric]" - "Which groups have the highest budget?" - "Show groups by leads generated" - "List groups sorted by CPL" - "Order groups by spending" DO NOT USE if the user: - Asks for details about a SPECIFIC group by name → use get_budget_group instead - Wants to find a group by name → use get_budget_group instead - Says "Find the [specific name] group" → use get_budget_group instead SORTING OPTIONS: You can sort by any of these fields (default: totalActiveExperiments descending): - totalActiveExperiments, monthlyCap, averageDailyBudgetPerExperiment - spent, totalBudget, endDate, startDate, leads, cpl SORT ORDER: - asc: Ascending order (lowest to highest, oldest to newest) - desc: Descending order (highest to lowest, newest to oldest) [DEFAULT]
list_experiment_keywords
ChatGPTSearch and browse keywords running in experiments with simplified response data. PURPOSE: Retrieve a paginated list of keywords that are currently running in experiments, with optional filtering by keyword or experiment name. Returns only essential fields for quick identification: keyword name, keywordExternalId, wizExperimentId, wizExperimentName, and status. WHEN TO USE: - Find keywords running in a specific experiment - Search for a keyword across all experiments - Look up keywordExternalId and wizExperimentId before pausing a keyword - Browse experiment keywords with pagination - Verify the status of a keyword after calling pause_experiment_keyword (note: pausing is an async flow, so the status may take some time to update) RESPONSE FORMAT: Returns a simplified paginated response: { "totalElements": 50, "totalPages": 5, "data": [ { "keyword": "digital marketing", "keywordExternalId": 12345, "wizExperimentId": 678, "wizExperimentName": "Q1 Campaign Test", "status": "ACTIVE", "primaryStatus": "NOT_ELIGIBLE", "primaryStatusReasons": ["CAMPAIGN_PAUSED", "CAMPAIGN_PENDING"] } ] } COMMON USE CASES: 1. Search by experiment name: list_experiment_keywords(keywordOrExperimentName="Q1 Campaign") 2. Search by keyword: list_experiment_keywords(keywordOrExperimentName="marketing") 3. Paginate through results: list_experiment_keywords(keywordOrExperimentName="test", page=0, size=20) list_experiment_keywords(keywordOrExperimentName="test", page=1, size=20) PARAMETERS: - keywordOrExperimentName: Required. Search term to filter by keyword or experiment name. - page: Page number for pagination (0-based, default: 0) - size: Number of items per page (default: 10) TIP: Use this tool first to find the keywordExternalId and wizExperimentId needed by the pause_experiment_keyword tool.
list_extensions
ChatGPTList the account's Google Ads / Microsoft Ads library extensions (sitelinks, callouts, snippets, etc.) with their internal ids. ALSO KNOWN AS: list extensions, show extensions, find sitelink, which extensions do we have, extension library, browse extensions KEYWORDS: list, show, find, browse, extensions, sitelink, callout, library, google ads, microsoft ads, bing, id WHEN TO USE: - "What sitelinks do we have?" / "Show our Google Ads extensions" - ALWAYS before add_extensions_to_native_campaign or remove_extensions_from_native_campaign — those need internal ids, and this is the only tool that returns them. The create__extension tools return an empty body and cannot tell you the new id. WHEN NOT TO USE: - Creating a new extension → use the relevant create__extension tool - Non-search channels (Facebook / LinkedIn / Reddit) — extensions do not exist there INPUTS: - channel (required): GOOGLE_ADS or MICROSOFT_ADS - types (optional): filter, e.g. ["SITELINK"] - name (optional): name filter. Extension names are AUTO-DERIVED, not user-chosen — a sitelink's name is its link text and both description lines joined by newlines, truncated to 50 chars. Filter by types and match on the returned fields instead of guessing a name. - page / size (optional): pagination, defaults 0 / 50 Returns {totalElements, totalPages, data:[{id, name, type, createdDate, ...}]}. Only campaign-attachable extensions are listed (account-level ones are excluded by the platform).
list_keywords
ChatGPTList and search keywords with filtering, sorting, and pagination options. PURPOSE: Retrieve a paginated list of keywords from the Metadata platform with advanced sorting and filtering capabilities. Optionally search by keyword name. Use this tool to discover, analyze, and export keyword data for campaign planning and optimization. WHEN TO USE: - Browse all available keywords in the account - Search for specific keywords by name - Find keyword variations and similar terms - Export keyword data with custom sorting - Analyze keyword metrics (search volume, bid prices) - Build keyword lists for campaign creation - Filter keywords by archived status - Compare keyword performance metrics KEY FEATURES: - NAME SEARCH: Filter by keyword name for targeted searches (optional) - PAGINATION: Use page and size parameters to navigate large datasets - SORTING: Sort by creation order (the default, newest first), search volume, bid prices, name, or modification date - FILTERING: Include or exclude archived keywords - PERFORMANCE DATA: Get avgMonthlySearches, lowerPageBid, higherPageBid metrics NAME SEARCH: The optional 'name' parameter supports: 1. Single name (string): Searches for one keyword name - "marketing" → Finds "digital marketing", "email marketing", "marketing automation" - "seo" → Finds "SEO services", "SEO tools", "SEO analytics" - "ppc" → Finds "PPC advertising", "PPC campaigns" 2. Multiple names (array of strings): Searches for multiple keywords at once - ["marketing", "seo", "ppc"] → Aggregates results from all three searches - Makes separate API requests for each name and combines results - Automatically deduplicates keywords by ID - Returns all unique keywords matching any of the provided names - Omit 'name' parameter to list all keywords without filtering - Both single and multiple searches support partial matching PAGINATION STRATEGY: The API returns paginated results. Use these parameters to navigate: - page: 0-based page number (default: 0, meaning first page) - size: Number of results per page (default: 25, recommended: 25-100) To get the next page of results, increment the 'page' parameter. Example: - page=0, size=25 → Returns items 0-24 - page=1, size=25 → Returns items 25-49 - page=2, size=25 → Returns items 50-74 SORT OPTIONS (use format: field,direction): Available fields for sorting: - avgMonthlySearches,desc/asc: Sort by average monthly search volume - lowerPageBid,desc/asc: Sort by lower page bid (CPC floor price) - higherPageBid,desc/asc: Sort by higher page bid (CPC ceiling price) - name,desc/asc: Sort by keyword name alphabetically - id,desc/asc: Sort by creation order, newest first with desc (default) - modifiedDate,desc/asc: Sort by when the keyword was created or last re-saved, archived or unarchived Direction options: - desc: Descending order (highest to lowest) - asc: Ascending order (lowest to highest) SORT EXAMPLES: - sort="avgMonthlySearches,desc": Keywords with highest search volume first - sort="avgMonthlySearches,asc": Keywords with lowest search volume first - sort="lowerPageBid,desc": Keywords with highest CPC floor first - sort="higherPageBid,asc": Keywords with lowest CPC ceiling first - sort="name,asc": Keywords in alphabetical order (A-Z) - sort="name,desc": Keywords in reverse alphabetical order (Z-A) FILTERING: - archived: Filter by archived status (true/false, default: false) Set to true to include archived keywords Set to false to show only active keywords (recommended) PAGINATION WORKFLOW: 1. Start with page=0 to get the first set of keywords 2. Check the response metadata to see if more results exist 3. If needed, increment page number and fetch again 4. Continue until all desired results are retrieved PARTIAL PAGES: A page is partial when totalElements is larger than the rows it returns, and the response then carries a note saying so. A multi-name search counts only the rows it read, so its note names the searches that had more matches than one page or that failed. A keyword missing from a partial result may still exist: search it by name, or read the other pages, before saying…
list_linkedin_conversions
ChatGPTList the LinkedIn conversion actions (Insight Tag conversions) available on the connected LinkedIn ad account, with id, name, type and whether each is enabled. Use it to pick the ids for update_linkedin_channel_settings.conversion_action_ids (which conversions a campaign optimizes toward and reports on), and to answer "which LinkedIn conversions do we track?" or "is the /pricing page conversion set up?". KEYWORDS: linkedin, conversions, conversion actions, conversion tracking, insight tag, website visit conversion, lead gen form conversion, url conversion, page visit, pixel Requires a connected LinkedIn channel (check get_integrations_status). Conversion actions are created in LinkedIn Campaign Manager, not here: when the one the user needs (for example a URL rule for /pricing) is missing, say so and point them at Campaign Manager instead of inventing an id. RESPONSE: {success, count, conversions:[{id, name, type, enabled, last_received_at}]} enabled: false conversions cannot be attached to a campaign (launch validation rejects them). last_received_at is when LinkedIn last recorded a hit; null means the conversion has never fired.
list_marketing_automation_lists
ChatGPTList a Marketing-Automation provider's contact library lists — the selectable source for creating a Marketing-Automation-contacts audience. PREREQUISITE: • The provider MUST be connected. Only HUBSPOT and MARKETO expose library lists. WHEN TO USE: • Before create_marketing_automation_contacts_audience, to find the library_list_id. • "list my HubSpot lists", "which Marketo lists can I use for an audience". PARAMETERS: • provider (required): HUBSPOT or MARKETO. • list_type (optional): SMART_LIST | STATIC_LIST | ACTIVE_LIST. If omitted, the provider's own list types are queried and merged (HubSpot: STATIC_LIST + ACTIVE_LIST; Marketo: all three). • name (optional): filter by list name (partial). RETURNS: { lists: [ { library_list_id, name, status, listType, objectsCount } ] }. Use library_list_id for create. For HubSpot a list is usable only when status is DONE; for Marketo when READY.
list_negative_keywords_list
ChatGPTList and search negative keywords lists by name filter. PURPOSE: Retrieve a list of negative keywords lists from the Metadata platform with optional name filtering. Use this tool to discover and search for specific negative keywords lists for campaign management and optimization. ACCOUNT LIMIT: WARNING: MAXIMUM 20 NEGATIVE KEYWORDS LISTS PER ACCOUNT Each account can have a maximum of 20 negative keyword lists. Use this tool to check your current list count and manage your existing lists. If you need to create a new list but have reached the limit, you'll need to delete or archive existing lists first. WHEN TO USE: - Browse all available negative keywords lists in the account - Search for specific negative keywords lists by name - Find negative keywords lists by partial name matching - Get all negative keywords lists data - Discover available negative keywords lists for campaign use - Check current list count to manage the 20-list limit KEY FEATURES: - NAME SEARCH: Filter by negative keywords list name for targeted searches (optional) - MULTIPLE SEARCH: Search for multiple list names at once with automatic deduplication - SIMPLE INTERFACE: Only name-based filtering, no pagination or sorting needed - LIST COUNTING: Use to verify your current count against the 20-list maximum NAME SEARCH: The optional 'name' parameter supports: 1. Single name (string): Searches for one negative keywords list name - "branded" → Finds negative keywords list named "Branded" - "competitor" → Finds negative keywords list named "Competitor" - "generic" → Finds negative keywords list named "Generic" 2. Multiple names (array of strings): Searches for multiple negative keywords lists at once - ["branded", "competitor", "generic"] → Aggregates results from all three searches - Makes separate API requests for each name and combines results - Automatically deduplicates lists by ID - Returns all unique negative keywords lists matching any of the provided names - Omit 'name' parameter to list all negative keywords lists without filtering - Both single and multiple searches support partial matching RESPONSE FORMAT: Returns a response with: { "data": [ { "name": "BRanded", "id": 123 }, { "name": "Competitor", "id": 124 } ] } COMMON USE CASES: 1. List all negative keywords lists: list_negative_keywords_list() 2. Search for "branded" negative keywords list: list_negative_keywords_list(name="branded") 3. Find specific negative keywords list: list_negative_keywords_list(name="BRanded") 4. Search for multiple negative keywords list names at once: list_negative_keywords_list(name=["branded", "competitor", "generic"]) 5. Search multiple negative keywords list names: list_negative_keywords_list(name=["competitor", "generic"]) PARAMETERS: - name: Optional negative keywords list name or partial name to search for. Can be a string or array of strings. Supports partial matching. Omit to list all negative keywords lists. (optional) PERFORMANCE TIPS: - Use name parameter for targeted searches to reduce result set - When searching multiple names, each name triggers a separate API request Use reasonable list sizes to avoid excessive API calls - Results are automatically deduplicated when searching multiple names EXAMPLES: - list_negative_keywords_list() - Get all negative keywords lists - list_negative_keywords_list(name="branded") - Search for branded negative keywords list - list_negative_keywords_list(name=["branded", "competitor"]) - Search multiple negative keywords lists - list_negative_keywords_list(name="competitor") - Find competitor negative keywords list - list_negative_keywords_list(name=["branded", "generic"]) - Multiple list names search 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.
list_salesforce_mixed_criteria
ChatGPTList the account's saved Salesforce "mixed criteria" (contact-list criteria) — the selectable source for creating a Salesforce-contacts audience. PREREQUISITE: • Salesforce integration MUST be connected. If it is not, tell the user to connect Salesforce first (connect_crm with crm="salesforce"). WHEN TO USE: • Before create_salesforce_contacts_audience, to find the criteria_id. • "list my Salesforce contact criteria", "which Salesforce lists can I use for an audience". PARAMETERS: • qualified (optional): when true, keep only criteria whose generated filter matches qualified-signal fields. RETURNS: a list of { id, name, description }. Use id as the criteria_id for create_salesforce_contacts_audience. Note: this does NOT include a contacts count.
list_search_terms
ChatGPTReview the Google Ads search terms report with filtering, sorting, and pagination. PURPOSE: List the actual search queries that triggered the account's Google Ads, so you can review wasteful or off-target terms and decide which ones to add to a negative keywords list. Mirrors the "Search Terms" library page in the Metadata UI. WHEN TO USE: - Investigate which queries are costing money without producing clicks or conversions - Find queries to add to a negative keywords list (pair with add_keywords_to_negative_lists) - Inspect search terms tied to a specific experiment or matched keyword - Sort by cost / clicks / conversions to surface the worst offenders FILTERS (all optional): - searchTerm: substring match on the search term text - experiment: experiment name substring match - keyword: matched keyword substring - matchType: array subset of [PHRASE, BROAD, EXACT, NEAR_EXACT, NEAR_PHRASE] - startDate / endDate: ISO-8601 timestamps (e.g. 2026-06-01T00:00:00.000Z). The UI defaults to the last 30 days when both are omitted. PAGINATION & SORT: - page: 0-based (default 0) - size: rows per page (default 12, max 100) - sort: "<field>,<direction>". Sortable fields include searchTerm, matchType, experiment, addedExcluded, keyword, impressions, clicks, ctr, averageCpc, spent, conversions, costPerConversion. Direction is asc or desc. Default: "clicks,desc". RESPONSE FORMAT: Returns a paginated response: { "totalElements": 123, "totalPages": 5, "data": [ { "id": "bGVhZCBnZW5lcmF0aW9uIGNhbmFkYQ", "searchTerm": "lead generation canada", "experiment": "MD_Experiment", "experimentId": "179908", "matchType": "PHRASE", "keyword": "lead generation", "addedExcluded": "Added", "impressions": 200, "clicks": 11, "ctr": 5.5, "averageCpc": 2.3, "spent": 25.30, "conversions": 0, "costPerConversion": null }, ... ] } COMMON USE CASES: 1. Top spenders with zero conversions in the last 30 days: list_search_terms(sort="spent,desc") then filter the response client-side for conversions == 0. 2. Worst CTR among phrase matches: list_search_terms(matchType=["PHRASE"], sort="ctr,asc") 3. Search terms tied to a specific experiment: list_search_terms(experiment="Q2 Brand Test") 4. Date-bounded review: list_search_terms( startDate="2026-05-01T00:00:00.000Z", endDate="2026-05-31T23:59:59.999Z", sort="spent,desc" ) PARAMETERS: - searchTerm (string, optional): substring filter on the search term text. - experiment (string, optional): experiment name substring filter. - keyword (string, optional): matched keyword substring filter. - matchType (array of strings, optional): subset of [PHRASE, BROAD, EXACT, NEAR_EXACT, NEAR_PHRASE]. - startDate (string, optional): ISO-8601 timestamp lower bound. - endDate (string, optional): ISO-8601 timestamp upper bound. - page (integer, optional): 0-based page index (default 0). - size (integer, optional): rows per page (default 12). - sort (string, optional): "<field>,<direction>" (default "clicks,desc"). 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 reports, so never substitute one channel for the other to get "close enough" results.
list_segments
ChatGPTList the account's saved Insights (Spotlight) account-journey segments: {id, name, status, last_update_date}. Segments are shared with the SaaS UI (Spotlight > Journey), so a marketer may already have the one you need: check here BEFORE create_segment and reuse instead of creating a near duplicate. name filters fuzzily (case-insensitive contains or a close match). An empty list means the account has no segments yet, not an error: create one with create_segment when the ask needs it. Creating needs an ACTIVE Insights (Spotlight) subscription on the account: create_segment checks it first and refuses with the subscription state when it is expired or missing. Relay that to the user instead of retrying; existing segments stay usable either way. STATUS: READY can be used; PENDING is still extracting a CRM field (re-check later); FAILED cannot back an audience. NEXT: get_segment_criteria(segment_id, lookback_window) to read a segment's filter and how many accounts it matches in a window; create_audience_from_segment to turn it into an audience; get_insights_report(criteria=...) to browse its accounts.
list_target_groups
ChatGPTList and search target groups in Metadata platform. USE FOR: "list all target groups", "show available target groups", "search target groups with name X", "find target groups containing 'engineer'", "get target group IDs by name", "what target groups do I have?" WORKFLOW: list_target_groups(name="X") → get ID → retrieve_target_group_by_id(target_group_id=ID) for full details. RESPONSE: Paginated {content: [{id, name, channel, audienceSize, createdDate, modifiedDate, status}], totalElements, totalPages} SEARCH: Partial matching, case-insensitive. name="engineer" matches "Engineers EMEA", "Senior Engineers", etc.
list_user_accounts
ChatGPTList accounts the current user has access to, with optional name filtering. USE FOR: "which accounts do I have access to?", "show me my accounts", "what accounts can I manage?", "what is my account ID?", "which account am I logged into?", "what role do I have?", "show me account named X", "do you have an account called X?" AUTH METHODS: JWT tokens (OAuth) | PAT tokens (prefix "pat-") ARGS: - name (optional for regular users, REQUIRED for super users unless account_id is given): partial account name to search for. Super users span the whole platform and would otherwise return an unbounded list, so a search term is mandatory for them. If a super user calls this with neither name nor account_id, the tool returns an error asking for one — re-call with the user's intended search term. - account_id (optional): exact account id to look up. Use this instead of name when the search term is a number ("account 4368", "the 12057 account"), since account names are not ids and a numeric name search finds nothing. It satisfies the super-user search requirement on its own; supplying both narrows to accounts matching BOTH. RESPONSE FORMAT (identical for JWT and PAT — the token format does not change the result): Regular users: user_id, email, default_account_id, is_super_user, token_type, accounts[{account_id, name, role}] Super users with neither argument: error response — supply name or account_id and retry. Super users with name: matching accounts platform-wide (paged at 20). Super users with account_id: the single matching account, or an empty list when no account carries that id.
list_wizard_campaigns
ChatGPTList wizard (Metadata-native) campaigns for the current account with pagination, sorting, and experiment-status filtering. KEYWORDS: campaigns, list, browse, wizard, native, all campaigns, campaign list, launched campaigns, paused campaigns, active campaigns USE THIS TOOL WHEN THE USER ASKS: - "Show me all campaigns" / "List campaigns" / "What campaigns do we have?" - "Show active campaigns" / "List paused campaigns" / "Show completed campaigns" - "Show recent campaigns" / "Last N campaigns" - "Campaigns sorted by spend / leads / CPL / created date" - Page-by-page campaign browsing for the campaigns UI DO NOT USE if the user: - Wants details on ONE SPECIFIC campaign by name → use search_campaigns_by_names - Wants budget group info (not campaigns) → use list_budget_groups / get_budget_group - Wants per-experiment performance → use experiment_performance_stats / search_experiments TWO INDEPENDENT FILTERS (COMBINE TO MATCH UI TABS): 1) status — filters by CAMPAIGN status. Accepts a comma-separated subset of: Draft, Launched, Finished. - Draft: the campaign exists but has never been launched. - Launched: the campaign has been launched (experiments may be Active, Paused, or idle). - Finished: the campaign has reached its end date. - Omit to include all three. 2) experiment_statuses — filters by EXPERIMENT status inside each campaign. Accepts a comma-separated subset of: Active, WithoutSpend, Paused, Completed, Failed. Omit to include all five. HOW TO MIX THEM (mirrors the UI tabs on /campaigns): - "All" tab: omit both → API returns everything. - "Active" tab: status="Launched", experiment_statuses="Active,WithoutSpend" (launched campaigns with live or not-yet-spending experiments). - "Paused" tab: status="Launched", experiment_statuses="Paused" (launched campaigns whose experiments are paused). - "Draft" tab: status="Draft" (campaign hasn't been launched yet — experiment status doesn't apply). - "Finished" tab: status="Finished". SORTING: - sort_by: createdDate (default), startDate, endDate, name, budget, spent, leads, cpl, cpc, ctr, impressions, clicks, status - sort_order: asc | desc (default: desc) PAGINATION: - page: 0-based page index (default 0) - size: results per page (default 25; the UI campaign list fetches 25–50) RESPONSE SHAPE: { "totalElements": 435, "totalPages": 18, "data": [ { "id": 173290, "accountId": 1455, "name": "2026_Q2_NA_Builder_Content_...", "createdDate": "2026-01-15T12:00:00Z", "visibility": "VISIBLE" | "ARCHIVED", "budget": 25, "startDate": "...", "endDate": "...", "status": "Launched" | "Draft" | ..., "activeExperiments": 9, "pausedExperiments": 0, "totalExperiments": 9, "leads": 0, "spent": 0, "impressions": 48, "clicks": 0, "cpc": 0, "cpl": 0, "ctr": 0.0, "goal": "CTR" | "CPL", "campaignGroup": "TOF - AO - Social - Billing - BA", "tags": [...] }, ... ] } WORKFLOW (UI-style): list_wizard_campaigns(page=0, size=25) → render list → user clicks campaign → search_campaigns_by_names / get_campaign_by_wizard_id for details.
manage_campaign
ChatGPTManage a campaign by pausing or restarting it. KEYWORDS: pause, stop, restart, resume, unpause, campaign, control, manage, halt WHEN TO USE: - User asks to "pause campaign X" - User wants to "stop campaign Y" - User requests to "restart campaign Z" - User wants to "resume campaign A" - User asks to "unpause campaign B" ACTIONS: - pause: Temporarily pause an active campaign to stop ad serving and budget spend - restart: Resume a paused campaign to continue ad serving and budget spend REQUIRED PARAMETERS: - campaign_id: The unique identifier of the campaign to manage (integer, required) - action: The action to perform - "pause" or "restart" (string, required) CAMPAIGN ID SOURCES: Campaign IDs can be obtained from: - search_campaigns_by_names tool - create_campaign tool response - Campaign management interface URLs IMPORTANT VALIDATION REQUIREMENTS: - CRITICAL: You can ONLY pause campaigns that are currently "Active" - CRITICAL: You can ONLY restart campaigns that are currently "Paused" - Before attempting to pause or restart, use search_campaigns_by_names to verify the current campaign status
manage_experiment
ChatGPTPause or restart a whole experiment (a launched channel campaign inside a wizard campaign). KEYWORDS: pause, stop, restart, resume, unpause, experiment, control, manage, halt WHEN TO USE: - User asks to "pause experiment X" - User wants to "stop the LinkedIn experiment" - User requests to "restart experiment Y" - User wants to "resume/unpause a paused experiment" SCOPE - DO NOT CONFUSE WITH SIMILAR TOOLS: - manage_experiment (this tool) acts on ONE WHOLE EXPERIMENT. - pause_experiment_keyword / restart_experiment_keyword act on ONE KEYWORD inside an experiment - they never pause the experiment itself. - manage_campaign acts on the whole wizard campaign, which can span several experiments/channels. ACTIONS: - pause: Stop ad serving and budget spend for the experiment - restart: Resume a paused experiment so it serves ads and spends again WORKFLOW: 1. Find the experiment: search_experiments(search_name="my experiment") and note experimentId and statusLabel from the results 2. Pause it: manage_experiment(experiment_id=123, action="pause") 3. Or restart it: manage_experiment(experiment_id=123, action="restart") IMPORTANT VALIDATION REQUIREMENTS: - CRITICAL: You can ONLY pause experiments that are currently active - CRITICAL: You can ONLY restart experiments that are currently Paused - Use search_experiments first to verify the current experiment status RESTART BUDGET CONFIRMATION FLOW: Restarting first estimates the impact on budget groups (the same check the main UI runs). If any budget group is impacted, the tool does NOT restart: it returns status="requires_confirmation" with the impacted groups in budgetImpact. Present the impact to the user, and only after they explicitly confirm, call again with confirm_budget_impact=true. WARNING: This changes the live state of the experiment on the ad channel. WARNING: ASYNC FLOW: The channel-side status change may take a moment to propagate. Verify later with search_experiments.
pause_experiment_keyword
ChatGPTPause a specific keyword running in an experiment. PURPOSE: Pause a keyword that is currently active in an experiment. This stops the keyword from being used in the experiment without removing it entirely. SCOPE - THIS TOOL ACTS ON ONE KEYWORD, NOT ON THE EXPERIMENT: It pauses a SINGLE keyword INSIDE an experiment. The experiment itself keeps running with its other keywords. To pause or restart a WHOLE experiment, use manage_experiment instead. WHEN TO USE: - Pause an underperforming keyword in an experiment - Temporarily stop a keyword from running in a specific experiment - Manage keyword performance within experiments PREREQUISITE: Use list_experiment_keywords first to find the keywordExternalId and wizExperimentId for the keyword you want to pause. Both come from that tool's results: keywordExternalId identifies the keyword on the ad channel, and wizExperimentId is the experiment's ID (the same ID search_experiments returns as experimentId). WORKFLOW: 1. Search for the keyword: list_experiment_keywords(keywordOrExperimentName="my keyword") 2. Note the keywordExternalId and wizExperimentId from the results 3. Pause it: pause_experiment_keyword(keywordExternalId=12345, wizExperimentId=678) 4. (Optional) Verify later: list_experiment_keywords(keywordOrExperimentName="my keyword") to check the status has changed PARAMETERS: - keywordExternalId: Required. The external ID of the keyword to pause (from list_experiment_keywords). - wizExperimentId: Required. The experiment ID where the keyword is running (from list_experiment_keywords). WARNING: This action changes the state of the keyword in the experiment. The keyword will stop running in the specified experiment. WARNING: ASYNC FLOW: Pausing a keyword is an asynchronous operation. The status change may not be immediately reflected. Use list_experiment_keywords after some time to verify the keyword status has been updated.
performance_metrics
ChatGPTGranular performance metrics for ads, audiences, creatives, offers, target groups, keywords. IMPORTANT: Always specify endpoint parameter. Always use ISO 8601 for dates. USE FOR: Best performing ads/audiences/creatives/offers/target groups, ingredient comparisons, ad type analysis (IMAGE, VIDEO, CAROUSEL), lead gen forms vs landing pages, pipeline by ingredient, creative previews, keyword performance. NOT FOR: Account-level stats, experiment-level analysis without ingredient focus. ENDPOINT LOGIC: - 'target group' → customAudience/group - 'audience' → customAudience - 'offer'/'lead gen'/'landing page' → offer - 'creative' → creative - 'keyword' → keywords - 'ad'/'ads' or default → ads AD TYPES: IMAGE, VIDEO, CAROUSEL, DOCUMENT, CONVO, SPOTLIGHT, SEARCH, MESSAGE - The adFormat field on each response row identifies the ad type. METRICS: spend, impressions, clicks, leads, mqls | opens, sends, actionClicks, costPerOpen, costPerSend (CONVO/MESSAGE ads) | cpl, cpc, cpm, ctr, conversionRate, formConversionRate, mqlRate | totalOpps, totalTriggered, oppsAmount, triggeredAmount | cpMql, cpOppInfluenced, cpOppTriggered | channel, goal, adFormat, audienceSize, statusLabel | previewUrl CONVO/MESSAGE AD CAVEAT: when adFormat is CONVO or MESSAGE (LinkedIn message ads), success is measured by opens, sends, and actionClicks (and costPerOpen / costPerSend), NOT clicks/ctr/cpc. Do not rank these ads by CTR or dismiss them when clicks=0. Use sort='actionClicks,desc' or sort='opens,desc' for conversational performance ranking. RULES: Field 'id' corresponds to endpoint queried. Exclude $0 CPL experiments from calculations.
query_metadata_analytics_account
ChatGPTQuery the caller's own account CONTEXT from the Metadata.io knowledge base — a rolled-up summary (firmographic, recent 90-day campaign history, open drafts, per-experiment performance) refreshed overnight. Use it to GROUND a recommendation or plan in the account's own history before you suggest or generate something. USE FOR: firmographic (industry, size, revenue, country) and high-level recent-history context to back a decision — e.g. "given our recent LinkedIn performance, what should we try next quarter?". NOT FOR the account's CURRENT LIVE STATE. This is a periodic roll-up, not the live platform — it can miss or misreport granular state (e.g. answer "nothing runs in Germany" while many live campaigns target Germany). For "what's running / what's live", "which campaigns target <country/segment>", "list our campaigns / audiences / offers", or real-time spend / pacing, use the live platform analytics tools instead (account_level_stats, performance_metrics, demographic_country_stats, search_campaigns_by_names, etc.). Also NOT FOR cross-account industry benchmarks or a different company (cross-tenant queries are rejected). The caller's account_id is resolved server-side from the credentials the call acts as. It cannot be supplied or overridden by the caller.
query_metadata_analytics_benchmarks
ChatGPTQuery the Metadata.io marketing knowledge base for cross-account industry benchmarks and priors.
regenerate_flexible_background
ChatGPTRegenerate ONLY the background scene of a flexible creative, keeping the editable text/logo layers untouched. Returns the new background image URL so the editor swaps just the background layer. USE FOR: "regenerate the background", "try a different scene", "new background, same text". Accepts an optional image_source (the current background) to guide a same-style regeneration; omit it for a fresh scene.
remove_ad_from_campaign
ChatGPTRemove specific ads (ad groups) from one or more channels in an existing campaign. Use this tool when you need to detach a named ad from a particular channel (e.g. remove "Pixel Ads in Minutes_v2_LI" from LINKEDIN). Channel and ad group IDs are resolved internally — you only need the human-readable channel type and ad name. Works on both campaign structures. On a Channel-First / Native (N×N×N) campaign the ad is removed from its WizNativeAdContainer's native ads (resolved by ad name via the ads library); any container then left with no asset at all is dropped. KEYWORDS: remove, delete, ad, creative, ad group, channel, campaign WHEN TO USE: - User wants to remove a specific ad from a channel - User wants to clean up ad groups from one or more channels - Multiple ads across multiple channels can be removed in a single call RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one entry per requested removal recording its success or error. ALWAYS check removal_results — a partial failure (e.g. one of two names not found) still returns normally, so report only what actually came back successful. REQUIRED PARAMETERS: - campaign_id: Campaign ID (numeric identifier) - channel_ads: Object mapping channel type → list of ad names to remove CHANNEL TYPES: FACEBOOK, INSTAGRAM, GOOGLE_ADS, LINKEDIN, MICROSOFT_ADS, REDDIT, TWITTER EXAMPLES: Remove one ad from LINKEDIN: remove_ad_from_campaign({ "campaign_id": 42546, "channel_ads": { "LINKEDIN": ["Pixel Ads in Minutes_v2_LI"] } }) Remove ads from multiple channels at once: remove_ad_from_campaign({ "campaign_id": 42546, "channel_ads": { "LINKEDIN": ["Ad A", "Ad B"], "FACEBOOK": ["Ad C"] } }) INTEGRATION WITH OTHER TOOLS: - Use get_campaign_by_wizard_id to inspect current ads per channel before removing - Use search_campaigns_by_names to find the campaign ID
remove_audiences_from_campaign
ChatGPTRemove specific audiences from one or more channels in an existing campaign. Use this tool when you need to detach a named audience/group from a particular channel (e.g. remove "European Digital Nomad Investors" from FACEBOOK). Channel and audience IDs are resolved internally — you only need the human-readable channel type and audience name. Works on both campaign structures. On a Channel-First / Native (N×N×N) campaign the audience is cleared from its WizNativeAdContainer(s); any container then left with no asset at all (no audience, target group, keyword, ad or offer) is dropped, and on a draft the audience's group is deleted from the channel, so the campaign no longer lists it. A container left holding ads with nothing to target them is named in the removal message. KEYWORDS: remove, delete, audience, group, channel, campaign, targeting WHEN TO USE: - User wants to remove a specific audience from a channel - User wants to clean up audiences from one or more channels (targeting groups: remove_target_groups_from_campaign) - Multiple audiences across multiple channels can be removed in a single call RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one entry per requested removal recording its success or error. ALWAYS check removal_results — a partial failure (e.g. one of two names not found) still returns normally, so report only what actually came back successful. REQUIRED PARAMETERS: - campaign_id: Campaign ID (numeric identifier) - channel_audiences: Object mapping channel type → list of audience names to remove CHANNEL TYPES: FACEBOOK, INSTAGRAM, GOOGLE_ADS, LINKEDIN, MICROSOFT_ADS, REDDIT, TWITTER EXAMPLES: Remove one audience from FACEBOOK: remove_audiences_from_campaign({ "campaign_id": 42545, "channel_audiences": { "FACEBOOK": ["European Digital Nomad Investors_p2w8"] } }) Remove audiences from multiple channels at once: remove_audiences_from_campaign({ "campaign_id": 42545, "channel_audiences": { "FACEBOOK": ["Audience A", "Audience B"], "LINKEDIN": ["Audience C"] } }) INTEGRATION WITH OTHER TOOLS: - Use get_campaign_by_wizard_id to inspect current audiences per channel before removing - Use search_campaigns_by_names to find the campaign ID
remove_channels_from_campaign
ChatGPTDisable one or more entire channels from an existing campaign. Use this tool when the goal is to turn off a whole channel (e.g. stop running ads on FACEBOOK entirely). To remove a specific audience from a channel instead, use remove_audiences_from_campaign. KEYWORDS: remove, delete, disable, channel, campaign WHEN TO USE: - Disable/remove an entire channel from a campaign (e.g. remove FACEBOOK or GOOGLE_ADS) - Multiple channels can be disabled in a single call - Returns the campaign state before and after the change RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one entry per requested removal recording its success or error. ALWAYS check removal_results — a partial failure (e.g. one of two names not found) still returns normally, so report only what actually came back successful. REQUIRED PARAMETERS: - campaign_id: Campaign ID (numeric identifier) - channels: Array of channel types to disable CHANNEL TYPES: FACEBOOK, INSTAGRAM, GOOGLE_ADS, LINKEDIN, MICROSOFT_ADS, REDDIT EXAMPLES: Disable a single channel: remove_channels_from_campaign({ "campaign_id": 12345, "channels": ["FACEBOOK"] }) Disable multiple channels at once: remove_channels_from_campaign({ "campaign_id": 12345, "channels": ["FACEBOOK", "GOOGLE_ADS", "INSTAGRAM"] }) INTEGRATION WITH OTHER TOOLS: - Use search_campaigns_by_names to find the campaign ID - Use get_campaign_by_wizard_id to inspect active channels before removal - Use remove_audiences_from_campaign to remove a specific audience from a channel
remove_extensions_from_native_campaign
ChatGPTDetach extensions from a native-structure Google Ads / Microsoft Ads campaign. The extension stays in the account library — only the campaign binding is removed. ALSO KNOWN AS: remove extension from campaign, detach sitelink, unlink extension, take sitelink off campaign KEYWORDS: remove, detach, unlink, unbind, extension, sitelink, callout, campaign, native, native structure, google ads, microsoft ads, bing WHEN TO USE: - "Remove that sitelink from campaign X" - "Take the old promotion extension off the native search campaign" - Undoing a wrong add_extensions_to_native_campaign call WHEN NOT TO USE: - Deleting the extension from the library entirely — this only unbinds it from one campaign - The campaign uses the Precision / METADATA structure — native-structure campaigns only INPUTS (all required): - campaign_id: wizard campaign id - channel: GOOGLE_ADS or MICROSOFT_ADS - extension_ids: internal ids from list_extensions BEHAVIOUR: only the named ids are detached; other attachments are preserved. Safe to re-run. EXAMPLE: remove_extensions_from_native_campaign(campaign_id=8421, channel="GOOGLE_ADS", extension_ids=[551])
remove_keywords_from_campaign
ChatGPTRemove Google Ads keyword groups and/or negative keyword list attachments from a campaign's GOOGLE_ADS channel. Use this tool to clear keywords/negative lists from a DRAFT campaign so the user can replace them with new ones (e.g. "I don't like these keywords, use these instead" — call this tool to remove the old set, then call add_and_edit_campaign_elements with the new google.keywords / google.negative_keyword_lists). Works on both campaign structures. On a Channel-First / Native (N×N×N) campaign a positive keyword group is also unlinked from its WizNativeAdContainer (keywordGroupId); negative-list detach is channel-level and unchanged. KEYWORDS: remove, delete, keyword, keywords, negative, group, google, campaign PLATFORM CONSTRAINT: - Only the Draft state allows keyword removal; the platform rejects DELETE on launched/launching campaigns. CHANNEL: GOOGLE_ADS only (other channels do not have keyword groups). RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one {channel, keyword_group|negative_keyword_list, success, message|error} entry per requested removal. ALWAYS check removal_results — a partial failure (e.g. one of two group names not found) still returns normally. - If EVERY requested removal failed, the tool errors instead of returning. REQUIRED: - campaign_id: Campaign ID (numeric identifier) - At least one of channel_keywords OR channel_negative_keyword_lists must be provided. OPTIONAL FAST PATH: - channel_id: When you already have the GOOGLE_ADS channel id in context (e.g. from a recent get_campaign_by_wizard_id call), pass it to skip the full-campaign lookup. The tool will fetch only that single channel. EXAMPLES: Remove one keyword group: remove_keywords_from_campaign({ "campaign_id": 42546, "channel_keywords": { "GOOGLE_ADS": ["CRM Keywords"] } }) Remove a negative keyword list attachment: remove_keywords_from_campaign({ "campaign_id": 42546, "channel_negative_keyword_lists": { "GOOGLE_ADS": ["Competitor Brands"] } }) Remove both at once: remove_keywords_from_campaign({ "campaign_id": 42546, "channel_keywords": {"GOOGLE_ADS": ["CRM Keywords", "Demo Keywords"]}, "channel_negative_keyword_lists": {"GOOGLE_ADS": ["Competitor Brands"]} }) Remove with known channel id (skips campaign lookup): remove_keywords_from_campaign({ "campaign_id": 42546, "channel_id": 88123, "channel_keywords": {"GOOGLE_ADS": ["CRM Keywords"]} }) INTEGRATION WITH OTHER TOOLS: - Use get_campaign_by_wizard_id to inspect current keyword groups on a channel before removing. - After removal, use add_and_edit_campaign_elements with google.keywords / google.negative_keyword_lists to add replacements.
remove_keywords_from_negative_list
ChatGPTRemove keywords from a single existing Google Ads negative keyword list, matched by text. PURPOSE: Drop keywords that no longer belong in a negative keyword list (e.g. a search term that turned out to convert after all, or an over-eager exclusion). The tool fetches the list internally, finds entries whose text matches what you pass, and removes every match. MATCHING: - Comparison is case-sensitive and exact (whole-text equality). - If the same text appears under multiple match types (e.g. "free" as PHRASE AND as EXACT), all of them are removed. - Inputs that don't match anything are reported back in 'notFound' without failing the call. WHEN TO USE: - Undo a previous add_keywords_to_negative_lists mistake - Clean up a list during the day-to-day review loop - For full-list wipe use the platform's deleteAll endpoint instead (not currently wrapped here) NOT FOR: - Detaching the list from a campaign (use remove_keywords_from_campaign). - Deleting the list itself. COMMON USE CASES: 1. Remove a single keyword: remove_keywords_from_negative_list( listId=43256533, keywords=["free download"], ) 2. Remove several at once: remove_keywords_from_negative_list( listId=43256533, keywords=["competitor a", "tutorial", "wiki"], ) PARAMETERS: - listId (integer, required): negative keyword list id (from list_negative_keywords_list). - keywords (array of strings, required, min 1): exact text(s) to remove. RESPONSE FORMAT: { "listId": 43256533, "removed": [{"text": "free download", "keywordMatchType": "PHRASE", "resourceName": "..."}, ...], "notFound": ["wiki"] } 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.
remove_offers_from_campaign
ChatGPTRemove offers — Lead Gen forms OR Landing Pages — from one or more channels in an existing campaign. Use this tool to detach a named offer from a channel (e.g. remove "Demo Request Form" from FACEBOOK, or "Pricing LP" from GOOGLE_ADS). The offer type (Lead Gen vs Landing Page) and its IDs are resolved internally — you only need the channel type and the offer name. This is the single offer-removal tool (it replaced the Lead-Gen-only remove_leadgen_offer_from_campaign). Works on both campaign structures. On a Channel-First / Native (N×N×N) campaign the offer is cleared from EVERY WizNativeAdContainer native ad that references it (leadGenFormId / landingPageId), channel-wide — the ad is kept, and any container then left with no asset at all is dropped. To remove an offer from only ONE container/row, use add_and_edit_native_campaign_elements.modify_containers instead. On Precision/METADATA it uses the legacy per-offer delete. KEYWORDS: remove, delete, offer, lead gen, landing page, form, channel, campaign WHEN TO USE: - User wants to remove a specific offer (Lead Gen form or Landing Page) from a channel - User wants to clean up offers from one or more channels - Multiple offers across multiple channels can be removed in a single call RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one entry per requested removal recording its success or error. ALWAYS check removal_results — a partial failure (e.g. one of two names not found) still returns normally, so report only what actually came back successful. REQUIRED PARAMETERS: - campaign_id: Campaign ID (numeric identifier) - channel_offers: Object mapping channel type → list of offer names to remove CHANNEL TYPES: FACEBOOK, INSTAGRAM, GOOGLE_ADS, LINKEDIN, MICROSOFT_ADS, REDDIT EXAMPLES: Remove a Lead Gen form from FACEBOOK and a Landing Page from GOOGLE_ADS: remove_offers_from_campaign({ "campaign_id": 42545, "channel_offers": { "FACEBOOK": ["Demo Request Form"], "GOOGLE_ADS": ["Pricing LP"] } }) INTEGRATION WITH OTHER TOOLS: - Use get_campaign_by_wizard_id to inspect current offers per channel before removing - Use search_campaigns_by_names to find the campaign ID
remove_target_groups_from_campaign
ChatGPTRemove targeting groups from one or more channels in an existing campaign. Use this tool to detach a named Targeting Group from a channel (e.g. remove "Tech Decision Makers" from LINKEDIN). Channel + targeting-group IDs are resolved internally — you only need the channel type and the targeting group name. (Targeting groups are NOT audiences — to remove a standard audience use remove_audiences_from_campaign.) Works on both campaign structures. On a Channel-First / Native (N×N×N) campaign the targeting group is cleared from its WizNativeAdContainer.targetingGroupId; any container then left with no asset at all is dropped, and on a draft the targeting group is also deleted from the channel's groups; a container left holding ads with nothing to target them is named in the removal message. On Precision/METADATA it uses the legacy group delete. KEYWORDS: remove, delete, targeting group, target group, channel, campaign RESPONSE: - Returns the refreshed campaign state plus a removal_results list with one entry per requested removal recording its success or error. ALWAYS check removal_results — a partial failure (e.g. one of two names not found) still returns normally, so report only what actually came back successful. REQUIRED PARAMETERS: - campaign_id: Campaign ID (numeric identifier) - channel_target_groups: Object mapping channel type → list of targeting group names EXAMPLE: remove_target_groups_from_campaign({ "campaign_id": 42545, "channel_target_groups": {"LINKEDIN": ["Tech Decision Makers"]} })
render_flexible_creative
ChatGPTFlatten a layered flexible-creative document into a final PNG (rendered from the SAME layout the editor shows) and upload it to the creatives library. Returns the rendered image URL, the library image id, and pixel dimensions. INTERNAL SAVE-PATH TOOL — invoked by the backend when the user clicks Save in the editor; not part of the chat generation flow. Renders the doc's background + text/CTA/logo/image layers so the flat image is pixel-identical to the editor preview.
resize_image
ChatGPTMake a resized copy of an image at an exact pixel size. Deterministic image processing: no AI model runs and nothing in the image is redrawn. USE FOR: fitting an existing image (an uploaded file, a library creative, a creative made earlier) to a placement's size, e.g. LinkedIn 1200x628 or 1200x1200, Meta feed 1080x1080 or 1440x1800, Stories 1080x1920, display 300x250 or 728x90. SIZE: give width and height for an exact size, or only one of them to scale proportionally. Each side is at most 4096 px. WHEN THE SHAPE CHANGES (width and height given, in an aspect ratio other than the source's), fit decides: - pad (default): keeps the whole image, scaled to fit inside the target, and fills the empty bands with background. Nothing is cut off or distorted. - crop: scales the image to cover the target and trims the overflow, keeping the part named by crop_focus. WARNING: text, logos or faces near the trimmed edges are lost. - stretch: scales each side independently. Distorts the image; use it only when asked to. A source within 1% of the target's shape is scaled straight to the exact size. DOES NOT: redesign or re-lay out a creative for a new shape, change the source image, or save anything to the creatives library. OUTPUT: the URL of a NEW image (s3_url), stored temporarily outside the creatives library, with its image_size, the source's source_size, fit_applied (none when the shape was kept), the pad's background, upscaled (true when the source was enlarged, which cannot add detail and looks softer) and format. To use it in an ad, upload the URL with upload_image_creative, which gives it a NEW library id.
resolve_linkedin_ad_library_links
ChatGPTMap LinkedIn Ad Library links (linkedin.com/ad-library/detail/<id>), sponsoredCreative URNs or bare LinkedIn creative ids to the ads in this account's Metadata library, so an ad the user points at by its LinkedIn link can be REUSED in a new campaign instead of rebuilt. WHAT IT CAN AND CANNOT RESOLVE (repeat this to the user when a link is not found): - It resolves ONLY ads that were launched THROUGH METADATA. Every ad Metadata publishes to LinkedIn is recorded with the LinkedIn creative id LinkedIn gave it, and that id is exactly what the Ad Library link carries. Those come back with the library ad (id, name, type) plus the experiment and campaign that ran them, ready to attach by name. - An ad launched natively in LinkedIn Campaign Manager (a sponsored personal post, a Thought Leader ad, anything built outside Metadata) is NOT in the library and CANNOT be imported from the link, by this tool or any other. The only way to run it here is to rebuild it from its source files (image, video, PDF) with the ad tools. - LinkedIn only. Meta or Google ad library links are refused per item. HOW IT SEARCHES: the platform has no lookup by LinkedIn creative id, so this scans the account's LinkedIn ads newest first (100 per page, max_pages pages, default 20, so the newest 2,000 ads) and stops as soon as every id is found. A miss with reached_end: false means the ad may simply be older than the scan: pass campaign_ids to narrow the scan to the campaigns that ran it, or raise max_pages. A miss with reached_end: true means the account never launched that ad through Metadata. PARAMETERS: - links: Ad Library URLs, urn:li:sponsoredCreative:<id> URNs or numeric LinkedIn creative ids (1 to 20 per call). - campaign_ids: optional wizard campaign ids that restrict the scan. - max_pages: optional, 1 to 50, default 20. RETURNS: {success, found, not_found, scanned_ads, scanned_pages, reached_end, results: [{input, linkedin_creative_id, found: true, library_ad: {id, name, type, channel, status, image_url}, experiment: {id, name, goal}, campaign: {id, name, status}, stats: {spend, impressions, clicks, leads}, destination_url, reuse} | {input, linkedin_creative_id, found: false, reason}]} NEXT STEPS: attach a found ad by its library NAME through create_campaign / add_and_edit_campaign_elements (ads.list), or read it with get_ad_details(ids=<library_ad.id>). Never re-upload a found ad's creative: that creates a duplicate library entry.
restart_experiment_keyword
ChatGPTRestart a specific paused keyword in an experiment. PURPOSE: Restart a keyword that was previously paused in an experiment. This re-enables the keyword so it starts running again in the specified experiment. SCOPE - THIS TOOL ACTS ON ONE KEYWORD, NOT ON THE EXPERIMENT: It restarts a SINGLE keyword INSIDE an experiment. It cannot restart a paused experiment. To pause or restart a WHOLE experiment, use manage_experiment instead. WHEN TO USE: - Restart a keyword that was previously paused in an experiment - Re-enable a keyword after resolving performance issues - Resume keyword activity in a specific experiment PREREQUISITE: Use list_experiment_keywords first to find the keywordExternalId and wizExperimentId for the keyword you want to restart. Both come from that tool's results: keywordExternalId identifies the keyword on the ad channel, and wizExperimentId is the experiment's ID (the same ID search_experiments returns as experimentId). WORKFLOW: 1. Search for the keyword: list_experiment_keywords(keywordOrExperimentName="my keyword") 2. Note the keywordExternalId and wizExperimentId from the results 3. Restart it: restart_experiment_keyword(keywordExternalId=12345, wizExperimentId=678) 4. (Optional) Verify later: list_experiment_keywords(keywordOrExperimentName="my keyword") to check the status has changed PARAMETERS: - keywordExternalId: Required. The external ID of the keyword to restart (from list_experiment_keywords). - wizExperimentId: Required. The experiment ID where the keyword is running (from list_experiment_keywords). WARNING: This action changes the state of the keyword in the experiment. The keyword will resume running in the specified experiment. WARNING: ASYNC FLOW: Restarting a keyword is an asynchronous operation. The status change may not be immediately reflected. Use list_experiment_keywords after some time to verify the keyword status has been updated.
retrieve_target_group_by_id
ChatGPTGet detailed target group information by ID. USE FOR: "get target group details for ID X", "show target group with ID Y", "check target group configuration", "show audiences in target group X", analyze setup before changes. PREREQUISITE: If you don't have the ID, use list_target_groups(name="X") first. RESPONSE: {id, name, channel, audiences, targeting, status, createdDate, modifiedDate, size, configuration, ...} WORKFLOW: list_target_groups(name="target_group_name") → get ID → retrieve_target_group_by_id(target_group_id=ID)
search_ads_by_names
ChatGPTSearch for ads by name in the Metadata platform library, with pagination. USE THIS TOOL WHEN THE USER ASKS ABOUT: - Ad details, information, or status - Finding an ad by name - Getting ad IDs - Checking if an ad exists - Looking up ad creative assets (images, thumbnails) - Ad type or channel information - Any question containing words like: "ad", "creative", "show me", "find", "search", "image" SEARCH FEATURES: - Partial, case-insensitive matching on ad names - Returns ad ID, name, channel type, ad type, status, and image URLs - Three-state status filter via the status param (default "active", preserves the prior active-only behaviour): `"active"` → active ads only "archived" → archived (soft-deleted) ads only; use this to find an ad id for unarchive_ad * "all" → both active and archived in one response PAGINATION: - Supports page and size parameters (defaults: page=0, size=25). - Page numbering starts at 0. - Recommended size: 5-25 to keep responses LLM-friendly. Use up to 100 only when the caller needs a wider sweep — large pages can blow your context budget. - Returned total_elements and total_pages are taken from the platform's PageResponse so callers can drive a paginator. - When ad_names carries multiple entries, the platform endpoint accepts only ONE name per request — this tool fires one paged request per name and merges results. page/size apply PER-NAME, total_elements is the SUM across names, and total_pages is the MAX across names. Single-name searches get clean pagination semantics; multi-name is best-effort. PARAMETERS: - ad_names: Array of ad name strings to search for (required, ≥1) - page: Zero-based page index (optional, default 0) - size: Results per page (optional, default 25) - sort: Spring sort clause (optional, default "createdDate,desc"; also valid: "id,desc", "name,asc", etc.) - status: "active" (default) / "archived" / "all". Pick the bucket you want; "archived" is the unarchive discovery path, "all" is the rare both-buckets case. RETURNS: { "found_ads": [ { "id": 190084, "name": "AI_Marketing_Audit_Q4_2025_Demo_LI_LI", "channelType": "LINKEDIN", "adType": "IMAGE", "completionStatus": "COMPLETED", "status": true, "thumbnail": "https://...", "imageUrl": "https://..." } ], "missing_names": ["NonExistent"], "total_found": 1, "page": 0, "size": 25, "sort": "createdDate,desc", "total_elements": 1, "total_pages": 1 } CHANNEL TYPES: LINKEDIN, FACEBOOK, INSTAGRAM, GOOGLE, REDDIT, MICROSOFT_ADS AD TYPES: IMAGE, VIDEO, CAROUSEL, TEXT STATUS: true (active) or false (inactive)
search_campaigns_by_names
ChatGPTSearch for campaigns by name to get campaign details, IDs, and status. KEYWORDS: campaign, search, find, lookup, status, active, paused, draft, marketing, advertising USE THIS TOOL WHEN THE USER ASKS ABOUT: - Campaign details, information, or status - Finding a campaign by name - Getting campaign IDs - Checking if a campaign exists - Looking up campaign status (active, paused, draft) - Any question containing words like: "campaign", "show me", "find", "search", "list", "details", "status" ALWAYS use this tool first before launching, updating, or referencing any campaign. SEARCH FEATURES: - Partial, case-insensitive matching (e.g., "Q1" matches "Q1_2026_Campaign") - One entry per searched name: the best match (the exact name when the account has one, else the newest neighbour), the other matches, and the best match's FULL campaign as payload - Searches up to 150 campaigns per term PARAMETERS: - campaign_names: Array of campaign name strings to search for (required) RETURNS: { "found_campaigns": [ { "search_name": "LinkedIn_BoFu", "id": 159490, "name": "LinkedIn_BoFu_Q1_2026", "statusLabel": "Active", "visibility": "VISIBLE", "exact_match": false, "other_matches": [{"id": 159491, "name": "LinkedIn_BoFu_Q1_2026 v2", "statusLabel": "Draft", "visibility": "ARCHIVED", "exact_match": false}], "payload": { ...the full campaign: channels[] with groups[] (audience groups, each with channelCustomAudiences[] carrying customAudienceId and name), groupsExclude[], targetingGroups[], adGroups[], landingPages[], leadGenForms[]... } } ], "missing_names": ["NonExistent"], "total_found": 1 } Read exact_match before treating the entry as the campaign the user named: a substring search also returns "<name> SaaS" for "<name>", and when no exact match exists the entry is a neighbour. visibility is ARCHIVED for an archived campaign. payload is the same document get_campaign_by_wizard_id returns, so no second read is needed for the campaign's audiences, ads or offers. STATUS LABELS: Active, Paused, Draft, Completed, Unknown Use returned campaign IDs with launch_campaign or manage_campaign tools. Anchor all date-related decisions to the REAL current date — call get_current_date if you are not already certain what today is.
search_campaigns_by_utm_value
ChatGPTFind campaigns whose UTM tracking parameters CONTAIN a given value - the only correct way to answer "which campaigns use / still say X in their UTMs". KEYWORDS: utm, utms, utm_source, utm_medium, utm_campaign, utm_term, utm_content, tracking parameters, search utm, find utm, placeholder, UPDATE ME, audit USE THIS TOOL WHEN THE USER ASKS: - "Which campaigns still have UPDATE ME in their UTMs?" - "Which campaigns tag utm_source as <something>?" - Any audit of UTM VALUES across campaigns. CRITICAL - DO NOT ANSWER THIS FROM CAMPAIGN NAMES. Campaign names, experiment names and tags do not contain UTM values. Searching them returns nothing and produces a confident WRONG "no campaigns found" - the exact failure this tool was built to end. If this tool errors or is unavailable, say you cannot check rather than falling back to a name search. INHERITANCE RULE - READ BEFORE ANSWERING ANY UTM QUESTION: UTMs are inherited, never blank. A campaign channel with an empty stored mapping does NOT have "no UTMs" - it tracks with the account's UTM defaults, and where the account set nothing it tracks with the Metadata platform default. Roughly half of all channel rows in production are in that inherited state. NEVER report "no UTMs configured" from an empty stored field: report the resolved value and its origin. ORIGIN IS PER CHANNEL, not per key: a channel with an empty stored mapping inherits the account default whole, so a channel whose resolved mapping differs at all from that is stored on the campaign and every one of its values is an override. The per-key same_as_default flag says whether that one key happens to match the default anyway. ORIGIN VALUES: - campaign_override: stored on this campaign channel, differs from what it would inherit. - account_default: inherited from this account's UTM defaults. - platform_default: inherited from the Metadata-wide default (account set nothing). - not_set: the channel really has no UTM mapping (non-sponsored channels only). HONEST LIMIT: a campaign that stores a mapping identical to the default it would inherit is reported as inherited. The platform returns resolved values with no provenance, so that case cannot be distinguished - say so rather than claiming the campaign has no override. TRACKING TIMING AND TOKEN MEANING: Leads using server-resolved campaign UTMs use the current saved mapping when the platform processes them, without waiting for an ad republish. Captured URL or caller-supplied values can follow a different ingestion path, so do not generalize this timing to every new lead. Native click-time macros retain values captured from the lead's click URL. Ad click URLs have a separate publication timeline: a draft uses the saved mapping at launch, and launched ads use it on their next campaign publish. Saving a launched Microsoft Ads campaign triggers a live UTM push. AD_NAME is a dynamic token, not necessarily an individual ad name: standard experiments use their ad group name when present, otherwise their creative name; native ad structures use the native ad's own name. CAMPAIGN_NAME uses the wizard campaign name. Saving a launched campaign can also queue an asynchronous existing-lead UTM refresh. Do not assume historical rows are immutable or that all old rows have already refreshed. Verify the saved mapping with get_campaign_utms and actual lead values and ingestion timing separately from live ad click URLs; a supplied or backfilled lead creation date alone does not prove when its UTMs were resolved. The match is a case-insensitive SUBSTRING over each enabled channel's EFFECTIVE (post-inheritance) UTM value, so a campaign that inherits a matching account default is returned too - which is correct, that is what it actually tracks with. It matches VALUES, not keys: searching "utm_source" finds nothing. MINIMUM 3 CHARACTERS. A shorter value is refused rather than sent, because the platform ignores a sub-minimum filter and would return the whole campaign list, which reads as "everything matches". Optional filters mirror list_wizard_campaigns: page, size, sort_by, sort_order, status (Dr…
search_experiment_recipes
ChatGPTFind proven CAMPAIGN CONFIGURATIONS to build from — combinations of channel, ad format, audience type, bid strategy and budget band that have run together successfully across multiple advertisers. USE THIS WHEN you are composing a campaign and need to decide HOW to build it: which channel and format pairing, what kind of audience, which bid strategy, roughly what daily budget. It answers "what should I build", not "how is my account performing". DO NOT USE IT for cohort performance questions ("what's the median CPL for my industry", "how do we compare to similar companies") — that is query_metadata_analytics_benchmarks. Do not use it for the caller's own campaign history — that is query_metadata_analytics_account. Every returned recipe is backed by at least five distinct advertisers. Recipes below that floor are suppressed rather than returned, so an empty result means "no configuration is proven enough to recommend here", NOT "no data exists". Say so plainly rather than substituting a guess.
search_experiments
ChatGPTSearch for experiments by name, status, and budget group with flexible filtering. KEYWORDS: experiment, search, find, ad, test, status, active, paused, performance, campaign WHEN TO USE: - User wants to "find experiment X" - User asks to "show experiments for campaign Y" - User requests to "search for experiments matching Z" - User wants to "see all experiments with name containing A" - User asks "what experiments are in campaign B?" - User asks "what is the ID of experiment C?" - User wants to "find experiments in budget group X" - User asks to "search experiments in specific budget groups" - User wants to "show all active experiments" - User asks "list paused experiments" - User wants to "find experiments with status X" PURPOSE: This tool searches across all experiments with flexible filtering options. You can search by name (partial, case-insensitive), filter by budget groups, and filter by status. All filters are optional - use any combination to narrow down results. SEARCH CAPABILITIES: - Search by experiment name: Returns experiments with matching names - Search by campaign name: Returns all experiments from campaigns with matching names - Filter by budget groups: Narrow results to specific budget group IDs - Filter by status: Show experiments with specific statuses (Active, Paused, etc.) - Partial matching: Search term doesn't need to be exact - Case-insensitive: "Test" matches "test", "TEST", "TeSt" STATUS VALUES EXPLAINED: - Active: Currently running and spending budget - WithoutSpend: Running but not currently spending budget - Paused: Temporarily stopped, can be restarted - Completed: Finished (reached end date or completion criteria) - Failed: Encountered an error during execution - Disconnected: Connection to ad channel was lost RETURN EXPERIMENT DATA FIELDS: - experimentId, experimentName, wizCampaignId, wizCampaignName - campaignGroup, statusLabel, dailyBudget, spent, impressions, clicks - startDate, endDate
search_insights_criteria_fields
ChatGPTDiscover the fields an Insights (Spotlight) account-journey segment can filter on: the exact field names, their type, the operators each accepts, and the picklist options. USE BEFORE create_segment, and before get_insights_report when you filter it. Omit search_keywords to get the whole catalog in compact form; pass keywords to narrow it (matched against field names and labels: "impressions", "score", "visits", "pricing", "opportunity"). WHAT A SEGMENT FILTERS: the companies in the account's Spotlight journey, one row per company, with engagement metrics that are computed INSIDE the lookback window the audience is later created with (create_audience_from_segment.lookback_window). Needs the Insights (Spotlight) subscription on the account: without it the catalog comes back empty or the call fails, and the right move is to say so, not to guess fields. STATIC FIELDS (always present; use the NAME in criteria): - Marketing touchpoints: LINKEDIN_IMPRESSIONS (NUMERIC), LINKEDIN_ADS_ENGAGEMENT (NUMERIC, LinkedIn clicks), FORM_SUBMISSIONS (NUMERIC), CHANNEL (MULTIPICKLIST: LINKEDIN, FACEBOOK, GOOGLE_ADS, INSTAGRAM, EMAIL, THIRD_PARTY, DIRECT), HIGH_INTENT_PAGES (BOOLEAN) - Website engagement: WEBSITE_VISITS, TOTAL_PAGE_VIEWS, UNIQUE_VISITORS (NUMERIC), PAGE_URL (STRING; LIKE "/pricing" is the page-visit filter), IDENTIFIED_VISITORS (BOOLEAN), IS_ABM (BOOLEAN), UTM_SOURCE / UTM_MEDIUM / UTM_CAMPAIGN / UTM_TERM / UTM_CONTENT / UTM_KEYWORD / REFERRER (ARRAY) - Engagement score: SCORE (MULTIPICKLIST classification), CONFIDENCE_SCORE and TREND (MULTIPICKLIST) - CRM: ACCOUNT_STATUS (opportunity status, MULTIPICKLIST), IN_CRM (BOOLEAN), ACCOUNT_OWNER (MULTIPICKLIST); HubSpot adds DEAL_TYPE and DEAL_STAGE; Salesforce adds EMAILS, CALLS, EVENTS (NUMERIC), CAMPAIGN_NAME, CAMPAIGN_TYPE, CAMPAIGN_MEMBER_STATUS, RESPONDED; any connected CRM adds DYNAMIC fields (criterion field "DYNAMIC" plus entity and property) - Firmographic: INDUSTRIES, REVENUES, EMPLOYEES, COUNTRIES (MULTIPICKLIST), COMPANY_DOMAIN, COMPANY_NAME (STRING), ACCOUNT_LIST (MULTIPICKLIST of the account's ABM lists) RESPONSE: {fields: [{name, label, criteria_fields: [{name, label, type, operators, options (first 10), options_total, dynamic?, entity?, status?}]}], missing_crm_fields, criteria_rules}. criteria_rules restates the value shape per type. A dynamic field with status PENDING is still being extracted from the CRM and cannot be used yet.
search_library_creatives_by_name
ChatGPTSearch or list creative assets in the library by name, across ALL content types — images, videos, GIFs and documents. Returns detailed information about matching assets with pagination support. KEYWORDS (for tool discovery): search creative library, list video creatives, find videos, list uploaded videos, browse video library, search videos by name, list all creatives, find creative by id, look up creative id, list documents, list GIFs, library assets, video assets, creative assets, list creatives by type. This is the general-purpose library search/list tool for every content type — there is no separate "list videos" or "get library items" tool. WHEN TO USE: - Find specific creatives by name in the library - List all creatives in the library (when creativeName is omitted) - Search for creative assets with partial name matching - Filter by content type (IMAGE, VIDEO, GIF, DOCUMENT) - Locate creatives for use in ad creation - Verify creative asset availability before campaign setup - Get creative metadata and IDs for asset management - Browse through paginated results SEARCH BEHAVIOR: - Supports partial name matching when creativeName is provided - Case-insensitive search - Returns all creatives matching the search term - Automatically URL encodes the search name - When creativeName is omitted, returns all creatives in the library - Supports optional content type filtering (IMAGE, VIDEO, GIF, DOCUMENT) - Use lower number in the size parameter. Preference for 5 or 10 max. PAGINATION: - Supports pagination with page and size parameters. - Defaults: page=0, size=10 (server-side default in MetadataAPIClient.search_library_creatives_by_name). - Page numbering starts at 0. - The platform returns Spring PageResponse shape (totalElements, totalPages, data) so callers can drive a paginator off the response. - Recommended size: 5-10 to keep LLM responses manageable. Larger windows (up to ~25) are accepted; anything beyond blows token budgets fast. - sort takes a Spring field,direction clause and defaults to id,desc. Sort on labelName for the display name; name holds the generated UUID. RETURNED DATA: - Creative asset ID and name - File properties (size, dimensions, format) - Upload and modification timestamps - Visibility status and permissions - Preview URLs and download links - Associated metadata and tags - Pagination metadata (total count, page info) USE CASES: - "List all images in the library" - "Find all images with 'product' in the name" - "Search for logo images in the library" - "Get image ID for 'campaign-hero-banner.jpg'" - "Find all images uploaded for the Q4 campaign" - "Browse images page by page (page=0, size=5)" - "List only videos: contentTypes=VIDEO" - "Filter for images and videos: contentTypes=IMAGE,VIDEO" - "Get all documents: contentTypes=DOCUMENT" - "Find all asset types: contentTypes=IMAGE,VIDEO,GIF,DOCUMENT" NOTE: This is the single tool for searching/listing ALL creative asset types. To restrict to a type, pass contentTypes (e.g. VIDEO for videos only); omit it to return every type. Use fetch_creative_details when you already have a specific creative id and want its full metadata.
search_linkedin_engagement_sources
ChatGPTFind which LinkedIn campaigns or pages to retarget, for a chosen engagement source type. STEP 2 of the LinkedIn Engagement Retargeting flow. Each result's id is the LinkedIn URN to pass as engagement_source_urns to create_linkedin_engagement_retargeting_audience. The audience will contain people who engaged with the sources you select, so this choice determines who is in it. REQUIRED FIRST: call get_linkedin_engagement_source_types and pick an engagementSourceType plus an engagementTrigger. ALWAYS PASS engagement_trigger AND lookback_window_days TOGETHER. With both, every candidate carries engagementCount, the volume of engagement behind it, sorted highest-first — which is the only way to tell which sources are worth retargeting. Without the pair the platform returns no counts and the order is not meaningful. Use the same trigger and lookback you intend to create the audience with, or the numbers describe a different audience than the one you are about to build. DO NOT CALL THIS FOR THE WEBSITE SOURCE TYPE. Website retargeting is defined by URL match rules, not by picking sources, and this tool refuses it. Go straight to the create tool with page_set_name and url_match_groups. READING THE RESULTS: - id — the LinkedIn URN (e.g. urn:li:sponsoredCampaign:743409464). Pass it verbatim. It is NOT the numeric campaign id and must never be reconstructed. - name — the campaign or page name, for telling the user what you picked. - engagementCount — how many engagements that source drew under the trigger and lookback you passed. Absent when you did not pass both. - engagementMetricLabel / engagementMetric — WHAT was counted, which follows the trigger: "Total Engagement" for an any-interaction trigger, "Opens" for a conversation open, clicks for a chargeable-click one. Quote this label when you report numbers, so "1,200 opens" is not reported as impressions. - status — the campaign's state. PENDING_DELETION campaigns still appear and are still valid engagement history, but prefer live ones when both have volume. ORGANIZATION_PAGES candidates carry no status; that is normal, not missing data. HOW TO CHOOSE: - Prefer sources with real engagementCount. A source with 0 builds an audience that will stay empty however long LinkedIn is given. - Selecting several sources is normal and usually right: the audience is the UNION of everyone who engaged with any of them, so more sources means more reach. - IF EVERY CANDIDATE SHOWS 0, do not silently build from all of them. That means the account has no engagement of this kind in the window. Say so, and offer the real options: a longer lookback, a shallower trigger, a different source type, or waiting until campaigns have run. Building anyway produces an empty audience the user will believe is populated. - Only the top limit results come back, not the whole account. Narrow with search rather than assuming the list is complete. WHEN TO USE: - After picking a source type, to find what can be retargeted - "Which of my video campaigns got the most engagement?" - "Find my lead gen form campaigns" - To resolve a campaign the user named to its URN, via search PARAMETERS: - engagement_source_type: an engagementSourceType from step 1 (required). WEBSITE is not valid here. - engagement_trigger: a trigger valid for that source type. Pass it WITH lookback_window_days to get engagement counts and a meaningful order. - lookback_window_days: 30, 60, 90, 180 or 365. Pairs with engagement_trigger. - search: narrow by name, case-insensitive substring. Use it when the user named a campaign, or when the account has many campaigns. - limit: how many to return (default 12, max 100). RETURNS: - sources[]: the candidates, as described above - engagementMetricLabel: what the counts measure - count: how many came back - next_step: which tool to call next IMPORTANT NOTES: - ORGANIZATION_PAGES returns exactly one candidate, the account's own company page. That is the whole result set, not a truncated one. - An empty sources list means the account has nothing of that type. Report…
search_ma_lists
ChatGPTSearch the connected marketing automation (MA) tool's destination lists by name. USAGE INSTRUCTIONS FOR LLM: Use this to find a concrete marketing-automation list before setting it as the account's default destination list. This tool is the ONLY safe way to resolve a list id: never invent, guess, or reuse a list id from memory or from a different account. Always call this first, confirm the match with the user if there are several, and pass the exact "listId" from the result to set_default_ma_list. WHEN TO USE THIS TOOL: - User wants to set or change the default marketing automation destination list - User asks "which MA lists do we have?" or "find the list named X" - Before calling set_default_ma_list RESPONSE FORMAT: Returns {"lists": [{"listId": int, "name": str}, ...]}. An empty array means no marketing automation tool is connected, or nothing matched the search text. EXAMPLE: "Set the default MA list to Newsletter Signups" -> search_ma_lists(name="Newsletter Signups") then set_default_ma_list(list_id=<matched listId>)
search_reddit_criteria
ChatGPTGet available Reddit targeting criteria and their reference values (externalId + name) for target group creation. USE FOR: "what Reddit communities match X?", "search Reddit interests/keywords", "find subreddits about Y", get valid references before create_reddit_target_group, resolve location countries/states for Reddit. CRITERIA TYPES: - communities: Search subreddits/communities by name (requires search_terms) - interests: Search Reddit interest categories (requires search_terms) - keywords: Search contextual keywords (requires search_terms) - locations: Country/state options for the mandatory LOCATION criterion (search_terms optional; omit to list all) RESPONSE: For communities/interests/keywords, a list of {externalId, name} options, each search_terms entry searched on its own and merged — use externalId in the COMMUNITIES/INTERESTS/KEYWORDS criteria. For locations, {countries, states, regions} where each item has a numeric id — put that numeric id (NOT the object) into the LOCATION criterion's countries/states arrays. WORKFLOW: search_reddit_criteria → build targeting (LOCATION first) → create_reddit_target_group
search_target_group_criteria
ChatGPTGet available criteria and their supported values (names and IDs) for target group creation/updates. USE FOR: "what targeting criteria are available?", "what options for [criteria type]?", "supported values for industries/seniority/job functions", "how to search job titles/interests/member groups?", validate criteria before creating target group, get valid IDs for create_target_group. CRITERIA TYPES: 1. LIST-BASED (returns predefined options): - age-ranges: Age range options - company-categories: Company classifications - company-growth-rates: Growth rate ranges - revenues: Revenue ranges - employees: Employee count ranges - industry-taxonomy: Industry codes/names - jobFunctions: Job function categories - seniority: Seniority levels - followed-companies: Company follow options - locations: Geographic data (MANDATORY as FIRST criteria for LinkedIn) - use search_terms for filtering 2. SEARCH-BASED (use search_terms): - job-title: Search job titles (reference_type: LINKEDIN_JOB_TITLES) - member-groups: Search LinkedIn groups (reference_type: LINKEDIN_MEMBER_GROUPS) - member-skills: Search professional skills - interests: Search interests (reference_type: LINKEDIN_INTERESTS) - traits: Search behaviors (reference_type: LINKEDIN_TRAITS) 3. NUMERIC: years-of-experience (0-12, not retrieved via this tool) OPERATION MODES: - List: search_target_group_criteria(channel="LINKEDIN", criteria_type="seniority") - Search: search_target_group_criteria(channel="LINKEDIN", criteria_type="job-title", search_terms=["engineer"], exact_match=false) - Direct: search_target_group_criteria(channel="LINKEDIN", reference_type="LINKEDIN_JOB_TITLES", search_terms=["engineer"]) RESPONSE: Array of {externalId, name}. Use externalId in target group config, show name to users. CHANNEL: Only LINKEDIN supported.
set_campaign_utms
ChatGPTSet or clear the UTM tracking parameters of ONE channel on a wizard campaign, merging into what the channel already stores. KEYWORDS: utm, utms, set utm, change utm, utm_source, utm_medium, utm_campaign, utm_term, utm_content, tracking parameters, campaign override, UPDATE ME USE THIS TOOL WHEN THE USER ASKS: - "Set utm_source=Linkedin and utm_medium=paid-social on this campaign" - "Fix the UPDATE ME placeholder in campaign X's UTMs" - "Use utm_campaign=DG_Touch-3 on the LinkedIn channel" INHERITANCE RULE - READ BEFORE ANSWERING ANY UTM QUESTION: UTMs are inherited, never blank. A campaign channel with an empty stored mapping does NOT have "no UTMs" - it tracks with the account's UTM defaults, and where the account set nothing it tracks with the Metadata platform default. Roughly half of all channel rows in production are in that inherited state. NEVER report "no UTMs configured" from an empty stored field: report the resolved value and its origin. ORIGIN IS PER CHANNEL, not per key: a channel with an empty stored mapping inherits the account default whole, so a channel whose resolved mapping differs at all from that is stored on the campaign and every one of its values is an override. The per-key same_as_default flag says whether that one key happens to match the default anyway. ORIGIN VALUES: - campaign_override: stored on this campaign channel, differs from what it would inherit. - account_default: inherited from this account's UTM defaults. - platform_default: inherited from the Metadata-wide default (account set nothing). - not_set: the channel really has no UTM mapping (non-sponsored channels only). HONEST LIMIT: a campaign that stores a mapping identical to the default it would inherit is reported as inherited. The platform returns resolved values with no provenance, so that case cannot be distinguished - say so rather than claiming the campaign has no override. TRACKING TIMING AND TOKEN MEANING: Leads using server-resolved campaign UTMs use the current saved mapping when the platform processes them, without waiting for an ad republish. Captured URL or caller-supplied values can follow a different ingestion path, so do not generalize this timing to every new lead. Native click-time macros retain values captured from the lead's click URL. Ad click URLs have a separate publication timeline: a draft uses the saved mapping at launch, and launched ads use it on their next campaign publish. Saving a launched Microsoft Ads campaign triggers a live UTM push. AD_NAME is a dynamic token, not necessarily an individual ad name: standard experiments use their ad group name when present, otherwise their creative name; native ad structures use the native ad's own name. CAMPAIGN_NAME uses the wizard campaign name. Saving a launched campaign can also queue an asynchronous existing-lead UTM refresh. Do not assume historical rows are immutable or that all old rows have already refreshed. Verify the saved mapping with get_campaign_utms and actual lead values and ingestion timing separately from live ad click URLs; a supplied or backfilled lead creation date alone does not prove when its UTMs were resolved. INPUT: - campaign_id: the WIZARD campaign id (from list_wizard_campaigns / search_campaigns_by_names). - channel: the enabled channel to edit: LINKEDIN, FACEBOOK, INSTAGRAM, GOOGLE_ADS, MICROSOFT_ADS or REDDIT. UTMs are stored per channel; call once per channel. - utms: object of UTM key to value. Standard keys UTM_SOURCE, UTM_MEDIUM, UTM_TERM, UTM_CAMPAIGN, UTM_CONTENT (utm_source style is accepted and normalised); other keys are custom static parameters. A value is either literal text ("paid-social") or one of the platform's dynamic tokens: AD_CHANNEL, AD_NAME, CAMPAIGN_NAME, OFFER_TYPE, OFFER_FORM_NAME, AUDIENCE_NAME_OR_KEYWORD, EXPERIMENT_ID, EXPERIMENT_NAME, NATIVE_CHANNEL_CAMPAIGN_ID, NATIVE_CHANNEL_ADGROUP_ID, NATIVE_CHANNEL_CREATIVE_ID, NATIVE_CHANNEL_KEYWORD, NATIVE_CHANNEL_SEARCH_TERM. Keys you omit keep their current value; an empty string clears a key (the channel then inherits that key's default again only if the who…
set_landing_subdomain
ChatGPTSet the subdomain this account's generated landing pages are served from. USE FOR: "set our landing page domain", "I want our pages on zoom.ad.live", "use acme as our landing subdomain", "our landing pages should be branded". SET ONCE: this claims a subdomain for an account that has NONE. It cannot change or release one that is already set, and it does not fail loudly when asked to; it returns status "locked" and changes nothing. A change is support's to make. WHEN TO OFFER IT UNPROMPTED: new accounts start with no subdomain, so their landing pages are served from a long shared service URL. If get_account_details shows landingSubdomain is null and the user is creating or about to create a landing page, offer to set one, since a branded URL is what goes into their ads. Suggest a label derived from their own company domain (acme.com -> "acme") and let them confirm or change it. Do NOT set one without the user agreeing to the specific name. ARGS: - subdomain (required): the label ONLY, never the full hostname. Pass "zoom", not "zoom.ad.live" and not "https://zoom.ad.live". Pass an empty string to release the account's current claim. RULES THE LABEL MUST MEET: 1-63 characters of a-z, 0-9 and hyphens; no leading or trailing hyphen; not all digits; not a reserved name (www, api, app, mail, cdn, admin and similar). The platform only trims and lowercases what you send; it does NOT rewrite an invalid label into a valid one, so build a valid label yourself before calling: "Zoom Events" is refused, "zoom-events" is accepted. Always report the value the tool returns rather than what you sent, because the two can differ. SCOPE: acts on the CALLER'S OWN account only. There is no account argument and it cannot be pointed at another account; to set one for a different account, an operator does it from the platform admin screen. RESPONSE status AND WHAT TO DO NEXT: - "set": claimed. Tell the user the stored subdomain. - "cleared": the claim was released; pages fall back to the default URL. - "unavailable": another account already holds that name. This is NOT an error. Tell the user it is taken, suggest a variant, and call again once they choose. - "invalid": the label breaks the rules above. Rewrite it, confirm with the user, call again. - "not_permitted": the caller is not an account admin, and nothing was changed. Tell them an admin on their account has to set it, under Settings then Configurations. Do not ask them for a name and do not retry. - "locked": the account already has a subdomain and nothing was changed. Tell the user it is already set, name it, and say support changes it. Do NOT retry and do NOT offer to pick a different name. IMPORTANT: the name is globally unique and first come first served, and once pages are live it is baked into ad URLs already in market, so changing it later breaks them. That is why it is set once and only support can move it.
set_search_channel_final_url_suffix
ChatGPTSet or clear the Final URL Suffix on a wizard campaign's search channel (Google Ads or Microsoft Ads). The suffix is appended to every final URL the platform serves — typically UTM parameters for tracking (utm_source, utm_medium, utm_campaign, ...). Matches the platform UI's "Final URL Suffix" input under the Google Ads / Microsoft Ads channel's Advanced Settings section. KEYWORDS: final url suffix, final-url-suffix, url suffix, suffix, utm, utm parameters, utm source, utm medium, utm campaign, tracking, tracking template, url tracking, tracking parameters, google ads, google, microsoft ads, microsoft, bing, search channel, search campaign, campaign settings, advanced settings WHEN TO USE: - Add or change UTM / tracking parameters on Google Ads or Microsoft Ads final URLs - Clear an existing suffix (pass empty string "") REQUIREMENTS: - The campaign MUST already have the target channel enabled (via create_campaign / add_and_edit_campaign_elements with a google and/or microsoft block). - Final URL Suffix is search-channel-only. LinkedIn / Meta / Reddit do NOT support it and the tool will reject other channel types. PARAMETERS: - campaign_id (required): the wizard campaign ID. - channel (required): "GOOGLE_ADS" or "MICROSOFT_ADS". - final_url_suffix (required): the suffix string. Max 2048 chars. Format: key=value pairs separated by &. Allowed characters: A–Z a–z 0–9 . _ ~ = & { } - or %XX percent-encoded. Spaces and [ ] ( ) ? must be percent-encoded. Pass empty string "" to clear. EXAMPLES: Set UTMs on a Google Ads channel: set_search_channel_final_url_suffix({ "campaign_id": 177214, "channel": "GOOGLE_ADS", "final_url_suffix": "utm_source=metadata&utm_medium=cpc&utm_campaign={campaignid}" }) Clear the suffix on a Microsoft Ads channel: set_search_channel_final_url_suffix({ "campaign_id": 177214, "channel": "MICROSOFT_ADS", "final_url_suffix": "" }) RESPONSE: {success, campaign_id, channel_id, channel, applied:{final_url_suffix}, errors?} INTEGRATION WITH OTHER TOOLS: - Use search_campaigns_by_names / get_campaign_by_wizard_id to find the campaign. - Google Ads / Microsoft Ads channels are enabled by create_campaign or add_and_edit_campaign_elements with a google / microsoft block.
set_search_channel_locations
ChatGPTSet the geographic targeting of a wizard campaign's search channel (Google Ads or Microsoft Ads) — which countries/states the campaign serves in, and which countries to exclude. Matches the platform UI's "Location" picker under the Google Ads / Microsoft Ads channel SETTINGS panel, plus the "Negative Locations" editor under that channel's Advanced Settings. WARNING: NEW SEARCH CAMPAIGNS DEFAULT TO UNITED STATES. The platform seeds the Location field with United States, so a campaign created without calling this tool serves in the US only. Whenever the user names a geography — "target Canada and the UK", "run this in EMEA", "exclude India" — set it explicitly; do not assume the default is what they want. KEYWORDS: geo, geos, geo targeting, geotargeting, geographic, geography, location, locations, location targeting, country, countries, state, states, region, territory, market, target location, exclude location, exclude geo, exclude country, negative location, negative locations, location exclusion, excluded locations, where the campaign runs, google ads, google, microsoft ads, microsoft, bing, search channel, search campaign, campaign settings WHEN TO USE: - Point a search campaign at specific countries/states instead of the US default - Exclude countries the campaign must not serve in - Clear targeting back to all locations (countries=[], states=[]) REQUIREMENTS: - The campaign MUST already have the target channel enabled (via create_campaign / add_and_edit_campaign_elements with a google and/or microsoft block). - Geo targeting here is search-channel-only. LinkedIn / Meta / Reddit carry location on the audience or target group instead — use create_target_group or the audience tools for those. PARAMETERS (each one REPLACES that side of the targeting; omit to leave untouched): - campaign_id (required): the wizard campaign ID. - channel (required): "GOOGLE_ADS" or "MICROSOFT_ADS". - countries: country NAMES to target, e.g. ["United States", "Canada"]. Pass [] to clear (= all locations). - states: US state NAMES to target, e.g. ["Texas", "California"]. Pass [] to clear. States are US-only. - excluded_countries: country NAMES the campaign must NOT serve in. Pass [] to clear all exclusions. Names are matched case-insensitively against the platform's location catalog and common shorthand resolves ("USA", "UK", "UAE"). An unrecognised name is REJECTED rather than skipped — a silently dropped geo would serve the campaign somewhere nobody chose. At least one of the three lists must be given. WARNING: EXCLUSIONS ARE COUNTRY-LEVEL ONLY. The platform stores exclusions as bare location ids with no country/state discriminator, and state ids overlap country ids, so an excluded state would be read back as an unrelated country. The UI's Negative Locations picker is countries-only for the same reason. To narrow within a country, target the states you want via states instead of excluding the ones you don't. EXAMPLES: Target Canada and the UK on Google Ads (replacing the US default): set_search_channel_locations({ "campaign_id": 177214, "channel": "GOOGLE_ADS", "countries": ["Canada", "United Kingdom"] }) Target three US states only: set_search_channel_locations({ "campaign_id": 177214, "channel": "GOOGLE_ADS", "countries": ["United States"], "states": ["Texas", "California", "New York"] }) Keep targeting as-is but exclude two countries on Microsoft Ads: set_search_channel_locations({ "campaign_id": 177214, "channel": "MICROSOFT_ADS", "excluded_countries": ["India", "Pakistan"] }) RESPONSE: {success, campaign_id, channel_id, channel, applied:{locations?:{countries,states}, excluded_locations?:{countries}}, errors?} applied echoes the resolved location NAMES, so you can confirm back to the user what the campaign now targets. INTEGRATION WITH OTHER TOOLS: - Use search_campaigns_by_names / get_campaign_by_wizard_id to find the campaign. - create_campaign and add_and_edit_campaign_elements accept the same geo inline on their google / microsoft blocks — prefer that when creating, and use this tool to change geo on a campaign that alr…
stop_impersonation
ChatGPTSwitch back from a client account to your own default Metadata account. Reverses impersonate_account: subsequent tools operate on the caller's own account again. Safe to call even when not currently impersonating (no-op). Call it when the user is done working in the other account, or before switching to a different one.
unarchive_ad
ChatGPTUnarchive (restore) one or more previously archived ads. Brings an archived (soft-deleted) ad back to active status. The reverse of archive_ad. The ad's id, creative_json, and history are preserved across archive/unarchive — same row, status flip. USE THIS TOOL WHEN: - User asks to restore, unarchive, undelete, recover, reactivate, bring back, or undo the archiving of an ad. - User wants to reuse an ad they previously archived. HOW TO GET THE id(s) FOR ARCHIVED ADS: - Archived ads are NOT returned by search_ads_by_names by default (the default status="active" filters them out). - Call search_ads_by_names(ad_names=[...], status="archived") to get ONLY archived ads in the results, then pass the matching ids to this tool. Use status="all" if you also want active matches in the same response (rare; usually you want just "archived"). - get_ad_details(ids=...) works on archived ids too if you already have the id. ALSO KNOWN AS: unarchive ad, restore ad, undelete ad, recover ad, reactivate ad, bring back ad, undo archive. KEYWORDS: unarchive, restore, undelete, recover, reactivate, bring back, undo archive, revive, resurrect. PARAMETERS: - ids: Array of integer ad ids (at least one). Bulk-friendly. RETURNS: { "success": true, "unarchived_ids": [123, 456], "count": 2 }
unarchive_audience
ChatGPTUnarchive (restore) a previously archived custom audience on the Metadata platform. Use this tool when the user wants to unarchive, restore, or reactivate a custom audience. 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 unarchiving. PARAMETERS: • custom_audience_id (optional): The numeric ID of the custom audience to unarchive. • audience_name (optional): The name of the custom audience to unarchive. 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 unarchived successfully.
update_brand_kit
ChatGPTUpdate existing brand kit with brand DNA parameters. Only company_url is required; all others are optional. UPDATABLE FIELDS (grouped by section): TOP-LEVEL: - long_description: Company marketing description - logo_url / logo_urls: Direct URL(s) to logo images (permanent override; super-user only) - clear_logos: true removes the permanent logo override (super-user only) - search_keywords: List of SEO/search keywords - colors: Legacy flat color list [{hex, type, name?}] - fonts: Legacy flat font list [{name, type}] - website_background: Hex color of the brand website's background, used by generate_brand_creative as the default ad background COLOR PALETTES (each entry: {hex, name, usage}): - primary_colors, accent_colors, extended_palette, semantic_colors TYPOGRAPHY (string values): - primary_font, primary_font_usage, secondary_font, secondary_font_usage - headline_font, headline_weight, headline_size, headline_case, headline_linespace, headline_letterspace - eyebrow_font, eyebrow_weight, eyebrow_case, eyebrow_linespace, eyebrow_letterspace - subtitle_font, subtitle_weight, subtitle_linespace, subtitle_letterspace - body_font, body_weight, body_size, body_linespace, body_letterspace - cta_font, cta_weight, cta_size, cta_linespace, cta_letterspace LOGO USAGE: - logo_on_dark, logo_on_light, logo_clear_space: string rules - logo_misuse: list of misuse rules CTA SYSTEM: - button_shape, button_background, button_text_color, button_text_weight, button_text_case, button_padding - standard_ctas: list of CTA labels - cta_placement: placement guidance SIGNATURE ELEMENTS: - tagline, tagline_placement: strings - tagline_variants, visual_motifs, promotional_elements: lists MESSAGING: - tone: string - value_propositions, headline_formulas, proof_points: lists - product_names: dict (e.g. {platform: "X", vlm: "Y"}) CONTENT HIERARCHY: - content_hierarchy_order: list, content_hierarchy_spacing: string, content_hierarchy_text_max_width: string PHOTOGRAPHY: - photography_style, photography_treatment, photography_avoid: strings - photography_subjects: list RULES: - dos: list of "do" rules - donts: list of "don't" rules LAYOUT & CHANNELS: - primary_layouts: list of layout dicts - channel_linkedin, channel_facebook, channel_display: channel config dicts EXAMPLE: {"company_url": "ambient.ai", "tagline": "See what matters.", "headline_font": "Chakra Petch", "primary_colors": [{"hex": "#FFFFFF", "name": "White", "usage": "Primary background"}]}
update_experiment_end_date
ChatGPTMove the end date of ONE running Google Ads or Microsoft Ads experiment, leaving the campaign's other experiments as they are. KEYWORDS: experiment, end date, extend, shorten, schedule, stop date, run until WHEN TO USE: - User wants experiment X to run until a later or earlier date - User wants to change one experiment's end date without touching the rest of its campaign WHAT THE PLATFORM ALLOWS: - Google Ads and Microsoft Ads experiments that are running (Active): this tool. - A Completed experiment, any channel: manage_experiment(action="reactivate", end_date=...), which runs it again until that date. - A LinkedIn, Facebook, Instagram or Reddit experiment: the platform moves its end date only campaign-wide (add_and_edit_campaign_elements or add_and_edit_native_campaign_elements, which move every experiment of that campaign). This tool refuses them and changes nothing. - A Paused experiment: its end date moves only while it runs; restart it (manage_experiment) only if the user wants it running again. - Google Ads re-applies the experiment's saved countries and states with the date, so the tool refuses Performance Max, an experiment that excludes locations, and one with no saved countries or states. PARAMETERS: - experiment_id: experimentId from search_experiments - end_date: YYYY-MM-DD, today or later and within a year; the experiment runs through that day RESULT: status="submitted" means the change was sent: the channel applies it in the background, and search_experiments shows the new end date once the channel confirms. Say it was requested, not that it changed, until a read shows it. status="unchanged" means it already ended on that date and nothing was sent. success=false comes with an error that says why nothing was changed. WARNING: This changes the live schedule of the experiment on the ad channel.
update_experiments_daily_budgets
ChatGPTUpdate daily budget allocations for one or more experiments in the Metadata platform. KEYWORDS: experiment, budget, daily, update, change, adjust, spending, allocation, modify WHEN TO USE: - User wants to "change the daily budget for experiment X" - User asks to "adjust daily budget for experiments A, B, C" - User requests to "update experiment budgets" - User wants to "allocate more budget to experiment Y" - User asks to "set daily budget to X for multiple experiments" PURPOSE: This tool allows you to adjust the daily budget amount for active experiments. The daily budget controls how much money each experiment can spend per day. REQUIRED PARAMETERS: - budgets: A dictionary mapping experiment IDs to their new daily budget values BUDGET VALUE FORMAT: Budget values can be provided as: - Strings with comma separator (European format): "100,50" → 100.50 - Strings with dot separator (US format): "100.50" → 100.50 - Numbers: 100, 100.5, 100.50 - All values are automatically converted to 2 decimal places INPUT EXAMPLES: - Single experiment: {"budgets": {"12345": "100.50"}} - Multiple experiments: {"budgets": {"12345": 100.50, "12346": "150,75", "12347": 200}} INTEGRATION WITH OTHER TOOLS: - Use search_experiments to find the experiment IDs to update the daily budget.
update_linkedin_channel_settings
ChatGPTUpdate the LinkedIn channel settings of an existing DRAFT wizard campaign: native objective, bidding optimization goal (including Reach), bid strategy with manual bid amount, and the LinkedIn conversion actions the campaign optimizes toward. These are the settings the platform UI shows in the LinkedIn channel drawer of the campaign draft page (Native Objective, Bidding Optimization Goal, Bid, Conversion Actions). The campaign MUST already have its LinkedIn channel enabled (via create_campaign / add_and_edit_campaign_elements with a linkedin block). WARNING: DRAFT-ONLY: the platform rejects these edits once the campaign is Launching/Launched. KEYWORDS: linkedin, linkedin campaign, linkedin settings, campaign settings, draft campaign, objective, native objective, brand awareness, website visits, engagement, video views, bidding optimization goal, optimization goal, reach, impressions, landing page clicks, engagement clicks, bid, bid strategy, auto bid, manual bid, maximum delivery, conversion, conversions, conversion actions, conversion tracking, insight tag, settings WHEN TO USE: - Set the LinkedIn native objective (e.g. Brand Awareness instead of the default Engagement) - Optimize a Brand Awareness campaign for REACH instead of IMPRESSIONS - Switch between auto bid (LinkedIn maximum delivery) and a manual bid - Pick which LinkedIn conversion actions the campaign optimizes toward and reports on PARAMETERS (campaign_id required; everything else optional, and an unspecified setting keeps its current value on the channel): - campaign_id: the wizard campaign ID - objective: BRAND_AWARENESS | WEBSITE_VISIT | ENGAGEMENT | VIDEO_VIEW, the LinkedIn native objective. Only selectable on Brand Awareness (CTR) campaigns: a Lead Gen (CPL) campaign derives it from its offer at launch (lead-gen form -> LEAD_GENERATION, landing page -> WEBSITE_CONVERSION). The platform default for a new LinkedIn channel is ENGAGEMENT. Every ad already on the channel must be supported by the objective (VIDEO_VIEW is video-only, MESSAGE ads only fit WEBSITE_VISIT, DOCUMENT ads lock the objective, a video-only channel accepts only ENGAGEMENT or VIDEO_VIEW). A channel holding CTV ads is always Brand Awareness / Reach at launch and cannot be changed here. Changing the objective also resets the cost type and the bidding optimization goal to the objective's default (BRAND_AWARENESS -> IMPRESSIONS, WEBSITE_VISIT -> LANDING_PAGE_CLICKS, ENGAGEMENT -> ENGAGEMENT_CLICKS, VIDEO_VIEW -> VIDEO_VIEWS), so pass bidding_optimization_goal in the same call when you want something else. - bidding_optimization_goal: what LinkedIn optimizes delivery for. Allowed per objective: BRAND_AWARENESS -> IMPRESSIONS | REACH; WEBSITE_VISIT -> LANDING_PAGE_CLICKS | IMPRESSIONS; ENGAGEMENT -> ENGAGEMENT_CLICKS | IMPRESSIONS; VIDEO_VIEW -> VIDEO_VIEWS | IMPRESSIONS. Conversation and Message ads are always IMPRESSIONS. CTR campaigns only. - bid_strategy: AUTO_BID (LinkedIn "maximum delivery", what the campaign builder applies by default) or MANUAL_BID (needs bid_amount). CTV ads REQUIRE AUTO_BID; Spotlight and Text ads REQUIRE MANUAL_BID. - bid_amount: manual bid in the account currency, used only with MANUAL_BID. - conversion_action_ids: ids of LinkedIn conversion actions (from list_linkedin_conversions) the campaign should optimize toward and count as conversions: website visits, URL-rule page views, lead form fills. REPLACES the current selection; pass [] to clear it (the campaign then falls back to the account's default Insight Tag URL match). Every id must exist and be enabled on the connected LinkedIn account, or launch validation fails. NOTE: the platform UI only shows this picker for campaigns with landing-page offers and an objective other than Brand Awareness; ids stored outside that case are still sent to LinkedIn at launch, but that path is not exercised by the UI. NOT SETTABLE ANYWHERE IN THE PLATFORM (say so instead of promising them): LinkedIn Audience Network on/off and its category exclusions, audience expansion (campaigns always launch with expansion OFF), frequency cap…
update_meta_placements
ChatGPTSet the channel-level Meta placement default of an existing DRAFT wizard campaign's Facebook or Instagram channel: automatic placements (Meta decides where ads serve) or a manual list of surfaces (Feed, Stories, Reels, ...). Placements are where the ads serve inside Meta's networks. This is the same "Placements" control the platform UI shows in the Facebook/Instagram section of the campaign draft page. The campaign MUST already have the channel enabled (via create_campaign / add_and_edit_campaign_elements). WARNING: DRAFT-ONLY: the platform rejects the edit once the campaign is Launching/Launched. KEYWORDS: meta, facebook, instagram, threads, placements, placement, feed, stories, reels, explore, search results, profile feed, automatic placements, manual placements, advantage+ placements, where ads serve, surfaces, channel settings, campaign settings WHEN TO USE: - Serve ads only on specific surfaces (e.g. Instagram Reels and Stories) - Switch a channel back to automatic placements (Meta optimizes delivery) - The user asks where their Facebook/Instagram ads will appear PARAMETERS: - campaign_id: the wizard campaign ID (required) - channel: FACEBOOK | INSTAGRAM (required — the campaign channel to edit) - mode: AUTO | MANUAL (required). AUTO = automatic placements, clears any manual set. MANUAL = serve only on the placements listed. - placements: array of placement codes, required when mode=MANUAL, ignored for AUTO. Facebook surfaces: FB_FEED, FB_STORIES, FB_REELS, FB_SEARCH_RESULTS. Instagram surfaces: IG_FEED, IG_PROFILE_FEED, IG_EXPLORE, IG_EXPLORE_HOME, IG_STORIES, IG_REELS, IG_SEARCH_RESULTS. Threads: TH_THREADS_STREAM. PLACEMENT RULES (enforced; violations return a descriptive error): - Companion rules: FB_STORIES and FB_SEARCH_RESULTS require FB_FEED; IG_PROFILE_FEED, IG_SEARCH_RESULTS and IG_EXPLORE require IG_FEED; IG_EXPLORE_HOME requires IG_EXPLORE; TH_THREADS_STREAM requires IG_FEED. - An INSTAGRAM channel accepts IG_ placements only. - A FACEBOOK channel always accepts FB_ placements. IG_ / TH_ placements on a FACEBOOK channel additionally need the account's unified-placement rollout (feature flag CORE_META_IG_PLACEMENT_ON_FB) — the platform rejects them on accounts without it. - IG_PROFILE_FEED is not available on Lead Gen (CPL) campaigns. - AUTO is rejected while the channel has ad groups (per-ad-group setups keep manual placements). This tool sets the campaign-wide default for the channel. Per-ad-group placement overrides exist in the platform UI but are not editable through chat yet — send users to the campaign page for per-ad-group customization. EXAMPLES: Instagram channel, Reels + Stories + Feed only: update_meta_placements({"campaign_id": 12345, "channel": "INSTAGRAM", "mode": "MANUAL", "placements": ["IG_FEED", "IG_STORIES", "IG_REELS"]}) Facebook channel back to automatic placements: update_meta_placements({"campaign_id": 12345, "channel": "FACEBOOK", "mode": "AUTO"}) RESPONSE: {success, campaign_id, channel_id, channel, campaign_status, applied:{mode, placements}, previous?, errors?} previous echoes the channel's placement state before the edit. INTEGRATION WITH OTHER TOOLS: - Use search_campaigns_by_names / get_campaign_by_wizard_id to find the campaign - The channel is enabled by create_campaign or add_and_edit_campaign_elements - Reddit placements (feed/conversations) are a different system: use update_reddit_channel_settings for those
update_reddit_channel_settings
ChatGPTUpdate the Reddit channel settings of an existing DRAFT wizard campaign: native objective, allow comments, placements (feed/conversations), conversion pixel, and (for manual-bid objectives) the bid amount. These are the same settings the platform UI shows in the Reddit section of the campaign draft page. The campaign MUST already have its Reddit channel enabled (via create_campaign / add_and_edit_campaign_elements with a reddit block). WARNING: DRAFT-ONLY: the platform rejects these edits once the campaign is Launching/Launched. KEYWORDS: reddit, reddit campaign, reddit settings, campaign settings, draft campaign, objective, native objective, traffic, brand awareness, reach, views, video views, video views 6s, impressions, clicks, comments, allow comments, placements, placement, feed, conversations, pixel, conversion pixel, conversion tracking, bid, bid amount, manual bid, auto bid, settings WHEN TO USE: - Change the Reddit objective (e.g. from Brand Awareness to Traffic) - Toggle "Allow comments" on Reddit ads - Select placements (Feed and/or Conversations) - Attach or clear a Reddit conversion pixel - Set a manual bid amount for Brand Awareness / Video Views objectives PARAMETERS (campaign_id required; everything else optional — unspecified settings keep their current values on the channel): - campaign_id: the wizard campaign ID - objective: IMPRESSIONS (Brand awareness and Reach) | CLICKS (Traffic) | VIDEO_VIEWABLE_IMPRESSIONS_6S (Video Views 6s). Mirrors the platform UI's Native Objective dropdown. WARNING: Lead Gen (CPL) campaigns only accept CLICKS (landing pages require it). WARNING: Video Views requires the channel to contain ONLY video ads. - allow_comments: whether Redditors can comment on the promoted post (platform default: true) - placements: {"feed": bool, "conversations": bool}. At least one must stay selected (Feed wins if both are false). Conversations is forced OFF when the channel has video ads. - conversion_pixel_id: pixel id from the account's Reddit Ads Manager. Pass an empty string "" to clear. Pixels are managed in Reddit Ads Manager, not here. - bid_amount: manual bid amount. Only applied when the effective objective uses MANUAL_BID (IMPRESSIONS / Video Views). Ignored for CLICKS (AUTO_BID). BID STRATEGY (automatic): changing the objective re-applies the UI's auto-switch — CLICKS → AUTO_BID; IMPRESSIONS / VIDEO_VIEWABLE_IMPRESSIONS_6S → MANUAL_BID. The bid strategy is left untouched when neither objective nor bid_amount is sent. EXAMPLES: Switch a Brand Awareness campaign's Reddit channel to Traffic: update_reddit_channel_settings({"campaign_id": 12345, "objective": "CLICKS"}) Disable comments and run Feed-only: update_reddit_channel_settings({ "campaign_id": 12345, "allow_comments": false, "placements": {"feed": true, "conversations": false} }) Brand awareness with a manual bid and a conversion pixel: update_reddit_channel_settings({ "campaign_id": 12345, "objective": "IMPRESSIONS", "bid_amount": 1.5, "conversion_pixel_id": "pixel_abc123" }) RESPONSE: {success, campaign_id, channel_id, campaign_status, applied:{...}, errors?} applied echoes exactly what was pushed to the platform. INTEGRATION WITH OTHER TOOLS: - Use search_campaigns_by_names / get_campaign_by_wizard_id to find the campaign - Reddit channel is enabled by create_campaign or add_and_edit_campaign_elements - Reddit ads come from create_update_image_ad / create_update_video_ad with channels=["REDDIT"]
update_target_group
ChatGPTUpdate existing target group with new name and/or targeting criteria. Supports BOTH include AND exclude rules — including adding/removing exclude audiences. CRITICAL - PUT REQUEST: You MUST provide ALL fields, not just changed ones. - 'name' is ALWAYS REQUIRED even if not changing - If updating targeting, provide complete targeting object (full include + exclude) - Always retrieve current config first via retrieve_target_group_by_id and merge changes onto it PREREQUISITE WORKFLOW: 1. list_target_groups(name="X") → get ID 2. retrieve_target_group_by_id(target_group_id=ID) → get current config, check isModifiable fields, copy existing exclude audiences 3. search_target_group_criteria → get new criteria IDs 4. estimate_target_group → MANDATORY: verify isMatchCountTooSmall=false 5. update_target_group with ID and ALL required fields (full targeting object) MODIFIABILITY: Name always modifiable. LOCATION usually isModifiable=false. Check retrieve_target_group_by_id response for other fields. TARGETING STRUCTURE: Same as create_target_group — full include array + single exclude object containing both criteria and audiences. See create_target_group description for the full example payload (with NATIVE_LOCATION, AGE, COMPANY_NAME exclude criteria, and FIRMOGRAPHIC_EXCLUDE audience). Only update criteria with isModifiable=true. 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. ADDING/REMOVING EXCLUDE AUDIENCES: Provide the COMPLETE desired exclude.audiences array. Each entry needs: mdAudienceId (integer, REQUIRED — the numeric Custom Audience id like 49067 from get_matched_audiences, its customAudienceId / mdAudienceId field, NEVER that row's id, NEVER the audience name string, NEVER a placeholder like 1/2/3/4 (rejected pre-flight), and NEVER a Target Group id from list_target_groups; see the AUDIENCES ≠ TARGET GROUPS note above), name, type (EXCLUDE variant like FIRMOGRAPHIC_EXCLUDE/RETARGETING_EXCLUDE/CONTACT_LIST_EXCLUDE), matchCount, matchCountType, inactive, and the audience's own criteria array. To remove an exclusion, omit it from the array. To add one, append it. RESPONSE: {id, name, channel, audienceSize, status, modifiedDate, targeting} VALIDATION: Must estimate first and verify isMatchCountTooSmall=false before updating.
upload_account_list_csv_audience
ChatGPTUpload a list of company ACCOUNTS (name + website) as an Account List CSV and create a FIRMOGRAPHIC_INCLUDE audience on the Metadata platform, optionally overlaid with platform-side contacts criteria. AUDIENCE TYPE: Account List CSV / CSV Upload - Accounts (platform stores customAudienceType=FIRMOGRAPHIC_INCLUDE; the main UI's audience-map renders this enum as "CSV Upload - Accounts"). This tool is ONLY for company/account-level data (company names and websites). Do NOT use this tool for contact-level data (emails, phone numbers, individual people). For contacts, use upload_contact_list_csv_audience instead. TWO WAYS TO SUPPLY THE ACCOUNT LIST — provide EXACTLY ONE of: • companies: an inline JSON object map { "<companyname>": "<companywebsite>", ... }. Use this for short ad-hoc lists you have already parsed into context. • companies_source_csv_url: a public URL of a CSV file with header EXACTLY companyname,companywebsite (case-insensitive, whitespace-trimmed). Use this WHENEVER THE USER ATTACHED A CSV to the chat — the URL is surfaced to you via AudienceBrief.attached_file_urls; pass it through verbatim. The MCP server downloads + validates + parses the CSV so a multi-megabyte file never has to travel through your context. If both are provided, or neither, the tool errors with a clear message — pick one. OPTIONAL CONTACTS CRITERIA: layer per-contact filters on top of the account list, matching the same shape create_firmographic_audience uses: • location_country_ids / location_state_ids — geography • job_title_includes / job_title_excludes — free-text title keywords • job_function_include_ids / job_function_exclude_ids • seniority_include_ids / seniority_exclude_ids • contacts_per_company_limit When set, the resulting audience matches only contacts inside the listed companies that ALSO satisfy these filters — e.g. "this 1,999-account list, but only VP/Director/Manager Engineering contacts in Canada + Saint Pierre and Miquelon + United States" becomes a single call. When all of these are omitted, every contact in every uploaded company is matched. WHEN TO USE: - "Upload these companies/accounts as an audience" / "Create an account list audience" / "Upload account list CSV" - "Create a CSV Upload - Accounts audience with this CSV and these contact filters" - The user attached a CSV of companies (company name + website) and asked for a CSV-Upload audience WHEN NOT TO USE: - When the data is contact-level (emails, phone numbers, individual people) — use upload_contact_list_csv_audience. - For pure firmographic targeting without an attached account list — use create_firmographic_audience. INLINE-MAP DATA MAPPING RULES (when you choose the companies path): - Each KEY must be the company name; each VALUE must be the company website URL. - Format: { "<companyname>": "<companywebsite>", ... } - Example: { "Acme Corp": "https://acme.com", "Globex International": "https://globex.com", "Salesforce": "https://salesforce.com" } - DO NOT pass column headers as keys; DO NOT reverse the mapping; DO NOT send raw file paths or bytes. CSV-URL HEADER RULES (when you choose the companies_source_csv_url path): - The first row of the CSV MUST be exactly companyname,companywebsite (case-insensitive — Company Name,Website is rejected; rename the columns first or fall back to the inline map path). - Rows with an empty company name are dropped server-side. - The server enforces a 50 MB cap on the downloaded file. PARAMETERS: - audience_name (required) - companies (optional, mutually exclusive with companies_source_csv_url) - companies_source_csv_url (optional, mutually exclusive with companies) - location_country_ids / location_state_ids (optional contacts criteria) - job_title_includes / job_title_excludes (optional) - job_function_include_ids / job_function_exclude_ids (optional) - seniority_include_ids / seniority_exclude_ids (optional) - contacts_per_company_limit (optional) RETURNS: - success, id / audience_id, audience_name, audience_type (FIRMOGRAPHIC_INCLUDE), file_id, companies_count, uplo…
upload_contact_list_csv_audience
ChatGPTUpload a list of individual CONTACTS (people) as a Contact List CSV and create a CONTACT_LIST audience on the Metadata platform. ALSO KNOWN AS: "CSV Upload - Contacts", "Contacts List", "Contact List CSV", "CSV Contacts audience", "CSV Upload - Contacts List Audience". AUDIENCE TYPE: Contact List / CSV Upload - Contacts. This tool is ONLY for contact/people-level data (email, first name, last name, job title, etc.). Do NOT use this tool for company/account-level data (company names and websites) — use upload_account_list_csv_audience instead. This tool performs a two-step process: 1. Generates a Contact List CSV file from the provided contact data and uploads it. 2. Creates a CONTACT_LIST audience using the uploaded contact list file. WHEN TO USE: - "Create a CSV Upload - Contacts with the list" - "CSV Upload - Contacts" - "Create a contacts list audience" - "Upload these contacts as an audience" - "Create a contact list audience from these people" - "I have a list of emails and names, create an audience" - "Build a contact list audience" - "Upload contact list CSV" - When the data contains people-level fields: email, first name, last name, job title, company, country WHEN NOT TO USE: - When the user wants to upload company accounts (company name + website) — use upload_account_list_csv_audience. - When the data is account/company-level, not contact/people-level. WORKFLOW: 1. Provide the audience name and an array of contact objects. 2. The tool generates a CSV with the header: email,firstname,lastname,jobtitle,employeecompany,country,appleidfa,googleaid 3. Uploads the CSV, then creates the CONTACT_LIST audience. CRITICAL — DATA MAPPING RULES (READ CAREFULLY BEFORE CALLING THIS TOOL): The "contacts" parameter is a JSON array of objects. Each object represents one contact/person and MUST use these exact field names: - "email" → The contact's email address (REQUIRED per contact) - "firstname" → The contact's first name - "lastname" → The contact's last name - "jobtitle" → The contact's job title / role - "employeecompany" → The company the contact works at - "country" → The contact's country - "appleidfa" → Apple IDFA (advertising identifier), optional - "googleaid" → Google Advertising ID, optional Example: [ { "email": "jane@metadata.io", "firstname": "Jane", "lastname": "Johnson", "jobtitle": "Marketing Manager", "employeecompany": "Metadata.io", "country": "United States", "appleidfa": "EA7583CD-A667-48BC-B806-42ECB2B48606", "googleaid": "" }, { "email": "john@metadata.io", "firstname": "John", "lastname": "Johnson", "jobtitle": "Marketing Manager", "employeecompany": "Metadata.io", "country": "United States", "appleidfa": "", "googleaid": "cdda802e-fb9c-47ad-9866-0794d394c912" } ] IF THE USER PROVIDES A FILE (CSV, XLSX, spreadsheet, or any tabular data): 1. You MUST first read and inspect the file contents. 2. Identify which columns map to: email, firstname, lastname, jobtitle, employeecompany, country, appleidfa, googleaid. - The columns may NOT be literally named as above. They could be named: "Email Address", "E-mail", "First Name", "First", "Last Name", "Surname", "Job Title", "Title", "Role", "Position", "Company", "Organization", "Employer", "Country", "Location", "Apple IDFA", "IDFA", "Google AID", "GAID", or any variation. - Use your best judgment to map the correct columns to the expected field names. - If ambiguous, ask the user to clarify which column maps to which field. 3. Extract every row from the file and build the contacts array yourself, mapping each column value to the correct field name. 4. Do NOT pass raw file contents, column headers, or file paths — always transform into the array-of-objects format described above. 5. Skip rows where email is empty/missing (email is the minimum required field per contact). 6. For any field not present in the source data, omit it or pass an empty string. 7. If the file has no identifiable email column, ask the user which column contains emails. DO NOT: - Use the source file's column names as field names — always normalize to: email, firstname, lastname, jobtitle,…
upload_document_creative
ChatGPTUpload PDF documents to the Metadata platform library so they can be promoted as LinkedIn Document Ads. Downloads each PDF from its URL and uploads it to the platform library as a DOCUMENT asset. WARNING: PDF-ONLY: the downloaded file MUST have the application/pdf content-type and be at most 100 MB (platform limits for document assets). Images go through upload_image_creative, videos through upload_video_creative. WARNING: WHEN YOU NEED TO CALL THIS: Call this BEFORE create_update_document_ad ONLY when the document is not in the library yet. If search_library_creatives_by_name(contentTypes="DOCUMENT") already finds it, pass that id straight to create_update_document_ad as libraryId. WORKFLOW INTEGRATION (when an upload IS needed): 1. Upload the PDF URL with this tool -> response contains the integer id (the library id). 2. Pass that integer id as libraryId in create_update_document_ad. REQUIRED PARAMETERS: - documents: Array of publicly accessible PDF URLs. OPTIONAL PARAMETERS: - names: Library label per document, positional against documents. Defaults to the file name from the URL. Use the document's real title ("2026 B2B Benchmark Report") so the library stays readable. RESPONSE FORMAT: Returns array of objects, one per document. id is returned as a string; pass it to create_update_document_ad as an integer. [ {"url": "https://example.com/report.pdf", "name": "2026 B2B Benchmark Report", "id": "15791", "success": true}, {"url": "https://example.com/bad.pdf", "name": "bad.pdf", "id": null, "success": false, "error": "..."} ] ERROR HANDLING: - If one upload fails, others continue. - A content-type other than application/pdf is rejected with a clear error.
upload_image_creative
ChatGPTUpload images directly to Metadata platform library to create image creatives. Downloads images from provided URLs and uploads them to the platform. REQUIRED STEP IN AD CREATION WORKFLOW: This tool MUST be called between generate_brand_creative and create_update_image_ad. WORKFLOW INTEGRATION: This tool is part of the ad creation workflow and should be used: 1. BEFORE creating ads with create_update_image_ad (which requires imageLibraryId/creativeID) 2. IN COMBINATION with generate_brand_creative to create AI-generated images first, then upload them 3. When you need to upload existing images from external sources COMMON WORKFLOWS: - Upload existing images → Get imageLibraryId → Use in create_update_image_ad - Generate image with generate_brand_creative → Download generated image → Upload with this tool → Use in create_update_image_ad - Batch upload multiple creative assets for campaign preparation IMPORTANT: The returned image ID (imageLibraryId/creativeID) is REQUIRED when creating ads. Every ad needs a creative asset, so you must upload images first before calling create_update_image_ad. REQUIRED PARAMETERS: - images: Array of image URLs to upload IMAGE REQUIREMENTS: - URLs must be valid and publicly accessible - Supported formats: PNG, JPG, JPEG, GIF, WebP, and others - Images will be downloaded and then uploaded to platform - Filenames with spaces will have spaces replaced with underscores EXAMPLES: Single Image: upload_image([ "https://my-bucket.s3.amazonaws.com/images/sample-image.png" ]) Multiple Images: upload_image([ "https://my-bucket.s3.amazonaws.com/images/logo.png", "https://example-assets.s3.us-west-2.amazonaws.com/photos/banner.jpg", "https://content-bucket.s3.eu-west-1.amazonaws.com/uploads/hero image.webp" ]) RESPONSE FORMAT: Returns array of objects for each image: [ { "url": "https://original-url.com/image.png", "name": "image.png", "id": 12345, "success": true }, { "url": "https://failed-url.com/bad.png", "name": "bad.png", "id": null, "success": false, "error": "Download failed: Connection timeout" } ] ERROR HANDLING: - If one upload fails, others will continue - Each result includes success status - Failed uploads include error message - Successful uploads include platform image ID USE CASES: - Upload creative assets before creating ads - Import images from external sources - Batch upload multiple campaign images - Migrate images from other platforms
upload_video_creative
ChatGPTUpload videos directly to the Metadata platform library to create video creatives. Downloads videos from provided URLs and uploads them to the platform. WARNING: VIDEO-ONLY: The downloaded file MUST have a video/* content-type (e.g. video/mp4, video/quicktime). GIFs and image formats are rejected — use upload_image_creative for those. WARNING: WHEN YOU NEED TO CALL THIS: Call this BEFORE create_update_video_ad ONLY when you don't already have a videoLibraryId. If the user (or an earlier step) has already given you a creativeID for the video, skip the upload and pass that id straight to create_update_video_ad. WORKFLOW INTEGRATION (when an upload IS needed): 1. Upload your video URL with this tool → response contains the integer id (the videoLibraryId). 2. Pass that integer id as creativeID in create_update_video_ad. COMMON WORKFLOWS: - Upload existing video → Get videoLibraryId → Use as creativeID in create_update_video_ad. - For Reddit VIDEO ads, ALSO upload a thumbnail image via upload_image_creative and pass that image library id as redditThumbnailLibraryId to create_update_video_ad. REQUIRED PARAMETERS: - videos: Array of video URLs to upload. OPTIONAL PARAMETERS: - thumbnail_library_id: Existing imageLibraryId to attach to the uploaded video as its platform thumbnail. Most callers don't need this — Reddit VIDEO ads handle thumbnails at ad-creation time via redditThumbnailLibraryId, not here. - usage_type: "CTV" to upload the video for a LinkedIn CTV (Connected TV) ad. The platform then validates the file as CTV inventory (6 to 60 seconds, 1920x1080 or 1280x720, at most 500 MB; LinkedIn recommends exactly 15, 30, 45 or 60 seconds) and only such an upload can back create_update_ctv_ad. A non-compliant file is rejected at upload with the platform's reason. Omit for in-feed video ads. VIDEO REQUIREMENTS: - URLs must be valid and publicly accessible. - Supported formats: MP4 (recommended), MOV, and other video/* MIME types. - For GIFs (image/gif): use upload_image_creative instead. RESPONSE FORMAT: Returns array of objects, one per video. id is returned as a string (the platform's library ids are integers but the upload response stringifies them); pass it to create_update_video_ad as an integer (Python int(id) if you need the cast). [ { "url": "https://example.com/video.mp4", "name": "video.mp4", "id": "12345", videoLibraryId — use as creativeID in create_update_video_ad "success": true }, { "url": "https://example.com/bad.mp4", "name": "bad.mp4", "id": null, "success": false, "error": "Download failed: Connection timeout" } ] CHANNEL READINESS: success and id mean the platform library accepted the file. Meta uploads are asynchronous and may still be UPLOADING. Use fetch_creative_details to read per-channel status; a Facebook or Instagram VIDEO ad must wait until that channel is READY. ERROR HANDLING: - If one upload fails, others continue. - Each result includes a success flag and (on failure) an error message. - A content-type that does not start with video/ is rejected with a clear error pointing the caller at upload_image_creative.
website_engagement_stats
ChatGPTWebsite visitor engagement metrics: session data, page views, visitor behavior analytics. USE FOR: Website traffic/engagement, visitor behavior analysis, session/page view metrics, website conversion funnel, engagement trends, website performance by period. NOT FOR: Campaign ad performance (use experiment_performance_stats), account list performance (use account_list_performance), budget groups (use budget_group_performance), geographic demographics (use demographic_country_stats). TIMEFRAMES: YESTERDAY, LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, LAST_MONTH, MONTH_TO_DATE (default), LIFETIME METRICS: sessions, uniqueVisitors, newVisitors, returningVisitors | pageViews, pagesPerSession, avgSessionDuration | bounceRate, exitRate, timeOnPage | conversions, conversionRate, goals REQUIRED: Valid timeframe must be specified. Default: MONTH_TO_DATE if ambiguous.