Meta Ads connects AI agents to Facebook and Instagram advertising accounts to analyze campaign performance, create and edit campaigns, ad sets and creatives, manage custom audiences and product catalogs, inspect conversion tracking signals, run A/B tests, and investigate advertising issues.
Encrypted at rest, isolated from the model
Resolved from an AES-256-GCM vault at the moment of the call and attached to the request — the model never sees the secrets.
Try asking
Fetches activity log entries for an ad account, showing changes to campaigns, ad sets, ads, and other ad objects. Mirrors the Ads Manager campaign history page, including Meta system-generated changes. ## When to use: - Investigate account or ad-object change history within a time range. - Find who changed budgets, status, targeting, or creatives. ## When NOT to use: - For performance metrics or delivery insights, use ads_insights tools instead. - For error diagnostics, use ads_get_errors instead. ## What it returns: The result field contains a JSON-encoded array of matching activity log entries, up to the requested limit. Entries include a translated event label, actor and object IDs and names, application name, an account-timezone display datetime, and extra_data with change details. An empty array means no matching entries. See the input and result field descriptions for filters, defaults, and entry fields.
Activates a campaign, ad set, or ad by changing its status from PAUSED to ACTIVE, effectively publishing the entity. ## When to use: - Call this tool ONLY after the user has explicitly confirmed they want to publish/activate. - Use after the user has reviewed the entity via ads_create_campaign or ads_update_entity. - Supports entity_type values: "campaign", "ad_set", or "ad". ## When NOT to use: - Do NOT call without explicit user confirmation to publish. - Do NOT use for pausing active entities. Use ads_update_entity with fields={"status":"PAUSED"} instead. When that update returns is_draft=false, the pause was sent to the live object: do NOT call this tool to commit or verify it, even if the entity has other staged edits. This tool can undo the pause or publish unrelated changes; verify with ads_get_ad_entities instead. ## Status Hierarchy: - Activating a parent does NOT automatically activate its children. Each live entity is activated individually. Objects staged in a draft are not: read the account's draft objects to collect the campaign, ad set and ad ids, pass them together in object_ids, and the whole set publishes in one call. - For ads to deliver, ALL levels in the hierarchy must be ACTIVE (campaign, ad set, and ad) — including an ad published from a draft whose parents were already live. - Activating a child entity while its parent is paused will succeed, but the child will NOT deliver until the parent is also activated. - After creating a full campaign structure of live entities, activate from top to bottom: campaign first, then ad set, then ad. ## Response Guidelines: 1. For live entities, when verification_hint is present, follow it to read back the configured and effective status with ads_get_ad_entities before confirming activation. Configured ACTIVE alone does not prove delivery. 2. A PUBLISHING status means only that the objects cleared the checks this call runs and were handed to the publisher, which finishes afterwards. The publisher applies further checks of its own and can still reject an object; this tool is not told when that happens. Report PUBLISHING as handed off, never as published or live. When verification_hint is present, follow it to immediately poll ads_get_ad_entities for the affected draft and live objects. Confirm only changes observed in live read-back; disappearance from the draft alone is not proof. If still unverified, report pending or unavailable and offer Ads Manager as a fallback. 3. If the call is rejected for validation errors, the message lists the offending campaign, ad set, or ad and its errors. Nothing was published. Relay the errors, fix them with ads_update_entity, then activate again. If the user would rather publish the rest now, call again with ignore_validation_errors=true; the broken objects stay behind in the draft. 4. Provide the entity ID, entity type, and new status. 5. If activating a child entity, remind the user that all parent entities must also be active for ads to deliver. ## CRITICAL: - This action makes the entity live and will start spending budget. - Always get explicit user confirmation before calling this tool. ## POTENTIAL NEXT STEP — RECOMMEND OPPORTUNITY SCORE: After a successful activation, suggest calling `ads_get_opportunity_score` to check the account's optimization status and get personalized recommendations from Meta to maximize ad performance while spending is active. ## Draft mode: Draft mode is enabled for you, so the objects created via ads_create_campaign/ads_create_ad_set/ads_create_ad are staged in a draft and are NOT live yet. Publish by listing the exact objects in object_ids: everything listed is published together and nothing else is touched. Edited one ad under an already-live ad set? List that ad alone, with entity_id and entity_type naming that same ad — publishing its campaign instead would also ship every other change staged under that campaign. Built a whole campaign? List the campaign, its ad sets and its ads. List a parent only when that parent is itself still unpublished. Do not work the ids out yourself: call ads_get_ad_entities with object_state=draft, scoped by putting the object you care about in object_ids, and pass back the ad_object_id of everything it returns that you want live. The call tells you if an object has nothing staged. ONLY IF you omit object_ids: a newly-created draft child still depends on its unpublished parent, so call on the campaign (entity_type=campaign). A staged edit to an already-live campaign, ad set or ad can be published directly. Publishing applies the staged edits and nothing more, so an already-live object that is paused stays paused: set publish_as_active=true when the user asked to activate, turn on, or make the target named by entity_id live, and leave it false when they asked only to publish or apply their changes (including a staged pause). If the result carries publish_as_active_applied=false, the target was published as staged without forcing it ACTIVE: do not claim that the activation request was applied. Everything being published is validated first: if any object has a validation error the call is rejected, nothing is published, and the error names the object to fix. Relay those errors and offer to fix them; if the user instead wants the rest to go live now, call again with ignore_validation_errors=true and the broken objects are left behind. Otherwise the call returns PUBLISHING, which means the objects were handed to the publisher and it finishes afterwards. The publisher runs further checks these ones do not cover and can still reject an object; this call does not report that outcome, so do not say an object is live. When verification_hint is present, follow it to poll ads_get_ad_entities for the affected draft and live objects immediately; confirm only changes observed in live read-back. Use Ads Manager as a fallback when verification is unavailable.
Creates an Instagram ad from an existing IG post. Supports a plan/confirm two-step flow. Required: ad_account_id, ig_account_id, and ig_media_id unless another field already identifies the post. That is enough for a simple profile boost; other goals can require a promoted_object naming a page, pixel, conversion, or application. For full control, override campaign (L3), ad set (L2), or ad (L1) fields using compatible combinations. ## When to use: - Call with confirmed=false FIRST to get a plan showing all resolved settings. - Call with confirmed=true ONLY after the user has reviewed and approved the plan. - For an ordinary boost, use after ads_get_ig_accounts and ads_get_ig_media to get the required IDs. ## When NOT to use: - Do NOT call with confirmed=true without first showing the user the plan. - Do NOT use for creating regular (non-IG-boost) ad campaigns — use ads_create_campaign instead. ## Response Guidelines: 1. In plan mode: Show all resolved settings across L3/L2/L1, including defaults. 2. In creation mode: Return all created entity IDs and confirm PAUSED state. 3. Remind user they can activate with ads_activate_entity when ready. ## Call to action: - Use call_to_action_type plus the optional call_to_action_value object. Don't use call_to_action field; it's deprecated. - Website CTAs (LEARN_MORE, SHOP_NOW, WATCH_MORE, CONTACT_US, BOOK_NOW, SIGN_UP, SEE_DETAILS) need call_to_action_value.link. - VIEW_INSTAGRAM_PROFILE links to the boosting account's profile automatically. - Messaging CTAs build their destination automatically and need the matching destination_type: INSTAGRAM_MESSAGE with INSTAGRAM_DIRECT, WHATSAPP_MESSAGE with WHATSAPP (the account must have a linked WhatsApp Business number), MESSAGE_PAGE with MESSENGER. - Without call_to_action_type the ad uses VIEW_INSTAGRAM_PROFILE, even when destination_type is a messaging destination. Pass the matching messaging CTA to get a message button. - To learn more about Instagram ad goals and their CTAs, see https://www.facebook.com/business/help/1058474831011088. - For every call to action type Meta supports, see https://www.facebook.com/business/help/410873986524407. This tool accepts only the call_to_action_type enum values. ## CRITICAL: - All entities are created in PAUSED state. Budget is NOT spent until activated. - Always show the plan first and get explicit user confirmation before creating. - The ig_account_id must be linked to the ad_account_id and the app must have `instagram_basic` permission for it. Use ads_get_ig_accounts to find eligible accounts. - Defaults: roughly the $5 USD/day-equivalent in the ad account's local currency for 6 days, OUTCOME_TRAFFIC objective, INSTAGRAM_PROFILE destination, US targeting, IMPRESSIONS billing, LOWEST_COST_WITHOUT_CAP bidding. - All budget amounts are in the smallest unit of the ad account's currency (e.g. cents for USD, whole yen for JPY). The plan output includes a `currency` field — present budgets in that currency, never assume USD. - A campaign budget (campaign_daily_budget or campaign_lifetime_budget) moves budget and bidding to the campaign: do not also send daily_budget, lifetime_budget, bid_strategy, or bid_amount, and use campaign_bid_strategy for bidding. - The ad must run for at least 24 hours and at most 365 days. ## Objective, destination, and performance goal: - Profile visits: OUTCOME_TRAFFIC + INSTAGRAM_PROFILE + VISIT_INSTAGRAM_PROFILE. - Reach: OUTCOME_AWARENESS + UNDEFINED + REACH (or IMPRESSIONS). - Post engagement: OUTCOME_ENGAGEMENT + ON_POST + POST_ENGAGEMENT. - Video views: OUTCOME_ENGAGEMENT + ON_VIDEO + THRUPLAY. - An omitted destination_type or optimization_goal defaults from the objective: OUTCOME_TRAFFIC uses INSTAGRAM_PROFILE + VISIT_INSTAGRAM_PROFILE (WEBSITE + LINK_CLICKS for a website destination or goal); OUTCOME_ENGAGEMENT uses ON_POST + POST_ENGAGEMENT (ON_VIDEO for video-view goals); OUTCOME_AWARENESS uses UNDEFINED + REACH; OUTCOME_LEADS and OUTCOME_SALES use WEBSITE + OFFSITE_CONVERSIONS; OUTCOME_APP_PROMOTION uses APP + APP_INSTALLS. A destination_type given without a goal gets that destination's usual goal, else the objective's default when the destination allows it, else the one goal the destination allows for the account, for example PROFILE_AND_PAGE_ENGAGEMENT (or LINK_CLICKS) for engagement on INSTAGRAM_PROFILE, LEAD_GENERATION for leads on MESSENGER, and QUALITY_CALL on PHONE_CALL; only when none of these applies does the error list the valid goals. A goal the default destination cannot take, such as a messaging or profile goal, needs an explicit destination_type. Values you provide must be compatible with each other. Account and media eligibility also apply. - ON_AD is a lead-form destination, not a destination for post engagement or video views. FACEBOOK is not a supported destination for this tool. - Promoted-object prerequisites are checked during planning. When a page is required and can be resolved from the linked Instagram account, the plan includes it. Otherwise supply the required promoted_object fields before confirming. ## Partnership Ads (branded content): - A Partnership Ad promotes a post authored by a *creator* on behalf of a brand. ig_account_id remains the advertiser's linked brand IG account used for ad creation and the brand-side permission check, while ig_media_id identifies the creator-owned post. Creator media may not appear in ads_get_ig_media for the advertiser's account. - When verification succeeds, the Partnership Ad displays the creator as its primary identity and credits the advertiser's brand as sponsor. - Pass the creator-owned post as ig_media_id, or pass ad_code when the creator issued a per-post code. An ad_code identifies the post by itself, so ig_media_id is not needed with it. - Do NOT pass sponsor_id or ad_code to boost a post the advertiser authored themselves — that is an ordinary boost. - For an Instagram profile-visit Partnership Ad, planning selects optimization_goal=PROFILE_VISIT when the account and connection are eligible. VISIT_INSTAGRAM_PROFILE does not show partnership controls in Ads Manager and is rejected for this PA flow. Review a new confirmed=false plan before creating and resend its exact goal with confirmed=true. If PROFILE_VISIT is unavailable, ask the advertiser to choose another supported goal; do not change the goal or reconnect automatically. - After creation, inspect partnership_ad_verification_status. A value of verified means the server derived an existing-post Partnership Ad. For not_partnership_ad, unexpected_partnership_ad_type, or unverifiable, relay the returned message and do not retry creation or activate the ad automatically. is_partnership_ad is null when verification could not complete.
Creates a catalog: a structured inventory of products or other items and their details that Meta can rank and show in ads. It is best for advertisers with multiple or frequently changing items who want personalized promotion at scale: Advantage+ catalog ads dynamically select products for prospecting or retargeting, while Product Extensions keep an image or video ad and add relevant catalog products below it. Check `ads_catalog_list_catalogs` first and reuse a suitable catalog when possible. Optionally upload one feed URL, inline item batch, or file; omit product data to create an empty catalog.
Create a new transformation rule on a product feed. Feed rules map or transform attributes during ingestion to fix common feed schema mismatches without the advertiser editing their source file. When to use: - The advertiser's feed column name does not match a Meta product attribute (use mapping_rule, e.g. params={"map_from": "desc"} on attribute="description"). - A specific value needs translation (use value_mapping_rule, e.g. map "yes"/"no" availability values to "in stock"/"out of stock"). - Letter case needs normalization (use letter_case_rule with type=to_upper|to_lower|capitalize_all|capitalize_first). - A default value should be filled in when the feed leaves a column empty (use fallback_rule with user_default_value). - A regex find/replace is needed on values (use regex_replace_rule). When NOT to use: - To inspect existing rules on a feed (use ads_catalog_get_feed_rules). - To upload or modify feed data itself (use the catalog ingestion endpoints). - To create a catalog, feed, or product set (use ads_catalog_create for a catalog, ads_catalog_create_product_feed for a feed, ads_catalog_create_product_set for a product set). Notes: - params is a JSON-encoded object of string-to-string key-value pairs, e.g. {"map_from": "desc"}. - Both attribute and rule_type are immutable after creation; only params can be updated later via a separate endpoint. - The combination (product_feed_id, rule_type, attribute) must be unique. Re-creating the same combination returns a duplicate error.
Create a new product feed (a "data source") under a catalog. A product feed is the entry point for ingesting product data into a catalog, either by uploading a file or by pointing Meta at a URL to fetch on a recurring schedule. This complements ads_catalog_create, which creates the catalog itself. When to use: - The advertiser wants to add a new source of products to an existing catalog. - The advertiser wants Meta to fetch a feed file (CSV/TSV/XML) from a URL on a recurring schedule (pass the schedule object). - Setting up a feed before uploading items or attaching feed rules. When NOT to use: - To create the catalog itself (use ads_catalog_create). - To upload items into an existing feed right now (use the catalog ingestion / upload-session endpoints). - To add transformation rules to an existing feed (use ads_catalog_create_feed_rule). - To inspect existing feeds (use ads_catalog_list_product_feeds). Notes: - schedule is optional. When omitted, the feed is created with no automatic fetch schedule. When provided, it is a structured object; "interval" and "url" are always required and (S)FTP URLs additionally require "username"/"password". "DAILY" requires "hour"; "WEEKLY" requires "hour" and "day_of_week"; "MONTHLY" requires "hour" and "day_of_month"; "HOURLY" requires none of these timing fields. Example: {"interval":"DAILY","hour":6,"url":"https://example.com/feed.csv"}. - If the feed is created successfully but the schedule fails to attach, use ads_catalog_update_product_feed with replace_schedule to add the schedule to the existing feed. Do not create a duplicate feed. - The feed is created under the catalog identified by catalog_id; the output id is the new feed's Meta-assigned ID. - Requires EDIT_PRODUCT_CATALOG permission on the catalog.
Triggers a new upload session on an existing product feed, forcing an immediate refresh from the configured remote source URL. Returns the new upload session ID for polling via `ads_catalog_get_product_feed_upload_sessions`. Only works for feeds with a remote fetch URL configured — check with `ads_catalog_list_product_feeds` first; a feed with no source URL cannot start a session. ## When to use: - Refresh / re-pull / re-ingest products from an existing remote feed without waiting for the scheduled run (e.g. after fixing the source file or updating the hosted feed). ## When NOT to use: - Feed has no source URL (manual/batch-only catalog) → `ads_catalog_update_product_feed` with `replace_schedule` first. - Creating a new feed → `ads_catalog_create_product_feed`; inspecting past runs → `ads_catalog_get_product_feed_upload_sessions`; changing schedule/URL/credentials → `ads_catalog_update_product_feed`. ## Errors: - No source URL → fails, nothing to fetch. Concurrent upload running → fails "upload already in progress": do NOT retry immediately; wait or poll `ads_catalog_get_product_feed_upload_sessions`. ## Shared resources: Fetch via resources/read: `catalog://id-conventions`, `catalog://errors`.
Creates a dynamic product set from a structured filter and returns the set ID + matched count. Always preview the filter with `ads_catalog_list_products` first — set creation mutates the catalog with no undo via this tool. ## When to use: - User explicitly confirmed they want to create a product set from a filter already previewed via `ads_catalog_list_products`. - User wants to materialize a catalog segment defined by product attributes. ## When NOT to use: - Filter not yet confirmed → call `ads_catalog_list_products` first and surface sample + total_count. - Static set of explicit product IDs → not supported yet. - Update existing set → `ads_catalog_update_product_set`. ## Identifier types See `catalog://id-conventions` via resources/read. ## Input - `catalog_id` required (call `ads_catalog_list_catalogs` first if you don't have it), `name` required non-empty, `filter` required. Build it with `ads_catalog_get_suggested_filter` and pass the `filter` it returns back verbatim. - `retailer_id` is optional and should be set only if the user explicitly provides it. - See `catalog://errors` via resources/read for duplicate/rejection handling. ## Returns - `product_set_id`, `catalog_id`, `name`, `product_count`, `filter_rule`, etc. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://errors` via resources/read
Delete existing catalog items from one catalog through a batch-shaped request. Supply `catalog_id` once and identify each item by its merchant-defined `retailer_id` in `items`. When to use: - A merchant wants to permanently remove catalog items that should no longer appear in ads or on Meta surfaces. - You know the catalog ID and each retailer ID, usually from `ads_catalog_list_products`. When NOT to use: - To hide an item reversibly, use `ads_catalog_update_product` with `visibility="hidden"`. - To mark an item unavailable, use `ads_catalog_update_product` with `availability="out of stock"`. - To delete a product set, use `ads_catalog_product_set_delete`. - To delete an entire catalog, use Commerce Manager because MCP does not support that operation. Inputs and results: - `catalog_id` identifies the catalog that owns every submitted item. - `items` contains objects with a required `retailer_id`. Empty and oversized batches fail before execution. - Results include submitted, accepted, and rejected counts, ordered validation details, and ordered successful deletion results. - Unknown retailer IDs are rejected individually while accepted items continue. Every occurrence of a duplicated retailer ID is rejected. - `SOURCE_MAY_OVERWRITE`: the listed feed, partner platform or website still supplies the item and can add it back. Warn the user to remove it there to ensure it is deleted. Timeouts: - If a call times out or fails with a server error and returns no result, some items may already have been applied. Retry the same items in smaller calls of about half the previous batch size. Retrying is safe: already-deleted items return `UNKNOWN_RETAILER_ID` rejections, creates upsert, and updates reapply the same values. Deletion is permanent and cannot be undone through the API. Recreating an item requires supplying its details again. The current synchronous per-call cap is 25.
Connect an event source to a product catalog so its signals can be matched against the catalog's products (for dynamic ads and Advantage+ catalog ads). Event sources are also commonly called "pixels" or "datasets"; the source can be a PIXEL (data from the seller's website), an APP (data from the seller's app), or an OFFLINE_CONVERSION_DATA_SET (data from in-store transactions). The Conversions API (CAPI) is an enhancement that augments PIXEL or APP data — it is not a standalone event source type. To pick which source to connect, use ads_catalog_event_source_get_recommendations. Matching only happens for connected sources: a dataset's event content IDs are matched against the catalog's product retailer IDs only when that pixel/dataset is connected to the catalog. If the dataset tools (e.g. ads_get_dataset_details, ads_get_dataset_quality) show content IDs are being sent, check ads_catalog_event_source_get_health to verify that they are matching products in the catalog (`match_rate`). When to use: - The advertiser wants to connect a pixel / event source to a catalog (e.g. after ads_catalog_event_source_get shows an expected source is missing). - To fix product-matching gaps where a catalog is not receiving a source's events. When NOT to use: - To list the event sources already connected to a catalog (use ads_catalog_event_source_get). - To check event-source match rate or setup issues (use ads_catalog_event_source_get_health). - To find which catalogs an event source is connected to (use ads_catalog_event_source_get_catalogs). Notes: - The operation is idempotent: connecting an already-connected source succeeds and returns already_connected=true without making a change. - The catalog and event source must belong to the same business.
Disconnect a PIXEL, APP, or OFFLINE_CONVERSION_DATA_SET from a product catalog. This removes only the catalog link: the source keeps collecting events, but its signals stop matching catalog products, which can reduce retargeting and optimization for dynamic or Advantage+ catalog ads. If the request provides catalog_id but not event_source_id, first call ads_catalog_event_source_get to identify the connected source; ask for clarification only if the results do not identify a unique match. Once the source is identified, call this tool to request user confirmation. The action is blocked while the catalog has active ad spend. The catalog and event source must belong to the same business. The operation is idempotent: was_connected=false means no link changed. To connect, list, or diagnose event sources, use ads_catalog_event_source_connect, ads_catalog_event_source_get, or ads_catalog_event_source_get_health.
List event sources connected to a product catalog for matching website, app, or offline events to catalog products. Returns each source's event_source_id, name, and type (PIXEL, APP, or OFFLINE_CONVERSION_DATA_SET). For sources that create or update catalog items, use ads_catalog_get_data_sources instead.
Get the product catalogs connected to a given event source (pixel, CAPI app, or offline conversion data set). ## When to use: - Step 1 of "how will this pixel event be matched?": call with the pixel/event source ID. For each returned catalog, call `ads_catalog_list_products` with `entity_id=<catalog_id>` and `filter={"retailer_id":{"eq":"<content_id>"}}` to find matched products. - Advertiser asks which catalogs are linked to a pixel or event source. ## When NOT to use: - Searching for a specific product with a known catalog ID → `ads_catalog_list_products` directly. - You already know the catalog ID — skip this tool (note: unconnected catalogs won't match events unless the catalog ID is in the event). ## Input: `event_source_id` (required, the only argument): positive numeric pixel / CAPI app / offline conversion data set ID. Do NOT pass an ad account ID or catalog ID — neither resolves. With only a catalog ID, call `ads_catalog_event_source_get` first. ## Shared resources: Fetch via resources/read: `catalog://id-conventions`, `catalog://errors`.
Report the match rate and setup issues for the event sources connected to a product catalog. "Match rate" is the percentage of conversion events (e.g. Purchase, AddToCart) whose content IDs matched a product in the catalog — higher match rates mean better ad targeting and measurement. Each event source has a source_type: PIXEL (data from the seller's website), APP (data from the seller's app), or OFFLINE_CONVERSION_DATA_SET (data from in-store transactions); the Conversions API (CAPI) is an enhancement that augments PIXEL or APP data, not a standalone source type. This tool returns the latest overall match rate (match_rate) AND the historical per-date, per-event-type match rate stats over the past 28 days (match_rate_stats). The historical data is useful to detect trends, regressions, or sudden changes in match quality over time. It also returns a list of setup issues (each with a type, description, and severity). This is the same measurement-layer data Commerce Manager surfaces in its "Events" tab. When to use: - To diagnose why catalog products are not matching signals / events ("low match rate", "events not matching products") - To detect match rate trends or regressions over the past month - To list the setup issues for a pixel / event source connected to a catalog - To report match quality for one event source (pass event_source_id) or all connected sources (omit it) When NOT to use: - To just list which event sources are connected, without health data (use ads_catalog_event_source_get) - To check feed-level catalog diagnostics like broken images or missing fields (use ads_catalog_get_diagnostics) - To run Dynamic Ads integration health checks (use ads_catalog_get_dynamic_ads_health)
Recommend the event sources (pixels) to connect to a product catalog. Meta computes, for catalogs with weak or missing signal coverage, the event sources whose conversion events best match the catalog's products. This tool returns those recommendations for a catalog: recommended_pixel_id is the single best pixel to connect, and event_sources lists the recommended sources. Each event source has a source_type: PIXEL (data from the seller's website), APP (data from the seller's app), or OFFLINE_CONVERSION_DATA_SET (data from in-store transactions); the Conversions API (CAPI) is an enhancement that augments PIXEL or APP data, not a standalone source type. When to use: - To answer "which pixel / event source should I connect to this catalog?" - During catalog setup, to proactively suggest the best signal source to connect When NOT to use: - To list the event sources ALREADY connected to a catalog (use ads_catalog_event_source_get) - To get match rate / setup issues for an already-connected source (use ads_catalog_event_source_get_health) - To check feed-level catalog diagnostics like broken images or missing fields (use ads_catalog_get_diagnostics)
Lists businesses the authenticated identity can access. Results are identity-scoped, not ad-account-scoped. Never attribute a returned business to an ad account unless an account-scoped tool confirms the relationship. ## When to use: - The user asks which businesses their authenticated identity can access. - The user needs a `business_id` before listing catalogs owned by that business. - The user asks about business ownership or access. ## When NOT to use: - To identify the business associated with an ad account. Call `ads_catalog_list_catalogs` with the ad account ID as `entity_id`, then use the `business` in its account-scoped catalog results. - Never describe these identity-scoped results as the advertiser's or ad account's Business Manager without separate account-scoped evidence. - For products, use `ads_catalog_list_products`. ## Handoff: - Pass a returned `business_id` as `entity_id` to `ads_catalog_list_catalogs`. - An empty list means no accessible business matched the request. ## Shared resources: - ID and scope conventions: See `catalog://id-conventions` via resources/read. - Pagination conventions: See `catalog://pagination` via resources/read.
List all sources that create or update items in a product catalog, including feeds, Batch API, Graph API, partner integrations such as Shopify, WooCommerce, and Salesforce Commerce Cloud (SFCC), website crawling, and Smart Pixel product ingestion. Use this for a cross-source inventory with basic item count, last-update, and status details. For a partner store's connection health, sync history, or errors, use ads_catalog_list_partner_integrations. For Meta Pixel, app, or offline event-source connections used to match events to catalog products, use ads_catalog_event_source_get instead.
Fetches diagnostic issues for a product catalog, including errors and warnings that may affect ad delivery. ## When to use: - User reports catalog issues or products not showing in ads; asks about catalog errors, warnings, or quality issues (broken images, missing fields, policy violations). - Diagnosing why products may not be eligible for certain ad surfaces. - Catalog-level broken/failed product images (for per-product image status, also check `image_fetch_status` from `ads_catalog_list_products`). ## When NOT to use: - Individual product details → `ads_catalog_list_products`. - Feed rules / why catalog data differs from the feed file → `ads_catalog_get_feed_rules`. - Stale/failing store sync (Shopify/WooCommerce/Magento) → `ads_catalog_list_partner_integrations` (connection failure, not item quality). - Why a SPECIFIC product is not_eligible for Dynamic Ads → `ads_catalog_list_products` with that product's ID as `entity_id`; the per-item `issues`. This tool only reports catalog-level aggregates, not the per-item blocking reasons. ## Response Guidelines: Prioritize MUST_FIX over OPPORTUNITY; explain each diagnostic with corrective actions; group related ones. `number_of_affected_items` counts VARIANTS/SKUs, never "products" — do not compare or sum across issues. When `affected_channels` is non-empty the issue affects only those channels ("mini_shops" = FB/IG Shops, "da" = Dynamic Ads, "marketplace" = FB Marketplace, "ig_shopping" = IG Shopping, "whatsapp" = WhatsApp catalog); empty means broad. Do not overstate severity. To find affected products, try `ads_catalog_list_products` with `error_type` (best-effort). ## Shared resources: Fetch via resources/read: `catalog://id-conventions`, `catalog://pagination`, `catalog://errors`.
Run Dynamic Ads (DA) integration health checks for either a product catalog OR a single product set. Each check returns passed, failed, or inconclusive. ## Scope (catalog vs product set): - `catalog_id` → catalog-level checks: pixel/event source setup, match rate, eligible product count, DA configuration issues. - `product_set_id` → creative-quality checks for the set (e.g. slideshow/video quality), NOT catalog-wide DA setup. Owning catalog resolves automatically. At least one of the two is required; if both are given, `product_set_id` wins. Response echoes `scope` so you can confirm which ran. - Different from `ads_catalog_get_diagnostics`: that reports item-level data quality (missing images, feed errors, policy violations); this checks DA / creative-quality health. ## When to use: - DA setup health/readiness for a catalog; "why are my Dynamic Ads not working?", "is my catalog set up for DA?"; DA not delivering or poor performance; pixel setup / event source / match rate issues; creative quality of a product set. ## When NOT to use: - Item-level diagnostics → `ads_catalog_get_diagnostics`; individual products → `ads_catalog_list_products`; feed rules → `ads_catalog_get_feed_rules`; set membership → `ads_catalog_list_products` with the set ID. ## Response Guidelines: Prioritize failed checks; explain each with corrective actions; group related ones. MUST_FIX first. Treat inconclusive checks as unavailable data. Confirm healthy only when `is_complete` is true, `total_checks_run` is positive, and `failed_count` is zero. Use `action_uri` for the Commerce Manager link. Item-level issues → suggest `ads_catalog_get_diagnostics` separately. ## Shared resources: Fetch via resources/read: `catalog://id-conventions`, `catalog://pagination`, `catalog://errors`.
Gets the data transformation rules applied to a product data feed during ingestion, with cursor-based pagination. `product_feed_id` identifies a feed, NOT a catalog — use `ads_catalog_get_data_sources` with the catalog_id to discover valid feed IDs first. ## When to use: - User asks about feed rules, transformations, or why catalog data differs from the feed file ("what rules are on my feed?", "how is my feed data modified?"). - Debugging data-quality fixes or feed-format adaptations (column/value/case/default/regex — see `catalog://feed-rule-types`). ## When NOT to use: - Upload status, schedule, or ingestion progress → `ads_catalog_list_product_feeds`. - Products or product sets → `ads_catalog_list_products` / `ads_catalog_list_product_sets`. - Catalog-level details → `ads_catalog_list_catalogs`; diagnostics → `ads_catalog_get_diagnostics`. ## Response Guidelines: Present each rule's ID, attribute, rule_type, and params; explain each rule in plain language using its type definition. Invalid feed ID → tell the user the feed ID may be invalid. If `page_info.has_next_page`, mention more rules are available. ## Shared resources: Fetch via resources/read: `catalog://feed-rule-types` (the 5 rule types + params), `catalog://id-conventions`, `catalog://pagination`, `catalog://errors`.
Lists product-feed upload sessions, newest first. Pass upload_session_id to return one session with rolled-up errors and remediation guidance. Use this tool to check upload status, diagnose failed or low-persistence uploads, and compare a repaired upload with a failing session. Request samples only when a representative invalid value is needed. Do not use it for feed configuration or to start an upload. Use ads_catalog_list_product_feeds for configuration and ads_catalog_create_product_feed_upload_session to start an upload. The tool returns a not-found error when the feed or selected session does not exist or is not visible. Malformed IDs are rejected before execution. Remediation is advisory: do not invent missing values or change feed rules without explicit confirmation. Inspect conflicting_rule_ids before proposing a rule change.
Turns a plain-language description of products into a valid product-set filter rule for one specific catalog. This tool reads only — it creates and changes nothing, and it does not search the catalog; pass the filter to `ads_catalog_list_products` to see what matches. Prefer it over writing a filter by hand: it is built from the catalog's own brands, categories, custom labels, and price ranges, so it will not reference fields or values that this catalog does not have. ## When to use: - The user describes products in words and you need a filter rule for `ads_catalog_list_products`, `ads_catalog_create_product_set`, or `ads_catalog_update_product_set`. - You are about to hand-author a `filter` JSON rule — call this instead. - A filter you wrote was rejected as invalid, or matched nothing — describe the intent here rather than guessing again. ## Supported attributes: - Brand, category, product type, name, price, currency, availability, condition, color, size, material, pattern, gender, age group, custom labels, inventory count, `retailer_id`, and `retailer_product_group_id`. - Not supported: URL, feed or data source, tags, and description text. ## When NOT to use: - You already have a filter rule the user gave you verbatim — pass it straight to the tool that needs it.
Reads catalogs: every catalog you can access, catalogs under a business or ad account, or one catalog by ID. Pass whichever ID you have as `entity_id`; single-catalog read = one-row page. ## What `entity_id` can be: - omitted → every catalog you can access, paginated. - business ID → catalogs owned by that business, paginated. - ad account ID → catalogs for that ad account's business (bare "123" or "act_123"). - catalog ID → that one catalog with counts, one-row page, `name`/`limit`/`cursor` ignored. ## Identifier types See `catalog://id-conventions` via resources/read. ## When to use: - Browse/search catalogs → omit `entity_id`, optionally with `name`. - List catalogs under business/ad account → pass that ID. - Inspect one catalog (vertical, counts) → pass catalog ID. ## Input - `entity_id` optional FBID. See `catalog://id-conventions` via resources/read. - `name` optional substring, `limit` default 20 max 100, `cursor` — see `catalog://pagination` via resources/read. ## Returns - `catalogs[]`, `page_info`, optional `next_steps`. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://pagination` via resources/read - `catalog://errors` via resources/read
Lists and ranks DPA / Advantage+ eligible catalogs for an ad account, with optional context tuning (ad_url, pixel/page) and health signals. Backed by MAIBA's advertisable-catalogs fetcher: the eligible set merged best-first with the catalog_adoption recommendation. Use this instead of `ads_catalog_list_catalogs` when you need DPA-ready catalogs with health signals and context-aware ranking. Use `ads_catalog_list_catalogs` for the full catalog inventory. ## What ad_account_id can be: - ad account ID (bare or act_) → eligible catalogs for its business, ranked. Business/catalog IDs are rejected. Permissions are business-gated: an empty result may mean no permission, not no catalogs. ## When to use: - Choose a catalog for DPA / Advantage+ catalog ads for an ad account. - Rank eligible catalogs using health signals and optional ad URL, pixel, page, or ad format context. ## When NOT to use: - List every catalog regardless of DPA eligibility → `ads_catalog_list_catalogs`. - Catalog or item diagnostics → `ads_catalog_get_diagnostics`. - Event source and catalog wiring → `ads_catalog_event_source_get_catalogs`. - Create a catalog → `ads_catalog_create`. ## Shared resources - catalog://id-conventions via resources/read - catalog://errors via resources/read
Returns Meta's guidance for catalog creative work as markdown, to follow while you plan, create, and review. Reads only: it generates, creates, and changes nothing, and it reads no catalog data. ## When to use: - Before planning, generating, or reviewing work that a guidance below covers. Follow it over general knowledge. - Request every guidance the task needs in one call. ## Available guidance: - `video_creation`: Before planning, generating, or reviewing a new video of catalog products for ads: product fidelity, optional brand inputs, safe zones, pacing, audio, Product Video Creator templates, blocking review checks, and attaching the finished video to catalog items. ## When NOT to use: - Uploading or attaching a video the advertiser already has. Upload it directly. - Questions about a specific catalog's data or health. Use the catalog read tools.
List partner platform integrations connected to a catalog — Shopify, WooCommerce, Magento, etc. — with connection health, sync timeline, and errors. ## What `entity_id` can be: - catalog ID (numeric FBID). ## Identifier types See `catalog://id-conventions` via resources/read. ## Output `partner_integrations[]`, `page_info`. See `catalog://pagination` via resources/read. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://pagination` via resources/read - `catalog://errors` via resources/read
Reads product feeds from catalog ID or one known feed ID. Pass either numeric ID as `entity_id`; same paginated shape in both cases. ## Scope - `entity_id=<catalog_id>` → feeds ordered by creation time descending, paginated. - `entity_id=<feed_id>` → that feed as one-row page, rejects `cursor`. ## Identifier types See `catalog://id-conventions` via resources/read. ## Fields Omit `fields` for defaults. Expensive fields loaded only when selected — see spec. ## Pagination `limit` default 20 max 25. See `catalog://pagination` via resources/read. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://pagination` via resources/read - `catalog://errors` via resources/read
Reads product sets: all sets in a catalog, one set by ID, or sets containing a product. Pass whichever ID you have as `entity_id`; single-set read = one-row page. ## What `entity_id` can be: - catalog ID → product sets in catalog, paginated (hidden/auto-generated excluded). - set ID → that one set, one-row page, `name`/`limit`/`cursor` ignored. - item ID → sets containing that product, paginated. ## Identifier types See `catalog://id-conventions` via resources/read. ## When to use: - Browse/search sets in catalog → pass `entity_id=<catalog_id>`, optionally with `name`. - Inspect one set → pass `entity_id=<product_set_id>`. - Find sets containing product → pass `entity_id=<product_id>`. ## Input - `entity_id` required FBID. See `catalog://id-conventions` via resources/read. - `name` optional substring, `limit` default 20 max 100, `cursor` — see `catalog://pagination` via resources/read. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://pagination` via resources/read - `catalog://errors` via resources/read
Preferred Ads catalog reader for browsing, attribute search, and affected-item search. Reads a catalog, set, or item via `entity_id`; a single-item read returns a one-row page. Use before set creation to preview matching items. ## What `entity_id` can be: - catalog ID → products matching filter, paginated. - set ID → products in set, filter AND'd onto set rule. - item ID → that one product, filter/limit/cursor ignored. ## Identifier types See `catalog://id-conventions` via resources/read. ## When to use: - List/browse/search products in catalog → pass `entity_id=<catalog_id>` (e.g. "what's in my catalog?", "show out-of-stock"). - Find affected items → get a diagnostic type from `ads_catalog_get_diagnostics`, then pass it separately as `error_type`; add `filter` to narrow the affected items. For lightweight discovery, request `fields=["retailer_id","name"]`; product_id is always included. - List each Shopify product once → pass `view=product_groups`. Each row is the best matching item variant for its group, not a canonical representative. - Count matches before set creation via `page_info.total_count`. - List products ingested by a specific feed → use a product-feed filter. - List products ranked by Product Views → use `top_products=all`; use `top_products=missing_video` to prioritize video coverage work. - See inside existing product set → pass `entity_id=<product_set_id>`. - Fetch full details of one known product → pass `entity_id=<product_id>`. - Debug per-product issues (missing fields, prices, availability, image_fetch_status). - Inspect a product's status and issues: `eligibility_status` and per-item `issues[]` reason codes are returned by default; `issues[]` lists the ads or Shops issues behind any status other than `eligible`. - List products by status: write `filter` directly as `{"eligibility_status":{"eq":"<status>"}}` with one of `eligible`, `not_eligible`, `not_approved`, `hidden`, `hidden_in_shops`, `not_eligible_for_shops`. The suggested-filter tool cannot build status filters. ## When NOT to use: - Which sets contain a product → `ads_catalog_list_product_sets` with `entity_id=<product_id>`. - List/inspect sets themselves → `ads_catalog_list_product_sets`. - Catalog-level diagnostic summaries/counts → `ads_catalog_get_diagnostics`, overview → `ads_catalog_list_catalogs`. If an error_type cannot be filtered, report the limitation and diagnostic count; do not present an unfiltered page as affected items. - No text-search parameter — build a product filter from the requested attributes. - Performance analysis beyond the returned ranking evidence → use Product Insights. Build it with `ads_catalog_get_suggested_filter` and pass the `filter` it returns back verbatim. - `limit` default 20 max 100, `cursor`, `fields`, `error_type`, `top_products` separate AND — see `catalog://errors` via resources/read and `catalog://pagination` via resources/read. ## Examples - Catalog all: `entity_id=<catalog_id>`, omit `filter`. - Catalog SKU lookup: `entity_id=<catalog_id>`, `filter={"retailer_id":{"eq":"ABC-001"}}`. - Top products without video: `entity_id=<catalog_id>`, `top_products=missing_video`. - Shopify products once each: `entity_id=<catalog_id>`, `view=product_groups`. - Single item: `entity_id=<product_id>`. - What's in set: `entity_id=<product_set_id>`. ## Shared resources - `catalog://id-conventions` via resources/read - `catalog://pagination` via resources/read - `catalog://errors` via resources/read
Create or upsert catalog items through a batch-shaped request with one `catalog_id` and nested `items[]`. The catalog vertical determines each item type. ## When to use: - Add one or more items to an existing catalog with a known catalog ID. ## When NOT to use: - Create a catalog and initial items → `ads_catalog_create`; update only existing items → `ads_catalog_update_product`; saved filter → `ads_catalog_create_product_set`. ## Inputs: - `catalog_id` is required. `items[]` contains nested objects; each object requires `retailer_id` and `name`. - Optional nested fields include description, URLs, prices, currency, availability, condition, brand, visibility, and `properties`. - Existing retailer IDs are updated. Invalid items are rejected individually, and results preserve submission order. - Successful results include `product_id` when immediately resolved. Otherwise, find it with `ads_catalog_list_products`. - Empty and oversized batches fail before execution. ## Timeouts: - If a call times out or fails with a server error and returns no result, some items may already have been applied. Retry the same items in smaller calls of about half the previous batch size. Retrying is safe: already-deleted items return `UNKNOWN_RETAILER_ID` rejections, creates upsert, and updates reapply the same values. ## Shared resources: Fetch via resources/read: `catalog://product-write-fields`, `catalog://id-conventions`, `catalog://errors`. The current synchronous per-call cap is 25.
Delete a product feed (data source) from a catalog. The feed and its schedule are removed, and the products it ingested are deleted from the catalog as well (items also supplied by another data source are kept). Product removal happens asynchronously. When to use: - A merchant wants to remove a feed data source and the products it brought into the catalog. - You already know the feed ID (from ads_catalog_get_data_sources or ads_catalog_list_product_feeds). When NOT to use: - To stop/pause/turn off a feed's automatic refreshing without removing the feed — this is NOT a deletion. Use ads_catalog_update_product_feed with clear_replace_schedule (and/or clear_update_schedule) to stop the schedule; the feed and its products are kept. - To delete a single product rather than the whole feed — use ads_catalog_delete_product. - To delete an entire catalog — needs to be done from Commerce Manager. Notes: - This action cannot be undone through the API. Treat it as permanent. - Product removal is asynchronous, so catalog item counts may take a little while to update.
Permanently delete a transformation rule from a product feed. This action is irreversible — the rule is removed and no longer applied to future feed ingestions. The feed and its products are not affected; only the transformation rule is removed. When to use: - To remove a feed rule that is no longer needed - To clean up a feed rule created in error or with the wrong configuration (attribute and rule_type are immutable, so a misconfigured rule must be deleted and recreated) When NOT to use: - To change a rule's parameters — update the rule instead (its params can be modified without deleting it) - To inspect existing rules on a feed (use ads_catalog_get_feed_rules) - To delete a product set, product, or feed — use the dedicated tools. Deleting an entire catalog is not supported via MCP (use Commerce Manager). Notes: - Only the transformation rule is deleted; feed data and products are left unchanged.
Permanently delete a product set from a catalog. This action is irreversible — the product set and its filter rule are removed. Products themselves are not deleted; only the set that groups them. When to use: - To remove a product set that is no longer needed - To clean up product sets created in error When NOT to use: - To change which products a dynamic set contains — adjust its filter rule (use ads_catalog_update_product_set) - To rename a product set (use ads_catalog_update_product_set) - To delete individual products — use ads_catalog_delete_product. Deleting an entire catalog is not supported via MCP (use Commerce Manager). Notes: - Only leaf product sets can be deleted. A set that has child sets cannot be deleted until its child sets are removed first. - A product set that is in use by an active usage (e.g. a live ad) cannot be deleted until that usage is deactivated or detached. This tool does not modify ads or other usages.
Update an existing catalog's settings, and set up, change or TEST the checkout URL that hands buyers off to the seller's own website to pay. This is the only tool that can test a catalog's checkout URL: it reads the URL already saved on the catalog and runs a real cart through it. At least one field besides catalog_id must be provided. When to use: - To rename a catalog - To set up or change a checkout URL. Removing one is not supported here. Pass setup_checkout_url=true as soon as you know that is what the seller wants. Ask the seller for the URL in your reply and drive the steps below yourself. A setup card may also render and do it for you — collecting the URL, running a real test cart and saving — but you cannot tell whether the surface drew one, so never rely on it or tell the seller it is there. - To test a checkout URL the catalog already has saved. Pass checkout_url_test_only alone. You do not need the seller to paste the URL and you must not hand-build example links instead — this tool reads the saved URL and runs a real cart through it. A seller who names a catalog or gives its id has told you everything this tool needs: call it directly. Do not read the catalog with ads_catalog_list_catalogs first — call this tool, then ask for the checkout base URL in your reply to its result. Checkout URL setup is still rolling out and is not available to every account yet. A checkout URL call on an account that is not in the rollout comes back unauthorized. Tell the seller it is not available for their account yet; there is no way to turn it on for them, including through their Meta contact. Renaming is unaffected and always works. Checkout URL steps, by what you pass alongside catalog_id: - setup_checkout_url=true: starts setup and may also render the card. Saves nothing, always safe. Pass it on its own — adding checkout_url_test_only skips setup and starts a real crawl instead. - checkout_url_test_only alone: runs a test cart through the saved URL without saving. Returns a checkout_validation_result_id. - checkout_base_url + checkout_url_test_only: runs a test cart without saving. Returns a checkout_validation_result_id. - checkout_validation_result_id: reads back the outcome of a test already running. - checkout_base_url alone: saves the URL and starts the crawl that monitors it from then on. Testing is asynchronous: a test returns progress=IN_PROGRESS and the outcome lands within a few minutes. Poll it yourself in this same conversation — call again with checkout_validation_result_id about every 15 seconds until it resolves, for up to about 4 minutes, which is the cadence and ceiling the setup card uses. Do NOT schedule a task, hand the turn back, or tell the seller to come back later while you are still inside that window: finish the test and report the outcome in the turn they asked for it. If it has still not resolved after about 4 minutes, say so and offer to check again. When NOT to use: - To create a new catalog (use ads_catalog_create) - To view catalog details without changing anything (use ads_catalog_list_catalogs) - To delete a catalog — not supported via MCP - To remove a checkout URL — not supported via MCP. Saving a different URL replaces it, but there is no way to clear one from here - To learn what the checkout URL contract is, or to build an example URL for a seller who has not written their endpoint yet (read the ads://commerce/checkout-url-spec resource). Testing a catalog's real checkout URL is this tool with checkout_url_test_only, not a set of example links for the seller to open by hand. - Do NOT save a checkout URL (checkout_base_url without checkout_url_test_only) until the seller has given you that URL and said to save it. This changes where their buyers are sent. - Do NOT append products or coupon to the URL. Save the base endpoint; Meta appends the cart on every handoff. Responding on a checkout URL call: - On mode=card, reply in one or two short sentences: name the catalog from the result and ask for the checkout base URL. Do NOT explain the URL format, the test cart or the save step on this turn — the card covers them when it renders, and you can explain them once the seller sends a URL. A card may render alongside your reply, so mention it only as another way in; you cannot tell whether the surface drew it, and its result never comes back to you either way. Never tell the seller a card is open. - On mode=tested, say which single thing to fix first rather than repeating the check rows. A blocked_reason means no checks ran and re-reading will not change it. An unhealthy check on a VALID result is a warning, not a blocker. - When you save rather than the card, first tell the seller in these words that by providing this URL they authorize Meta to automatically review their website's checkout experience on a periodic basis. The card prints this itself, so do not repeat it on a mode=card turn.
Update existing catalog items through a batch-shaped request with one `catalog_id` and nested `items[]`. Only supplied fields are changed. Accepted request example: `{"catalog_id":"1234567890","items":[{"retailer_id":"SKU-123","name":"Wool coat","description":"Warm wool coat","url":"https://example.com/products/SKU-123","image_url":"https://example.com/images/SKU-123.jpg","video_urls":["https://example.com/videos/SKU-123.mp4"],"price":"129.99","sale_price":"99.99","currency":"USD","availability":"in stock","condition":"new","brand":"Northstar","visibility":"published","properties":{"custom_label_0":"winter"}}]}` ## Identifying items: Each nested item requires `retailer_id`, the merchant's SKU or content ID. The Meta-assigned product item ID is not accepted. Unknown retailer IDs are rejected, never created. ## When to use: - Change item fields or hide items reversibly with `visibility="hidden"`; `visibility="published"` restores them. ## When NOT to use: - Create items → `ads_catalog_product_create`; inspect values → `ads_catalog_list_products`; edit sets, feeds, or catalogs → dedicated tools. ## Batch and field rules: - Each item needs one effective update. Price fields require `currency` in the same nested item. - `video_urls` replaces the item's videos and Meta fetches them afterwards; send the full list. Google Drive and Dropbox share links are accepted as-is; do not ask for a direct file URL. - Public availability values: `in stock`, `out of stock`, `preorder`, `available for order`, `discontinued`, `pending`, `mark_as_sold`, `mark_as_expired`. - Public condition values: `new`, `refurbished`, `used`, `used_like_new`, `used_good`, `used_fair`, `cpo`, `open_box_new`. - Public visibility values: `published`, `hidden`. - Invalid items are rejected individually. Valid results preserve submission order, and duplicated retailer IDs are rejected. - Split oversized updates across calls. Empty and oversized batches fail before execution. - `SOURCE_MAY_OVERWRITE`: the listed feed or partner platform also supplies the item, and its next update may undo this change. Warn the user in bold. ## Timeouts: - If a call times out or fails with a server error and returns no result, some items may already have been applied. Retry the same items in smaller calls of about half the previous batch size. Retrying is safe: already-deleted items return `UNKNOWN_RETAILER_ID` rejections, creates upsert, and updates reapply the same values. ## Shared resources: Fetch via resources/read: `catalog://product-write-fields`, `catalog://id-conventions`, `catalog://errors`. The current synchronous per-call cap is 25.
Update settings on an existing product feed (a "data source") under a catalog. This is the "edit feed" counterpart to ads_catalog_create_product_feed. Only the fields you provide are changed; omitted fields are left as-is. ## When to use: - Rename a feed; change parsing/format (delimiter, encoding, quoted_fields_mode) or default currency. - Change the recurring fetch schedule / source URL (`replace_schedule`) or incremental update schedule (`update_schedule`). - Stop/pause automatic refreshing WITHOUT deleting: `clear_replace_schedule` and/or `clear_update_schedule` (feed + ingested products kept). Do NOT delete the feed for this. ## When NOT to use: - New feed → `ads_catalog_create_product_feed`; immediate refresh → `ads_catalog_create_product_feed_upload_session`; transformation rules → `ads_catalog_create_feed_rule`; inspect only → `ads_catalog_list_product_feeds`. ## Schedule rules: - `replace_schedule` and `update_schedule` are independent. Within a schedule, "interval" is required, "url" optional (omit to keep existing URL, change timing). (S)FTP needs username/password. Example: `{"interval":"DAILY","hour":6,"url":"https://example.com/feed.csv"}`. - To stop a schedule set the clear_* flag instead of a schedule object (safe no-op if absent). clear_replace_schedule can't combine with replace_schedule (same for update). ## Shared resources: Fetch via resources/read: `catalog://id-conventions`, `catalog://errors`.
Update an existing product set's name, filter rules, or retailer ID. At least one field besides product_set_id must be provided. When to use: - To rename a product set - To change the filter rule that defines which products belong to a set - To update the retailer ID When NOT to use: - To create a new product set (use ads_catalog_create_product_set) - To view product set details without changing anything (use ads_catalog_list_product_sets) - To delete a product set (use ads_catalog_product_set_delete) - To add or remove individual products from a set — product membership is controlled by the filter rule - To nest a set under a parent set — product set hierarchy is not managed through this API. Tell the advertiser to arrange the hierarchy in Commerce Manager. ## Filter Build it with `ads_catalog_get_suggested_filter` and pass the `filter` it returns back verbatim. Notes: - A product set's filter must be unique within its catalog. Duplicate filters are rejected: updating a set's filter to one already used by another set in the same catalog will fail with a duplicate error. Use ads_catalog_list_product_sets to inspect existing filters before changing one. Re-saving a set with its own current filter is allowed.
Creates a single ad under an existing ad set in PAUSED state. There is no status input: to make the ad live, create it, then call ads_activate_entity on it. DRAFT MODE: Draft mode is enabled for you, so this tool does NOT create a live ad. It stages the ad in the account's Ads Manager draft under the given ad set and returns status=DRAFT with the allocated ad_id. Nothing is created until you publish that campaign with ads_activate_entity on the campaign; published objects go live ACTIVE. Any validation errors are surfaced in active_errors.
Creates a single ad set under an existing campaign in PAUSED state. BEFORE CALLING: The `ads_create_campaign` response includes `valid_optimization_goals` and `recommended_optimization_goal` for the campaign's objective. Use ONLY values from that list for `optimization_goal`. That list is per objective only: the server either replaces a goal outside it with the recommended default, or rejects a goal the ad set's `destination_type` and `promoted_object` do not offer and names the goals they do. A goal on the list can still be rejected for its `destination_type`, `promoted_object`, or `billing_event`; follow the pairings on those parameters. TARGETING — META RECOMMENDS ADVANTAGE+ AUDIENCE: Keep Advantage+ Audience (A+A) on wherever the ad set supports it. Omit `targeting_automation` (the server enables A+A) or send `targeting_automation.advantage_audience` = 1. Under A+A, Meta's delivery system finds the audience most likely to convert and uses the advertiser's targeting as suggestions: `age_min`/`age_max`, `genders`, interests and behaviors, custom audiences and lookalikes. Locations, `excluded_custom_audiences`, languages and `age_min` up to 25 stay hard controls. Pass ages as-is: the server sends them as suggestions under `targeting_automation.advantage_audience`, so `age_max` stops being a hard cap and `age_min` stays a hard minimum clamped to 18-25 (send at least 20 when targeting Thailand). A target-customer description ("women 25-45"), an age range, an `age_max` of 65, interests, or a custom audience is NOT a reason to turn A+A off. That also holds when no targeting details are given, or when the only audience details are gender or interests: keep A+A on. If you duplicate a source set with A+A off, decide independently; the source setting alone is not an opt-out request for the new set. Set `targeting_automation.advantage_audience` = 0 ONLY when the advertiser explicitly asks to turn Advantage+ Audience off, requires an age limit A+A cannot enforce (a hard maximum below 65 or a hard minimum above 25), or requires delivery to ONLY the people in a custom audience; then tell them A+A is off and why. For HOUSING, EMPLOYMENT or FINANCIAL_PRODUCTS_SERVICES campaigns, the special ad category age rules on `targeting` take precedence. TARGETING — INTERESTS: Do NOT invent interest IDs. Omit interests and use broad targeting via `geo_locations` (recommended); only include interest IDs the user has explicitly provided. PLACEMENTS: Advantage+ placements is the default when the advertiser did not specify placements. Honor an explicit restriction by putting `publisher_platforms` and the matching position arrays inside `targeting`; omit all placement fields for Advantage+ placements. Never claim that placements were selected unless those fields were sent. LEAD ADS: When `optimization_goal` is `LEAD_GENERATION` or `QUALITY_LEAD`, the Page in `promoted_object.page_id` must have `leadgen_tos_accepted=true` — check the page list returned by `ads_get_ad_account_pages`. If the user's page has not accepted ToS, instruct them to do so at https://www.facebook.com/legal/leadgen/tos before creating the ad set. MESSAGING DESTINATIONS: When `destination_type` is `WHATSAPP`, `MESSENGER`, or `INSTAGRAM_DIRECT` (or, where enabled, a multi-destination messaging bundle such as `MESSAGING_INSTAGRAM_DIRECT_MESSENGER`), `promoted_object.page_id` is required. If omitted, the tool auto-infers it from the ad account's primary promoted Page. PROFILE VISIT ADS: pair `OUTCOME_TRAFFIC` with `optimization_goal=PROFILE_VISIT` or `OUTCOME_ENGAGEMENT` with `optimization_goal=PROFILE_AND_PAGE_ENGAGEMENT`. Set `destination_type` to `INSTAGRAM_PROFILE` or `FACEBOOK_PAGE` for single-destination, or `INSTAGRAM_PROFILE_AND_FACEBOOK_PAGE` for multi-destination. EU / DSA: When `geo_locations.countries` includes any EU country, `dsa_beneficiary` and `dsa_payor` are required for Digital Services Act compliance. If omitted, both are auto-filled from the ad account's business name; provide them explicitly to override. BUDGET: Read `min_daily_budget_cents` from `ads_get_ad_accounts` before setting `daily_budget` — budgets below the per-currency minimum are rejected. Before setting an ad-set budget, call `ads_get_ad_entities` for the parent campaign and request its budget fields. If it has a campaign-level budget, leave `daily_budget` and `lifetime_budget` unset. All budget values are in the smallest unit of the ad account's `currency` (e.g., cents for USD). `daily_budget` and `lifetime_budget` are not interchangeable. Use one only when the advertiser states that cadence. A periodic amount such as "$2,000/month" is neither; if unclear, ask and wait instead of choosing one. ADVANTAGE+ CATALOG / DYNAMIC ADS: When the creative (attached at ad creation) is catalog-backed — `ads_create_creative` with `product_set_id` — check the catalog supporting it is healthy: use `ads_catalog_get_diagnostics` and `ads_catalog_get_dynamic_ads_health` to surface feed, data-source, or product-set issues that would prevent the ad set from delivering, and `ads_catalog_list_products` / `ads_catalog_list_product_sets` to verify the product set is non-empty. DRAFT MODE: Draft mode is enabled for you, so this tool does NOT create a live ad set. It stages the ad set in your draft under the given campaign and returns status=DRAFT with the allocated ad_set_id. Nothing is created until you publish the whole draft with ads_activate_entity on the campaign; published objects go live ACTIVE. Any validation errors are surfaced in active_errors.
Creates a single campaign (campaign group) in PAUSED state. Use this to create just a campaign without an ad set or ad. BUDGET PLACEMENT — DEFAULT TO CBO: Unless the advertiser explicitly requests ad-set-level budgeting (ABO), put their stated budget at campaign level (CBO). CBO controls where the budget is allocated; it does not determine the amount or cadence. BUDGET AMOUNT AND CADENCE — DO NOT INFER: Set campaign_daily_budget only when the advertiser states a daily amount, and campaign_lifetime_budget only when they state a total campaign budget. Pass every budget value in the ad account currency's smallest unit (for example, cents for USD). A periodic amount such as "$2,000/month" is neither. If the amount or cadence is unclear, ask and wait before calling this tool; do not stage an assumed value for confirmation. CBO (Campaign Budget Optimization): Pass campaign_daily_budget OR campaign_lifetime_budget here. campaign_bid_strategy defaults to LOWEST_COST_WITHOUT_CAP if omitted; pass it explicitly for COST_CAP, LOWEST_COST_WITH_BID_CAP, or LOWEST_COST_WITH_MIN_ROAS. ABO (Ad Set Budget Optimization): Leave campaign_daily_budget, campaign_lifetime_budget, AND campaign_bid_strategy unset on this call, then pass daily_budget / lifetime_budget on the subsequent ads_create_ad_set call. Only use ABO if the advertiser specifically asks to control budget per ad set. Setting any campaign-level budget field implicitly switches the campaign to CBO; if the advertiser asked for ABO, do NOT set them. ENFORCED: ads_create_ad_set pre-validates this and will reject calls that pass daily_budget or lifetime_budget under a CBO parent campaign. VERIFY THE RESULT: After a successful create, call `ads_get_ad_entities` with the returned campaign ID in `object_ids`, `level=campaign`, and `fields` containing the changed fields plus `effective_status`. Report the returned values to the advertiser. POTENTIAL NEXT STEP — RECOMMEND OPPORTUNITY SCORE: After verifying the campaign, suggest calling `ads_get_opportunity_score` with the ad account ID to check whether the account follows Meta best practices and to get personalized recommendations that can improve performance. DRAFT MODE: Draft mode is enabled for you, so this tool does NOT create a live campaign. It stages the campaign in the account's Ads Manager draft (visible/editable in Ads Manager) and returns status=DRAFT with the allocated campaign_id. The draft may already contain other campaigns; this adds one more. Nothing is created until you publish: add an ad set (ads_create_ad_set) and an ad (ads_create_ad) under it, then call ads_activate_entity on the campaign to publish that campaign (its ad set and ad). Published objects go live ACTIVE (publishing is the advertiser's go-live intent), so there is no separate activate-after-publish step. Any staged object's validation errors are surfaced in active_errors.
Creates an ad creative on the specified ad account. Supports these formats: single-image, single-video, Placement Asset Customization (PAC), multi-media optimization (MMU), Advantage+ catalog carousel, static carousel (manually specified cards), boosted post (an existing organic Page post), Instagram post (an existing organic Instagram post), Facebook Partnership Ads from existing posts, and Instagram Partnership Ads built from new media. ## Required fields by format: **Image ads:** - `ad_account_id`, `page_id`, `link_url` (`link_url` is not required for click-to-messaging creatives — see below) - One of `image_hash` or `image_url` (the ad image; never both) **Video ads:** - `ad_account_id`, `page_id`, `video_id` - `link_url` — optional in general, but REQUIRED if you set `description` (see below), unless `call_to_action_type` is a click-to-messaging CTA - One of `image_hash` or `image_url` — required; represents the **video thumbnail** (cover image shown before the video plays; never both) - Setting `description` on a video ad also requires `link_url`, unless `call_to_action_type` is a click-to-messaging CTA. `description` maps to `video_data.link_description`, which the backend rejects unless the video has a call to action — and this tool attaches the CTA only when `link_url` is present (button defaults to LEARN_MORE, or `call_to_action_type` if you set one), or when `call_to_action_type` is a click-to-messaging CTA (`WHATSAPP_MESSAGE` / `MESSAGE_PAGE`), which attaches its own button and takes no `link_url`. Any other `call_to_action_type` alone, without `link_url`, does NOT attach a CTA. So to add a video `description`, provide `link_url` (and optionally `call_to_action_type`), or use a click-to-messaging `call_to_action_type` without `link_url`. **Product Extensions (catalog products shown beneath the ad's own media):** Not available on every single-image or single-video ad. Request it explicitly through `advantage_plus_creative_features` or `degrees_of_freedom_spec`, and supply `objective`, `conversion_location`, and `link_url`; the tool then resolves an eligible catalog product set and keeps the supplied image or video as the main media. Every condition below must hold: - Single-image or single-video only. PAC, MMU, carousel, collection, boosted-post, Instagram-post, and Partnership Ad creatives are rejected. - Campaign setup is `objective` OUTCOME_SALES with `conversion_location` PIXEL, or OUTCOME_TRAFFIC with WEBSITE. No other pairing is eligible. - Do not pass `product_set_id` — that builds an Advantage+ catalog carousel instead, and combining the two is rejected. - The ad account must have an eligible catalog product set, and must not be in a sensitive vertical. An explicit request that fails any of these is rejected with an actionable error — the creative is NOT silently created without Product Extensions. Check the conditions before offering it to the advertiser. **Placement-customized media ads:** - `ad_account_id`, `page_id`, `placement_customizations` (2–10 entries) - Each entry requires exactly one of `image_hash`, `image_url`, or `video_id`. Images and videos may be mixed in one creative. - Exactly one entry must be the fallback and omit every placement field. Every other entry requires `publisher_platforms` and may narrow delivery with the matching platform position fields. Rules may not overlap. - `link_url` is required when any entry is an image. Copy, link, display link, headline, description, and CTA are shared across all entries. - Do not provide top-level `video_id`, `image_hash`, `image_url`, `product_set_id`, `cards`, or `object_story_id`. `placement_videos` remains a supported video-only legacy alias; do not combine the two fields. - Image hashes are checked against this ad account. Image URLs are downloaded into the account and returned as hashes. Every video must exist, be visible to the caller, and have status `ready` before the creative write starts. **Multi-media ads (MMU):** - `ad_account_id`, `page_id`, `multi_media` (2–10 entries) - Each entry requires exactly one of `image_hash`, `image_url`, or `video_id`. Images and videos may be mixed. - Use MMU when Meta should choose the best asset at delivery time. There are no fallback or placement rules. For exact placement-to-asset mapping, use `placement_customizations` instead. - `link_url` is required when any entry is an image. Use `primary_texts`, `headlines`, and `descriptions` for up to five variants of each; Meta chooses the combination at delivery time. The singular `message`, `headline`, and `description` fields remain supported as one-variant aliases. Link, display link, and CTA are shared across the asset pool. - Do not combine `multi_media` with PAC, top-level media, `product_set_id`, `cards`, `object_story_id`, or a Partnership Ad. - Image URLs are downloaded into the ad account. Every image and video is checked before the creative write starts. The tool also supplies the MMU fields MAPI requires, including video thumbnails. **Advantage+ catalog carousel ads:** - `ad_account_id`, `page_id`, `product_set_id`, `link_url` - Do not provide `image_hash`, `image_url`, or `video_id` — catalog ads source media from the product catalog automatically. **Static carousel ads:** - `ad_account_id`, `page_id`, `cards` (2–10 cards) - Each card: one of `image_hash` or `image_url` (an image card), or `video_id` for a video card (a thumbnail is optional — if you omit `image_hash`/`image_url`, the video's default thumbnail is used). Per card you may also set `link`, `headline` (or `name`), `description`, and `call_to_action_type`. - Provide `cards` alone — do not combine with `image_hash`, `image_url`, `video_id`, or `product_set_id`. Top-level `link_url` and `call_to_action_type` act as per-card fallbacks; each image card must have a link (its own or the fallback), while video cards may omit the link. Under a click-to-messaging CTA the tool supplies card links instead, and a card with its own non-messaging `call_to_action_type` needs its own link or a top-level `link_url` (see below). **Boosted-post ads (boost an existing organic Facebook Page post):** - `ad_account_id`, `page_id`, `object_story_id` — the existing post as `{page_id}_{post_id}` (e.g. "1234567890_9876543210"). - The `page_id` must match the page embedded in `object_story_id`. The post must still exist, be published, belong to that Page, and be visible/promotable by the caller. If it was deleted, unpublished, or is inaccessible, choose a current post or create an inline creative instead; retrying the same ID cannot repair it. - For an ad set optimized for link clicks, use an existing post only if that post already has a valid external destination and CTA. Existing-post copy and CTA cannot be added or repaired by this tool; use an inline creative with `link_url` and `call_to_action_type` when either is missing. - The post's existing media and copy are used as-is: do NOT also provide `image_hash`, `image_url`, `video_id`, `placement_customizations`, `placement_videos`, `multi_media`, `product_set_id`, `cards`, `link_url`, `message`, `primary_texts`, `description`, `descriptions`, `headline`, `headlines`, `call_to_action_type`, or `display_link`. - You may provide `instagram_user_id` for Instagram placement delivery. - This is a plain self-boost of the advertiser's own Page post (no partner). To boost a creator's post as branded content with a partner, use `facebook_partnership_ad` instead (below) — a top-level `object_story_id` is NOT a Partnership Ad. **Instagram post ads (promote an existing organic Instagram post):** - `ad_account_id`, `page_id` (the Facebook Page linked to the Instagram account), `instagram_user_id` (the numeric ID of the Instagram account that owns the post), and `source_instagram_media_id` — an `id` returned by `ads_get_ig_media` for that account. - Pass the organic post itself. Ad media, such as a boosted copy or the effective Instagram media ID read from an existing creative, is rejected. - The post's own media and caption are used as-is: do NOT also provide `object_story_id`, `image_hash`, `image_url`, `video_id`, `placement_customizations`, `placement_videos`, `multi_media`, `product_set_id`, `cards`, `message`, `primary_texts`, `description`, `descriptions`, `headline`, `headlines`, or `display_link`. - `link_url` optionally adds a button that opens that URL; `call_to_action_type` picks its label (defaults to LEARN_MORE when only `link_url` is set). Without either, the creative has no button. A `call_to_action_type` without `link_url` is passed through as-is, and creation decides whether it is valid. - Partnership Ads are currently not supported with `source_instagram_media_id` when only creating a creative. **Facebook Partnership Ads (branded content):** Boosts an existing Facebook branded-content post. A Partnership Ad always has two identities: `facebook_partnership_ad.sponsor_page_id` is always REQUIRED and names the partner Page, while the boosted post's own owner is the primary. Which Page you put in the sponsor slot is what makes the ad sponsor-led or creator-led — there is no separate mode field. Supplying the sponsor (or an ad code) under `facebook_partnership_ad` is what routes the request to a Partnership Ad rather than a plain boosted post. Creating a Facebook branded-content post inline from media is not supported. - Reference the source post with exactly one of `facebook_partnership_ad.facebook_boost_post_access_token` (the encrypted ad code a creator generated to authorize this advertiser) or `facebook_partnership_ad.object_story_id` (an existing branded-content post, formatted `<post_owner_page_id>_<post_id>`, the advertiser already has permission on). - Do not combine either with `image_hash`, `image_url`, `video_id`, `product_set_id`, or `cards` — the boost reuses the existing post's own media. Partnership Ads can run with an Advantage+ catalog, but only as a separate creative shape (a collection ad, a catalog-carousel intro card, or the "Show Products" optimization) — not by adding a `product_set_id` to this boost — and this tool does not build those catalog shapes yet. - `facebook_partnership_ad.ad_format` — optional header format, an integer; omit it unless the advertiser asked for a specific header. 1 = dual header (both identities — the default), 2 = single header, 3 = dynamic header (the identity shown is optimized at delivery). - To promote a creator's *Instagram* post that already exists, use `ads_boost_ig_post` — not this tool. **Instagram Partnership Ads (branded content, built from new media):** Builds a NEW branded-content creative rather than boosting a post the creator already published. Set `instagram_user_id` to the CREATOR's numeric account ID, username, `@handle`, or Instagram profile URL — their handle is what the ad runs under — and name the sponsoring brand in `instagram_partnership_ad.sponsor_instagram_user_id` and `.sponsor_page_id`. The tool resolves the creator to a professional account and derives its Page-compatible ads identity: either its linked Facebook Page or its Instagram Account Backed Page. Omit `page_id`, or provide that matching identity ID. Both sponsor fields are required together. - Unlike the Facebook object above, this one DOES take media: supply `image_hash`, `image_url`, `video_id` or `cards` as normal. - Cannot be combined with `object_story_id` or an ad code — those mean an existing post, which is `ads_boost_ig_post`'s job. Cannot be combined with `source_instagram_media_id` either. - After creation, check `partnership_ad_verification_status`. `verified` means the server derived a real, currently usable Partnership Ad. `verification_pending` means it derived a real Partnership Ad whose asynchronous processing has not settled yet. `verified_with_issues` means processing settled with a real Partnership Ad that cannot deliver yet. `verified_not_ready` means it derived a real Partnership Ad, but the creative is not `ACTIVE` and is not in either expected processing state. For any value other than `verified`, relay `partnership_ad_message` and do not retry or attach the creative to an ad automatically. ## Click-to-messaging creatives (CTWA / CTM): Set `call_to_action_type` to a messaging CTA and the creative's button opens a chat thread instead of a web page. This is the creative half of a messaging ad; pair it with an ad set whose `destination_type` matches. | `call_to_action_type` | Opens | Ad set `destination_type` | | --- | --- | --- | | `WHATSAPP_MESSAGE` | WhatsApp (CTWA) | `WHATSAPP` | | `MESSAGE_PAGE` | Messenger (CTM) | `MESSENGER` | - **Omit `link_url`** for these. The click destination is the messaging thread, and the tool fills in the standard per-surface link. A `link_url` that already is that surface's link (e.g. `https://api.whatsapp.com/send?phone=…`) is replaced with the standard one; any other `link_url` is rejected. - The messaging destination is derived from `call_to_action_type` alone; there is no separate destination field to set. - The CTA must agree with the ad set's `destination_type` (table above) — a mismatch is rejected when the ad is created. - Click-to-messaging is rolling out per ad account, and where it is not enabled the creative gets no messaging button: the request fails (saying click-to-messaging is not enabled, or asking for `link_url`), or the creative is created without that button. A creative whose buttons open the messaging thread comes back with `click_to_messaging_destination` set to that surface (`WHATSAPP` or `MESSENGER`), which must match the ad set's `destination_type`. If the response lacks it, or the request failed that way, tell the advertiser click-to-messaging is not available for that ad account yet; do not retry with a `link_url`. `ads_get_creatives` cannot confirm this either way: it returns the same `call_to_action_type` and links whether or not the button opens the thread. - The WhatsApp business number is configured on the **Page**, not on the creative. This tool does not set a creative-level welcome message, so the Page's default greeting applies. - **WhatsApp prerequisite:** a WhatsApp ad can only run if the Page (or its Instagram account) has a verified WhatsApp Business number linked. Without one, the creative and a PAUSED ad are still created, but activating the ad fails with "Reconnect your WhatsApp number to your Facebook Page or Instagram account to run this ad." If you see that error, tell the advertiser to link and verify a WhatsApp number in the Page's WhatsApp settings, then retry the activation — do not recreate the creative. - Works with the image, single-video, and static-carousel formats. **Not** the catalog (DA) carousel: that format still requires `link_url`, because its link is the catalog destination. - For a static carousel, every messaging CTA in the creative, top-level and per-card, must open the same surface: the one the ad set's `destination_type` names. A card whose effective CTA is a messaging one gets its link from the tool the same way, so leave its `link` unset. A click-to-Messenger carousel must use `MESSAGE_PAGE` at the top level and on every card. On a click-to-WhatsApp carousel, a card with its own *non*-messaging CTA (e.g. `SHOP_NOW`) needs its own `link` unless the creative has a top-level `link_url`, even when there is no top-level CTA. It never inherits the messaging link, which would leave it pointing at a chat URL with no recipient. A non-messaging top-level `call_to_action_type` needs `link_url`, since the top-level button is the one every card without its own `call_to_action_type` uses. - End-to-end messaging ad: `ads_create_campaign` → `ads_create_ad_set` (`destination_type: WHATSAPP`) → `ads_create_creative` (`call_to_action_type: WHATSAPP_MESSAGE`) → `ads_create_ad`. ## Optional fields (all formats): - `message` — one body/primary-text value shown above the image, video, or carousel. For `multi_media`, use `primary_texts` instead when you want multiple variants. For carousel ads, may contain template strings like {{product.name}} filled from the catalog at delivery time. - `primary_texts` — `multi_media` only; 1–5 body/primary-text variants. Do not combine with `message`. Meta chooses among them at delivery time. - `display_link` — the short URL/domain shown on the ad (for example `Verizon.com`). This is presentation text, not the click destination; continue to put the destination in `link_url` (a click-to-messaging creative takes none). Must be URL-shaped (a bare domain is fine); arbitrary text is rejected. Maps to Marketing API `caption`, including the CTA caption used by video creatives. The link line that shows it is being removed from Facebook mobile Feed for single-image and single-video ads, so it may not be visible there. - `description` — one short description value under the headline. For `multi_media`, use `descriptions` instead when you want multiple variants. Facebook Feed does not display it on single-image or single-video ads and Instagram has no description line, so tell the user it may not be visible. For carousels, prefer per-card `cards[].description`. On a single-video ad this maps to `video_data.link_description`, which the backend rejects without a call to action; this tool attaches the CTA only when `link_url` is present or `call_to_action_type` is a click-to-messaging CTA, so also provide `link_url` when you set `description` on a video ad, unless its `call_to_action_type` is a click-to-messaging one. - `descriptions` — `multi_media` only; 1–5 short-description variants. Do not combine with `description`. Meta chooses among them at delivery time. - `headline` — one short headline shown under the image, video, or carousel cards. For `multi_media`, use `headlines` instead when you want multiple variants. - `headlines` — `multi_media` only; 1–5 headline variants. Do not combine with `headline`. Meta chooses among them at delivery time. - `call_to_action_type` — CTA button type (defaults to LEARN_MORE). Must be an exact UPPER_CASE value from the accepted enum — arbitrary values are rejected. The messaging values WHATSAPP_MESSAGE / MESSAGE_PAGE make this a click-to-messaging creative — see that section above. See the field description for the full accepted list. Telephone CTAs (CALL, CALL_NOW, CALL_ME, MISSED_CALL) are not supported because they require a tel: destination, which this tool cannot supply. Use a supported CTA such as CONTACT_US, or create the telephone CTA in Ads Manager. - `name` — name of this ad creative as seen in the ad account's library. Strongly recommended. - `instagram_user_id` — IG user (Instagram Business Account) ID for IG placement delivery. For `instagram_partnership_ad`, this instead accepts the creator's numeric account ID, username, `@handle`, or Instagram profile URL. With `source_instagram_media_id` it is required and names the account that owns the post. Omit it from other formats and the creative will not deliver on Instagram surfaces. - `self_ai_disclosure` — AI-generated content disclosure. "OPT_IN" declares the creative contains third-party AI-generated/edited media; "OPT_OUT" declares it does not. Omit if unknown. When opted in, Meta may display an "AI info" label on the ad; whether it appears depends on the ad's delivery regions and their AI-transparency requirements. Decide this before you create the creative — no update tool can set it afterwards. Always list this field for the advertiser so they can decide; disclosure is their responsibility, so never set or infer a value on their behalf. The declaration takes effect only where AI-transparency rules require it — currently the European Region, India, Taiwan, California, and New York. - `advantage_plus_creative` — set true to turn on the master Advantage+ Creative feature. Set false to leave that master feature off; false does not override a supplied `degrees_of_freedom_spec`. - `advantage_plus_creative_features` — specific Advantage+ Creative feature names (exact lower_snake_case, e.g. "image_touchups", "text_optimizations") to opt into individually. Use only when the advertiser asks for specific enhancements; most callers only need `advantage_plus_creative`. - `degrees_of_freedom_spec` — the raw Marketing API degrees_of_freedom_spec, for feature opt-outs or per-feature customizations. Do not combine it with `advantage_plus_creative=true` or a non-empty `advantage_plus_creative_features` list. It may be combined with `advantage_plus_creative=false` while preserving the raw spec. ## When to use: - The user wants a click-to-WhatsApp or click-to-Messenger ad creative (set the matching messaging `call_to_action_type`). - The user wants to create a single-image link ad creative from a pre-uploaded image. - The user wants to create a single-video ad creative from a pre-uploaded video. - The user wants to use different images, videos, or both for different placements, with one fallback asset. - The user wants Meta to optimize delivery across a pool of images, videos, or both, without fixed placement rules. - The user wants to create an Advantage+ catalog carousel ad creative from a product set. - The user wants to create a static carousel ad creative from a list of manually specified cards. - The user wants to boost an existing organic Page post (create a creative from an existing post via top-level `object_story_id`). - The user wants a creative from an existing organic Instagram post (top-level `source_instagram_media_id`). To create the campaign, ad set, and ad from the post in one step, use `ads_boost_ig_post` instead. - The user wants to create a Facebook Partnership Ad from an existing branded-content post. - The user wants to create an Instagram Partnership Ad from new image, video, or carousel media. ## Safe flexible-media workflow: 1. If the user supplies multiple assets without explicitly choosing a format, do not guess or call this tool. Ask: "Do you want a carousel with swipeable cards, specific assets assigned to placements, or Meta to optimize across an asset pool?" 2. Choose one mode: `placement_customizations` for exact placement rules, or `multi_media` for a delivery-optimized asset pool. 3. Check the matching `applied_placement_customizations` or `applied_multi_media` response. 4. Call `ads_create_ad` with `creative` set to `{"creative_id":"<CREATIVE_ID>"}`. That tool creates the ad in PAUSED state. 5. Call `ads_get_ad_preview` for the intended Feed, Stories, and Reels placements. Keep the ad paused until a person approves it. ## When NOT to use: - Lead-gen or app-install creatives — not supported. - The user wants the creative attached to an ad in the same call — this tool only creates the creative. ## Catalog carousel — verify before you create: - Discover a valid `product_set_id` with `ads_catalog_list_product_sets` (list sets for a catalog) or `ads_catalog_list_products` (preview which products match a filter). - Check catalog health with `ads_catalog_get_diagnostics` (policy/data issues that block delivery) and `ads_catalog_get_dynamic_ads_health` (DA-specific checks) before relying on a catalog carousel to deliver. A non-empty but unhealthy catalog/product set can cause the new creative's ads to never deliver. ## Response: Returns the new `creative_id` plus echoed `name` and `account_id`. PAC returns `applied_placement_customizations`; MMU returns `applied_multi_media`. These show the normalized assets submitted to MAPI. A creative whose buttons open a messaging thread returns `click_to_messaging_destination`. For an Instagram Partnership Ad, attach the creative to an ad only when `partnership_ad_verification_status` is `verified`. Use `ads_get_creatives` afterward to inspect the created creative. When `warnings` is present, the creative WAS created, but some inputs were stored without being displayed on common placements. Relay every warning to the user; do not report a clean success without them. ## Known limitations: - Top-level image and video-thumbnail hashes are not prevalidated. Image hashes inside `placement_customizations` and `multi_media` are checked against the ad account before the creative write. - Duplicate detection: if a creative with identical content already exists and is active on the account, the existing `creative_id` is returned instead of creating a new one — your "new" creative may be a reused old one. - Creative content, including `display_link`, is immutable after publication. To change it, create a replacement creative and attach that replacement to the ad. - No support for `instagram_actor_id`, `effective_authorization_category` (political/issue ads), `url_tags`, or `applink_treatment`. - Placement customization changes the image or video asset. Text, link, display link, headline, description, and CTA are shared across placements. - MMU supports up to five ad-level primary-text, headline, and description variants. Per-media text, destination, crop, placement-exclusion, and audience-persona fields are not exposed yet. - `object_story_id` accepts only the plain `{page_id}_{post_id}` form of a Facebook Page post — not substory or timeline-aggregate post tokens. An existing Instagram post goes in `source_instagram_media_id` instead.
Creates a custom audience under an ad account. Supported subtypes are CUSTOM (customer list), WEBSITE, ENGAGEMENT, MOBILE_APP, and LOOKALIKE. ## When to use Use this tool only to create a new custom audience. - Use ads_update_custom_audience_users to add or remove customer-list users. - Use ads_update_custom_audience to modify an existing audience. - Use ads_delete_custom_audience to delete an audience. ## Subtype requirements ### CUSTOM - Requires customer_file_source. - Creates an empty audience. After creation, use ads_update_custom_audience_users to upload users. - Set is_value_based=true only when uploaded rows will include customer values. - retention_days must be between 1 and 180. ### WEBSITE - Requires rule with a "pixel" event source and pixel ID. If the pixel ID is unknown, use ads_get_datasets. - The audience populates automatically from pixel events. - Supported templates include ALL_VISITORS for all website visitors, VISITORS_BY_URL for URL or event filters, and TOP_TIME_SPENDERS for percentile-based time-spent audiences. - For all visitors, use a URL "i_contains" filter with an empty value. Do not use a PageView event filter. ### ENGAGEMENT - Requires rule with a supported engagement event source: "ig_business", "page", "shopping_page", "shopping_ig", "marketplace_listings", "lead", "ig_lead_generation", or "canvas". - Use the appropriate Instagram account, Page, form, or Instant Experience ID. Lead-form and Instant Experience sources also require owner_id. - By default, include both "lead" and "ig_lead_generation" sources for a lead form unless the user requests only one surface. - Use retention_seconds=0 for current-follower events such as "INSTAGRAM_PROFILE_FOLLOW" and "page_liked". - The audience populates automatically from engagement events. Use only documented event names; do not invent them. ### MOBILE_APP - Requires rule with an "app" event source and the numeric Meta App SDK ID. Do not use an App Store or Play Store package name. - The maximum retention is 180 days. - Supported standard templates are MACA_APP_LAUNCHED_USERS with "fb_mobile_activate_app", MACA_MOST_ACTIVE_USERS with "fb_mobile_activate_app" and count aggregation, and MACA_TOP_PURCHASE_USERS with "fb_mobile_purchase" and purchase-value aggregation. - Percentile templates support only the top 5%, 10%, or 25%. - Custom app events may omit template, but their exact event names must come from the user. - The audience populates automatically from app events. ### LOOKALIKE - Requires origin_audience_id and lookalike_ratio. - The origin may be CUSTOM, WEBSITE, ENGAGEMENT, or MOBILE_APP, but cannot be another LOOKALIKE. - lookalike_ratio must be between 0.01 and 0.20. Use 0.01 when the user does not request a broader audience. - Do not ask for a country or geographic location; geography is handled automatically. - Do not pass rule, customer_file_source, is_value_based, retention_days, prefill, or audience_labels. - The audience is built asynchronously and cannot be used for delivery until it is ready. ## Rule format For WEBSITE, ENGAGEMENT, and MOBILE_APP, rule must be a JSON-encoded string, not a nested JSON object. Build the rule object in this shape, replace every placeholder with a real value, and then serialize the complete object once so the rule argument is a string: { "inclusions": { "operator": "or", "rules": [{ "event_sources": [{"type": "<SOURCE_TYPE>", "id": "<SOURCE_ID>"}], "retention_seconds": 2592000, "filter": { "operator": "and", "filters": [{ "field": "<FIELD>", "operator": "<FILTER_OPERATOR>", "value": "<VALUE>" }] } }] } } - Use "inclusions" for people to add to the audience. Add an "exclusions" object with the same operator-and-rules shape only when needed. - At either operator level, "or" matches any child and "and" matches every child. - Each rule needs one or more event_sources, an integer retention_seconds, and a filter. Use the source type and ID required by the selected subtype. Include owner_id in an event source when that source requires an owner. - Each filter leaf needs field, operator, and value. Nest filter groups when the requested logic combines multiple conditions. - Add template or aggregation as sibling fields of event_sources, retention_seconds, and filter only when the selected audience flow requires them. - Do not send comments, ellipses, placeholder values, or a nested JSON object as rule. When the user requests multiple rules, ask whether the audience should match any rule (OR) or all rules (AND). Default to OR only when the user has no preference. ## Response guidelines - Confirm creation and report audience_id. - For CUSTOM, tell the user that the audience is empty and users must be uploaded with ads_update_custom_audience_users. If is_value_based=true, mention that uploads may include LOOKALIKE_VALUE. - For WEBSITE, ENGAGEMENT, and MOBILE_APP, explain that the audience will populate automatically from events. - For LOOKALIKE, report the selected percentage and explain that modeling may take minutes or hours before the audience is ready.
Delete an existing ad creative by ID. After deletion, the creative can no longer be used for new ads. ## Required: - `creative_id` — the numeric ID of the ad creative to delete (e.g. "123456789"). ## Optional: - `ad_account_id` — account context, with or without the `act_` prefix. The creative ID already determines the account; when supplied, this value must match the creative's account. ## When to use: - The user wants to delete/remove a creative — e.g. "delete creative 123456". ## When NOT to use: - The user wants to rename a creative or change its labels/status (use the update creative tool). - The user wants to change the creative's media, copy, link, or call-to-action — those are immutable; create a new creative instead. ## Notes: - Before deleting, use `ads_get_creative_ads` to check whether the creative is attached to an ad. If it is, resolve those ads first; the creative cannot be deleted while it is in use. - A deleted creative no longer appears when listing an account's creatives, but it can still be looked up directly by its ID. ## Response: Returns the `creative_id` and `success`.
Update metadata on an existing ad creative by ID. This tool can rename a creative, activate it, or change its labels. It cannot edit the creative's visible content. ## Before calling: - Resolve the `creative_id` with `ads_get_creatives`. Do not call this tool without a specific creative ID. - `ad_account_id` is optional account context. When supplied, it must own the creative. - Do not pass read fields or content fields such as `fields`, `body`, `title`, `headline`, `message`, `link_url`, `url_tags`, call-to-action fields, images, or videos. ## Editable fields (provide at least one): - `name` — rename the creative as seen in the ad account's library. Must be non-empty when provided. A deleted creative can still be renamed. - `status` — set a non-deleted creative's status to `ACTIVE`. `ACTIVE` is the only accepted value; use the delete creative tool to delete a creative. - `adlabels` — a JSON array of ad-label specs, each `{"id":"..."}` or `{"name":"..."}` (e.g. `[{"name":"Q3 Launch"}]`). - `adlabels_operation` — how to apply `adlabels`: `set` (default; replaces existing labels), `add`, or `remove`. Requires `adlabels`. ## When to use: - The user wants to rename a creative — e.g. "rename creative 123456 to Summer Sale". - The user wants to set a non-deleted creative's status to ACTIVE. - The user wants to set, add, or remove ad labels on a creative. ## When NOT to use: - The user wants to delete a creative (use the delete creative tool). - For a deleted creative, only its name can be updated; its status and labels cannot be changed. - The user wants to change the creative's media, copy, link, tracking tags, or call-to-action. Published creative content is immutable. Explain that a replacement creative and ad are required, and ask for confirmation before creating them. - The user wants to update the ad itself (targeting, budget, schedule), not the creative. ## Response: Returns the `creative_id` and `success`. Use `ads_get_creatives` afterward to inspect the updated creative.
Prepare a short-lived Upload Service capability for one local image or video selected in the Ads MCP App.
Upload images or videos to an advertiser's ad account from either a local device or a publicly accessible URL. This is the preferred media upload tool. ## Local files - Set `upload_source` to `LOCAL_FILE` only when the client supports interactive MCP Apps. - If the client does not support interactive MCP Apps, use `URL` with `media_type` and a direct, publicly accessible `media_url` instead. - Local uploads support JPEG, PNG, GIF, MP4, and MOV/QuickTime files. - For a local video, use `LOCAL_FILE`; do not require the user to provide a public URL or set `media_type`. - The tool opens the upload app so the user can choose a file from their device. - `media_type`, `media_url`, and `name` are ignored for local uploads. ## Public URLs - Set `upload_source` to `URL`. - Set `media_type` explicitly to `IMAGE` or `VIDEO`. - Set `media_url` to a direct, publicly accessible media URL. - `name` is used as the image library name for images and the title for videos. - Google Drive, Dropbox, Canva, and similar share links are not supported when they require sign-in or return an HTML interstitial instead of the media bytes. ## Response - `result_kind=LOCAL_FILE` means the interactive local media upload app is ready for images and videos. - `result_kind=URL_IMAGE` returns the uploaded image hash, library metadata, dimensions, and URLs. - `result_kind=URL_VIDEO` returns the durable video ID, processing status, title, and creation time. ## Checking upload status - For returned image hashes, use `ads_get_ad_images` to get the latest image metadata and status. - For returned video IDs, use `ads_get_ad_videos` to get the latest processing status. - Video encoding is asynchronous. A `processing` status means the upload completed but the video is not ready for an ad creative yet; use it only after its status becomes `ready`. Use this unified tool for all new image and video uploads.
Permanently deletes a custom audience by its ID. ## When to use: - Call this tool when the user explicitly asks to delete or remove a custom audience. - Use when cleaning up unused or outdated audiences. ## When NOT to use: - Do NOT use to remove users from an audience — use ads_update_custom_audience_users with operation="REMOVE" instead. - Do NOT use to pause or deactivate an audience — deletion is permanent and irreversible. - Do NOT use on audiences that have active lookalike audiences derived from them — delete the lookalikes first. - Do NOT use on system-managed audiences — only user-created custom audiences can be deleted. ## CRITICAL: - Deletion is PERMANENT and cannot be undone. Always confirm with the user before calling this tool. - If the audience has existing lookalike audiences, those must be deleted first. The tool will return an error listing this requirement. - Any active ad sets using this audience will be automatically paused before deletion. - Audiences with child audiences cannot be deleted — delete the children first. - Certain lookalike audiences derived from promoted posts cannot be deleted via this tool — the error message will indicate this limitation. ## Response Guidelines: 1. BEFORE calling this tool, you MUST first call ads_get_custom_audience_adsets to check which ad sets use this audience. 2. Present the list of ad sets (by name and ID) to the user and warn them about ALL THREE of the following: a. Deletion is PERMANENT and cannot be undone. b. If the audience has lookalike audiences, those must be deleted first or the call will fail. c. The listed ad sets will be automatically paused upon deletion. Ask the user to confirm they want to proceed after presenting these warnings. 3. If the tool returns success, inform the user the audience has been permanently deleted and the listed ad sets have been paused. 4. If the error mentions lookalike audiences, advise the user to delete those first, then retry. 5. If the error mentions child audiences, advise the user to delete the children first.
Delete one uploaded image from the selected ad account in the Ads MCP App.
Create an A/B test (split test). Supports campaign-level (L3), ad-set-level (L2), and creative-level (L1) tests. At least 2 cells are required; the maximum depends on the test type and ad account eligibility. Provide exactly one ad entity ID in each cell. The test runs for a specified duration. Each cell is one variant and must contain one ID at the same entity level, from the same ad account. For example: `[{"name":"Control","ad_entity_ids":["120000000000001"]},{"name":"New creative","ad_entity_ids":["120000000000002"]}]`. These are campaign, ad set, or ad IDs—not study IDs or the `act_...` ad account ID. Use `YYYY-MM-DD` dates, such as `2030-01-15`; do not send Unix timestamps. KPIs: the primary KPI defaults to cost_per_result and determines the test winner. To use a different primary KPI, pass `primary_kpi` using one of the supported values below. To also measure additional KPIs that are reported but do NOT affect the winner, pass `secondary_kpis` as an array. Supported primary_kpi values (most common): - "cost_per_result" (default — recommended for most tests) - "cpp" (cost per 1000 people reached) - "cost_per_action_type:link_click" (cost per link click) - "cost_per_action_type:lead" (cost per lead) - "cost_per_action_type:omni_purchase" (cost per purchase) - "cost_per_action_type:omni_add_to_cart" (cost per add-to-cart) - "cost_per_action_type:omni_complete_registration" (cost per registration) - "cost_per_action_type:omni_app_install" (cost per app install) - "cost_per_action_type:video_view" (cost per video view / ThruPlay) - "cost_per_action_type:landing_page_view" (cost per landing page view) - "cost_per_action_type:post_engagement" (cost per post engagement) - "cost_per_action_type:onsite_conversion.messaging_first_reply" (cost per messaging conversation) - "cost_per_estimated_ad_recallers" (cost per estimated ad recall lift) Important: Do NOT use shorthand forms like "cost_per_link_click" or "cost_per_lead". Always use the "cost_per_action_type:<action>" format shown above. An unsupported KPI (or a secondary KPI that duplicates the primary or another secondary) is rejected with the list of supported values, so surface that list to the user rather than silently falling back. Omit primary_kpi to default to cost_per_result (recommended for most cases).
Returns details of a specific A/B test by its study ID—name, status, type, start/end dates, and the cells with their assigned ad entities. Use this when the user asks about a specific test by ID, or to confirm a test's configuration after creating it. **ID ROUTING:** `study_id` must be a known A/B test study ID, such as one returned by `ads_experiment_list_tests` or `ads_experiment_abtest_create_test`. A bare numeric ID is not enough evidence that it is a study ID. Even wording such as "show me the A/B test for ID 123" does not establish the ID type; ask where the user copied it from or request the Ads Manager URL instead of calling this tool. Never pass an ad account, campaign, ad set, or ad ID. If the user provides an ID with an `act_` prefix, call `ads_experiment_list_tests` with `ad_account_id`; if the conversation identifies it as a campaign, ad set, or ad ID, call that tool with `ad_entity_id`. If the ID type is unknown, do not guess or call this tool. Route it only after the source or prior tool output establishes the object type. Only study_id is required — the ad account is automatically resolved from the study, so do not ask the user for it. Note: "A/B test" and "split test" refer to the same thing. You can mirror the user's preferred terminology. A/B tests isolate the impact of a single variable (creative, audience, or placement) so advertisers can learn what drives results. **When interpreting outcomes, focus on business-outcome metrics like cost per result rather than surface metrics like CPM, and evaluate the winning variant against the advertiser's actual objective.** ## Performance metrics (spend, cost per result, etc.): This tool does NOT return spend or cost metrics. ONLY when the user asks about performance metrics (spend, cost per result, CPM, etc.) should you call `ads_get_ad_entities`. Do NOT call `ads_get_ad_entities` for configuration questions — dates, budget, cells, objectives, or winner — answer those from this tool's response alone. When metrics ARE requested, call `ads_get_ad_entities` scoped to this study: - `level`: the `ad_entity_level` field returned here ("campaign", "adset", or "ad"). - `filtering`: `[{"field":"id","operator":"IN","value":["<each cell's ad_entity_ids>"]}]`. - `time_range`: `{"since":"<metrics_window_start>","until":"<metrics_window_end>"}` — both are already `YYYY-MM-DD` in the ad account's timezone (the same tz ads_get_ad_entities applies to `time_range`) and reflect the window Test & Learn sums over. Use `metrics_window_*`, NOT `start_time`/`end_time` (those are the study schedule). Do NOT rely on the default date window — it falls back to the current month (`this_month`) and will not match the study period. If `ad_entity_level` is null the cells span mixed levels; ask the user rather than guessing the level. For creative tests (`winner_result.is_creative_test` = true), the configured test-ad budget is returned directly as `test_ad_daily_budget` (a fixed daily budget) or `test_ad_lifetime_budget_percentage` (a percentage of the existing lifetime budget); answer test-ad budget questions from those without calling `ads_get_ad_entities`. ## When to use: - When the user asks about a specific study whose ID type is established - When the user wants test results, winner, or high performers - After creating a test, to confirm its configuration ## When not to use: - Do not use this to list or discover tests—use ads_experiment_list_tests instead.
Edits or cancels a running A/B test by study ID. Only the study ID and action are required—the ad account is resolved automatically. **ID ROUTING:** `study_id` must be a known A/B test study ID, such as one returned by `ads_experiment_list_tests` or `ads_experiment_abtest_create_test`. A bare numeric ID is not enough evidence that it is a study ID. Never pass an ad account, campaign, ad set, or ad ID. If the user provides an ID with an `act_` prefix, call `ads_experiment_list_tests` with `ad_account_id`; if the conversation identifies it as a campaign, ad set, or ad ID, call that tool with `ad_entity_id`. If the ID type is unknown, ask where the user copied it from or request the Ads Manager URL; do not guess. For date updates, use `YYYY-MM-DD`, such as `2030-01-15`, rather than a Unix timestamp. **Supported actions:** - "cancel" stops the test with no results preserved. - "end_test_now" ends the test immediately with results preserved. - "update" edits the test name, start date, or end date. The start date can only change before the test begins. Allow tests to run their full planned duration whenever possible—ending or changing a test early reduces the reliability of its results. Prefer "end_test_now" over "cancel" when winding a test down so the results collected so far are retained for learning, and evaluate those results against the advertiser's business objective. The response echoes the resulting test name, status, and schedule (start/end dates) after the edit is applied, so you can confirm the changes took effect.
**CRITICAL TRIGGER:** Call this tool whenever a user asks about measuring incrementality, incremental conversions, causal impact, or if their ads can run an A/B test or Lift study. ALWAYS call this tool to verify account eligibility before attempting to create a new experiment. **CAPABILITIES:** Evaluates an ad account (or specific entities) to determine eligibility for both A/B tests (split tests) and Lift studies. Returns available test types, warnings, and recommendations. **RESPONSE RULES & STRATEGIC PITCH:** 1. **SUMMARIZE:** Clearly report which test types the account is eligible for, surface any existing-study warnings, and provide the recommended path. 2. **ADVOCATE FOR LIFT:** If the account is eligible for a Lift study, strongly encourage it. Briefly frame incrementality as the ultimate source of truth (conversions truly caused by ads via a randomized holdout) and proactively offer to set it up right now using `ads_experiment_lift_create_test`. 3. **POSITION A/B TESTS:** If recommending an A/B test, frame it specifically as a tactical tool to test the impact of changes to a variable, such as creative, audience, or placements, so they can see what works best.
**CRITICAL TRIGGER:** Act as an advocate for incrementality. Proactively pitch this tool whenever a user evaluates ad performance, questions ROAS/CPA, expresses attribution doubts, or asks if their ads are actually working. Frame this test as the gold standard for proving true incremental value. **CAPABILITIES:** Automatically handles all technical setup (mapping pixels, datasets, and objectives) to immediately launch a single-cell, account-level lift study. **GUARDRAILS:** • To check eligibility without creating a test, use `ads_experiment_check_eligibility`. • To fetch results of an existing test, use `ads_experiment_lift_get_test`. **INPUTS:** • ad_account_id (Required): The Meta ad account ID. • study_name (Optional): Defaults to "Conversion Lift - <account> - <date>". • start_time (Optional): ISO 8601 (e.g., "2026-08-15"). Defaults to 4 hours from now. If the requested date is today, it automatically adjusts to 30 mins from now. • end_time (Optional): ISO 8601. Defaults to 30 days after start. Must be at least 5 days after start_time. **RESPONSE RULES:** 1. **SUCCESS:** Provide the Study ID, list the created objectives (e.g., "Purchase (Omni)"), confirm it is active, and instruct the user to check back later using `ads_experiment_lift_get_test`. 2. **ELIGIBILITY FAILURE:** Explain the exact blocker and provide actionable fixes. 3. **NO EVENTS FOUND:** Direct the user to https://www.facebook.com/test-and-learn or their Meta representative.
Fetches a single lift study by its study ID and returns full details — cells, objectives, and incremental results. Use this when you already have a specific study ID and want the full configuration and results. **ID ROUTING:** `study_id` must be a known lift study ID, such as one returned by `ads_experiment_list_tests` or `ads_experiment_lift_create_test`. A bare numeric ID is not enough evidence that it is a study ID. Never pass an ad account, campaign, ad set, or ad ID. If the user provides an ID with an `act_` prefix, call `ads_experiment_list_tests` with `ad_account_id`; if the conversation identifies it as a campaign, ad set, or ad ID, call that tool with `ad_entity_id`. If the ID type is unknown, ask where the user copied it from or request the Ads Manager URL; do not guess. When presenting results, lead with the study name, status, and time period. For conversion lift, highlight incremental conversions, confidence, cost per incremental conversion, and incremental ROAS; for brand lift, highlight brand lift in percentage points and confidence. **Prioritize these incremental, business-outcome metrics over standard reporting metrics like CPM, as they measure the causal value the ads created.** If the study is still active, note that results may be preliminary. **When not to use:** Do not use this to search for studies by campaign, ad set, or ad — use ads_experiment_list_tests instead.
Finds A/B tests (also referred to as split tests) and lift studies associated with an ad entity (ad account, campaign, ad set, or ad) — whether active, scheduled, or recently finished. The entity type is auto-detected. Use this to check whether something is part of a measurement study before making changes. **ID ROUTING:** When the user provides an ad account, campaign, ad set, or ad ID and wants to find its tests, use this tool. Pass an ID with an `act_` prefix as `ad_account_id`; pass a known campaign, ad set, or ad ID as `ad_entity_id`. Do not pass these IDs as `study_id` to a get-test tool. If the user provides a bare numeric ID and its type is not clear from the conversation or prior tool output, do not guess. Ask where they copied the ID from or ask them to share the Ads Manager URL so you can identify the object type. Lift studies measure the causal, incremental impact of ads on business outcomes — the most rigorous form of measurement available. A/B tests isolate the impact of a single variable (creative, audience, or placement) so advertisers can learn what drives results. **If an active study is detected, always warn the user before proceeding with any modifications (budget, targeting, or creative), as changes during measurement can compromise the validity of incremental results.** When reviewing results, prioritize incremental metrics — incremental conversions, cost per incremental conversion, and incremental ROAS — over surface metrics like CPM, as these reflect the true business value of the ads. **When not to use:** Do not pass a study ID. To retrieve full results for a known study, use `ads_experiment_abtest_get_test` for an A/B test or `ads_experiment_lift_get_test` for a lift study.
Validate a completed Upload Service media upload and add it to the selected ad account library.
Lists custom audiences for a given ad account, with optional filtering by subtype. Results are paginated. ## When to use: - Call this tool when the user asks to list, show, or enumerate their custom audiences. - Use when the user wants to find audiences of a specific type (e.g., all lookalike audiences, all customer lists). - If `next_cursor` is returned, call this tool again with the cursor to get the next page. ## When NOT to use: - Do NOT call this tool to get details of a single audience — use ads_get_custom_audience instead. - Do NOT call this tool to create, update, or delete audiences — use the corresponding write tools. ## Response Guidelines: 1. Present the list of audiences with their names, subtypes, and sizes. 2. If many audiences are returned, summarize the count and list the first several. 3. Highlight any audiences with non-normal operation status or inactive delivery status. 4. If `next_cursor` is non-null, inform the user there are more audiences and offer to fetch the next page.
Retrieves the list of Facebook Page IDs associated with (promoted under) a given ad account. Results are paginated; default page size is 50, configurable via limit ## When to use: - Call this tool when you need to discover available Pages before creating an ad that requires a page_id (e.g., for the creative's object_story_spec). - Call this tool when the user asks which Pages are linked to or promoted under a specific ad account. - If `next_cursor` is returned, call this tool again with the cursor to get the next page of results. ## When NOT to use: - Do NOT call this tool if you already have the page ID from the client context or a previous call. - Do NOT call this tool to list the user's Pages in general — this tool is scoped to a specific ad account. ## Response Guidelines: 1. Present the list of pages to the user, including their names. 2. If many pages are returned, summarize the count and list the first several. 3. Each entry in `pages` contains `page_id` (numeric), `page_name`, and `leadgen_tos_accepted` (bool). 4. If `next_cursor` is non-null, there are more pages available. Call the tool again with the cursor to retrieve additional pages. ## Lead Ads Requirement: - Lead Generation campaigns (objective `OUTCOME_LEADS` with optimization_goal `LEAD_GENERATION` or `QUALITY_LEAD`) require the promoted Page to have accepted the Lead Generation Terms of Service. - Use the `leadgen_tos_accepted` field to filter pages eligible for lead ads BEFORE attempting to create one. - If the user picks a page where `leadgen_tos_accepted` is false, instruct them to accept the Lead Generation ToS at https://www.facebook.com/legal/leadgen/tos before creating the ad set.
Retrieves the list of ad account IDs that the current user has access to. Results are paginated in chunks of 50. ## When to use: - Call this tool when the user asks which ad accounts they have access to. - Call this tool when you need to discover the user's ad accounts before performing other operations. - Call this tool when the user asks to list, show, or enumerate their ad accounts. - If `next_cursor` is returned, call this tool again with the cursor to get the next page. ## When NOT to use: - Do NOT call this tool if you already have the ad account ID from the client context. - Do NOT call this tool for fetching ad account details, metrics, or performance data — use other tools for that. ## Response Guidelines: 1. Unless guideline 7 applies, present the list of ad accounts to the user, including their business associations. 2. Unless guideline 7 applies, if many accounts are returned, summarize the count and list the first several. 3. Each entry in `ad_accounts` contains `ad_account_id` (numeric), `ad_account_name`, `business_id`, `business_name`, and `is_ads_mcp_enabled`. The business fields reflect the **owning** business only. Ad accounts shared with ad agencies may have additional businesses with access that are not shown here. An empty string for `business_id` or `business_name` indicates the account has no owning business. If `is_ads_mcp_enabled` is false for an ad account, do NOT use that ad account id or any ad objects under it in subsequent tool calls. 4. If `next_cursor` is non-null, there are more accounts available. Call the tool again with the cursor (the one that was just returned by the previous call) to retrieve additional pages. 5. `is_queryable` shows the ability of account being able to use the `ads_get_ad_entities` tool. If `is_queryable` is false, do NOT call `ads_get_ad_entities` for that account — instead surface `not_queryable_reason` to the user. 6. Catalog recommendations are fetched only for the first few returned accounts. If you need catalog recommendations for an account without one, call `ads_catalog_list_dpa_eligible_catalogs` with its `ad_account_id`. 7. When the result includes `suggested_actions`, the user sees an interactive card that already lists their ad accounts. Do NOT show a table or list of the ad accounts, since it is redundant with the card. Still flag any issues with the accounts, such as `is_queryable` false (surface its `not_queryable_reason`), `has_payment_method` false, or an `account_status` other than ACTIVE. Do not repeat the suggested actions.
Retrieves live or draft campaigns, ad sets, ads, and their metrics. COMPLETION CONTRACT: After this tool returns, inspect `next_actions` before answering. If it is present, the request is not complete yet: call every action with `read_only: true` in ascending `step` order, using its `suggested_args`. These are required continuation calls, not optional suggestions; do not replace them with other analyses or stop after the first one. Only then combine the results and answer. Never call an action with `requires_user_confirmation: true` without approval; surface that change as a concrete proposal instead. WHEN TO USE: levels of ad, adset, campaign, or account. You can specify entity metrics, metric breakdowns, or attributes. Campaign, adset, and ad requests can apply filters and sorting parameters to customize the output. Account-level requests do not support filtering or sorting. **Workflow**: 1. Pick candidate fields from FIELDS below. 2. Verify them with `ads_get_field_context` (see FIELD VERIFICATION). 3. Call ads_get_ad_entities. **Precondition**: - If you don't already know whether the target ad account is queryable, call ads_get_ad_accounts first and check `is_queryable`. If false, surface `not_queryable_reason` to the user instead of calling this tool. Note: `is_queryable=true` is best-effort — the call may still fail for transient or input-related reasons. **Time range (metrics, filtering, sorting)**: - Metrics use the selected range, or the last 28 days by default. Metric filtering and sorting use the same range. - Provide one of: - `date_preset` (string). Date range preset. Exactly one of: today, yesterday, this_month, last_month, this_quarter, maximum, data_maximum, last_3d, last_7d, last_14d, last_28d, last_30d, last_90d, last_week_mon_sun, last_week_sun_sat, last_quarter, last_year, this_week_mon_today, this_week_sun_today, this_year. - `time_range` (string, JSON): `'{"since":"YYYY-MM-DD","until":"YYYY-MM-DD"}'`. - If neither `date_preset` nor `time_range` is provided, the tool defaults to the last 28 days. - Do not pass both `date_preset` and `time_range`. **Breakdowns**: Multiple compatible breakdowns can be requested in one call; unsupported ones or invalid combinations return an error. **Pagination**: - Omit `cursor` on the first call. - If the response has `pagination.next_cursor`, call again with it as `cursor` and resend every other query parameter unchanged; any other change invalidates the cursor. - Never refetch a page you already have. Limitations: - Account-level requests do not support `filtering` or `sort`. Do not pass those parameters when `level` is `ad_account` or `account`. - Each call returns one page, so a single call may not return every matching entity. To retrieve both the highest and lowest values of a metric, call this tool twice with opposite sorting directions. DO NOT: - Request `actions` or `action_values` as a standalone field. Check the available fields below. - Pass any field that is not listed in the FIELDS section for the level you are querying. Fields are level-scoped — a field valid at `campaign` may not exist at `ad`, and vice versa. - Pass any operator that is not in `supported_filter_operators` for that field. - Pass any enum value that is not in `enum_values` for that field. - Invent parameter names, field names, operators, or enum values. If it isn't in the catalog or the Arguments section, it is not supported. VALID FILTERING EXAMPLES (value is always an array of strings): - {"field":"effective_status","operator":"IN","value":["ACTIVE"]} - {"field":"name","operator":"CONTAIN","value":["summer"]} - {"field":"name","operator":"CONTAINS_ANY","value":["summer","spring"]} - {"field":"amount_spent","operator":"GREATER_THAN","value":["100"]} - {"field":"impressions","operator":"IN_RANGE","value":["1000","10000"]} DRAFTS (`object_state=draft`): Drafts are changes staged in Ads Manager, not yet published: not serving, no metrics. Pass `object_state=draft` to list them; the default `live` returns published objects as above. - STILL ROLLING OUT. If a `draft` call fails the account is not enabled: use `object_state=live` and point the advertiser to Ads Manager. Do not retry. - Scoped to the calling user: what THIS user staged, not everyone's. - `filtering` is rejected; `fields`, `sort`, `breakdowns`, `date_preset`, `time_range`, `time_increment` are accepted but ignored — a staged change has no metrics. - `object_ids`: only staged objects under the campaign, ad set or ad IDs you name — use it to check specific objects for unpublished changes. IDs may nest; results are deduplicated. - `limit` counts campaigns, each with its whole subtree (default 10, max 25); page with the returned `next_cursor` as `cursor`. - Results arrive in `ad_drafts`, not `ad_entities`; the staged object's ID is `ad_object_id`, not `id`. Everything below is `object_state=live` only. FIELDS (comma separated): Common to all levels (campaign, adset, ad, ad_account): amount_spent, app_custom_event_fb_mobile_purchase, app_install, average_purchases_conversion_value, clicks, comment, cost_per_2_sec_continuous_video_view, cost_per_action_type, cost_per_conversion, cost_per_lead, cost_per_link_click, cost_per_link_click_result, cost_per_omni_add_to_cart, cost_per_omni_app_install, cost_per_omni_complete_registration, cost_per_omni_initiated_checkout, cost_per_omni_landing_page_view, cost_per_omni_purchase, cost_per_outbound_click, cost_per_thruplay, cost_per_video_view, cpc, cpm, cpp, ctr, frequency, id, impressions, instagram_profile_follow_v2, landing_page_view, lead, like, link_click, media_views, mobile_app_install, mobile_app_purchase_roas, name, offline_conversion_purchase, offsite_conversion_fb_pixel_purchase, offsite_conversion_fb_pixel_purchase_values, omni_add_to_cart, omni_app_install, omni_complete_registration, omni_initiated_checkout, omni_landing_page_view, omni_purchase, omni_purchase_values, omni_view_content, onsite_conversion_lead_grouped, onsite_conversion_purchase, outbound_clicks, outbound_clicks_ctr, page_engagement, post_engagement, post_reaction, post_save, purchase_roas, reach, result_roas, result_values, results, shop_clicks, unique_link_click, unique_link_clicks_ctr, video_avg_time_watched_actions, video_continuous_2_sec_watched_actions, video_p100_watched_actions, video_p25_watched_actions, video_p50_watched_actions, video_p75_watched_actions, video_p95_watched_actions, video_play_actions, video_thruplay_watched_actions, website_ctr, website_purchase_roas campaign (additional): 3_second_video_plays, account_id, ad_creation_package_config, bid_strategy, budget_remaining, buying_type, conversions, cost_per_result, created_time, daily_budget, delivery, effective_status, lifetime_budget, objective, pacing_type, post_shares, smart_promotion_type, special_ad_category_country, spend_cap, start_time, status, stop_time, updated_time adset (additional): 3_second_video_plays, account_id, adset_schedule, attribution_setting, attribution_spec, bid_amount, bid_constraints, bid_strategy, billing_event, budget_remaining, campaign_id, campaign_name, cost_per_result, created_time, daily_budget, daily_min_spend_target, daily_spend_cap, delivery, delivery_sub_status, destination_type, effective_status, end_time, frequency_control_specs, is_dynamic_creative, learning_stage_info, lifetime_budget, optimization_goal, pacing_type, post_shares, promoted_object, start_time, status, stop_time, targeting, updated_time ad (additional): account_id, adset_id, adset_name, bid_amount, campaign_id, campaign_name, conversion_domain, cost_per_result, created_time, creative_id, delivery, effective_status, objective, status, updated_time ad_account (additional): 3_second_video_plays, post_shares, timezone_name FIELD RESTRICTIONS: Not available at level=account (listed as `ad_account` in FIELDS): account_id, ad_creation_package_config, adset_id, adset_name, adset_schedule, attribution_setting, attribution_spec, bid_amount, bid_constraints, bid_strategy, billing_event, budget_remaining, buying_type, campaign_id, campaign_name, conversion_domain, conversions, cost_per_result, created_time, creative_id, daily_budget, daily_min_spend_target, daily_spend_cap, delivery, delivery_sub_status, destination_type, effective_status, end_time, frequency_control_specs, is_dynamic_creative, learning_stage_info, lifetime_budget, objective, optimization_goal, pacing_type, promoted_object, smart_promotion_type, special_ad_category_country, spend_cap, start_time, status, stop_time, targeting, updated_time Not filterable - never use these in `filtering`: account_id, adset_name, adset_schedule, attribution_spec, average_purchases_conversion_value, bid_amount, bid_constraints, bid_strategy, billing_event, budget_remaining, campaign_name, comment, conversion_domain, conversions, cost_per_2_sec_continuous_video_view, cost_per_action_type, cost_per_conversion, cost_per_link_click_result, cost_per_thruplay, creative_id, daily_min_spend_target, daily_spend_cap, destination_type, frequency_control_specs, instagram_profile_follow_v2, is_dynamic_creative, learning_stage_info, offsite_conversion_fb_pixel_purchase_values, omni_purchase_values, onsite_conversion_lead_grouped, onsite_conversion_purchase, pacing_type, post_save, promoted_object, shop_clicks, smart_promotion_type, special_ad_category_country, spend_cap, targeting, timezone_name, video_continuous_2_sec_watched_actions, video_p100_watched_actions, video_p25_watched_actions, video_p50_watched_actions, video_p75_watched_actions, video_p95_watched_actions, video_thruplay_watched_actions FIELD VERIFICATION (required): Before passing any name in `fields`, `filtering`, or `sort`, call `ads_get_field_context` to verify it. Unverified field names will fail. Use its canonical `name` for tool requests, but use its `display_name` in table headers, text, and summaries. The response is the source of truth for `levels`, `filterable`, `sortable`, `supported_filter_operators`, and `enum_values`.
List ad images uploaded to an advertiser's ad account. **IMPORTANT — Partial results**: When called without `hashes`, this tool returns only `hash` and `name` for each image, and `fields` has no effect. If you need any field beyond `hash` and `name`, you MUST call this tool again with `hashes` (optionally with `fields`) — do NOT assume a field is empty just because it was missing from a previous listing response. ## When to use: - The user wants to see what images are available in their ad account. - The user wants to find an image by name. - The user needs image hashes for creating ad creatives. - The user asks about specific image fields (e.g. dimensions, URLs, status) — even if images were already listed earlier, re-call this tool with `hashes` to fetch the needed data, because the earlier listing only returned partial fields. - The user wants to download an original image file — call with `hashes` and `fields: ["download_url"]`. ## When NOT to use: - The user wants to list ad creatives (use ads_get_creatives instead). ## Available fields (returned for `hashes` lookups): - `hash`, `name`, `status`, `width`, `height`, `original_width`, `original_height`, `url` (full-size display URL), `url_128` (128px thumbnail), `permalink_url`, `created_time`, `updated_time`. - `download_url` — original, full-quality image download URL. Opt-in: returned only when named in `fields`, never by default. - These are the only accepted `fields` values. Any other name fails validation. ## Fields handling: - When the user asks for "details", "info", "full info", "all fields", "everything", or any other generic term indicating they want complete data, do NOT pass those words ("details", "info", "full info", "all fields", "everything", etc.) through `fields`. - Only pass `fields` when the user explicitly names specific fields they want. Omitting `fields` on a `hashes` lookup returns every field above except `download_url`. ## Notes: - Returns active images only, ordered by upload time (newest first). - The `hash` field uniquely identifies an image and is needed when creating ad creatives.
Generate a visual preview of how an ad creative appears on Facebook, Instagram, Messenger, or other placements. CRITICAL: after this tool returns, you MUST include the returned `preview_url` verbatim in your reply to the user as a clickable link — this is the primary way the user opens the preview in their browser. Do NOT summarize the ad without linking `preview_url`; do NOT rely on the iframe rendering silently in the host UI. Provide either an ad_id (to preview an existing ad — live or draft) or a creative_id (to preview an existing creative). This tool takes NO ad_account_id: the account is derived from the ad or creative, and passing ad_account_id is rejected as an unknown argument. FALLBACK: if a call with `ad_id` errors because the ad has not fully materialized (a very fresh draft ad), retry once with the `creative_id` you passed to `ads_create_ad` — that renders the same creative. Do NOT retry when the error says the ad or its account is not accessible: the creative sits in that same account and will fail identically. Report the access problem instead of cycling ids. The ad_format parameter controls which placement to preview (e.g., MOBILE_FEED_STANDARD for Facebook mobile feed, INSTAGRAM_STANDARD for Instagram feed). Omit ad_format to preview the ad set placements supported by the creative, in a stable order modeled on Ads Manager. When ad_format is provided, that placement is shown first and the derived placements remain available in the advanced preview. The response also includes preview_html (an iframe of the rendered ad), a `previews` list describing every previewed placement (each with a `screenshot_token` the UI card redeems for an image), and creative details (body text, headline, CTA button). Screenshots are captured on demand rather than returned inline, so the response carries no image bytes.
Internal capture sink for the Ads MCP App ad preview card. App-only; not intended for model use.
List ad videos uploaded to an advertiser's ad account. **IMPORTANT — Partial results**: When called without `video_ids`, this tool returns only `id` and `title` for each video, and `fields` has no effect. If you need any field beyond `id` and `title`, you MUST call this tool again with `video_ids` (optionally with `fields`) — do NOT assume a field is empty just because it was missing from a previous listing response. ## When to use: - The user wants to see what videos are available in their ad account. - The user needs video IDs for creating ad creatives. - The user asks about specific video fields (e.g. duration, description, permalink) — even if videos were already listed earlier, re-call this tool with `video_ids` to fetch the needed data, because the earlier listing only returned partial fields. - The user wants to download a video file — call with `video_ids` and `fields: ["download_hd_url"]`. ## When NOT to use: - The user wants to list ad creatives (use ads_get_creatives instead). - The user wants to list ad images (use ads_get_ad_images instead). ## Available fields (returned for `video_ids` lookups): - `id`, `title`, `description`, `length` (seconds), `created_time`, `updated_time`, `permalink_url`, `picture` (thumbnail URL), `status` (upload/processing state). - `download_hd_url` — HD MP4 download URL (the Marketing API calls this `source`). Opt-in: returned only when named in `fields`, never by default. Null when the video has no HD rendition or its source is not available to this app. - These are the only accepted `fields` values. Any other name (e.g. `source`, `thumbnails`, `format`) fails validation. ## Fields handling: - When the user asks for "details", "info", "full info", "all fields", "everything", or any other generic term indicating they want complete data, do NOT pass those words ("details", "info", "full info", "all fields", "everything", etc.) through `fields`. - Only pass `fields` when the user explicitly names specific fields they want. Omitting `fields` on a `video_ids` lookup returns every field above except `download_hd_url`. ## Notes: - Returns videos with OK status only, ordered by creation time (newest first). - The `id` field is the video FBID needed when creating video ad creatives.
Get the ads (adgroups) that use a given ad creative. ## When to use: - The user wants to know which ads reference a specific creative. ## When NOT to use: - The user wants to list all ads in an account (use ads_get_ad_entities instead). - The user wants creative details (use ads_get_creatives instead).
List ad creatives in an advertiser's ad account. By default, account-wide listings return `id`, `name`, `account_id`, `status`, `body`, `title`, and `call_to_action_type`, so the creative's core content is available in one call. Provide `fields` to request a different subset; `id` is always included. When looking up `creative_ids`, omitting `fields` returns all supported fields. ## When to use: - The user wants to see what creatives exist in their ad account. - The user wants to see the details of a specific creative identified by a given ID. - The user asks about specific creative fields (e.g. body text, link URL, image hash, CTA type) — pass those names through `fields` to fetch exactly that subset. ## When NOT to use: - The user wants to create or modify a creative (this tool is read-only). - The user wants to list images (use ads_get_ad_images instead). - The user wants to list videos (use ads_get_ad_videos instead). ## Fields handling: - When the user asks for "details", "info", "full info", "all fields", "everything", or any other generic term indicating they want complete data, do NOT pass those words ("details", "info", "full info", "all fields", "everything", etc.) through `fields`. - Only pass `fields` when the user explicitly names specific fields they want. ## Field naming: - Return text fields exactly as stored. Do NOT translate or rename them. - `body` is the Marketing API field name. It is called "primary text" in Ads Manager — but always return it as `body`. - `title` is the Marketing API field name. It is called "headline" in Ads Manager — but always return it as `title`. - In `child_attachments`, `name` is called "headline" in Ads Manager and `description` is the card description. - `description` and `display_link` return the values stored on the creative, using the same names as the `ads_create_creative` inputs. A stored value is not necessarily displayed: Facebook Feed does not show `description` on single-image or single-video ads. ## Catalog creatives: - When `product_set_id` is present the creative is Advantage+ catalog-backed (media is sourced from the catalog at delivery time, not from `child_attachments`). Use `ads_catalog_list_product_sets` or `ads_catalog_list_products` to inspect the product set, and `ads_catalog_get_diagnostics` / `ads_catalog_get_dynamic_ads_health` to check whether catalog health is blocking delivery.
Retrieves details of a specific custom audience by its ID, including size, status, delivery info, and type. ## When to use: - Call this tool when the user asks for details about a specific custom audience. - Use when you need to check audience size, delivery status, operation status, or subtype. - Use after creating or updating a custom audience to verify its current state. ## When NOT to use: - Do NOT call this tool to list all audiences in an ad account — use ads_get_ad_account_custom_audiences instead. - Do NOT call this tool to create, update, or delete audiences — use the corresponding write tools. - Do NOT call this tool without a specific custom_audience_id. ## Response Guidelines: 1. Present the audience details clearly: name, subtype, size range, delivery status, and operation status. 2. If operation_status_code is not 200, highlight the issue and explain what it means. 3. If delivery_status is INACTIVE or INVALID, explain to the user that the audience cannot be used for ad delivery. 4. Include time_created and time_updated so the user knows how fresh the audience is.
Returns ad sets (adgroups) that use a given custom audience in their targeting. ## When to use: - Call this tool BEFORE calling ads_delete_custom_audience to check which ad sets will be paused. - Use when the user wants to know which campaigns or ad sets are using a specific audience. ## When NOT to use: - Do NOT use to get audience details — use ads_get_custom_audience instead. - Do NOT use to list all audiences — use ads_get_ad_account_custom_audiences instead. ## Response Guidelines: 1. If adsets is non-empty, list the ad sets by name and ID and warn the user these will be paused if the audience is deleted. 2. If adsets is empty, inform the user that no ad sets are currently using this audience. 3. If total_count exceeds the number of returned adsets, inform the user there are more ad sets not shown.
Retrieves a paginated list of custom conversions for an ad account, optionally filtered to a specific dataset (pixel or offline conversion data set). Use when discovering which custom conversions exist on an ad account, auditing rules, or looking up conversion IDs before querying stats. Read-only — does not create or modify custom conversions. No metrics fields.
Retrieves identity and configuration metadata for a dataset (also known as pixel or application), including name, status, creation time, business association, and data-use settings. Use when asking about dataset setup, active status, ownership, or configuration. Does not return event volume or signal quality — use ads_get_dataset_stats for event counts, or ads_get_dataset_quality for match quality and freshness. Flag inactive datasets or stale last_fired_time / server_last_fired_time values in responses.
Retrieves signal quality and health metrics for a dataset (also known as pixel or application), including Event Match Quality (EMQ) scores, per-match-key coverage, and data upload freshness. Results are grouped by channel (web, offline, crm, custom_attribution). Use when investigating match quality, match-key coverage gaps, data freshness, or upload regularity. Does not return event volume or counts — use ads_get_dataset_stats instead. Flag low EMQ scores or poor match-key coverage in responses.
Retrieves event volume statistics for a dataset (also known as pixel or application). `start_time` must be no more than 28 days ago, and an explicit start/end range must span at most 28 days. Use Unix timestamp strings in seconds, not ISO 8601; do not call this tool for older dates. Use when asking about event counts, volume trends, traffic patterns, or whether specific events are being received. Does not return signal quality or data freshness — use ads_get_dataset_quality instead. Flag events with zero volume if they are used in an active campaign.
Retrieves a paginated list of datasets (also known as pixels or applications) owned or assigned to a business or ad account, including name, status, and creation time. Use to discover which datasets exist before querying stats or quality, or to audit dataset ownership. Does not return signal quality or event volume — use ads_get_dataset_quality or ads_get_dataset_stats. Only one of business_id or ad_account_id may be provided.
Fetches delivery-blocking errors for campaign, ad set or ad. These are hard-stop issues that keep assets inactive or prevent publish/delivery. Only use this tool at the ad account level if you are doing it to pull the errors for child entities and not the ad account itself. There are issues that this tool does not cover, such as: - performance, pacing, or optimization issues. - Disabled or restricted accounts - Ad rejection Catalog-backed ads: if the error mentions product set, catalog, feed, or product eligibility (e.g., product set empty, feed stale, items not eligible for dynamic ads), use `ads_catalog_get_diagnostics` and `ads_catalog_get_dynamic_ads_health` on the backing catalog to diagnose the root cause, and `ads_catalog_get_data_sources` / `ads_catalog_list_product_feeds` to check feed health and last upload. For shallow-catalog issues (too few eligible products), `ads_catalog_list_products` shows what matches the filter.
Returns rich metadata for ads fields (canonical name, display name, type, description, filterability, sortability, enum values, aliases, metric flag, supported levels). ## When to use: - User mentions a field that is not in the ads_get_ad_entities description and you need to confirm its existence/type before querying. - You need to resolve an alias (e.g. `spend` -> `amount_spent`, `actions:lead` -> `lead`). - You need the list of enum values for a field before constructing a filter. - You need to see which levels (campaign, adset, ad, ad_account) support a specific field. - You want to browse all available fields (call without field_names). ## Inputs: - field_names (optional): list of field names or aliases to look up. When omitted or empty, returns all available fields. ## Behavior: - If field_names is omitted or empty, returns all fields in the catalog. - If field_names is provided, looks up each name (resolving aliases) and returns matching field metadata. - Each field's metadata includes `levels` showing which levels support that field (campaign, adset, ad, ad_account). - Use `name` for tool requests and `display_name` as the field name when displaying data in table headers, text, and summaries. - Names that don't resolve are returned in unknown_fields. ## Output: - fields: structured metadata entries for each resolved field. See the output schema for the full per-field shape. - unknown_fields: array of input strings that did not resolve.
Retrieves help center articles relevant to the user's question about advertising concepts, policies, or how-to guides. ## When to use: - Call this tool when the user asks general questions about advertising concepts, policies, best practices, or how-to guides. - Use for questions about brand safety, content control, inventory filters, block lists, or content monitoring. ## When NOT to use: - Do NOT call this tool for account-specific metrics, performance data, or entity details. - Do NOT call this tool for performance optimization advice or bidding strategy recommendations. - Do NOT call this tool for disabled/restricted account issues or billing questions. ## Response Guidelines: Summarize the relevant information and include article URLs in the response. If no helpful articles are found, indicate that no relevant help articles were found for the query.
Retrieves Instagram accounts linked to an ad account that can be used for creating ads. Results are paginated in chunks of 25. ## When to use: - Call this tool when the user wants to boost an Instagram post. - Call this tool to discover which IG accounts are available for advertising. - Call this tool when you need to find the IG account ID for advertising. - If `next_cursor` is returned, call this tool again with the cursor to get the next page. ## When NOT to use: - Do NOT call this tool to fetch ads entities or ad account data — use other tools for that. - Do NOT call this tool if you already have the IG account ID. ## Response Guidelines: 1. Present the list of IG accounts with their usernames. 2. If multiple accounts exist, help the user choose the right one. 3. Include profile picture URLs for visual identification. 4. If `next_cursor` is non-null, there are more IG accounts available. Call the tool again with the cursor to retrieve additional pages. 5. If zero accounts are returned, tell the user that either no Instagram accounts are linked to this ad account for advertising, or the app has not been granted the `instagram_basic` permission for the linked accounts.
Fetches advertisable IG media owned by a linked advertiser IG account. Returns posts, reels, and stories that can be promoted. Results are paginated in chunks of 25. ## When to use: - Call this tool after ads_get_ig_accounts to list the advertiser's own media for an ordinary boost. You MUST provide the same ad_account_id used in ads_get_ig_accounts. - Call this tool when the user wants to choose which post to promote. - If `next_cursor` is returned, call this tool again with the cursor to get the next page. ## When NOT to use: - Do NOT call this tool without first getting the IG account ID from ads_get_ig_accounts. - Do NOT call this tool with an IG account that is not returned by ads_get_ig_accounts — the account must be both linked to the ad account and have the `instagram_basic` permission granted. - Do NOT use this tool to discover media owned by an unlinked third-party IG account; it only lists media for the linked advertiser account. ## Response Guidelines: 1. Present media with captions and types (IMAGE, VIDEO, CAROUSEL_ALBUM). 2. Include permalinks so users can preview the content. 3. Filter if the user wants only specific posts, such as specific date ranges or types. 4. If `next_cursor` is non-null, there are more media items available. Call the tool again with the cursor to retrieve additional pages.
Fetches the current account-level opportunity score (0-100) and the MAPI-supported subset of recommendations for an ad account. META RECOMMENDS calling this tool proactively — it identifies concrete steps to improve ad performance based on Meta's best practices. ## Recommendation coverage: The score is fetched separately from the recommendation list. This list is only the MAPI-supported subset; Ads Manager may show additional recommendations. Do not describe it as the complete account inventory or claim its highest-point item is the account's biggest remaining opportunity. ## When to use — PROACTIVELY RECOMMEND THIS TOOL: - User mentions Opportunity Score, account optimization, or recommendations. - User asks how to improve ad performance, get better results, or optimize their ads — use this tool as part of the analysis. - User asks "what should I do next?", "how can I improve?", or "what's wrong with my ads?" — call this tool. - After creating a campaign with `ads_create_campaign`, recommend checking the Opportunity Score to ensure the new setup follows Meta best practices. - User is reviewing account performance or asking about underperforming campaigns — Opportunity Score recommendations often identify the root cause (e.g., SCALE_GOOD_CAMPAIGN, ADVANTAGE_PLUS_AUDIENCE, AUTOMATIC_PLACEMENTS, CBO). - User is unsure what to change — this tool provides prioritized, actionable recommendations sorted by expected score improvement. ## Sequencing for broad analysis: - When the request requires current entity metrics plus trends or recommendations, call `ads_get_ad_entities` first and follow any `next_actions` it returns. Do not call this tool before that initial entity read. Call this tool directly first only when the user specifically asks for Opportunity Score or its recommendations. ## When NOT to use: - Do NOT use when the user needs ad-level creative feedback (use creative insight tools instead). - Do NOT use for delivery-blocking errors — use `ads_get_errors` instead. ## Response Guidelines: 1. Present the score prominently: "Your opportunity score is X out of 100." IMPORTANT: The score is ALWAYS account-level — NEVER claim it applies to a specific campaign, ad set, or ad. 2. Interpret the score: A higher score means better alignment with Meta best practices and improved performance over time. A lower score means there are untapped optimization opportunities. 3. Present recommendations sorted by **opportunity_score_lift** (highest first). Refer to lift values as **points** — NEVER as "impact" or other terms. 4. For each recommendation, explain the expected benefit using `lift_estimate` (e.g., "Up to 3% more Traffic") and the score improvement in points. 5. Persuasively convey the value: applying these recommendations will increase the score and is likely to improve ad performance. 6. Always surface the recommendation's `url` to review and apply it in Ads Manager. If the URL is absent, hand off to Ads Manager's Recommendations page. ## Common Issues to Avoid: - NEVER state that a campaign, ad set, or ad has an Opportunity Score. It is account-level only. - NEVER claim recommendations are sorted by "impact" — use "points." ## Catalog signals — connect to deeper catalog diagnostics: When the account runs catalog sales / Advantage+ catalog ads, poor performance or low delivery can trace to catalog health rather than targeting/creative. Use `ads_catalog_get_diagnostics` (catalog-wide MUST_FIX issues) and `ads_catalog_get_dynamic_ads_health` (DA health checks per catalog or product set) alongside this tool to rule out feed staleness, product eligibility, or product-set coverage as the driver before optimizing bids/audiences.
Retrieves the list of Facebook Pages owned by a specific business. Results are paginated in chunks of 50 by default. ## When to use: - Call this tool when the user wants to know which Pages belong to a business. - Call this tool when you need a page_id to use in ad creation (e.g., for the creative's page_id field). - Call this tool when the user asks to list, show, or enumerate Pages for a business. - If you do not have a business_id, call the `ads_get_ad_accounts` tool first to discover the business IDs accessible to the user. - If `next_cursor` is returned, call this tool again with the input `cursor` set to the value of `next_cursor` from the previous response to get the next page. ## When NOT to use: - Do NOT call this tool if you already have the page_id from prior context. - Do NOT call this tool for fetching Page insights or performance data. ## Response Guidelines: 1. Present the list of Pages to the user, including their names. 2. If many Pages are returned, summarize the count and list the first several. 3. Each entry in `pages` contains `page_id` and `page_name`. 4. If `next_cursor` is non-null, there are more Pages available. Call the tool again with the cursor (the one that was just returned by the previous call) to retrieve additional pages. The cursor is an opaque value — never fabricate or guess cursor values.
Retrieves all Facebook Pages the current user can use for advertising. Returns pages the user has CREATE_ADS permission on, including pages they directly admin and pages accessible through their businesses. Results are paginated; default page size is 50, configurable via limit. ## When to use: - Call this tool when you need to discover available Pages before creating an ad that requires a page_id (e.g., for the creative's object_story_spec). - Call this tool when the user asks which Pages they can use for ads. - Call this tool when you need a page_id but do not have a specific ad account or business context. - If `next_cursor` is returned, call this tool again with the cursor to get the next page of results. ## When NOT to use: - Do NOT call this tool if you already have the page ID from the client context or a previous call. - Do NOT call this tool to list Pages for a specific business — use ads_get_pages_for_business instead. ## Response Guidelines: 1. Present the list of pages to the user, including their names. 2. If many pages are returned, summarize the count and list the first several. 3. Each entry in `pages` contains `page_id` (numeric) and `page_name`. 4. If `next_cursor` is non-null, there are more pages available. Call the tool again with the cursor to retrieve additional pages.
Provides an overview of the advertiser's business context and marketing funnel to determine the most relevant optimization goal and approach
Surfaces alerts and warnings about deviations in ad performance, including unusual patterns, spikes or drops. Detects anything that may be worth investigating with regards to how an account, campaign, ad set, or ad is performing. When presenting findings, distinguish between observations and actionable causes — anomalies indicate areas for deeper analysis, not definitive conclusions. When to use: What's wrong with my ads performance? Are there any patterns I should be aware of? Why has my performance changed suddenly? What's being flagged in my ad account? When not to use: Only use this tool to indicate variance in performance, not delivery-blocking setup issues, policy, or publish errors. For causally linked, higher-confidence opportunities that quantify potential performance lift, refer to recommendations from the Opportunity Score tool, which are backed by rigorous analysis.
Highlights which ads have generated stronger results in the auction and identifies factors (bid, ad quality) that can be optimized for improved performance. Use this to diagnose auction competitiveness and guide optimization. Recommends consolidating similar ad sets and reducing audience fragmentation in cases of high auction overlap, as high overlap leads to under-delivery and budget fragmentation.
Compares ad set performance against aggregated benchmarks from similar advertisers, optionally filtered by spend tier, optimization goal, and an explicitly requested industry sub-vertical. When interpreting results, focus on business outcome metrics (like cost per result) rather than surface metrics (like CPM), and ensure comparisons are made between ad objects with similar optimization goals and conversion events. Above and below the benchmark describe performance, not the raw value: above is always the better standing, so for cost metrics an ad set performing above the benchmark is paying less than its peers and its line reads "below benchmark".
Analyzes the direction and changes in key ad performance metrics over time, including Cost Per Click (CPC), Cost Per Mille (CPM), Cost Per Result (CPR), Return on Ad Spend (ROAS), Click-Through Rate (CTR), and Conversion Rate (CVR). These insights provide a time-series view of performance, enabling advertisers to better understand campaign trends and make informed decisions for campaign summaries, performance evaluation, and diagnosis. This tool analyzes the full available history and accepts no date range: do not pass date_preset, date_from, or date_to. To analyze a specific window, use ads_get_ad_entities with a date_preset instead. For a broad analysis that combines current entity metrics with trends or recommendations, call ads_get_ad_entities first and follow any next_actions it returns. Call this tool directly first only when the user specifically asks for a trend or time-series analysis. If the response contains a `scorecard` field, an interactive card showing that data is ALREADY rendered to the user: do not visualize it and do not restate it as a text table or a per-object metric list. Reply with short prose that adds to the card — the takeaway, the likely cause, what to do next.
Compares an ad set's delivery and efficiency metrics (cost per result, CPM, CTR, plus its funnel stage's metrics such as landing page view rate, conversion rate and ROAS, and CPC when requested as analysis_metric) against a cohort of similar advertisers' ad sets, and returns the percentile for each metric. ## When to call: - The user asks how their ads are performing, or how to improve, diagnose or summarize them for any time period. "Is this good or bad?" can't be answered without an outside reference, so call this whenever you are judging performance, not only when the user says "benchmark", "industry" or "competitors". ## Reading the result: Use the result in two ways, and call out both in the answer: 1. Main KPI benchmark: identify the benchmark metric that matches the goal of the question and of the ad set (the analysis_metric when given, otherwise the result the ad set optimizes for) and lead with where the ad set stands against peers on it. Use the remaining benchmark metrics in this result as diagnostics that explain the ad set's standing on that main KPI benchmark, not as separate verdicts. 2. Funnel view: use all the benchmark metrics in this result to compare the ad set with its peers across the funnel, from impressions through clicks and landing page views to conversions, covering only the stages those metrics are available for, and call out the stages where it pulls ahead of or falls behind its peers. Pass ad set or campaign IDs in entity_ids (a campaign covers its ad sets), or omit entity_ids to cover the ad account's ad sets. At most 5 ad sets are benchmarked per call: the ones named directly first, then the biggest spenders. Compare percentiles within one ad set only: each ad set has its own cohort. Percentile is direction-aware: higher is always better, including for cost metrics. Use this analysis to complement the analysis from other tools.
Searches the Meta Ad Library for ads matching specified criteria. Returns publicly available ad data including ad creative, page info, and metadata. This tool is for advertisers researching the Ad Library to create better, more performant ads. It is only available to viewers who have at least one active ad account; callers without an active ad account will receive an error rather than results. ## When to use: - Call this tool when the user wants to search for ads in the Ads Library. - Use for competitive research, ad transparency queries, or finding ads by keyword, page, or country. - Use when the user asks questions like "show me ads from [page]", "find ads about [topic]", "what ads are running in [country]". ## When NOT to use: - Do NOT use for the user's own ad account management (use other ads tools instead). - Do NOT use for ad performance metrics. - Do NOT use for bulk data extraction/scraping of the Ad Library. ## Response Guidelines: 1. Present the search results in a readable format: ad creative text, page name, creation date, and ad snapshot URL. 2. If many results are returned, summarize the key findings and highlight notable patterns. 3. Always mention the total estimated result count so the user knows the scope. 4. Include the ad_snapshot_url for ads the user may want to inspect visually. ## Common Issues to Avoid: - Always require at least one of: search_terms, page_ids, or countries to be specified. - Country codes must be ISO-2 format (e.g., 'US', 'GB', 'DE').
Internal telemetry sink for the Ads MCP App UI widgets. App-only; not intended for model use.
Creates Meta Pixel conversion event rules. Batch-capable. AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{pixel_id, event_type, rule_type, match_value, operator?, domain_uri, parameters?: [{parameter_type, extractor_type, extractor_config_json}]}]`. Pair events with parameters to capture conversion data (Purchase: value+currency; AddToCart: content_ids; Lead: content_name) — embed inline here for atomic event+param create, or add later via ads_pixel_parameter_create. An event without parameters fires but captures no data. `event_type` must be a Meta standard event (see STANDARD EVENTS below). `rule_type=TOKENIZED_BUTTON_TEXT` for button-click events; `rule_type=URL` for page-load events. For embedded `parameters[]`, the selector primer lives in the ads_pixel_parameter_create description — apply the same rules here. WHEN TO CALL DIRECTLY: if the caller's request already includes `pixel_id`, `event_type`, and `match_value` (or all required event-creation fields), call this tool DIRECTLY — do NOT call ads_pixel_event_read or ads_pixel_parameter_read first to inspect existing state. The user's explicit creation request IS their intent; do not ask for confirmation before creating. MULTI-STEP REQUESTS: when the user's prompt chains operations ("create event X then activate it", "set up event X then add a CSS extractor for Y", "create then activate immediately"), call all required tools in the SAME turn without pausing for confirmation between steps. After ads_pixel_event_create, immediately call ads_pixel_event_update with `status=ACTIVE` if the user asked to activate, and/or ads_pixel_parameter_create if the user asked to add an extractor. The chained request IS the user's complete intent. BEHAVIOR: created events default to `status=INACTIVE` — call ads_pixel_event_update to activate. Default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/event per input item. WORKFLOW (end-to-end pixel event setup): (1) DISCOVER conversions to track. Preferred: Playwright headless Chromium 1280x1080 — `page.goto(url, wait_until='networkidle', timeout=20000)`, full-page screenshot, then `page.evaluate` to map clickables (`button, a, input[type=submit], [role=button]`), currency-formatted text (regex `/[$€£¥]\s?[\d,.]+|[\d,.]+\s?(?:USD|EUR|GBP|JPY|AUD|CAD)/`), and unique href paths. Always check `<script type="application/ld+json">` and `[itemprop=price]` first — they have higher extractor precedence than CSS. Fallback ladder: curl `-sS -L --compressed --max-time 20` (escalate when SPA shell: gzip body <50KB + empty `<div id="root|app|__next|__nuxt">`) → user-provided full-page screenshot → guided Q&A about button text, URL pattern, standard event choice, value/currency selectors. (2) PROPOSE the (event_type, rule_type, match_value, parameters[]) tuple to the user as a checklist and get explicit approval before the write. This step covers a tuple YOU derived in step (1) — the user has not seen it yet, so it needs their sign-off. It does NOT override WHEN TO CALL DIRECTLY above, and the waiver uses that same field list: when the request already supplies `pixel_id`, `event_type`, and `match_value`, there is nothing to propose — call directly, even if you filled in `rule_type` or `parameters[]` yourself. Propose and wait for approval only when you derived any of those three. (3) CALL ads_pixel_event_create — events default to status=INACTIVE. (4) ACTIVATE via ads_pixel_event_update with status=ACTIVE — the human-in-the-loop checkpoint between setup and firing. (5) VERIFY (see ads_pixel_event_update for the full verification ladder). STANDARD EVENTS — 17 case-sensitive Meta Pixel event names; pick exactly one for `event_type`. Triggers + disambiguation: - AddPaymentInfo: "Save Card/Payment", "Add Card", payment-info pages. Recommended params: content_ids, contents, currency, value. - AddToCart: "Add to Cart/Bag/Basket", "+ Add", quick-add icons. Recommended: content_ids, content_type, contents, currency, value (contents required for Advantage+ catalog ads). - AddToWishlist: "Save for Later", "Add to Favorites", "Add to Registry", heart-icon save. Recommended: content_ids, contents, currency, value. - CompleteRegistration: "Sign Up/Create Account/Register". Recommended: currency, value, status. Disambig: paid plan signup → Subscribe; free trial → StartTrial; soft lead-gen form → Lead. - Contact: "Contact Us/Call/Chat", mailto:/tel: links, contact-form submits. Disambig: quote/demo/pricing request → Lead. - CustomizeProduct: "Customize/Personalize/Configure/Build Your Own", in-PDP configurators. Disambig: cart-add itself → AddToCart (both can fire in one session). - Donate: "Donate/Give/Contribute/Pledge/Sponsor". Strongly recommended: currency, value. A donation flow with checkout-style steps is still Donate (NOT Purchase). - FindLocation: "Find a Store/Locator/Find Nearest", store-finder map searches, ZIP-code lookups. Disambig: catalog product search → Search. - InitiateCheckout: "Checkout/Proceed to Checkout/View Cart/View Bag". Recommended: content_ids, contents, currency, num_items, value. Disambig: "Place Order"/"Pay Now"/"Confirm Order" → Purchase, NOT InitiateCheckout. - Lead: "Get a Quote/Request Demo/Talk to Sales/Free Estimate/Download Whitepaper", lead-magnet email submits, /pricing page hits. Recommended: currency, value. Disambig: full account creation → CompleteRegistration; appointment with chosen time slot → Schedule; direct human contact → Contact. - Purchase: "Buy Now/Place Order/Pay Now/Confirm Order/Complete Purchase". URL patterns: /order-confirmation, /thank-you, /receipt, /order/{id}/success. **value AND currency parameters are REQUIRED for Purchase.** Recommended: content_ids, content_type, contents, num_items (contents or content_ids required for Advantage+ catalog ads). - Schedule: "Book Appointment/Schedule a Visit/Reserve a Slot/Make Reservation", calendar time-slot submits. Common verticals: medical, automotive, home-services, real estate, salons. Disambig: "have someone call me" form with no time picked → Lead. - Search: search-form submits, search-icon enter, autocomplete-result clicks. URL patterns: /search?q=, /results?query=. Recommended: content_ids, content_type, contents, currency, search_string, value (contents or content_ids required for Advantage+ catalog ads). - StartTrial: "Start Free Trial/Try Free/Begin Trial/Start Your 7-Day Free Trial". Recommended: currency, value, predicted_ltv. Disambig: paid recurring plan → Subscribe; free signup with no trial → CompleteRegistration. - SubmitApplication: "Apply Now/Submit Application/Apply for Card/Apply for Loan/Enroll Now". Common verticals: financial services, education, employment, insurance, healthcare enrollment. - Subscribe: PAID recurring "Subscribe/Start Subscription/Get Premium/Upgrade to Pro/Join Membership". Recommended: currency, value, predicted_ltv. Disambig: "Subscribe to newsletter"/free email signup → Lead or CompleteRegistration; free trial → StartTrial. - ViewContent: high-value PDPs (/product/, /p/, /products/), key articles (/article/, /blog/), high-intent landing pages. Recommended: content_ids, content_type, contents, currency, value (contents or content_ids required for Advantage+ catalog ads). Do NOT fire on every route — PageView already auto-fires from `fbq('init', ...)`. Reserve ViewContent for pages signaling real interest in a specific product or piece of content.
Deletes Meta Pixel conversion event rules. Batch-capable. Mirrors the same delete semantics as the Events Manager Pixel UI (EST) and IWL flow use — same backend (`EventRulesDeleteBusinessLogicTrait::genDeleteEventRule`). AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{event_rule_id}]`. Call this tool whenever the user says delete / remove / drop / get rid of / uninstall / clean up / kill / nuke an event rule. NOT for parameters — use ads_pixel_parameter_delete. DELETE BEHAVIOR (creation-source dependent): - `USER_CONFIG` (rules created via the Events Manager Pixel UI) → HARD delete: the rule and its atoms are removed; NOT reversible via this surface. - All other surfaces (`EST_ADS_MCP` — created via this MCP surface; `EST_API` — created via the public Marketing API; `IWL_CONFIG` / `IWL_SUGGESTION` — IWL flow) → SOFT delete: status set to archived; reversible via internal tooling. WHEN TO CALL DIRECTLY: if the user gave you `event_rule_id` (any numeric ID in their request), call this tool DIRECTLY — do NOT call ads_pixel_event_read first. Look up the `event_rule_id` via ads_pixel_event_read ONLY when the user names the event by label (e.g. "my Purchase rule") without an ID. The user's explicit delete request IS their intent; do not ask for confirmation before deleting. CASCADE: linked parameter extractors are NOT auto-deleted. When the user asks to delete BOTH the event and its parameters in one request, call ads_pixel_parameter_read (to enumerate orphans) and ads_pixel_parameter_delete in addition to this tool. Otherwise: call ads_pixel_parameter_read with the `pixel_id` → identify the now-orphaned parameters by `event_rule_id` matching the deleted rule → call ads_pixel_parameter_delete on each. BEHAVIOR: default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/event_rule_id per input item.
Reads Meta Pixel conversion event rules. Batch-capable. AUTH: requires the `ads_read`, `ads_management`, or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{pixel_id?, event_rule_id?, event_type?}]`. Per item: if `event_rule_id` is set, returns that one event in `event` (or 404 in `result.error`); else if `pixel_id` is set, returns all MCP-visible events on that pixel in `events`, optionally narrowed by `event_type`. WHEN TO CALL: to LIST or LOOK UP event rules — discovery, enumeration, audit. Use to discover `event_rule_id` ONLY when the caller hasn't already provided one. If the caller already supplied an `event_rule_id` for update/delete, call ads_pixel_event_update / ads_pixel_event_delete DIRECTLY — do NOT read first. The returned event does NOT include its parameters — call ads_pixel_parameter_read with the same `pixel_id` (or specific `event_rule_id`) to fetch the linked extractors. After activation, call this to confirm the rule is now ACTIVE before pointing the user at verification tooling (see ads_pixel_event_update for the verification ladder). BEHAVIOR: NOT for parameters — use ads_pixel_parameter_read. Default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/event(s) per input item.
Updates Meta Pixel conversion event rules. Currently status-only. Batch-capable. AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{event_rule_id, status}]`. `status` must be `ACTIVE` or `INACTIVE`. Call this tool whenever the user says activate / deactivate / enable / disable / turn on / turn off / pause / resume / set active / set inactive an event rule. NOT for parameters — use ads_pixel_parameter_update. WHEN TO CALL DIRECTLY: if the user gave you `event_rule_id` + the activate/deactivate intent (or an explicit `status` value), call this tool DIRECTLY — do NOT call ads_pixel_event_read first to confirm the rule exists. Look up the `event_rule_id` via ads_pixel_event_read ONLY when the user names the event by label (e.g. "the Purchase rule") without an ID. The user's explicit activate/deactivate request IS their intent; do not ask for confirmation. MULTI-STEP REQUESTS: when called as the second step of a chained request — "show me X and if INACTIVE then activate", "create then activate immediately" — execute without pausing. After ads_pixel_event_read returns INACTIVE status, immediately call this tool with `status=ACTIVE` in the SAME turn; after ads_pixel_event_create returns, immediately call this tool with `status=ACTIVE` if the user asked to activate. The chained request IS the user's complete intent. VERIFICATION: after activating a freshly created event, walk the user through the VERIFICATION ladder below to confirm the event fires; if verification fails, call this tool again with `status=INACTIVE` to turn it off, then fix and re-verify before re-activating. BEHAVIOR: default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/event per input item. VERIFICATION ladder (after activation; stop at the first tier that works): (a) PLAYWRIGHT NETWORK LISTENER on URL regex `r'https?://(www\.)?facebook\.com/tr/?(\?|$)'`. ALSO match first-party CNAME proxies (e.g. `analytics.<domain>/tr/` for sites using the Conversions API Gateway). The beacon transports across 3 paths — accept ALL: GET via `new Image()`, POST via `fetch()`, POST via `sendBeacon` with FormData. Key form fields: `id`=pixel, `ev`=event name, `dl`=URL, `cd*`=custom data fields, `eid`=CAPI dedup id, `o` carries bit flags (IS_HEADLESS:128, IS_SELENIUM:256). (b) FBQ() INTERCEPTION via `page.add_init_script` BEFORE `page.goto`. Use STUB-MIRROR + SETTER-REDIRECTION pattern, NOT a bare Proxy — fbevents.js replaces window.fbq during init and reads `.queue`/`.callMethod`/`.push`/`.loaded`/`.version`/`.agent`/`._fbq`/`.disablePushState` as own properties; preserve all of these on both the stub and the wrapper. (c) TEST EVENTS TAB in Events Manager: `https://business.facebook.com/events_manager2/list/dataset/<PIXEL_ID>/test_events`. Open the page, click "Open Website" to attach identity context, trigger the conversion, watch within seconds. Best human-in-the-loop path. For CAPI verification, set `test_event_code=TEST<n>` in the CAPI payload. (d) META PIXEL HELPER Chrome extension. Limitations: pre-enrichment data only, no CAPI events, no `<noscript>` pixels, EST events do NOT appear here; events are LOST on navigation. (e) DEVTOOLS NETWORK filtered by `tr`. Ad blockers (uBlock Origin, Privacy Badger, EasyPrivacy) and CMP consent gates often block `/tr` and `connect.facebook.net/*/fbevents.js` — confirm both before assuming the pixel is broken. (f) EVENTS MANAGER OVERVIEW (lowest fidelity, hours of latency). NOTE: fbevents.js detects headless browsers (UA regex `/HeadlessChrome/`, `navigator.webdriver`, `__webdriver_*`) but does NOT suppress the `/tr` beacon — it just ORs `IS_HEADLESS:128` into the `o=` field. Override the UA to a real Chrome string for clean fidelity testing.
Creates Meta Pixel parameter extractors (CSS or CONSTANT_VALUE), linked to an existing event rule. Batch-capable. AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{pixel_id, domain_uri, event_type, extractor_type, extractor_config_json?, event_rule_id?}]`. `extractor_type=CSS` reads `element.innerText` of the matched DOM node — CANNOT read URL fragments, attribute values, or JS state. `extractor_type=CONSTANT_VALUE` hardcodes a string. If the value is in the URL/attributes/JS, surface that limitation; do NOT ship a CSS selector that won't match. Set `event_rule_id` in nearly all cases — find it via ads_pixel_event_read ONLY when the user hasn't supplied one, or use ads_pixel_event_create with embedded `parameters` instead for atomic event+param creation. Standalone parameters (no `event_rule_id`) are rare and only useful when re-attaching extractors to a pre-existing rule outside this surface. WHEN TO CALL DIRECTLY: if the caller's request already includes `pixel_id` + extractor details (`event_type`, `extractor_type`, and selector/value), call this tool DIRECTLY — do NOT call ads_pixel_event_read or ads_pixel_parameter_read first to inspect existing state. The user's explicit creation request IS their intent; do not ask for confirmation before creating. HARDCODE / CONSTANT VALUE: when the user says "hard-code", "set to constant", "always use value X", "force the value", or describes a static value (e.g. "currency to EUR", "content_type to product"), use `extractor_type=CONSTANT_VALUE` and set the value via `extractor_config_json`. This is a CREATE operation — do NOT call ads_pixel_parameter_read first to check what's there. MULTI-STEP REQUESTS: when called as the second step of a chained request ("create event X then add a CSS extractor for Y", "set up event then attach standalone parameter"), execute without pausing. After ads_pixel_event_create returns, immediately call this tool in the SAME turn with the extractor details the user requested. The chained request IS the user's complete intent. PARAMETER TYPE DEFAULTS (start here, deviate only with reason): - `currency` → CONSTANT_VALUE (the store's currency: USD, EUR, …) - `content_type` → CONSTANT_VALUE (usually 'product' for AddToCart/ViewContent) - `value` → CSS at the price element (`.price`, `[itemprop="price"]`) - `content_ids` → CSS at the SKU/product code on the PDP. NOT a URL pattern — CSS can't read URLs. - `content_name` → CSS at the product name (e.g. PDP `<h1>`) - `num_items` → CSS at cart count, or CONSTANT_VALUE=1 for single-item flows - `order_id` → CSS at the order/confirmation number on the post-purchase page - `search_string` → CSS at the search input or results-header element BEHAVIOR: NOT for events — use ads_pixel_event_create. Default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/parameter per input item. STANDARD EVENTS (names only — see ads_pixel_event_create description for full triggers + disambiguation): AddPaymentInfo, AddToCart, AddToWishlist, CompleteRegistration, Contact, CustomizeProduct, Donate, FindLocation, InitiateCheckout, Lead, Purchase (value+currency REQUIRED), Schedule, Search, StartTrial, SubmitApplication, Subscribe, ViewContent. All names are case-sensitive. SELECTOR PRIMER — applies to `extractor_config_json.selector` for `extractor_type=CSS`: - ROOT TARGET: `TOKENIZED_BUTTON_TEXT` rules root the selector at the CLICKED element (NOT the document) — to reach an ancestor (e.g. surrounding product card), use `closest(<sel>)` then drill back down: `closest(.product-card) .price`. Without `closest`, descendant selectors only see DESCENDANTS of the click target. `URL` rules root at `document.body` — descendant selectors search the whole page. - WHAT CSS RETURNS: `element.innerText || textContent` of the FIRST match. CANNOT read URL fragments (`?id=42`, path slugs), HTML attribute values (`data-sku`, `href`), or JS / dataLayer state. If the value is not visible DOM text, surface the limitation rather than ship a non-matching selector. - EXTENSIONS (use inside the selector field, not standard CSS): `closest(<sel>)` walks UP the DOM; `children(<index>, <sel>)` picks the Nth child matching `<sel>`. NEVER emit jQuery `:contains()` — querySelector throws on it. - SELECTOR PRIORITY (most stable first): (1) stable `id` (`#price`, `#grand-total` — REJECT UUIDs, hex strings, React fiber tokens like `:r1:`, high-digit-ratio names like `#x_42_b1c`), (2) form `name` attr (`input[name="quantity"]`), (3) `[data-testid="..."]`, (4) other `data-*` / microdata (`[data-product-id]`, `[itemprop="price"]`, `[itemtype*="schema.org/Product"]`), (5) role+aria (`[role="button"][aria-label*="Buy"]`), (6) tag + domain-word class (`span.price`, `[class*="cart-total"]` — only if class is a real word). NEVER auto-generated classes (`.css-1abc23`, `.makeStyles-root-42`, `.sc-htjRhB-0`) — they change every webpack/styled-components rebuild. - VALIDATION: a good selector returns EXACTLY 1 element on the target page. 0 → broken; 2+ → ambiguous, refine. - SCHEMA.ORG / JSON-LD PRECEDENCE: when the page has `<script type="application/ld+json">` Product/Offer or `[itemprop=price]` markup, prefer SCHEMA_DOT_ORG / JSON_LD extractors over hand-rolled CSS. Per-pixel extractor precedence: CONSTANT_VALUE > CSS > URI > SCHEMA_DOT_ORG > JSON_LD > RDFA > OPEN_GRAPH > GTM > META_TAG > GLOBAL_VARIABLE — the CSS selector you write WINS over schema.org for the same parameter, so don't double-up. - EXTRACTOR CHOICE: CONSTANT_VALUE for static values (currency='USD', content_type='product'). CSS for visible DOM text only. If neither fits (e.g. value is in a URL fragment or an HTML attribute), surface the limitation.
Soft-deletes Meta Pixel parameter extractors. Batch-capable. Mirrors the same delete semantics as the Events Manager Pixel UI (EST) and IWL flow use — same backend (`EntSignalsIWLExtractorMutator::startDeletion`); status set to archived, reversible via internal tooling. AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{parameter_id}]`. Call this tool whenever the user says delete / remove / drop / get rid of / clean up / kill / nuke / uninstall a parameter extractor. Does NOT touch the linked event rule (use ads_pixel_event_delete for that). NOT for events — use ads_pixel_event_delete. WHEN TO CALL DIRECTLY: if the user gave you `parameter_id`, call this tool DIRECTLY — do NOT call ads_pixel_parameter_read first. Look up `parameter_id` via ads_pixel_parameter_read ONLY when the user names the parameter by label without an ID. The user's explicit delete request IS their intent; do not ask for confirmation before deleting. BEHAVIOR: default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/parameter_id per input item.
Reads Meta Pixel parameter extractors. Batch-capable. AUTH: requires the `ads_read`, `ads_management`, or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{pixel_id?, parameter_id?, domain_uri?, event_type?}]`. Per item: if `parameter_id` is set, returns that one parameter in `parameter` (or 404 in `result.error`); else if `pixel_id` is set, returns all MCP-visible parameters on that pixel in `parameters`, optionally narrowed by `domain_uri` / `event_type`. WHEN TO CALL: to LIST or LOOK UP parameters; also after ads_pixel_event_delete to enumerate orphaned parameters that need cleanup. Use to discover `parameter_id` ONLY when the caller hasn't already provided one. If the caller already supplied `parameter_id` for update/delete, call ads_pixel_parameter_update / ads_pixel_parameter_delete DIRECTLY — do NOT read first. BEHAVIOR: NOT for events — use ads_pixel_event_read. Default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/parameter(s) per input item.
Patches Meta Pixel parameter extractors. Batch-capable. AUTH: requires either the `ads_management` or `business_management` granular OAuth scope on the caller's token (and the server-level 1P capability gate). INPUT: `items=[{parameter_id, domain_uri?, event_type?, extractor_type?, extractor_config_json?, event_rule_id?}]`. Omitted fields are unchanged. Call this tool whenever the user says edit / change / modify / swap / patch / fix / update / tweak / adjust a parameter extractor. WHEN TO CALL DIRECTLY: if the user gave you `parameter_id` + the change details, call this tool DIRECTLY — do NOT call ads_pixel_parameter_read first to inspect current state. Look up `parameter_id` via ads_pixel_parameter_read ONLY when the user refers to the parameter by label without an ID. The user's explicit update request IS their intent; do not ask for confirmation. MULTI-STEP REQUESTS: when called as the second step of a chained request — "show me parameter X and if it uses wrong selector change it to Y" — execute without pausing. After ads_pixel_parameter_read returns the current state, immediately call this tool in the SAME turn with the user's requested change. The chained request IS the user's complete intent. BEHAVIOR: NOT for events — use ads_pixel_event_update. Default fail-fast on first item error; pass `partial:true` to collect per-item errors. Returns `results[]` with success/error/parameter per input item. SELECTOR PRIMER — applies to `extractor_config_json.selector` for `extractor_type=CSS`: - ROOT TARGET: `TOKENIZED_BUTTON_TEXT` rules root the selector at the CLICKED element (NOT the document) — to reach an ancestor (e.g. surrounding product card), use `closest(<sel>)` then drill back down: `closest(.product-card) .price`. Without `closest`, descendant selectors only see DESCENDANTS of the click target. `URL` rules root at `document.body` — descendant selectors search the whole page. - WHAT CSS RETURNS: `element.innerText || textContent` of the FIRST match. CANNOT read URL fragments (`?id=42`, path slugs), HTML attribute values (`data-sku`, `href`), or JS / dataLayer state. If the value is not visible DOM text, surface the limitation rather than ship a non-matching selector. - EXTENSIONS (use inside the selector field, not standard CSS): `closest(<sel>)` walks UP the DOM; `children(<index>, <sel>)` picks the Nth child matching `<sel>`. NEVER emit jQuery `:contains()` — querySelector throws on it. - SELECTOR PRIORITY (most stable first): (1) stable `id` (`#price`, `#grand-total` — REJECT UUIDs, hex strings, React fiber tokens like `:r1:`, high-digit-ratio names like `#x_42_b1c`), (2) form `name` attr (`input[name="quantity"]`), (3) `[data-testid="..."]`, (4) other `data-*` / microdata (`[data-product-id]`, `[itemprop="price"]`, `[itemtype*="schema.org/Product"]`), (5) role+aria (`[role="button"][aria-label*="Buy"]`), (6) tag + domain-word class (`span.price`, `[class*="cart-total"]` — only if class is a real word). NEVER auto-generated classes (`.css-1abc23`, `.makeStyles-root-42`, `.sc-htjRhB-0`) — they change every webpack/styled-components rebuild. - VALIDATION: a good selector returns EXACTLY 1 element on the target page. 0 → broken; 2+ → ambiguous, refine. - SCHEMA.ORG / JSON-LD PRECEDENCE: when the page has `<script type="application/ld+json">` Product/Offer or `[itemprop=price]` markup, prefer SCHEMA_DOT_ORG / JSON_LD extractors over hand-rolled CSS. Per-pixel extractor precedence: CONSTANT_VALUE > CSS > URI > SCHEMA_DOT_ORG > JSON_LD > RDFA > OPEN_GRAPH > GTM > META_TAG > GLOBAL_VARIABLE — the CSS selector you write WINS over schema.org for the same parameter, so don't double-up. - EXTRACTOR CHOICE: CONSTANT_VALUE for static values (currency='USD', content_type='product'). CSS for visible DOM text only. If neither fits (e.g. value is in a URL fragment or an HTML attribute), surface the limitation.
Updates an existing custom audience's metadata by its ID. Supports DFCA (customer list) and WCA (website) audiences. ## When to use: - Call this tool when the user wants to update an existing custom audience's name, description, rule, or labels. - For DFCA: user says "rename audience", "update audience description", "add audience label". - For WCA: user says "update website audience rule", "change pixel targeting", "modify WCA filters". ## When NOT to use: - Do NOT use to add or remove users from a DFCA — use ads_update_custom_audience_users instead. - Do NOT use to create a new audience — use ads_create_custom_audience instead. - Do NOT use to delete an audience — use ads_delete_custom_audience instead. ## CRITICAL: - You must provide the custom_audience_id of an existing audience. - At least one updatable field (name, description, rule, audience_labels) must be provided. - For DFCA (REGULAR type): you can update name, description, audience_labels. Retention days cannot be changed for DFCA audiences. - For WCA (PLATFORM type): you can update name, description, rule (JSON), audience_labels. Retention is controlled via retention_seconds in the rule JSON. - The rule field follows the same JSON format as ads_create_custom_audience's WEBSITE subtype. ## Response Guidelines: 1. Confirm the audience was updated and provide the audience_id. 2. If the error indicates the audience was not found, suggest the user verify the audience ID. 3. If the error indicates a permission issue, suggest the user check their access to the ad account.
Adds or removes users in a Data File Custom Audience (DFCA / customer list) by uploading hashed PII rows. Backs the POST /{audience_id}/users API (add) or DELETE /{audience_id}/users API (remove), selected via the `operation` field. ## When to use: - Call this tool when the user wants to add users to an existing customer list / DFCA audience (operation="ADD", default). - Call this tool when the user wants to remove users from an existing DFCA audience (operation="REMOVE"). - Use after creating an audience via ads_create_custom_audience. - Use when the user provides a list of customer identifiers (emails, phone numbers, mobile advertiser IDs) to upload. ## When NOT to use: - Do NOT use to create a new audience — use ads_create_custom_audience first. - Do NOT use for WCA/MACA/LAL audiences — those are rule-based or derived, not user-uploaded. ## Operation: - `operation="ADD"` (default): adds the supplied users to the audience. - `operation="REMOVE"` (also accepts `"DELETE"` as a synonym): removes the supplied users from the audience. Removal matches by hashed identifier just like add — supply the same schema/data shape you would use to add the user. The DFCA backend may apply low-reach safety checks: if removing the requested users would shrink the audience below minimum delivery thresholds for active campaigns, the call can be rejected with a VALIDATION error. LOOKALIKE_VALUE is ignored on REMOVE. ## PII handling (raw or hashed both accepted): - The tool accepts EMAIL, PHONE, FN, LN, ZIP, CT, ST, COUNTRY, DOB*, GEN, MADID values either pre-hashed (SHA-256 hex digest) or raw — whichever is more convenient. The tool normalizes (lowercase/trim email, strip non-digits from phone, etc.) and SHA-256 hashes raw values before they leave this server. Already-hashed values (64 lowercase hex chars) are passed through unchanged. - EXTERN_ID and LOOKALIKE_VALUE are NOT hashed; they are passed through as-is. - Empty string "" is allowed for missing values in multi-key rows. ## Schema field names: - Identifiers (raw or hashed accepted): EMAIL, PHONE, MADID, FN, LN, FI, ZIP, CT, ST, COUNTRY, DOBY, DOBM, DOBD, DOB, GEN - Pass-through: EXTERN_ID (advertiser-side stable ID, not hashed), LOOKALIKE_VALUE (numeric-string per-row weight, only valid for value-based audiences). - Legacy aliases (also accepted, signal "already hashed"): EMAIL_SHA256, PHONE_SHA256. Prefer EMAIL/PHONE — the tool figures out hashing automatically. ## Data layout: - `data` is a 2D array. Each inner array is one user row. - Inner array values must be in the same order as `schema`. - For multi-key matching (better match rate), include several columns per row, e.g. schema=[EMAIL, PHONE], data=[[hashed_email, hashed_phone], ...]. ## Response Guidelines: 1. Report num_received and num_invalid_entries so the user knows how many rows were accepted (or removed). 2. After the call, suggest checking the audience status with ads_get_custom_audience — it may be processing for some minutes. 3. If error_category is VALIDATION, the most common causes are: schema/data column mismatch, LOOKALIKE_VALUE missing on a value-based audience, invalid PII values that couldn't be normalized (e.g. malformed email format), or (on REMOVE) the deletion would shrink the audience below the low-reach safety threshold.
Updates fields on an existing campaign, ad set, or ad. ## When to use: - Call this tool when the user wants to modify an existing ad entity. - Use for changing name, budget, targeting, schedule, or other fields. ## When NOT to use: - Do NOT use for creating new entities. Use ads_create_campaign, ads_create_ad_set, or ads_create_ad instead. - Do NOT use for activating/publishing. Use ads_activate_entity instead. - Do NOT use to change an ad's creative, either its content (media, primary text, headline, or call to action) or which creative it uses: `creative` and `creative_id` are not accepted in `fields`. Ad creatives are immutable; to show different creative, create a new ad with ads_create_ad that references the creative_id (create the creative first with ads_create_creative if it doesn't exist), then pause the old ad. - Do NOT change a campaign's objective to a legacy value. Objective is chosen at creation; if you set it here it must be an ODAX outcome (OUTCOME_AWARENESS, OUTCOME_TRAFFIC, OUTCOME_ENGAGEMENT, OUTCOME_LEADS, OUTCOME_SALES, OUTCOME_APP_PROMOTION). Legacy objectives (LINK_CLICKS, APP_INSTALLS, CONVERSIONS, REACH, etc.) are rejected with error_category=VALIDATION. ## Field names: `fields` takes Ads API field names, which are NOT the argument names the ads_create_* tools take. Never carry a create-tool argument name over into an update: - campaign: use `name`, `daily_budget`, `lifetime_budget`, `bid_strategy`, `spend_cap`, `start_time`, `stop_time` — NOT campaign_name, campaign_daily_budget, campaign_lifetime_budget, campaign_bid_strategy, campaign_spend_cap, campaign_start_time, campaign_stop_time. - ad set: use `name` — NOT ad_set_name. - ad: use `name` — NOT ad_name. Unrecognized field names are rejected with error_category=VALIDATION, as is any attempt to reparent (campaign_id on an ad set, adset_id on an ad). ## Ad set targeting — keep Advantage+ Audience on: Meta recommends Advantage+ Audience (A+A). `targeting` replaces the ad set's whole targeting spec, so carry its current `targeting_automation` forward unchanged. Never add `targeting_automation.advantage_audience` = 0 unless the advertiser explicitly asks to turn A+A off, requires a hard maximum age below 65 or a hard minimum above 25, or requires delivery to ONLY a custom audience. Changing ages, genders, interests or custom audiences never requires turning A+A off: under A+A they are suggestions. A hard `age_max` below 65 or `age_min` above 25 is rejected under A+A, so (outside special ad categories, below) send a narrower age range as `age_min_suggestion` / `age_max_suggestion` inside `targeting_automation.advantage_audience` (for example `"targeting_automation":{"advantage_audience":{"age_min_suggestion":30,"age_max_suggestion":50}}`), and keep `age_min` between 18 and 25 (at least 20 when targeting Thailand). ## Special ad categories: When an ad set's campaign is HOUSING, EMPLOYMENT or FINANCIAL_PRODUCTS_SERVICES, targeting edits follow the same rules as ads_create_ad_set: give every city, address or custom location a `radius` of at least 15 miles (25 km); never use `zips`, `subcities`, `neighborhoods`, `subneighborhoods`, `metro_areas`, `small_geo_areas`, `electoral_districts` or `political_districts` in `geo_locations`; every country targeted by `geo_locations` must appear in the campaign's `special_ad_category_country`, though territories of those countries are also allowed; keep `age_min` at 18 and `age_max` at 65; do not add interests or other detailed targeting. ## Status changes: Set `status` inside `fields` (PAUSED, ARCHIVED, DELETED). To pause an already-published entity, send only `{"status":"PAUSED"}`: this updates the live object even in draft mode and returns `is_draft=false`. Do NOT call ads_activate_entity after a live pause; it is not a commit or verification step and can undo the pause. Verify with ads_get_ad_entities instead. A pause combined with other fields, or an edit to an unpublished object, remains staged when draft mode is enabled; read `is_draft` before deciding whether publication is needed. Do NOT set ACTIVE here — use ads_activate_entity to activate or publish; an ACTIVE value may be rejected with error_category=VALIDATION. Outside draft mode, a non-trivial edit on an ACTIVE entity is force-paused unless the request explicitly sets PAUSED, ARCHIVED, or DELETED. `status_forced_to_paused=true` means the tool injected the pause, not that activation is required. DELETED is permanent, so confirm with the user before sending it. ## Response Guidelines: 1. `updated_fields` echoes the submitted fields, not the stored state. Use `is_draft` to distinguish staged edits from live edits; draft changes remain pending publication even when active_errors is empty or absent. 2. If validation errors occur, explain what needs to be corrected. Ads Manager is an optional fallback, not a required verification step. 3. Returned recommendations are the MAPI-supported subset relevant to this entity, not the complete account inventory. Ads Manager may show additional recommendations. Always surface Ads Manager URLs to act on recommendations: use the recommendation URL when present, or navigate to the Recommendations page from the returned Ads Manager entity URL. ## Draft mode: Draft mode is enabled for you. A pause-only update (fields={"status":"PAUSED"}) to an already-published entity edits the live object directly and returns is_draft=false. Do NOT call ads_activate_entity afterward; verify the live pause with ads_get_ad_entities instead. Other edits, including a pause combined with other fields, are staged in the draft. Changes to an unpublished entity are always merged into its draft. When is_draft=true, tell the user the change is pending, not live, and publish only the intended staged objects with ads_activate_entity when the user asks to apply them. Draft edits do NOT auto-pause an active live entity.
One endpoint, the same key, whichever client you use.
~/Library/Application Support/Claude/claude_desktop_config.json (Mac) · %APPDATA%\Claude\claude_desktop_config.json (Windows)
Replace API_KEY with your own key.
Already have an "mcpServers" section in your config? Just add the server entry inside it.
Discovery, routing, credentials, tool scoping and execution logs all happen at the gateway→connections stay ACTIVE with no work from you
Meta Ads MCP runs through a gateway that holds the credentials, scopes the access and records every call.
Managed auth, hosted MCP servers, and every Meta Ads MCP tool your agent needs.
Free to start.