Documentation

Ad Configuration

Meta Edits

Meta Edits changes existing campaigns, ad sets and ads. Every change starts with a preview of the current and proposed values.

Edits are available to beta accounts while in beta. They are off until the user sets Agent Edit on the Account Permissions page, as an account-wide default or for one ad account. The ad account setting wins. Approval sends proposed changes to the Agent Inbox; Allowed applies them directly. ads account:info act_123 and ads_get_account expose the effective enabled, mode, approvalRule and source settings. The CLI and MCP cannot change them.

Agent Inbox

In review mode, preview returns mode: "review", reviewId, reviewUrl and proposal IDs on items. Share the absolute reviewUrl with the user. When every change already matches Meta, nothing is queued: the preview returns its NO_CHANGE warnings with summary.proposals: 0, nothingQueued: true and a nextStep message, and no reviewId or reviewUrl. No empty review is created, and a review you passed with reviewId is left unchanged. They select items in their Agent Inbox and use a blue outline Approve N button in a group or below the list, where N is the selected count. The filters are Waiting, Done, Needs attention, Failed and All. The table shows Time, Action, Campaign, Ad set, Ad, Before, After, Why and Status. Group by Run (default), Campaign or Date: groups appear newest first, with rows oldest first inside each group. Every row stays visible, without collapsed runs. Rows show a short day when a group spans several days. Long values show their full text on hover; ad names with a thumbnail show a preview on hover or keyboard focus. Archive and delete require a separate confirmation because they cannot be undone. The X in a pending row cancels that change immediately; Discard Selected confirms a selection before removing it. Extra pending suggestions for the same object and operation within a group carry a Duplicate badge. Done, skipped and failed rows retain their results, and untouched changes after a stopped apply remain pending. Changed Elsewhere loads Meta history only when opened.

Click an editable After value to adjust it in a modal, or click the agent's Why note, its pencil, or Add note to edit the explanation. You can save a note without changing the proposed value; the row then shows Edited by you. Agents always explain their suggestions, because notes are what make a suggestion reviewable. If you'd rather not see them in the list, click the X in the Notes column header to hide the column; Show Notes, next to the text size picker, brings it back. This browser remembers the choice, and Review and History still show every note.

Saved launches awaiting approval appear as Launch rows under their build names. A launch an agent sent into one of its runs (with that run's reviewId, or the same runTitle) appears inside that run instead. Changes and launches never run together, so a run with both shows a Changes section and a Launches section, each with its own select-all and button. Ticking one kind clears the other: Run N Changes runs only the changes, and Launch Now runs only the launches; History lists the launch under the same run. Their ad set names, budgets and ad counts are always shown beneath the launch, aligned with the table columns. Use Open in Uploader to review and launch the build. These rows cannot be selected for bulk approval in the inbox.

For local and staging previews, signed-in users can open /dashboard/inbox?mock=1. Production limits this preview to admins. The amber Mock data banner identifies the scenario; links switch between all scenarios, launches, duplicates, edits, states, notes and grouping. The preview uses the real inbox with sample accounts and simulated actions, without reading or changing live account data. Approving the States or All scenario includes a partial copy failure so you can try the retry flow. Open in Uploader opens a local preview of the sample launch. Launch ad sets appear as table rows under the Ad set, Ad and After columns. The duplicate scenario includes a 16-copy run to check long lists.

Pass reviewId in later preview bodies, or --review-id on CLI edit commands, to group related proposals. Each call supports up to 100 objects, with at most 50 IDs per bulk operation. Two 100-object previews can fill one review. Pending suggestions deduplicate across reviews for the same user and account: reused items carry reused: true, and summary.new/summary.reused give counts; there is no top-level reused array. Items include reviewId only when it differs from the response review; detail: "full" adds reusedProposalIds when non-empty. Existing review reads and approvals cover seven days after the last update; Agent Inbox history reads retained suggestions and outcomes from the last 90 days. Reviews hold up to 200 proposals, with up to 50 open reviews per account. Use your Agent Inbox to approve or discard items when a cap is reached.

Passing reviewId moves identical pending suggestions into that review with new proposal IDs and cancels their old copies; moved rows count in both summary.reused and summary.moved. Suggestions already being applied or in a building review stay there; without reviewId, identical pending suggestions are reused where they are.

GET /api/v1/edits/reviews?account_id=act_123 returns compact review metadata and status counts without proposals; add include=proposals for full proposal lists. GET /api/v1/edits/reviews/<reviewId>?account_id=act_123 returns compact proposal rows with statuses and edit IDs, 50 per page by default. Set limit up to 200 and pass paging.after to fetch the next page; detail=full includes full proposal fields. Reviews are visible with state: "building" while preview is reading Meta, then state: "open" while any suggestion is pending, stale or applying, and state: "complete" when all are resolved. The CLI equivalents are edit:reviews and edit:review <reviewId>, both with --json; MCP provides ads_list_edit_reviews and ads_get_edit_review.

Agent apply returns EDITS_REVIEW_REQUIRED in review mode, including for a plan created before switching from direct mode. Follow details.reviewUrl instead. Approval rules apply only in direct mode; review mode requires human selection on the web page. Hold Ad Creation still blocks spend increases.

Cancel Suggestions

POST /api/v1/edits/cancel uses the same bearer authentication and X-Ad-Account scope as preview. The reviewId is required; proposalIds is optional:

{ "reviewId": "<REVIEW_ID>", "proposalIds": ["<PROPOSAL_ID>"] }

Omit proposalIds to cancel every pending suggestion in that review. Cancelled suggestions have status: "cancelled" and count toward counts.cancelled in review summaries. They leave your Agent Inbox, and nothing changes in Meta. In-progress and other non-pending suggestions are refused. Applied suggestions include their editId and the instruction to use ads_edit_undo to reverse them. Unknown IDs are refused individually.

ads_get_edit_review marks pending copies in other open reviews with duplicateOf and reports summary.duplicates. To clean up older copies, call ads_edit_cancel with the older reviewId and duplicatesOnly: true (CLI: --duplicates-only), without proposalIds; only duplicate pending suggestions are cancelled and nothing changes in Meta.

The result is { "reviewId": "...", "state": "complete", "cancelled": 1, "results": [{ "proposalId": "...", "status": "cancelled" }], "pendingCount": 0 }. The review stays open if any suggestions are still pending, stale or applying. Refused results have status: "refused" and a reason. MCP exposes ads_edit_cancel with accountId, reviewId, and optional proposalIds or duplicatesOnly. The CLI offers ads edits cancel <reviewId> [--proposal <id> ...] and the ads edit:cancel alias, with optional --account and --json.

Preview And Apply

Edit previews, both duplication APIs and launches held for approval (POST /api/v1/ads, ads_create, ads create with Agent Launch set to Approval) accept optional reason and runTitle. A reason is a short note explaining the evidence for the suggestion; an operation's own reason overrides the top-level note. Reuse the same runTitle when appending suggestions to a reviewId. Notes are trimmed to 1,000 characters and titles to 120. CLI proposal commands expose --reason and --run-title; MCP accepts the same JSON keys. Existing payloads without notes remain valid. Notes are always accepted, and results report notes: "on".

Pass an optional idempotencyKey (8–128 letters, digits, underscores or hyphens) with preview and reuse it when retrying after a timeout. The same user, account, key and body return the stored response for 24 hours. While it is building, the API returns 409 PREVIEW_IN_PROGRESS: retry in a few seconds with the same key. Reusing a key for a different body returns 400. CLI preview commands accept --idempotency-key; MCP uses idempotencyKey.

Preview a campaign budget change using an Ads Uploader bearer token and the X-Ad-Account header:

POST /api/v1/edits/preview
X-Ad-Account: act_123
Content-Type: application/json

{"operations":[{"op":"set_budget","level":"campaign","id":"12345","daily":120}]}

Preview responses are compact by default: summary contains proposal/change counts, byOp, object and irreversible counts, and needsConfirmation; items contains before/after rows and review proposal IDs. Warnings with the same code and message are grouped once with ids; differing messages stay separate. Targeting and creative items use detail: "summary" and detailPaths counts; targeting before/after values summarize the paths. Request detail: "full" for full changes, per-path details, individual warnings and any validation actually performed. Skipped validation has no passed rows. currency and moneyUnit appear only for money changes. Review responses keep the effective settings.approvalRule and omit the top-level rule. Both summary and full edit previews include settings: { mode, approvalRule, approvalRuleAppliesTo: "edits", launch, source }. launch is the separate Agent Launch mode (allowed, approval or off) applied to the caller; an edit review does not gate a new-ad launch. Older stored plans may omit launch.

Deleted, missing and archived objects that cannot take the requested operation are returned in skipped with their IDs, operations, reason codes and plain reasons, plus summary.skipped; eligible items continue, and archived objects can still be deleted. If every item is skipped, preview returns 422 NOTHING_TO_PREVIEW with details.skipped and creates no review.

Review mode queues proposals after batched reads and local checks, with zero Meta POSTs. Meta accepts or rejects each change when the user applies it; results show each item as applied, failed, skipped or pending. Pending means not sent yet, with a reason; apply the same review again to send these changes. Failed proposals retain a safe Meta reason. One ad's failure does not stop other ads; account errors stop the run. Direct previews also skip validate_only for status, archive, delete and rename; other direct edits still validate. Money inputs use major units, such as 120 USD. Diff and history money values are strings in minor units, such as "12000", identified by moneyUnit: "minor". The request accepts optional detail: "summary" | "full" alongside operations, reviewId and idempotencyKey; full review responses also include proposalIds and planId: null. Direct mode returns planId, while review mode returns a deep link /dashboard/inbox?account_id=...&review=....

In direct mode, after reviewing the diff and warnings, apply the returned plan ID within 15 minutes:

POST /api/v1/edits/apply
X-Ad-Account: act_123
Content-Type: application/json

{"planId":"<PREVIEW_PLAN_ID>","confirmSpend":true}

Set confirmation flags only after explicitly approving the corresponding change. CONFIRMATION_REQUIRED lists missing flags. DRIFTED means an edited value changed since preview: that suggestion is skipped with the observed value, while independent changes continue. Status and name changes are sent without a reread; already deleted objects or objects already in the requested status are skipped. PLAN_STALE still protects against a creative source changing during loading. Two consecutive permanent failures stop the run; untouched review suggestions remain pending and can be approved again.

Supported Operations

OperationLevelsInputs
set_statusCampaign, ad set, adids, status: ACTIVE or PAUSED
archiveCampaign, ad set, adids
deleteCampaign, ad set, adids
renameCampaign, ad set, adid, name
set_budgetCampaign or ad set holding the budgetid, exactly one of daily or lifetime
set_spend_capCampaignid, spend_cap; null removes the cap
set_adset_spend_limitsAd set under a campaign daily budgetid, daily_min_spend_target and/or daily_spend_cap; 0 clears a limit
set_bidCampaign with a campaign budget, or ad setid, bid_strategy, ad set bid_amount or roas_floor
set_scheduleCampaign or ad setCampaign stop_time; ad set start_time and/or end_time
set_targetingAd setid, add, remove, set, optional group
set_adset_settingsAd setid and one or more settings below
set_creativeAdid and one or more creative fields below

A preview supports at most 100 object changes. Each bulk ids array supports at most 50 unique IDs. Multiple fields on one object are combined into one update; a field may appear only once. Archive or delete must be the only change to that object in a plan.

Budgets stay at their existing campaign or ad set owner. Switching between daily and lifetime budgets is refused. Daily budgets must meet the account minimum, and lifetime budgets cannot fall below the amount already spent. Lifetime budgets require an end time.

Bid strategies supported here are LOWEST_COST_WITHOUT_CAP, LOWEST_COST_WITH_BID_CAP, COST_CAP and LOWEST_COST_WITH_MIN_ROAS. Capped bidding requires an amount on the ad set. Under a campaign budget, change the strategy on the campaign and amounts or ROAS floors on its ad sets. A campaign capped strategy requires an existing bid amount on every child ad set; validation requires a complete page of at most 100 child ad sets. Minimum ROAS requires VALUE optimization on every affected ad set. roas_floor: 2.5 means 250%, stored as bid_constraints.roas_average_floor: 25000; floors accept at most four decimal places. Undo restores the prior strategy and constraints.

Schedule timestamps include a timezone, for example 2026-10-15T09:00:00+07:00. A null end removes the limit for a daily budget. Campaign start changes are outside this phase.

Targeting Patches

{"operations":[{"op":"set_targeting","level":"adset","id":"12345","add":{"countries":["CA"],"interests":[{"id":"6000000000001"}]},"remove":{"countries":["GB"]},"set":{"age_min":25}}]}

Replace example IDs with results from targeting search. List patches support countries, regions, cities, zips, geo markets, custom locations, excluded countries/regions/cities/zips, locales, detailed-targeting types, custom and excluded custom audiences, publisher platforms, Facebook/Instagram/Audience Network/Messenger positions, and device platforms. Lookalikes use custom audience IDs. Countries are uppercase ISO-2 codes; locales are numeric IDs. Locations use { "key": "<Meta key>" }; cities also accept radius and distance_unit. Custom locations require latitude, longitude, radius and distance_unit (mile or kilometer). Detailed targeting and audiences use { "id": "<Meta ID>" }.

Patches remove first, then add, deduplicating by ID, key or coordinates. Re-adding a city with a radius updates that city's radius. Each patch and resulting list supports at most 1000 list values. At least one included location must remain. Detailed targeting edits one OR group in flexible_spec; supply zero-based group when there are several. Unmentioned types and groups stay intact and appear in the full resulting audience.

set accepts age_min, age_max, genders ([], [1] or [2]), Boolean advantage_audience, and placements: "automatic". Automatic placements remove platform and position lists, including existing Threads and WhatsApp positions, while retaining device selection. Advantage+ keeps a hard minimum from 18 to 25 and moves a higher requested minimum into age_range. Maximum age becomes a suggestion and age_max is removed. Manual audiences use hard ages from 13 to 65 and remove age_range.

With detail: "full", the preview contains canonical full before/after targeting and readable per-path details. Apply sends the full resulting spec because Meta replaces targeting on update. Verification checks the patched paths and reconciled age values while allowing unrelated Meta defaults. Undo restores the full recorded audience, including types not exposed as flags. Public requests cannot use internal restore operations.

Ad Set Settings

set_adset_settings accepts optimization_goal, billing_event, promoted_object, attribution_spec, is_incremental_attribution_enabled, dsa_beneficiary and dsa_payor. A promoted object is exactly one of a pixel ID plus custom_event_type, custom_conversion_id, page_id, or application_id plus object_store_url.

Standard attribution is an array of { "event_type": "CLICK_THROUGH", "window_days": 7 }; event types also include VIEW_THROUGH and ENGAGED_VIDEO_VIEW. Incremental attribution must already be off; turn it off in a separate edit first. Destination type is read for compatibility warnings and cannot be edited. Meta checks the objective, destination, event and attribution combination at apply in review mode, and during validation in direct mode. Rejections retain its safe user-facing message.

Targeting and these settings do not count as spend increases. The all_live_changes rule still requires approval on active objects. Previews warn about learning resets, audience narrowing, special ad categories and conversion-event changes where relevant. Review proposals, refresh, web apply and undo use the same flow as other edits.

Creative Changes

{"operations":[{"op":"set_creative","level":"ad","id":"12345","primary_text":"New primary text","url_tags":"utm_campaign=autumn"}]}

A creative edit creates a new creative and attaches it to the existing ad. The ad ID stays the same. Likes, comments and shares stay with the old post and do not carry over. Preview warns about engagement loss, Meta review and a possible learning reset. Switching to an existing post uses that post's engagement instead.

Single-image and single-video creatives accept primary_text, headline, description, call_to_action (Meta CTA type), link (HTTPS), display_link and url_tags (query string without a leading ?). Empty text clears that field; empty display link or URL tags clears inheritance. Multi-text creatives use texts: { bodies, headlines, descriptions }, with 1 to 5 strings per supplied array. Unmentioned arrays are kept. Duplicate variants, including those differing only by surrounding whitespace, are refused.

You can edit placement-customised creatives (for example a 4:5 feed + 9:16 story/reels pair) and dynamic asset feeds with several images or videos. Edits preserve every media asset and placement rule. A text field with one row accepts its single-text field; several rows require texts.bodies, texts.headlines or texts.descriptions. Labelled rows require the same number of entries, matched in order; unlabelled dynamic text allows 1 to 5. Non-carousel placement feeds allow only one description. Link and display-link edits update every link row; CTA edits require a single CTA.

To change an image or video, create a new ad in the Uploader. Text-only edits keep the existing image or video.

Plain and placement-customised carousels support primary text, whole-carousel link, CTA, display link and URL tags. Use cards: [{ card: 2, headline: "Updated headline", description: "Updated description" }] for per-card text; card numbers start at 1. Plain carousels also accept per-card link; placement-customised carousels refuse it. Scalar headline and description edits are refused on carousels. Media and card order stay intact. Whole-carousel link edits on plain carousels update only cards that inherited the original link; distinct card links stay intact. Creatives backed only by an existing post accept URL tags or existing_post: { post_id: "<pageId>_<postId>" } to switch posts. Only URL tags may accompany a post switch. Text changes on an existing-post source are refused because they would create a new post. CREATIVE_EDIT_UNSUPPORTED gives a precise reason for flexible, catalog, partnership, language-customised or segment-customised creatives, and unknown asset-feed optimization types. Relaunch with ads_create (CLI: ads create) using the same media, or use the Uploader's copy settings from this ad flow.

Review preview loads the source creative and builds the payload for before/after details without posting to Meta. Direct preview validates the new creative with execution_options: ["validate_only"]. With detail: "full", the creative change row has the old ID in before, after: null until apply, and readable field values in details. Agent Inbox shows these values and the engagement warning. Direct apply uses the stored payload and skips the change (DRIFTED) if the ad's creative changed since preview. Review approval rebuilds the payload from the ad's current creative, records the new ID before attaching it, then attaches it sequentially. An earlier approved creative edit on the same ad therefore carries over: a headline suggestion approved after a primary text suggestion keeps both. The suggestion is skipped (DRIFTED) only when a field it changes no longer has the value it was suggested from; the reason names that field and both values, never creative IDs. The applied change's before is the creative it replaced, so undo restores that creative. Successful write responses are authoritative; only uncertain outcomes receive a batched readback after retry.

At most 10 creative edits fit in one plan. Creative edits are not spend increases, but all_live_changes still requires approval on active ads.

If creation succeeds but attachment fails, the failed change has error.details.orphanCreativeId; inspect that ID and the ad before proceeding. The creative is left in place and is not deleted. Repeating the plan cannot create it again. Undo uses a private restore_creative operation to reattach the old ID with one update and no new creative. Public preview requests cannot submit restore operations.

Approval Rules And Holds

RuleRequired Approval
noneNo spend or live-change confirmation
going_liveActivation requires confirmSpend
budget_and_going_liveActivation and potential spend increases on ACTIVE objects require confirmSpend
all_live_changesThe preceding spend approvals plus confirmLiveChange for any change to an ACTIVE object

Archive and delete always require confirmIrreversible. Budget changes above 50% in either direction always require allowLargeChange. These safeguards apply under every approval rule. ACTIVE means the object's configured status; a paused parent can still prevent delivery. Preview warns about parent status and changes that may reset learning.

Hold Ad Creation blocks potential spend increases, including increases on paused objects. Pauses, archive, delete and decreases remain available. Account write restrictions and CLI access blocks still apply.

CLI Commands

ads edit:status ad 12345 --paused --account act_123 --preview-only
ads edit:archive campaign 12345 --account act_123 --preview-only
ads edit:delete adset 12345 --account act_123 --preview-only
ads edit:rename ad 12345 "New Name" --account act_123 --preview-only
ads edit:budget campaign 12345 --daily 120 --account act_123 --preview-only
ads edit:spend-cap 12345 none --account act_123 --preview-only
ads edit:spend-limits 12345 --min 10 --max 50 --account act_123 --preview-only
ads edit:bid adset 12345 --strategy COST_CAP --amount 4 --account act_123 --preview-only
ads edit:schedule adset 12345 --end 2026-12-01T00:00:00Z --account act_123 --preview-only

Without --preview-only, interactive commands show a before/after table, warnings and separate approval prompts. Non-interactive apply requires --yes plus every applicable confirmation flag: --confirm-spend, --confirm-live-change, --confirm-irreversible and --allow-large-change. --yes alone does not approve a spend increase or irreversible change. All commands accept --account and --json.

To apply a plan already reviewed, use ads edit:apply <planId> --yes with its required confirmation flags. This command submits the existing plan without creating a new preview. With --json, an edit command returns the preview alone or one JSON object containing preview and the apply result.

History And Undo

GET /api/v1/inbox/history reads your Agent Inbox suggestions and direct edit outcomes retained within the last 90 days, without calling Meta. MCP exposes ads_list_inbox_history; the CLI supports ads inbox:history and ads inbox history, with table or --json output. Read permission is required. Hidden and Read-off accounts are excluded, and explicit requests for those accounts return 403.

Optional filters are accountId (or X-Ad-Account), campaignId, since, until, reviewId (one run), status, kind, action, limit and cursor. Without an account, the API reads all permitted accounts; CLI/MCP use the selected account if configured. Statuses are waiting, applied, failed, cancelled, skipped and stale; waiting includes applying and failed includes partial results. Kinds are edit and duplicate; actions are operation names such as set_bid, rename, duplicate and undo. Date filters accept inclusive ISO dates or timestamps with a timezone. A date-only until includes the whole UTC day. Direct edits match campaign filters only when that ID was recorded.

The response contains items and paging: { hasMore, cursor }. Each item includes time, run metadata (reviewId, runTitle, clientName, source), entity IDs/names, action, before/after, reason, reasonEdited, status, specific outcome, safe errors and appliedAt. revisions lists every change made to a suggestion after the agent made it, oldest first: at, by (user for the web Agent Inbox, or agent with its source and clientName), kind (value or note), action (edited, or restored_to_agent when the agent's original value or note was put back, also shown as restoredToAgent: true), field, and before/after (the proposed value, or the note text). revisedAt is the latest value revision; suggestions revised before revisions were recorded have revisedAt and an empty revisions list. ads_get_edit_review rows include the same revisions when a suggestion was changed. Time is resolution time when recorded, otherwise creation time; results are newest first. Page with limit (1–100, default 50) and the returned cursor, keeping the same filters. Existing review reads keep their seven-day scope, and the existing history/undo endpoints below keep their behavior.

Use GET /api/v1/edits?limit=25&after=<cursor> for one history page and GET /api/v1/edits/<editId> for its full result. Both are scoped to the authenticated user and selected account.

ads edits --account act_123 --json
ads edit:show <editId> --account act_123 --json
ads edit:undo <editId> --account act_123 --preview-only

POST /api/v1/edits/<editId>/undo creates a new preview restoring the before values of applied reversible changes. In review mode the inverse becomes review proposals. In direct mode apply the plan through the usual approval flow. The web Undo action previews and applies reversible edits with session approval. Archive and delete cannot be undone and are listed as not_reversible. An edit containing only irreversible changes returns no undo plan. Undo is based on current Meta values and can be refused by current budget, schedule, status or hold rules.

Partial Results And Limits

Apply returns an editId and a status for each field change: applied, failed, skipped or pending, with safe error codes where relevant. Pending changes were not sent yet and remain in your Agent Inbox with a reason. Apply the same review again to send them; no new proposal is needed. History excludes unsent changes. A response with partial: true uses HTTP 200. Inspect every result and the current Meta settings before planning the remaining work. Never retry a partial apply blindly.

A repeated apply of the same plan returns its stored result. An interrupted apply returns PLAN_IN_PROGRESS; check history before taking further action. Verification failure means the update may have reached Meta and must be inspected before another change.

Preview and cancellation are each limited to 30 requests per minute, apply and undo to 10 each, and list/get history to 60 each. Ads Uploader puts no budget or pause of its own on an edit's Meta calls: they go straight to Meta, and one apply runs at a time per ad account. If Meta throttles a request (Meta error 4, 17, 32, 613 or 80000-80014, or HTTP 429), the apply stops there and says so with Meta's code and Meta's own wait, for example Meta asked us to slow down (Meta error 17). Wait about 5 minutes and try again. The stop reason and each waiting change carry source: "meta", metaCode and metaSubcode. Untouched suggestions stay pending for later approval.

MCP Tools

  • ads_edit_cancel: cancel staged proposals without changing Meta
  • ads_discard_launch: discard a launch waiting in the Agent Inbox; the saved build stays
  • ads_edit_preview: queue review proposals or inspect a direct plan and required approvals
  • ads_edit_apply: apply a reviewed plan with explicitly approved confirmation flags
  • ads_edit_undo: preview restoration of reversible changes
  • ads_list_edit_reviews: list Edit Reviews
  • ads_get_edit_review: read proposal statuses and edit IDs
  • ads_list_inbox_history: read retained suggestions, agent notes, runs and outcomes for up to 90 days
  • ads_list_history with type: "changes": read changes from Ads Uploader History
  • ads_list_edits: deprecated; use ads_list_history with type: "changes"
  • ads_get_edit: inspect one edit's results

The hosted MCP only advertises edit tools when the user has edit access. Always preview and show the user the changes. Set confirmation flags only after the user explicitly approves those changes. Never retry a partial apply blindly. Archive and delete cannot be undone.